공부/Pwnable
pwntools 사용법 #1
현생준비중
2022. 1. 15. 21:05
pwntools는 파이썬으로 작성된 라이브러리 Pwnable 문제에서 쉘 코드 작성할 때 유용하게 쓰인다.
들어만 봤지 제대로 써본적이 없어서 이참에 한번 정리해보았다.
설치 방법은 간단하다.
pip install pwntools
모듈을 import 하는 방법은 아래와 같다.
from pwn import *
pwntools는 바이너리를 실행하거나 nc를 사용하는 외부 접속환경 둘 다 사용이 가능하다.
접속 또는 실행 관련
p = remote("127.0.0.1", 8080) # 127.0.0.1:8080 으로 접속
p = process("/home/user/bin1") # /home/user/bin1 실행
p = ssh("root", "192.168.0.3", 22, "password") # ssh 접속(user, IP, port, pw 순)
p.close() # 연결을 종료하려면 이렇게 쓰면 된다.
페이로드 전송(send)
p.send("AAAA") # AAAA 전송
p.sendline("aaaa") # aaaa\n 전송
p.sendafter("\n", "after") # 개행문자가 수신되면, after 전송
데이터 수신(recv)
result = p.recv(512) # 수신된 데이터 512바이트만큼 읽어들이기
print(result)
result = p.recvline() # 개행문자까지 읽어들이기
print(result)
result = p.recvuntil("end") # end라는 문자가 나올 때까지 읽어들이기
print(result)
패킹
리틀엔디언 또는 빅엔디언에 맞게 데이터를 패킹해주는 역할을 한다.
예를 들면 "ABCD"를 "DCBA"로 바꿔서 출력해준다.
두번째 인자로 endian='big' 으로 주면 빅 엔디언으로 출력해준다.
>>> print(p32(0x42424243))
b'CBBB'
>>> print(p32(0x42424243, endian='big'))
b'BBBC'
>>> print(p16(0x4242))
b'BB'
언패킹
언패킹은 반대로 정수로 반환해준다.
>>> print(u32("ABCD"))
<stdin>:1: BytesWarning: Text is not bytes; assuming ASCII, no guarantees. See https://docs.pwntools.com/#bytes
1145258561
>>> hex(1145258561)
'0x44434241'
ELF
개인적으로 가장 유용해 보인다.
>>> exe = ELF("/mnt/hgfs/Box/basic_exploitation_000")
[*] '/mnt/hgfs/Box/basic_exploitation_000' # ELF에 적용된 보호기법 확인 가능
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)
RWX: Has RWX segments
>>> exe.plt # ELF 내에 존재하는 plt 주소를 딕셔너리 형태로 반환
{'printf': 134513648, 'signal': 134513664, 'alarm': 134513680, 'puts': 134513696, 'exit': 134513712, '__libc_start_main': 134513728, 'setvbuf': 134513744, '__isoc99_scanf': 134513760, '__gmon_start__': 134513776}
>> exe.got # ELF 내에 존재하는 got 주소를 딕셔너리 형태로 반환
{'__gmon_start__': 134519000, 'stdin': 134519072, 'stdout': 134519076, 'printf': 134519016, 'signal': 134519020, 'alarm': 134519024, 'puts': 134519028, 'exit': 134519032, '__libc_start_main': 134519036, 'setvbuf': 134519040, '__isoc99_scanf': 134519044}
>>> exe.symbols # ELF 내에 존재하는 함수 주소를 딕셔너리 형태로 반환
{'stdout': 134519076, '_IO_stdin_used': 134514316, 'stdin': 134519072, '': 134519072, '__JCR_LIST__': 134518764, 'deregister_tm_clones': 134513856, 'register_tm_clones': 134513904, '__do_global_dtors_aux': 134513968, 'completed.7209': 134519080, '__do_global_dtors_aux_fini_array_entry': 134518760, 'frame_dummy': 134514000, '__frame_dummy_init_array_entry': 134518756, '__FRAME_END__': 134514656, '__JCR_END__': 134518764, '__init_array_end': 134518760, '_DYNAMIC': 134518768, '__init_array_start': 134518756, '__GNU_EH_FRAME_HDR': 134514348, '_GLOBAL_OFFSET_TABLE_': 134519004, '__libc_csu_fini': 134514288, 'alarm_handler': 134514043, '__x86.get_pc_thunk.bx': 134513840, 'data_start': 134519048, '_edata': 134519056, '_fini': 134514292, 'initialize': 134514066, '__data_start': 134519048, '__dso_handle': 134519052, '__libc_csu_init': 134514192, 'stdin@@GLIBC_2.0': 134519072, '_end': 134519084, '_start': 134513792, '_fp_hw': 134514312, 'stdout@@GLIBC_2.0': 134519076, '__bss_start': 134519056, 'main': 134514137, '__TMC_END__': 134519056, '_init': 134513596, 'printf': 134513648, 'plt.printf': 134513648, 'signal': 134513664, 'plt.signal': 134513664, 'alarm': 134513680, 'plt.alarm': 134513680, 'puts': 134513696, 'plt.puts': 134513696, 'exit': 134513712, 'plt.exit': 134513712, '__libc_start_main': 134513728, 'plt.__libc_start_main': 134513728, 'setvbuf': 134513744, 'plt.setvbuf': 134513744, '__isoc99_scanf': 134513760, 'plt.__isoc99_scanf': 134513760, '__gmon_start__': 134513776, 'plt.__gmon_start__': 134513776, 'got.__gmon_start__': 134519000, 'got.stdin': 134519072, 'got.stdout': 134519076, 'got.printf': 134519016, 'got.signal': 134519020, 'got.alarm': 134519024, 'got.puts': 134519028, 'got.exit': 134519032, 'got.__libc_start_main': 134519036, 'got.setvbuf': 134519040, 'got.__isoc99_scanf': 134519044}
>>> exe.search("buf") # buf라는 문자열 찾아서 위치 반환
<generator object ELF.search at 0x7efe73182890>
>>> exe.bss() # bss 섹션 주소 반환 1
134519072
>>> exe.get_section_by_name('.bss').header # bss 섹션 주소 반환 2
Container({'sh_name': 252, 'sh_type': 'SHT_NOBITS', 'sh_flags': 3, 'sh_addr': 134519072, 'sh_offset': 2320, 'sh_size': 12, 'sh_link': 0, 'sh_info': 0, 'sh_addralign': 32, 'sh_entsize': 0})
기본적으로 사용할 내용이라서 정리해보았다.
다음은 Shellcraft에 대해서 정리해봐야겠다.