STUDY/Pwnable

pwntools

da1seun9 2022. 10. 11. 01:49

개요

이번에 학교에서 새 컴퓨터에 대회에 필요한 툴들을 설치하는 김에 pwntools에 대해서 자세히 알아보는 시간을 가지게 되었다.
본 포스트는 드림핵을 포함한 pwntools에 대한 여러 정보를 재가공하여 하나로 모아 놓은 것이다.

pwntools이란?

python으로 작성된 exploit 작성을 간단하게 하기위해 만든 CTF framework, exploit 개발 라이브러리이다.
CTF 문제를 풀면서 계속 중복되는 코드가 발생하니깐 이거를 빠르고 간편하게 작성하기 위해서 pwntools을 만든 것이라고 한다.

pwntools 설치

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

pwntools api

process

로컬에 있는 바이너리를 대상으로 exploit할 경우 사용
(익스플로잇을 테스트하고 디버깅하기 위함)

p = process('./test')

remote

원격서버를 대상으로 할 때 사용하는 함수
서버를 대상으로 실제 공격을 할 때 사용

p = remote('192.168.10.2',65537)

send

데이터를 프로세스에 전송할 때 사용

p.send('A')
# p라는 프로세스에 'A'를 입력

p.sendline('A')
# p라는 프로세스에 'A'+'\n'을 입력

p.sendafter('hello','A')
# p라는 프로세스가 'hello'를 출력하면 'A'를 입력

p.sendlineafter('hello','A')
# p라는 프로세스가 'hello'를 출력하면, 'A'+'\n'을 입력

recv

프로세스에서 데이터를 받고 싶을 때 사용
recv(n) : 최대 n 바이트 만큼 받음, 받지 못해도 에러를 발생시키지 않음
recvn(n) : 정확히 n바이트의 데이터를 받지 못하면 계속 기다림

data = p.recv(1024)
# p가 최대 1024바이트까지 받아서 data에 저장

data = p.recvline()
# p가 출력하는 데이터를 '\n' 만날 때까지 받아서 data에 저장

data = p.recvn(5)
# p가 출력하는 데이터를 5바이트만 받아서 data에 저장

data = p.recvuntil('hello')
# p가 출력하는 데이터를 'hello'가 출력될 때까지 받아서 data에 저장

data = p.recvall()
# p가 출력하는 데이터를 프로세스가 종료될 때 받아서 data에 저장

packing & unpacking

p32 : 데이터를 32bit로 패킹
p64 : 데이터를 64bit로 패킹
u32 : 데이터를 32bit로 언패킹
u64 : 데이터를 64bit로 언패킹

interactive

셀을 획득하거나 직접 입력을 주면서 출력을 확인하고 싶을 때 사용
호출 시 터미널로 프로세스에 데이터를 입력하고 프로세스의 출력을 확인할 수 있음

p.interactive()

ELF

ELF헤더에는 exploit에 사용될 수 있는 각종 정보가 있음

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

exploit 코드에 버그 발생 시 디버깅할 때 사용

from pwn import *
context.log_level = 'error'
# 에러만 출력

context.log_level = 'debug' 
# 대상 프로세스와 익스플로잇간에 오가는 모든 데이터를 화면에 출력

context.log_level = 'info'  
# 비교적 중요한 정보들만 출력

context.arch

아키텍처 정보를 프로그래머가 지정할 수 있게 하며, 이 값에 따라 몇몇 함수들의 동작이 달라집니다.

from pwn import *
context.arch = "amd64" # x86-64 아키텍처
context.arch = "i386"  # x86 아키텍처
context.arch = "arm"   # arm 아키텍처

shellcraft

pwntools에는 자주 사용되는 쉘코드가 저장되어 있지만, 정적으로 생성된 것이기 때문에 실행 시, 메모리를 반영하지 못한다.

#!/usr/bin/python3
#Name: shellcraft.py
from pwn import *
context.arch = 'amd64' # 대상 아키텍처 x86-64
code = shellcraft.sh() # 셸을 실행하는 셸 코드 
print(code)

asm

어셈블리 기능임, 아키텍쳐를 미리 지정해야 함

from pwn import *
context.arch = 'amd64' # 익스플로잇 대상 아키텍처 'x86-64'
code = shellcraft.sh() # 셸을 실행하는 셸 코드
code = asm(code)       # 셸 코드를 기계어로 어셈블
print(code)

'STUDY > Pwnable' 카테고리의 다른 글

함수 호출 규약  (1) 2022.10.21
[Dreamhack] Shell_basic  (2) 2022.10.21
어셈블리어 기초  (0) 2020.01.15
환경변수 이용하는 법  (0) 2020.01.02
메모리 조작하기2  (0) 2019.12.24