HW_chick hacker
과유불급 문제 - CTF문제 본문
스택 버퍼오버플로우를 이용한 CTF문제를 풀려면 스택 프레임 구조를 파악하고 알고 있어야 한다.
스택이란?
Stack : Last in First out (LIFO)를 기반으로 작동하는 자료구조. push(), pop() 등의 함수를 사용하여 조작
스택 영역은 함수의 호출과 함께 할당됩니다. 함수가 끝나면 자연스럽게 사라지죠.
지역 변수, 매개 변수, 반환값(Return)들이 이 곳에 저장됩니다.
특징이 있다면 스택은 높은 주소에서 낮은 주소로 커지는데, 그 이유는 운영 체제의 핵심인 Kernel을 절대로 침범할 수 없게 하기 위해서입니다.
스택에서 꼭 알아야 할 두 가지 레지스터가 있는데, ebp와 esp라는 녀석입니다.
ebp는 베이스 포인터입니다. 스택에서 제일 낮은 위치(메모리 상에선 가장 높은 주소)를 가리킵니다.
esp는 스택 포인터입니다. 스택이 지금 어디에 있는지를 가리킵니다.
스택 프레임이란?
Stack Frame : 스택 영역에 저장되는 함수의 정보, 공간
어떤 함수던 실행될 때 스택 프레임을 생성합니다.
그 안에는 매개 변수, Return, 지역 변수들이 자리잡고 있죠.
자, 함수가 호출되었다!! 라고 생각해 보겠습니다.
우선 스택 프레임을 만드는 단계인 프롤로그가 진행됩니다,
push ebp
mov ebp, esp

베이스 포인터를 스택에 저장 후 스택 포인터를 베이스 포인터에 저장합니다.
이제 함수의 역할이 끝났으니 스택 프레임이 소멸되는 단계가 필요합니다. 이를 에필로그라고 해요.
mov esp, ebp
pop ebp
위 명령어로 인해 함수의 역할이 끝난 후 위 그림과 같은 상태로 돌아가는 겁니다.
pop 명령을 통해 RET 으로 이동하겠죠.
이제 어셈블리어를 뜯어봤을 때 프롤로그와 에필로그가 보인다!! 하면 함수의 시작과 끝이라고 생각하시면 됩니다.
버퍼 오버플로우
버퍼 오버플로우 취약점은 스택 프레임 내에서 선언된 지역 변수가 다른 영역을 침범해 발생합니다.
#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_me(){
system("/bin/sh");
}
void food() {
puts("do you like fastfood?");
puts("choose!");
puts("[h]amberger");
puts("[p]izza");
puts("[c]hiken");
printf("> ");
}
int main(int argc, char *argv[])
{
char name[0x50] = {};
char choose[2] = {};
initialize();
while(1) {
food();
read(0, choose, 2);
switch(choose[0]){
case 'h':
printf("i like hamberger!");
break;
case 'p':
printf("what do you want?");
read(0,name,79);
break;
case 'c':
printf("i don't like chiken.\n");
printf("pick another one: ");
read(0,name,0x100);
return 0;
default:
break;
}
}
}
코드를 보면 main함수에서 name은 0x50인 80바이트이다.
64비트로 되어 있어 80바이트+8(sfp)+실행흐름 바꿀 주소로 만들어 파이썬코드를 짜서 익스플로어 할겁니다.
case 'c'를 선택하여 버퍼주소를 넣어서 버퍼오버플로우를 할 것이다.
read_me 함수를 볼 때 system@plt에 /bin/sh가 존재 한다.
#!/bin/bash 란? 쉘스크립트 작성 시 제일 먼저 #!/bin/bash 를 기재하는 이유는 해당 파일을 bash 쉘로 실행시키겠다는 의미이다.,
gdb로 main함수를 뜯어 보겠다.

위 두줄을 볼 떄 프롤로그를 확인할수 있다.
read_me를 확인할수 없지만 disas main을 확인 후 쉘 코드 실행시키는 함수를 read_me함수를 확인해 보겠다.

버퍼의 공간이 read_me함수에 read_me<+0> 주소값 0x401214이므로 ret 공간에 주소를 채워봐야한다.
pwntool을 이용하여 파이썬코드를 짜서 익스시킬 것인데 0x401214 주소를 ret공간에 흐름을 바꿀 주소를 넣으면 문제가 생긴다. 나도 모르는 문제지만 주소에 1 이상을 더하면 익스 할 때 정상적으로 돌아간다 -.- ;;;
그래서 read_me<+4> 주소를 가져와 버퍼시켰다.,

파이썬 코드는 먼저 case 'c'를 선택 창에 두고 c코드를 보면 name 80바이트 이상인 name을 0x100를 read하겠다고 볼 수 있다. 먼저 sendline을 이용하여 'c'를 통해 다음 단계로 넘어가고 'a' 값을 88바이트(80바이트 + 8(SFP)) + p64 비트인 ret공간 주소를 넣어 payload문을 작성하여 익스하였다.

익스 후 해당 flag값이 있는 경로를 찾아가서 flag값을 찾으면 끝난다.,
마무리

우리 동아리 "협곡의 살모사"님이 만든 문제인데
저로써는 포너블이 거의 처음이라 파악하고 공부하고 푸는데 오래 걸렸다.
"협곡의 살모사"님 문제좀 살살 내주세요 -.-;;;
'Activity > Hawkis' 카테고리의 다른 글
| Plz Recovery - CTF문제 (0) | 2023.07.05 |
|---|---|
| babyforms, babysheet - CTF문제 (0) | 2023.07.05 |
| 웹 개발 및 SQL Injection - SQL Injection (2) (0) | 2023.02.04 |
| 웹 개발 및 SQL Injection - 개발 및 DB연동 (1) (1) | 2023.02.03 |
| 어셈블리어 - 이름 출력 (0) | 2023.01.08 |