process
p = process('./test') |
로컬 바이너리를 대상으로 할 때 사용함
remote
p = remote('example', 31337) |
원격 서버에 있는 바이너리를 대상으로 할 때 사용함
send
from pwn import * p = process('./test') p.send('A') # ./test에 'A'를 입력 p.sendline('A') # ./test에 'A'+'\n'을 입력 p.sendafter('hello', 'A') # ./test가 'hello'를 출력하면, 'A'를 입력 p.sendlineafter('hello', 'A') # ./test가 'hello'를 출력하면, 'A' + '\n'을 입력 |
데이터를 프로세스에 전송하기 위해 사용함.
recv
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에 저장(5바이트 이상 받지 않으면 프로그램이 계속 기다림) data = p.recvuntil('hello') # p가 출력하는 데이터를 'hello'가 출력될 때까지 받아서 data에 저장 data = p.recvall() # p가 출력하는 데이터를 프로세스가 종료될 때까지 받아서 data에 저장 |
프로세스에서 데이터를 받기 위해 사용함.
packing & unpacking
from pwn import * s32 = 0x41424344 s64 = 0x4142434445464748 print(p32(s32)) print(p64(s64)) s32 = "ABCD" s64 = "ABCDEFGH" print(hex(u32(s32))) print(hex(u64(s64))) ------------------출력값------------------ b'DCBA' b'HGFEDCBA' 0x44434241 0x4847464544434241 |
익스플로잇을 작성하다 보면 어떤 값을 리틀 엔디언의 바이트 배열로 변경하거나, 또는 역의 과정을 거쳐야 하는 경우가 자주 있음.
interactive
from pwn import * p = process('./test') p.interactive() |
셸을 획득했거나, 익스플로잇의 특정 상황에 직접 입력을 주면서 출력을 확인하고 싶을 때 사용하는 함수. 호출하고 나면 터미널로 프로세스에 데이터를 입력하고, 프로세스의 출력을 확인할 수 있음.
ELF
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에 저장 |
ELF 헤더에는 익스플로잇에 사용될 수 있는 각종 정보가 기록되어있음.
context.log
from pwn import * context.log_level = 'error' # 에러만 출력 context.log_level = 'debug' # 대상 프로세스와 익스플로잇간에 오가는 모든 데이터를 화면에 출력 context.log_level = 'info' # 비교적 중요한 정보들만 출력 |
익스플로잇에 버그가 발생하면 익스플로잇도 디버깅해야 함. pwntools에는 디버그의 편의를 돕는 로깅 기능이 있으며, 로그 레벨은 context.log_level변수로 조절할 수 있음.
context.arch
from pwn import * context.arch = "amd64" # x86-64 아키텍처 context.arch = "i386" # x86 아키텍처 context.arch = "arm" # arm 아키텍처 |
아키텍쳐 정보를 프로그래머가 지정할 수 있게 해줌. 이 값에 따라 몇몇 함수들의 동작이 달라짐.
shellcraft
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 |
자주 사용되는 셸 코드들이 저장되어 있어서, 공격에 필요한 셸 코드를 쉽게 꺼내 쓸 수 있게 해줌. 정적으로 생성된 셸 코드는 셸 코드가 실행될 때의 메모리 상태를 반영하지 못함. 또한, 프로그램에 따라 입력할 수 있는 셸 코드의 길이나, 구성 가능한 문자의 종류에 제한이 있을 수 있는데, 이런 조건들도 반영하기 어러움. 따라서 제약 조건이 존재하는 상황에서는 직접 셸 코드를 작성하는 것이 좋음.
이 부분은 직접 코드를 만들어봐야 이해될듯.
asm
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' |
셸 코드를 기계어로 어셈블 할 수 있음.이 기능도 대상 아키텍쳐가 중요하므로, 아키텍쳐를 미리 지정해야함.
공식 문헌 자료
https://docs.pwntools.com/en/latest/
pwntools — pwntools 4.10.0dev documentation
© Copyright 2016, Gallopsled et al. Revision 807f534c.
docs.pwntools.com
공부는 여기서
https://learn.dreamhack.io/59#5
로그인 | Dreamhack
dreamhack.io
'시스템해킹 > 공부' 카테고리의 다른 글
pwntool 사용법 (0) | 2024.04.29 |
---|---|
리눅스 리버싱 관련 명령어2 (0) | 2023.01.20 |
리눅스 리버싱 관련 명령어 (2) | 2023.01.17 |
(Dreamhack) 리눅스 메모리 구조 (0) | 2023.01.16 |