pwntools

이동화·2025년 7월 3일

pwnable

  • Pwn : 시스템이나 프로그램의 취약점을 이용해 제어권을 빼앗는 공격 행위
  • pwntools : 공격 스크립트를 신속하게 작성할 수 있도록 도와주는 python package 형태의 framework
    tcp socket 생성, paylaod 구성 및 packing, connect 및 send 등 번거로웠던 작업들을 간소화하여 모듈의 형태로 제공

venv

  • 프로젝트 마다 필요한 모듈이 dependency가 제각각인 경우가 많아 관리가 어려워, 별도의 local 환경에 설치하여 관리할 필요성이 있음
  • pip는 global 환경에 모듈을 설치하기 때문에 가상환경이 필요하다.
    Python 3.3부터 사용 가능한 가상 환경 라이브러리로, 안에 module을 설치하고 해당 가상환경의 python을 호출하는 방식으로 사용
  • 최근 python 정책 중 python 환경이 깨질 수 있는 install들은 막기 때문에 pwntools를 사용하려면 가상 환경 위에 패키지를 설치해야 함
  • 사용 시, pwntools를 사용할 스크립트에서
#!/home/username/project/venv/bin/python

를 주고 스크립트에 실행 권한을 주면 항상 venv 가상 환경의 python으로 실행되어 python 깨짐 없이 pwntools를 사용할 수 있다.

pwntools usage

process()
로컬 프로그램을 실행하여 통신할 때 사용하는 함수로, 인자로 통신할 프로그램의 경로를 전달하면 해당 프로그램과 연결을 맺어줌

from pwn import *
p = process("./binary")

pwnlib.tubes class를 반환하고 해당 클래스에는 데이터를 통신하는데 필요한 여러 멤버 함수들이 있다.
추가적으로, 프로그램에 인자를 전달하고 환경 변수도 설정할 수 있다.

from pwn import *
p = process(["./binary", "arg"], env={"LD_PRELOAD":"./libc.so.6"})

remote()
프로그램이 아닌, host의 domain 또는 IP 주소와 port 번호를 인자로 받아 원격 서버에 통신할 때 사용되는 함수이다. process와 같이 pwnlib.tubes 클래스를 반환 값으로 받는다.

from pwn import *
r - remote("ctf.kr", 1337)

마찬가지로 인자를 넣어줄 수 있는데, typ 인자로 통신 프로토콜을 바꿀 수 있다.


ssh()
SSH 서버에 접속하여 통신하기 위한 함수로,
사용자 이름, host ip, port 번호, 사용자 비밀번호를 인자로 전달해주어야 한다.


recv(), send()
생성된 pwnlib.tubes 클래스를 통해, 데이터를 수신, 송신하기 위해 사용한다. 해당 함수들은 데이터를 bytes 형태로 수신/송신한다.
recv의 경우 인자로 받을 byte수를 지정할 수 있다. 그만큼의 데이터를 받지 못하게 되면, 당장 받을 수 있는 만큼 수신한 후 함수를 종료하게 된다.
send의 경우, bytes 형태를 인자로 받아 전송하며, sendafter 또는 sendlineafter 함수는 인자로 전달된 데이터가 나올 때까지 데이터를 수신하고 그 이후 데이터를 전송한다.


inetractive()
터미널에서 사용자가 실시간으로 데이터를 수신하고 전송할 수 있게 하는 함수이다. 터미널을 통해 프로세스에 사용자가 원하는 입력 값을 표준 입력으로 전달할 수 있게 되고 프로세스의 출력도 실시간으로 터미널에 표시되어 마치 터미널에서 직접 프로그램을 실행시켜 조작하는 것과 비슷한 효과를 준다.
ctrl + D 를 통해 프로세스와의 연결을 끊어 통신을 종료할 수 있다.


close()
pwnlib.tubes 클래스 객체 내부 자원을 정리하고 연결을 종료할 때 사용한다. 단, interactive를 호출한 경우 함수 종료될 때 연결이 같이 종료되기에 close를 추가적으로 호출할 일은 없다.


conetxt.log_level
로그 출력의 상세한 정도를 설정할 수 있는데,
'debug' : 송수신 데이터, 내부 변수 등 모두 출력
'error' : 에러 메시지만 출력
'info' : 디폴트 설정이며, 일반적인 상태 메시지가 출력된다.


Packing
시스템 해킹에서는 정수 값을 bytes 클래스로 변환하거나 그 반대의 행위가 자주 필요하기에 pwntools에서 관련 기능을 제공한다.
p64() : 숫자를 bytes 클래스로 패킹 (64bit)
u64() : bytes 클래스를 숫자로 언패킹 (64bit)
little endian을 기반으로 동작하며, 인자로 endian을 설정해주어야 big endian으로 사용이 가능하다.

from pwn import *
s32 = 0x41424344
print(p32(s32))
b'DCBA'

기타

  • gdb.attach()
    process(), remote()로 생성한 객체 또는 프로세스의 pid를 인자로 넣으면 gdb 디버거를 프로세스에 붙여 디버깅을 수행할 수 있는 상태가 된다.
  • pause()
    디버거가 프로세스에 붙을 수 있는 시간을 벌어주기 위해 사용하는 중단 함수
  • context.archasm
    pwn에서 자주 사용하는 assmeble과 disassemble을 위하여 대상 아키텍처를 설정할 필요가 있는데, 그 때 사용하는 변수이다.
    context.arch = "amd64" #x86-64 arch
    아키텍처를 설정하였다면 asm(), disasm()으로 어셈블과 디스어셈블을 수행할 수 있다.
    code = asm('mov eax, 0')
     asm_code = disasm(code)
  • ELF
    ELF 파일 정보와 다양한 기능을 지원하는 함수가 담긴 클래스인 pwnlib.elf.elf.ELF를 반환한다.
    대표적으로, ELF 파일의 symbol 관련 정보에 접근할 수 있다.
    e = ELF("./example")
    print(hex(e.symbols['write']))
    print(hex(e.symbols.write)) 
    symbols는 doctdict 클래스로, dictionary처럼 사용할수도, 객체 속성처럼 사용할 수도 있다. 위 클래스에서 제공하는 주소는 가상 주소이다. PIE가 설정되어 있다면 상대 가상 주소를 제공한다.

checksec

linux 환경에서 존재하는 다양한 바이너리 보호 기법을 파악할 때 사용하는 도구이다. 총 4개의 기법에 대해서 적용 여부를 파악할 수 있다.

  • RELRO
  • canary
  • NX
  • PIE

그 외로 바이너리의 아키텍처, 파일 경로, RWX가 가능한 segment 정보, 즉 읽기 쓰기 실행 권한이 모두 허용된 메모리 영역이 있는지를 알려준다.
RWX flag를 가진 세그먼트는 shellcode 삽입의 타깃이 되기도 하기에 보안 상 취약점이 될 수 있다.

profile
notion이 나은듯

0개의 댓글