구글에 pwntools 검색 후 깃허브 링크로 들어감.
$ python3.5 //파이썬 인터프리터
>>> from pwn import *
remote: 원격 서비스에 접속하여 통신할 때 사용
-p = remote(“127.0.0.1”,5000)
127.0.0.1 주소에 열려있는 5000번 포트에 TCP 연결을 맺음. 연결이 성공적이면 remote 객체 리턴
-p = remote(“127.0.0.1”,5000, typ=’udp’)
typ에 udp 옵션을 전달하면 UDP 연결을 맺음.
process: 로컬 프로세스를 실행하여 통신할 때 사용되는 클래스
-p = process(“/home/theory/binary”)
로컬 파일시스템에 존재하는 /home/theory/binary 바이너리 실행
-p = process([“/home/theory/binary”,”AAAA”], env={“LD_PRELOAD”:”./libc.so.6”})
argv[1]에 “AAAA” 문자열을 전달하고 LD_PRELOAD 환경 변수를 ./libc.so.6으로 설정하여 실행함.
ssh: 서버에 접속하여 통신할 때 사용되는 클래스
-p = ssh(“theory”,”127.0.0.1”, port=22, password=”theory”)
127.0.0.1 서버에 theory 계정으로 ssh 로그인을 하여 연결하는 코드
send: 연결이 맺어진 객체에 데이터를 보내는 메소드
-p = remote(“127.0.0.1”, 22)
-p.send(“AAAA”)
”127.0.0.1”의 22번 포트에 연결한 후 “AAAA”를 보냄
sendline: 연결이 맺어진 객체에 개행을 포함하는 데이터를 보내는 메소드
-p = remote(“127.0.0.1”, 22)
-p.sendline(“AAAA”)
sendline은 send 메소드와 달리 “AAAA\n”을 송신함.
recv: 연결이 맺어진 객체로부터 수신한 데이터를 리턴하는 메소드
p = remote(“127.0.0.1”, 22) print p.recv(1024) SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.8
”127.0.0.1”의 22번 포트에 연결했을 때 출력되는 문자열을 1024바이트만큼 수신하여 출력함
recvline: 연결이 맺어진 객체로부터 개행까지 수신하여 리턴하는 메소드
P = remote(“127.0.0.1”,22) Print p.recvline() SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.8
읽을 바이트 수를 지정해주지 않고 개행까지 읽어들임
recvunitl: 연결이 맺어진 객체에서 원하는 문자 혹은 문자열까지 읽는 메소드
P = remote(“127.0.0.1”, 22) Print p.recvuntil(“SSH”) SSH
“SSH” 문자열까지 읽어들이고 출력함.`
sendafter: 원하는 문자 혹은 문자열까지 읽은 뒤 데이터를 보내는 함수
P = remote(“127.0.0.1”, 22) Print p.sendafter(“\n”,”AAAA”) SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.8
“127.0.0.1”의 22번 포트에 연결한 후 개행까지 읽어들이고 “AAAA”를 보냄.
Sendlineafter: 원하는 문자 혹은 문자열까지 읽은 뒤 개행을 포함하는 데이터를 보냄
P = remote(“127.0.0.1”, 22) Print p.sendlineafter(“\n”, “AAAA”) SSH-2.0-OpenSSH_7.2p2 Ubuntu-4ubuntu2.8
“127.0.0.1”의 22번 포트에 연결한 후 개행까지 읽어들이고 “AAAA\n”을 보냄.
P8: 1 바이트의 데이터를 패킹하는 함수
Print p8(0x41) A
0x41을 문자 형태로 변환하여 A를 리턴
p16: 2 바이트의 데이터를 패킹하는 함수
Print p16(0x4142) BA
0x4142를 리틀 엔디언 형태로 변환하여 BA를 리턴
p32: 4 바이트의 데이터를 패킹하는 함수
Print p32(0x41424344) DCBA
0x41424344를 리틀 엔디언 형태로 변환하여 DCBA를 리턴
p64: 8 바이트의 데이터를 패킹하는 함수
Print p64(0x4142434445464748) HGFEDCBA
0x4142434445464748을 리틀 엔디언 형태로 변환하여 HGFEDCBA를 리턴
Print p16(0x4142, endian=’big’) AB
빅 엔디언으로 변환하기 위해서는 endian=’big’을 명시해주면 됨.
u8: 1 바이트의 데이터를 언패킹하는 함수
Print u8(“A”) 65
A를 정수 형태로 변환하여 65를 리턴
u16: 2 바이트의 데이터를 언패킹하는 함수
Print u16(“AB”) 16961
AB를 정수 형태로 변환하여 16961을 리턴
hex 함수를 사용하여 16진수로 변환하면 0x4241임을 알 수 있음
u32: 4 바이트의 데이터를 언패킹하는 함수
Print u32(“ABCD”) 1145258561
ABCD를 정수 형태로 변환하여 1145258561을 리턴
hex 함수를 사용하여 16진수로 변환하면 0x41424344임을 알 수 있음
u64: 8 바이트의 데이터를 언패킹하는 함수
Print u64(“ABCDEFGH”) 5208208757389214273
ABCDEFGH를 정수 형태로 변환하여 5208208757389214273를 리턴.
hex 함수를 사용하여 16진수로 변환하면 0x4142434445464748임을 알 수 있음Print u16(“AB”, endian=’big’) 16706
빅 엔디언으로 변환하기 위해서는 endian=’big’을 명시해주면 됨.
Elf: Elf를 사용하면 ELF 헤더를 가지고 있는 파일의 경우 파일의 여러 데이터를 가져올 수 있음
elf = ELF(‘./elf’)
파일 로딩 가능. 해당 파일에 적용된 보호 기법을 알 수 있고 파일의 객체가 elf 변수에 저장됨.plt: 바이너리에 존재하는 PLT 주소를 가져옴
got: 바이너리에 존재하는 GOT 주소를 가져옴
symbols: 바이너리에 존재하는 함수의 주소를 가져옴
search: 바이너리에 존재하는 문자열의 주소를 가져옴
get_section_by_name: 바이너리에 존재하는 섹션의 주소를 가져옴
read: 원하는 바이너리 주소의 데이터를 읽어옴
write: 원하는 바이너리 주소에 데이터를 씀
파일 로딩
plt 주소를 가져옴
got 주소를 가져옴
giveshell 함수의 주소를 가져옴
bss 섹션과 text 섹션의 주소를 가져옴
0x400000 주소의 데이터를 4 바이트 읽어옴. 밑은 main 함수의 데이터를 4바이트 읽어옴.
asm: 명령어를 인자로 전달하면 바이트로 변환
두 개 이상의 명령어 또한 변환 가능
기본적으로 x86 아키텍처 지원
명령어를 전달받아 바이트로 변환. 두 개 이상의 명령어를 명령어 구분자를 사용하여 변환
시스템 아키텍처마다 명령어 혹은 레지스터가 다르기 때문에 아키텍처를 따로 지정해야함
context.arch를 사용하여 원하는 아키텍처를 지정하여 변환
disasm: 특정 바이트를 명령어로 변환함
Shellcraft: 원하는 시스템 콜과 인자를 지정해주면 쉘코드를 작성해주는 기능
dir(shellcraft): shellcraft에서 지원하는 시스템 콜 확인
Interactive: 연결이 맺어진 객체와 상호작용을 할 수 있도록 하는 함수
Cyclic: 버퍼의 크기를 제대로 계산하지 않고 수많은 데이터를 입력해 리턴 주소가 덮였을 때 버퍼와 리턴 주소의 간격을 정확하게 알아낼 수 있음
Cyclic(2048): 4바이트마다 다른 문자열로 2048 바이트의 문자열
Cyclic(16, n=1): N 옵션에 따라 바뀌는 바이트의 인덱스는 변경 가능
ROP: 코드 가젯을 연결하여 실행하려는 코드를 작성해주는 기능
Fmtstr: 연산이 필요없이 주소와 값을 입력하면 해당 주소를 덮어쓸 수 있도록 코드 작성 가능