pwntools
インストール
code:sh
sudo apt update && sudo apt upgrade -y
sudo apt install python3-dev libssl-dev libffi-dev build-essential
pip install --upgrade pwntools
チートシート
from pwn import *
プロセス
ローカル: io = process("./a")
process(["echo", "a"], env={"A":"B"})
リモート: io = remote("x.x.x.x", port)
io.interactive()
io = remote("x.x.x.x", port, level='debug')。levelにdebugを指定すると、受信したメッセージを表示してくれる。
送受信
受信: recv(), recvuntil(delim), recvall(),recvregex(pattern)。recv()はデフォルトで4096 bytes読み込む。recvuntil()はdrop=Trueを指定するとdelimを削除してくれる。改行であれば.recvline().strip()で十分の場合が多い。recvuntil(b"\n")するくらいならrecvline()のほうが綺麗。
送信: send(), sendline()。send(b"\n")とするくらいならsendline()で十分。bytesでなくstrを送っても良いがBytesWarning: Text is not bytes; assuming ASCII, no guarantees.とwarningが出る。改行コードは10なのでDEBUGモードだとSent 0x1 bytes: 10 * 0x1と表示される。
recvuntil()とsend()をまとめてやる: r.sendlineafter("hoge", b"-1")。
ペイロードを送信したあとに手動で色々入力したい: r.interactive()。シェル取ったあとに便利。
一度読み込んでからパースするのではなくrecvuntilを使ってパースしながら読み込むと良い。
packしたいときはp8(),p16(),p32(),p64(),pack(number, word_size)を使う。例えばreturn address書き換えでアドレスを送りたいときはp64(address)とする。
clean(): バッファリングされたデータを破棄。
ELFの解析
elf = ELF("hoge")でELFファイル読み込みでき、elf.symbols.function_nameで関数アドレス取得できる。
PLTはelf.plt.foo、GOTはelf.got.foo。 セクションのアドレス: elf.bss()
context.binary = elfをしないとどうなる? #? elf.addressにアドレス指定するとelf.symbols.function_nameの値も変わる? #? elf.address: ベースアドレス
elf.entry: エントリポイントのアドレス
elf.search("/bin/sh\x00")
asm(shellcraft.sh())
asm()に直接アセンブリコードを渡せる。
型変換
pack(1): \x01\x00\x00\x00
pack(-1): \xff\xff\xff\xfff
p8(),u8(),p16(),u16(),p32(),u32(),p64(),u64()
hex(unpack('\xef\xbe\xad\xde')): 0xdeadbeef
パラメータ: word_size, endian, sign。context.arch="i386",context.arch="amd64"などを指定しておけば自動でやってくれる。
ファイル入出力
write(filename, data),read(filename),read(filename, n)
エンコード・デコード
b64e,b64d
urlencode(b),urldecode(b)
url encodeもっと細かく指定できない? #? ハッシュ
md5sumhex(b),md5filehex(filename),sha1sumhex(b)
ユーティリティ
bits(): ビットのリストに変換。
unbits()
print(hexdump(read(filename, 32)))
cyclic(n): パターン文字列生成。cyclic_find(s)で見つける。
xor: string同士ができるらしい。
Context
context.arch
context.binary
context(os='linux', arch='i386')
context.log_level = 'debug'
gdb.debug(),gdb.attach()
GDB経由でバイナリを起動できる。
定数
constants.SYS_exit
SIGKILL,AF_INETなど。
CLIコマンド
usage: pwn [-h] {asm,checksec,constgrep,cyclic,debug,disasm,disablenx,elfdiff,elfpatch,errno,hex,phd,pwnstrip,scramble,shellcraft,template,unhex,update,version} ...
$ pwn checksec BINARY
PATHを通しておけばpwn は要らない。