일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- C++
- Bandit
- radare2
- 시스템프로그래밍
- 시스템해킹
- kernel
- 알고리즘
- wargame
- write up
- 리눅스 커널
- 시스템 프로그래밍
- 컴퓨터구조
- 어셈블리어
- C언어
- 리눅스커널
- 시스템
- Pwnable.kr
- 프로그래밍
- multiplexing
- 워게임
- css
- pwn.college
- 리눅스
- Leviathan
- 커널
- pwncollege
- 리버싱
- 하드링크
- 시그널
- 포너블
- Today
- Total
Computer Security
#4 pwntools 본문
1.설치
위 명령어들을 우분투에 설치
2.실행
$ python3
Python 3.6.9 (default, Apr 18 2020, 01:56:04)
[GCC 8.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pwn import *
>>>
위와 같이 pwntools를 import 했을 때, 에러가 발생하지 않으면 제대로 설치된 것이다.
초기 파이썬 익스플로잇 스크립트
#!/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를 사용한 익스플로잇 스크립트
#!/usr/bin/python3
from pwn import *
# Make TCP connection
r = remote("127.0.0.1", 31337)
# Build payload
payload = ""
payload += "Socket script"
payload += "\n"
# Send payload
r.send(payload)
# Print received data
data = r.recv(1024)
print(f"Received: {data}")
pwntools API 사용법
pwntools 모듈의 중요한 함수들을 설명하겠다.
1. process & remote
process 함수는 익스플로잇을 로컬 바이너리를 대상으로 할 때 사용하는 함수이고, remote 함수는 원격 서버를 대상으로 할 때 사용하는 함수다.
process는 보통 익스플로잇을 테스트하고 디버깅하기 위해, 그리고 remote는 대상 서버를 실제로 공격하기 위해 사용한다.
from pwn import *
p = process('./test') #로컬 바이너리 'test'를 대상으로 익스플로잇 수행
p = remote('example.com',31337) #'example.com'의 31337 포트에서 실행 중인 프로세스를 대상으로 익스플로잇 수행
2. send
send는 데이터를 프로세스에 전송하기 위해 사용한다.
pwntools에는 관련된 다양한 함수가 정의되어 있다.
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'을 입력
3. recv
recv는 프로세스에서 데이터를 받기 위해 사용한다.
마찬가지로 pwntools에는 관련된 다양한 함수가 정의되어 있다.
아래 코드에서 주의해서 봐야 할 것은 recv()와 recvn()의 차이점이다.
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('hello') #p가 출력하는 데이터를 'hello'가 출력될 때까지 받아서 data에 저장
data = p.recvall() #p가 출력하는 데이터를 프로세스가 종료될 받아서 data에 저장
4. packing & unpacking
익스플로잇을 작성하다 보면 어떤 값을 리틀 엔디언의 바이트 배열로 변경하거나, 또는 역의 과정을 거쳐야 하는 경우가 자주 있다.
pwntools에는 관련된 함수들이 정의되어 있다.
#!/usr/bin/python3
#Name: pup.py
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)))
$ python3 pup.py
b'DCBA'
b'HGFEDCBA'
0x44434241
0x4847464544434241
5. interactive
셸을 획득했거나, 익스플로잇의 특정 상황에 직접 입력을 주면서 출력을 확인하고 싶을 때 사용하는 함수다.
호출하고 나면 터미널로 프로세스에 데이터를 입력하고, 프로세스의 출력을 확인할 수 있다.
from pwn import *
p = process('./test')
p.interactive()
6. ELF
ELF 헤더에는 익스플로잇에 사용될 수 있는 각종 정보가 기록되어있다.
pwntools를 사용하면 이 정보들을 쉽게 참조할 수 있습니다. 아래 코드의 plt와 got는 나중에 소개하겠다.
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에 저장
7. context.log
익스플로잇에 버그가 발생하면 익스플로잇도 디버깅해야 한다.
pwntools에는 디버그의 편의를 돕는 로깅 기능이 있으며, 로그 레벨은 context.log_level변수로 조절할 수 있다.
from pwn import *
context.log_level = 'error' # 에러만 출력
context.log_level = 'debug' # 대상 프로세스와 익스플로잇간에 오가는 모든 데이터를 화면에 출력
context.log_level = 'info' # 비교적 중요한 정보들만 출력
8. context.arch
pwntools는 셸코드를 생성하거나, 코드를 어셈블, 디스어셈블하는 기능 등을 가지고 있는데, 이들은 공격 대상의 아키텍처에 영향을 받는다.
그래서 pwntools는 아키텍처 정보를 프로그래머가 지정할 수 있게 하며, 이 값에 따라 몇몇 함수들의 동작이 달라진다.
from pwn import *
context.arch = "amd64" # x86-64 아키텍처
context.arch = "i386" # x86 아키텍처
context.arch = "arm" # arm 아키텍처
9. shellcraft
pwntools에는 자주 사용되는 셸 코드들이 저장되어 있어서, 공격에 필요한 셸 코드를 쉽게 꺼내 쓸 수 있게 해준다.
매우 편리한 기능이지만 정적으로 생성된 셸 코드는 셸 코드가 실행될 때의 메모리 상태를 반영하지 못한다.
또한, 프로그램에 따라 입력할 수 있는 셸 코드의 길이나, 구성 가능한 문자의 종류에 제한이 있을 수 있는데, 이런 조건들도 반영하기 어렵다.
따라서 제약 조건이 존재하는 상황에서는 직접 셸 코드를 작성하는 것이 좋습니다.
#!/usr/bin/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
10. asm
pwntools는 어셈블 기능을 제공한다.
이 기능도 대상 아키텍처가 중요하므로, 아키텍처를 미리 지정해야 한다.
#!/usr/bin/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'
'시스템 해킹' 카테고리의 다른 글
#3 기본 시스템 용어2 (0) | 2022.06.07 |
---|---|
#2 기본 시스템 용어1 (0) | 2022.06.06 |
#1 Tool : gdb (0) | 2022.06.03 |