Protostar Stack0 문제
1. Protostar Stack0
https://exploit.education/protostar/stack-zero/
Stack Zero :: Andrew Griffiths' Exploit Education
Stack Zero This level introduces the concept that memory can be accessed outside of its allocated region, how the stack variables are laid out, and that modifying outside of the allocated memory can modify program execution. This level is at /opt/protostar
exploit.education
위 사이트에 들어가면 Stack0의 소스코드를 볼 수 있다.
프로토스타에서 /opt/protostar/bin/stack0 위치에서 문제를 확인할 수 있다.
하지만 나는 kali linux에서 문제를 풀어보도록 하겠다.
kali linux에서 위 사이트의 Stack0의 소스코드를 복붙하여 Stack0.c 파일을 만들어 주었다.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
volatile int modified;
char buffer[64];
modified = 0;
gets(buffer);
if(modified != 0) {
printf("you have changed the 'modified' variable\n");
} else {
printf("Try again?\n");
}
}
위의 소스코드를 보면 modified 변수와 buffer 배열이 선언되어 있고 modified의 값은 0으로 설정되어있다. 그리고 gets로 buffer에다가 문자들을 입력받는 것을 확인할 수있다.
if문에서 modified가 0이 아니면 "you have changed the 'modified' variable" 이라는 문자열을 출력하고 0일경우 "Try again?"이라는 문자를 출력한다.
이 문제는 modified를 0이 아닌 다른 문자로 바꾸어서 "you have changed the 'modified' variable"이라는 문자열을 출력하는 문제인것 같다.
gcc -z execstack -no-pie -w -o Stack0 Stack0.c 명령어를 통하여 스택영역 바이너리 실행권한을 주었고 메모리가 랜덤하게 되지 않도록 설정하였다.
ls 명령어로 확인해보니 컴파일이 잘된것을 알 수 있다.
Stack0 파일을 실행을 해보면 gets로 문자열을 받도록 멈춰있다. 아무값으로 입력을 하고 엔터를 누르면 Try again?이라고 출력이 된다.
왜냐하면 modified는 0으로 설정되어 있어 if문에서 거짓이 되기 때문이다.
python -c "print('a'*80)" 명령어로 a를 80개를 만들었고 그 값을 Stack0 입력값에 넣었다.
그러니 you have changed the 'modified' variable이라고 출력이 되어 modified값이 변경된것을 알 수 있다.
자세하게 알기 위해 gdb를 이용하여 확인해보겠다.
gdb를 실행하고 set disassembly-flavor intel 명령어를 통하여 어셈블리 문법을 intel 형식으로 보이도록 설정하였다.
disas main 명령어를 통하여 main함수를 디스어셈블하여 확인 할 수 있다.
어셈블리 언어를 자세히 살펴보니 test명령어가 보인다, test 명령어는 값을 비교할때 쓰는 연산으로 값이 0인지 아닌지 판단할 수 있다.
c언어 소스코드를 보면 if문에서 modified가 0인지 아닌지 확인하고 있는 부분이 있는데 이 부분이 test로 디스어셈블 된것이라고 판단된다.
test부분인 main+42위치에 브레이크 포인터를 걸고 run으로 실행하였고 값은 아무 값이나 넣어 주었다.
info reg $eax 명령어로 eax값을 확인해 보았다. eax에 0이라는 값이 들어있음을 알 수 있고 따라서 modified가 변조 되지 않았음을 알 수 있다.
modified를 변조하기 위해 run명령어로 재실행한 후 무수히 많은 입력값을 넣었다.
eax값을 확인해보니 0x616161로 a가 들어있음을 알 수 있다. modified가 변조된 것이다.
스택을 확인해보니 0x61로 a가 쌓여있음을 확인할 수 있다.
modified가 스택에 어디있는지 확인하기 위해 그림 11번에 코드를 살펴보니 eax값이 rbp -0x4에서 값이 왔으므로 rbp -0x4의 위치부터 4바이트가 modified의 할당된 스택값임을 알 수 있다.
rbp값은 0x7fffffffdf00인것을 알 수 있고 rbp -0x4의 위치는 7fffffffdefc이다.
그림 10번에 7fffffffdefc위치에 modified값이 변조되었음을 확인할 수 있다.
잘 이해가 안될수도 있으니 스택구조를 단계별로 그림으로 표현하였다.
1. rbp를 push함
2. rbp값을 rsp값과 같도록 이동시켜서 새로운 스택 프레임을 만들었음
3. 0x60바이트값만큼 스택 할당
4. rbp-0x4위치에 0을 넣었음(modified 변수 넣음), rbp-0x50위치에 eax를 넣었음(gets함수로 넣은 값)
5. rbp-0x50위치에 무수히 많은 입력값을 넣으면 modified를 변조할 수 있다.
그림 14와 같이 스택에 저장된다는것을 알 수 있다.
마무리로 정리하자면 gets로 입력받은 문자열들을 eax값으로 받아 rbp-0x50위치에 저장되고 modified 변수는 rbp -0x4위치에 저장된다. 0x50 - 0x4를 하면 0x44이고 10진수로 76바이트다.
gets로 76바이트를 입력하고 그다음 바이트부터 modified에 접근을하게된다.
a를 80바이트만큼 채우면 modified함수가 aaaa로 바뀌겠지
처음이라 자세하게 쓰지만 다음부터는 이정도로 자세하게는 안할거니깐 스택프레임을 이해하고 싶으면 내가 작성한 stack0을 다시 읽어봐라!!