pwntools 사용법

133210·2021년 7월 21일
0

2020 시스템

목록 보기
2/25
post-thumbnail

1. 설치

구글에 pwntools 검색 후 깃허브 링크로 들어감.
해당 사진 회색 박스에 있는 명령어들 사용하여 설치 (Ubuntu 16.04)

2. 실행

$ python3.5  //파이썬 인터프리터
>>> from pwn import * 

3. 기능

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: 연산이 필요없이 주소와 값을 입력하면 해당 주소를 덮어쓸 수 있도록 코드 작성 가능

0개의 댓글