Fixed
Status Update
Comments
pa...@google.com <pa...@google.com> #2
Thank you for this detailed write-up!
mnissler, you'll be awake and in working hours soonest; can you please take a look? Thanks!
mnissler, you'll be awake and in working hours soonest; can you please take a look? Thanks!
[Deleted User] <[Deleted User]> #3
Setting milestone and target because of Security_Impact=Stable and high severity.
For more details visithttps://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
For more details visit
mn...@google.com <mn...@google.com> #4
This is a chronos -> root priv esc, agree on severity high rating.
Let me break this down into individual bugs:
1. PPPD config injection:https://crbug.com/1077754
2. unrestricted setgid() in shill sandbox:https://crbug.com/1077756
(The trick with debugfs is neat, but presence of debugfs isn't really a risk - an attacker with cmd exec can just open raw block devices and mess around. Also, TIL that while the Linux VFS doesn't allow to create directory hard links, ext4 supports them and they can in fact be created via debugfs as demonstrated in exploit.sh)
3. TOCTOU race in cupsd.conf init script:https://crbug.com/1077761
(to be completed, need to attend a meeting now)
Let me break this down into individual bugs:
1. PPPD config injection:
2. unrestricted setgid() in shill sandbox:
(The trick with debugfs is neat, but presence of debugfs isn't really a risk - an attacker with cmd exec can just open raw block devices and mess around. Also, TIL that while the Linux VFS doesn't allow to create directory hard links, ext4 supports them and they can in fact be created via debugfs as demonstrated in exploit.sh)
3. TOCTOU race in cupsd.conf init script:
(to be completed, need to attend a meeting now)
mn...@google.com <mn...@google.com> #5
And one more: issue 172219872 for the command execution from writable file systems in run_oci.
For the ghostscript code to run the file replacement, that's certainly interesting from a technical perspective, but I don't see why this is needed vs. just executing the equivalent shell code you list above?
For the ghostscript code to run the file replacement, that's certainly interesting from a technical perspective, but I don't see why this is needed vs. just executing the equivalent shell code you list above?
ro...@rorym.cnamara.com <ro...@rorym.cnamara.com> #6
In my testing, spinning with bash wasn't fast enough. In this context it's shellcode as in raw assembly, so it's not running an entire dynamic binary with all the syscalling that entails.
The non pseudo shellcode is:
mov eax, 0x15
lea rdi, [rip + 0x3c]
mov esi, 0
syscall
cmp rax, 0
jne 0
mov eax, 0x54
lea rdi, [rip + 0x23]
syscall
mov eax, 0x58
lea rdi, [rip + 0x29]
lea rsi, [rip + 0xe]
syscall
mov eax, 0x3c
mov edi, 0
syscall
[followed by some strings]
The non pseudo shellcode is:
mov eax, 0x15
lea rdi, [rip + 0x3c]
mov esi, 0
syscall
cmp rax, 0
jne 0
mov eax, 0x54
lea rdi, [rip + 0x23]
syscall
mov eax, 0x58
lea rdi, [rip + 0x29]
lea rsi, [rip + 0xe]
syscall
mov eax, 0x3c
mov edi, 0
syscall
[followed by some strings]
ro...@rorym.cnamara.com <ro...@rorym.cnamara.com> #7
Attached is the actual code that is run by Ghostscript, dropped as 'race.shellcode' in exploit.sh
mn...@google.com <mn...@google.com> #8
Thanks Rory for clarifying on the ghostscript motivation.
mn...@google.com <mn...@google.com> #9
I'll mark this fixed after the config injection fix has landed since it breaks the chain, additional work to fix/improve things are tracked in the child bugs.
[Deleted User] <[Deleted User]> #10
This is sufficiently serious that it should be merged to beta. But I can't see a Chromium repo commit here, so you will need to investigate what - if anything - needs to be merged to M83. Is there a fix in some other repo which should be merged? Or, perhaps this ticket is a duplicate of some other ticket which has the real fix: please track that down and ensure it is merged appropriately.
For more details visithttps://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
For more details visit
[Deleted User] <[Deleted User]> #11
This bug requires manual review: To minimize risk and increase branch stability, all merge requests are being reviewed manually by the release team.
Before a merge request will be considered, the following information is required to be added to this bug:
1. Does your merge fit within the Merge Decision Guidelines?
- Chrome:https://chromium.googlesource.com/chromium/src.git/+/master/docs/process/merge_request.md#when-to-request-a-merge
- Chrome OS:https://goto.google.com/cros-release-branch-merge-guidelines
2. Links to the CLs you are requesting to merge.
3. Has the change landed and been verified on master/ToT?
4. Why are these changes required in this milestone after branch?
5. Is this a new feature?
6. If it is a new feature, is it behind a flag using finch?
Please contact the milestone owner if you have questions.
Owners: benmason@(Android), bindusuvarna@(iOS), cindyb@(ChromeOS), srinivassista@(Desktop)
For more details visithttps://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Before a merge request will be considered, the following information is required to be added to this bug:
1. Does your merge fit within the Merge Decision Guidelines?
- Chrome:
- Chrome OS:
2. Links to the CLs you are requesting to merge.
3. Has the change landed and been verified on master/ToT?
4. Why are these changes required in this milestone after branch?
5. Is this a new feature?
6. If it is a new feature, is it behind a flag using finch?
Please contact the milestone owner if you have questions.
Owners: benmason@(Android), bindusuvarna@(iOS), cindyb@(ChromeOS), srinivassista@(Desktop)
For more details visit
na...@google.com <na...@google.com> #12
*** Boilerplate reminders! ***
Please do NOT publicly disclose details until a fix has been released to all our users. Early public disclosure may cancel the provisional reward. Also, please be considerate about disclosure when the bug affects a core library that may be used by other products. Please do NOT share this information with third parties who are not directly involved in fixing the bug. Doing so may cancel the provisional reward. Please be honest if you have already disclosed anything publicly or to third parties. Lastly, we understand that some of you are not interested in money. We offer the option to donate your reward to an eligible charity. If you prefer this option, let us know and we will also match your donation - subject to our discretion. Any rewards that are unclaimed after 12 months will be donated to a charity of our choosing.
Please contact security-vrp@chromium.org with any questions.
******************************
Please do NOT publicly disclose details until a fix has been released to all our users. Early public disclosure may cancel the provisional reward. Also, please be considerate about disclosure when the bug affects a core library that may be used by other products. Please do NOT share this information with third parties who are not directly involved in fixing the bug. Doing so may cancel the provisional reward. Please be honest if you have already disclosed anything publicly or to third parties. Lastly, we understand that some of you are not interested in money. We offer the option to donate your reward to an eligible charity. If you prefer this option, let us know and we will also match your donation - subject to our discretion. Any rewards that are unclaimed after 12 months will be donated to a charity of our choosing.
Please contact security-vrp@chromium.org with any questions.
******************************
na...@google.com <na...@google.com> #13
Congrats! The Panel decided to award $30,000 for this report. Nice one!
ro...@rorym.cnamara.com <ro...@rorym.cnamara.com> #14
Thank you!
ro...@rorym.cnamara.com <ro...@rorym.cnamara.com> #15
Has the Ghostscript vulnerability been reported upstream? Is this something you would normally take care of?
jo...@google.com <jo...@google.com> #16
I don't believe the Ghostscript vulnerability has been reported upstream. We don't have set guidelines for upstream reporting, if you haven't reported either we can probably do it.
ro...@rorym.cnamara.com <ro...@rorym.cnamara.com> #17
I have not reported it upstream either.
ro...@rorym.cnamara.com <ro...@rorym.cnamara.com> #19
No that should cover it, the specific bug is on .setlanguagelevel as linked above which should be enough info to fix.
[Deleted User] <[Deleted User]> #20
This bug has been closed for more than 14 weeks. Removing security view restrictions.
For more details visithttps://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
For more details visit
Description
<b>VULNERABILITY DETAILS</b>
Newline injection in an IPSec/L2TP VPN configuration can result in command execution as shill with capabilities. The capabilities can be leveraged to gain unrestricted root command execution.
This chain has been confirmed to work on non-dev-mode devices, however it will not work in guest mode since ARC is not running. Only the root file write -> command execution gadget is non functional in guest mode, the rest of the chain up to this stage works as expected.
<b>VERSION</b>
81.0.4044.127 (Official Build) (64-bit)
Platform 12871.76.0 (Official Build) stable-channel eve
Firmware Version Google_Eve.9584.195.0
<b>REPRODUCTION CASE</b>
=== Repro requirement: L2TP server ===
It’s necessary to have a standard IPSec/L2TP vpn server running for successful authentication necessary during the initial exploit. I used the Docker container ’hwdsl2/ipsec-vpn-server’ with the following environmental variables for credentials:
VPN_IPSEC_PSK=pskpassword
VPN_USER=user
VPN_PASSWORD=userpassword
=== Repro steps ===
Download and mount (via Files double click) pppd.rar, without renaming.
Navigate to ChromeOS Settings, open dev tools and paste in the following payload:
chrome.networkingPrivate.createNetwork(false, {
"Name": "test",
"Priority": 0,
"Type": "VPN",
"VPN": {
"AutoConnect": true,
"Host": "172.16.2.72",
"IPsec": {
"AuthenticationType": "PSK",
"Group": "",
"SaveCredentials": false,
"PSK": "pskpassword"
},
"L2TP": {
"LcpEchoDisabled": false,
"Username": "username\npppoptfile=/media/archive/pppd.rar/pppd.conf\n[lac ignore]",
"Password": "userpassword"
},
"Type": "L2TP-IPsec"
}
}, guid => {
chrome.networkingPrivate.startConnect(guid);
window.delvpn = () => chrome.networkingPrivate.forgetNetwork(guid);
})
Modifying the Host parameter to suit. PSK must match as configured for the Docker container.
The VPN connection will fail pretty quickly with a notification, but exploitation progress can be viewed at file:///tmp/err and file:///tmp/log
DETAILS
=== shill cmdexec ===
The ‘Username’ field of an L2TP configuration is inserted into xl2tpd.conf without escaping [1], allowing for newline injection and control over the fields in the config. This configuration file can include the pppoptfile line which contains the configuration for the pppd daemon executed once the ipsec tunnel is up.
By pointing this option to a file in a readable location (ie the mounted rar file in /media/archive), we can modify the configuration for the resulting pppd and insert an ‘init’ line, which will execute the provided argument (nominally to initialize the serial line).
This results in command execution as shill:shill, with a handful of capabilities, notably CAP_SETGID, CAP_KILL. [2]
[1]
[2]
=== Symlink LSM bypass ===
Since there are no restrictions on setgid like there are on setuid, the command execution can change gid at will. By changing group to ‘disk’, the command execution can use the debugfs tool to modify the filesystem at /dev/mapper/encstateful (since encstateful is g+rw).
/var/cache/cups is removed if present, and /var/cache/echo is hardlinked to /var/cache/cups. Since the LSM check is by inode, and directory hardlinks share an inode, symlinks inside /var/cache/cups are now allowed.
Once changes are made, memory pressure is applied to evict the inode caches such that the changes to /var/cache/cups take effect. This bit takes variable amounts of time but is very reliable, it uses dd to write increasingly large files to a tmpfs until stat reports that the inodes for /var/cache/echo and /var/cache/cups match.
The highest I’ve seen it go on my 8gb Pixelbook is 18Gb. Sometimes Chrome is oom killed (and restarted) but I’ve not seen the exploit itself killed.
=== root chown ===
Now that symlinks are allowed in /var/cache/cups, we can race between the mkdir and chown in the cups init script [1] to swap in a symlink. Specifically, rss is targeted since the init script will make it 0775 [2], and therefore whatever we chown via symlink can be written using our setgid capability.
Cups can be triggered using setgid to lp followed by curl against the unix socket at /run/cups/cups.sock.
[1]
[2]
=== Ghostscript race ===
To be fast enough to win the race, a type confusion in Ghostscript was exploited. The type confusion is in .setlanguagelevel [1] which is disabled at runtime by default. A copy of the Ghostscript Init files are made and patched to enable .setlanguagelevel and other exploit primitives.
Exploitation of this vulnerability is not ChromeOS specific, however, the exploitation script does parse /proc/self/maps to bypass ASLR. /proc/self/mem is also used for egg hunting but only for reliability purposes rather than a strict need.
while(access("/var/cache/cups/rss", F_OK) != 0);
rmdir("/var/cache/cups/rss")
symlink("/run/containers/android-run_oci", "/var/cache/cups/rss")
exit(0)
[1]
=== File write root command execution ===
At this stage, /run/containers/android-run_oci is owned by cups:cups and is 0775. Again using setgid we can replace the config.json with a non-symlinked, editable copy, and add in a poststop hook which defines a command to be executed by arc-setup when the container stops. [1]
Using CAP_KILL we can now kill the container, the pid of which is stored in container.pid. After a few seconds arc-setup will have executed our defined poststop command.
The command is executed as root without restriction, in this case an ssh server is started in 31337. The root key can be found at the bottom of file:///tmp/log
[1]
=== Step by step exploitation of the entire chain ===
1. rar mount to provide pppoptfile in a shill readable location
2. Javascript snippet in the Settings devtools will create a VPN and initiate connection
3. xl2tpd.conf is modified by the newline injection to add an attacker controlled pppoptfile
4. When the IPSec connection is made, xl2tpd will start pppd with the attacker controlled pppd.conf
5. The init script in pppd.conf is executed as shill:shill with capabilities, which executes exploit.sh:
=== Step by step exploitation walkthrough of exploit.sh: ===
1. A combination of gid cups rm and debugfs (For items that are not gid writable/removable) is used to fully remove /var/cache/cups
2. Debugfs creates a hard link from /var/cache/echo to /var/cache/cups
3. Starting from the current Gb of ram and increasing by 1Gb each time, a mount namespace is created with a new tmpfs of this size, which is then written to using dd. The namespace automatically tidies itself up when the tmpfs becomes full. This is looped until the inode cache is evicted and the cups and echo directories share an inode
4. cups is executed (by gid lp curl --unix-socket to trigger the upstart socket listener) to chown /var/cache/cups (aka echo), such that it is cups gid writable again. cups is killed as only the init script was needed
5. The ghostscript shellcode and exploitation .ps file are dropped and executed as gid cups, spinning on the creation of /var/cache/cups/rss to replace with a symlink to /run/containers/android-run_oci
6. cups is executed again, this time chowning through the rss symlink as placed by the racer from 5
7. SSH files are dropped, the oci config.json is modified to include the poststop hook
8. The Android container is killed, causing the poststop hook (sshd) to be executed
9. /var/cache/cups and /var/cache/echo are cleaned up. If this is not done, or the exploit fails, the machine may be powerwashed on next boot.
10. The root ssh key is copied to the log file to make it accessible to validate.
<b>CREDIT INFORMATION</b>
Reporter credit: Rory McNamara