R136A1
[SWING] python pwntools 사용법 + 응용 예제 본문
노션으로 이전 완료
pwntools는 python 2 에서 쓰는 것이 호환 더 잘 됨
python 3는 더 디테일해서 간단한 문제 풀 때는 2가 나음
github.com/Gallopsled/pwntools-tutorial/blob/master/bytes.md
Python2 str == bytes
exploit을 작성할 때 매우 편리하다.
encode(=b' '), decode 작업 없어도 됨
Python3 unicode == str
byte로 변환하는 과정 필요
→ 아래에서 str을 인자로 쓸 경우 b'____' 안에 넣어야 한다
대부분의 반환값도 byte이기때문에 출력하려면 .decode() 해야 한다
from pwn import *
1. 연결 객체 생성
r = remote('주소', 포트번호) # 외부 서버에 있는 문제에 접속
p = process('주소') # 로컬 문제 파일 실행키셔 프로세스 형태로 로드
2. 데이터 받아오기(=위치포인터 이동하기)
p.recv(크기) # int만큼 데이터를 받아옴
p.recvn(buffer) # buffer만큼의 데이터가 차야 받아옴
p.recvline() # 현재 위치포인터 줄 끝(\n)까지 받아온 뒤 다음 줄로 이동
p.recvuntil(bytes) # 현재 위치포인터부터 해당 바이트(b'문자열')까지 받아옴(현재 줄 넘어서는 X)
3. 데이터 보내기
p.send(bytes) # 데이터 보냄 read()
p.sendline(bytes) # 데이터 보낼 때 \n 붙여서 보냄 scanf() gets() fgets()
string의 경우 자동으로 encode() 하나, int는 str로 변환 필요
p. sendafter(str, send_str)
p. sendlineafter(str, send_str) # str를 받으면 그 때 send_str\n 보냄
4. interactive() 쉘과 직접적으로 명령을 전송하고 수신할 수 있는 함수
수동 대화 상태로 돌아가는 것. 코드 맨 마지막에 사용한다
5. 연결 종료
p.close()
s = ssh("username", "localhost", port=포트번호, password="비밀번호")
s['whoami'] # 쉘에서 명령어 실행
s.set_working_directory()
s.ls()
s.download_file('주소') # 파일 다운로드
sh = s.run('sh') #
sh.sendline(b'명령어')
sh.recvline( )
s.close()
packing
문자열의 경우 ASCII코드 10진수 값이 그대로 들어감 \x67 = D
남은 바이트는 00으로 채워진다.
p32(____, endian='big') # 32비트(4byte) default 리틀 엔디안 방식으로 패킹
p64(____, endian='big') # 64비트(8byte) default 리틀 엔디안 방식으로 패킹
unpacking
u32(____, endian='big')u64(____, endian='big')
elf = ELF("파일주소")
# 바이너리를 인식시켜 적용되어 있는 보호 기법과 PLT, GOT 와 같은 ELF 정보를 가져오는 함수
elf.plt['함수이름'] # 함수의 PLT 주소를 찾음
elf.got['함수이름'] # 함수의 GOT 주소를 찾음
elf.symbols 등으로 접근 가능
+gdb와 연동
gdb.attach(연결객체) # 현재 프로그램의 상태에서 gdb 실행. local 파일 로드했을 때만 가능
+로그 보기
context.log_level = "info"
context.log_level = "debug"
먼저, 문제가 c 파일로 주어졌기 때문에 실행 파일로 변환하는 과정이 필요하다
gcc -o 출력파일이름 컴파일할파일이름
-o 옵션: 인자로 준 파일 이름으로 실행 파일을 출력한다
gcc -o swing_pwn_chall swing_pwn_chall.c 명령어를 통해 컴파일한다
(gcc는 설치해야 한다)
문제를 실행시켜보면 아래와 같은 형태로 실행된다
#문제번호: number1 + number2 = ?\n
> 입력하기
코드 작성
idle 내에서나 ./answer.py로 실행할 경우 pwn module을 찾지 못하는 관계로
(idle은 왜인지 모르겠는데, ./answer.py로 실행할 경우 (default)python2로 실행되는 듯 하다)
terminal에서 python3 answer.py로 실행해준다
코드 작성하면서 뭐가 안될때는 로그를 출력해본다
context.log_level = "debug"
process를 통해 연결객체를 만들어주고
for i in range(20): 을 통해 20번 실행하도록 한다(.c 파일코드에서 20까지 실행되도록 했기 때문)
p.recvuntil(b': ') : 까지 받아온다
#문제번호: number1 + number2 = ?\n
▲
> 입력하기
p.recvuntil(b' = ') = 까지 받아온다
#문제번호: number1 + number2 = ?\n
▲ ▲
> 입력하기
string에는 현재 number1 + number2 = 가 들어있다
+ 를 기준으로 split 하면 [0]에 number1 [1]에 number2 = 가 있으므로
[1]은 split을 한번 더 사용해 =을 떼준다
p.recvline() \n 까지 받아온다
#문제번호: number1 + number2 = ?\n
▲ ▲ ▲
> 입력하기
> 로 이동시키지 않아도 됨. 바로 scanf()가 실행되어 입력모드로 진입하기 때문
다 풀고 다른 분들 풀이(+swing ctf write up)를 본 결과 슬라이싱, 연산에 있어서 더 효율적인 방법 존재
1) p.recvuntil(':')까지 이동 후
number1 = p.recvuntil('+')[:-1]
number2 = p.recvuntil('=')[:-1]
p.sendline(str(number1+number2))
2) p.recvuntil(':')까지 이동 후
expr = p.recvuntil('=')[:-1]
p.sendline(str(eval(expr))
이게 최선의 풀이. 이렇게 풀면 연산자 제약도 없이 연산 가능
'SWING > [21-1] SYSTEM' 카테고리의 다른 글
[SWING] 6주차 문제풀이 (ROPasaurusrex, Dreamhack 30) (0) | 2021.05.26 |
---|---|
[SWING] gdb 사용법과 실습 (0) | 2021.05.12 |
[SWING] pwnable.kr collision (0) | 2021.05.05 |
[SWING] setuid 개념 및 예제, Capability Leak (0) | 2021.05.05 |
[SWING] 리눅스 메모리 구조 (0) | 2021.03.31 |