.prettyprint.linenums ol li, pre.prettyprint.linenums ol li { list-style: decimal; }

2017年7月27日 星期四

[Writeup] pwnable.tw applestore 200

喔耶,今天終於完成了許久以前就在做的applestore,然後發現我的排名掉好多......QAQ不過往好方面想,這是我第一次得到破千的分數耶^^

從學期中到昨天下定決心專心在這題上應該有3~4個月了八,解完覺得以前的我在幹嘛呀.......

不過這題我有點賽到,加上學了新招才搞定(不過到今天為止新招也變舊招了呵呵)


快速檢討:

1. 知道libc baseaddress後可以透過environ來找到stack地址:就算stack會偏移,但是偏移都是以一個page來移動,所以知道一個地址就能根據offset推算出其他stack上的地址

2. 不要糾結在過去所學上:以前學的很重要但是如果死板板的按照以前所學,那變化一點的就不會做了......。記住根本原理就好!

3. atoi遇到30~39以外的Ascii就會跳過

4. 可以透過printf來看出structure的一些結構成員

5. 只有一個參數而且可控的function很適合拿來改成system(這我之前好像寫過了= =?)

6. 可以透過修改ebp讓傳入參數更改位址(這是我覺得比較有用的技巧XDD)

因為這是很久以前就碰過的題目,所以老實說當時遇到什麼困難也有點忘記了,以後一定要紀錄RRRR

詳細過程:

題目在pwnable.tw有,就不附了,32bit,保護有canary NX

程式主要是選單題,功能分別有新增、刪除、列表、列選單、檢查、離開這些,可以從handler這function看到:

透過這些function可以讓你依據列表上的手機做購買,忘了說主題是applestore,選單能購買的都是iphone手機喇~

當我買了一隻手機(手機內容都幫你寫好了),就會malloc一塊空間存資料然後放進一個linked list裏面

因為在create裏面有malloc,所以以為是heap題,不過實際上heap用的比較多的是free(感謝學長提醒,雖然沒有馬上做XDD)。

linked list是double linked list,不過如果沒有設一個structure給他說實在是滿難看的......

我看了老半天才看明白原來他是這樣的:

struct Phone{
    char *name;
    int number;
    struct Phone *next;
    struct Phone *last;
}


然後透過後兩個pointer做連接

選單比較特殊的是有個奇怪的檢查:當你花費的金額等於7174時就會送你一隻iphone 8,更特殊的是iphone 8的structure不是放在bss段上而是在stack上,也就是說如果離開這function,內容隨時都會被改掉


不過說實在我數學不太好,要怎麼把花的錢調在7174滿傷腦筋的,所以我就交給z3 solver幫我解決~不過我忘記留script了QAQ


再來看delete,這段比較重要的是裡面的把linked list unlink這段,也是這次的關鍵,另外我leak function也是透過delete:

前面說過iphone 8的內容放在stack上,在stack frame上變動時很容易被其他function改到,而我發現my read這個輸入function剛好可以蓋到iphone 8!

雖然輸入進來的buf要傳給atoi轉成數字,但是因為atoi本身不轉換30~39以外的數字所以無妨。

加上delete裏面刪除後還會印出刪除的iphone name和number,如果我在my_read的buf寫上got就可以leak出libc function了

搞定leak後開始想怎麼exploit,由於關鍵點是unlink,當時我還沒學heap,所以......我就放下一切去學heap了XDD(雖然本題跟heap無關,但是就是想看看有沒有有用的資訊這樣)


我記得我5月的時候有回來看一次這題目,想說如果要控eip的話要嘛改got要嘛蓋ret address,由於我不知道任何可以leak出stack的位址的方式,所以一直在想怎麼蓋got,不過試了好久始終覺得直接蓋got不是好選項(事實證明我是錯的,有人真的用got overwrite搞定這題阿Orz),因為got勢必要填上instruction的地址,而unlink其中一個步驟套用在上面的話instruction附近的內容也會被改掉,想也知道這是不可能的事情。

※會想蓋got有部份也是因為看到unlink的古老用法,想說可不可以依樣畫葫蘆XDD不過最後還是有用到一點相關概念在exploit編寫上拉


當時我拼拼湊湊了很久,最後選擇放棄......

後來看到這名應該是交大的大大的repo,讓我找到一絲絲希望:
點我

裏面有說libc裏面有個東東叫environ,他其實是個stack address,如果能找到他就能得知stack位址。

不過這邊需要二次leak才能拿到,好在這邊因為iphone 8的next last都能被我控制,換句話說位在bss段的linked list在最後一個phone structure的next會接到stack上,而在delete後因為iphone 8的last被竄改過所以不會連回bss上的linked list,進而可以讓我一再的delete( = leak)


原先我還是想透過直接修改delete的ret address讓他直接被我控制,但是一直失敗。原因很簡單,ret address上原本應該是要擺instruction的地址,如果我擺instruction地址,那結果會跟擺got一樣,instruction附近的內容會被修改掉,而因為NX的關係,我也不能直接在stack上擺shellcode讓他跑。


這邊又卡了一段時間,後來想到如果直接利用不行,那如果我改ebp,讓他在leave ret的時候把esp遷到我想要的位址上,而該位址擺某instruction的地址的話......好像可行,但是變因有點多,因為每次的stack frame變動都有可能造成stack內容的改變。

一開始我很直接的選了delete的ebp,所以如果能控制到的話應該會發生在handler的ret上。

但是很可惜的......當我準備從handler離開時的printf會修改到stack上的內容,所以exploit失敗。
這邊如果繼續跑下去,可以預期在ret = pop eip的時候會把stack上的位址傳給eip,在NX情況下會報錯

delete不能改讓我又多花了點時間(我承認我中間看了滿多集的美劇,順帶一提,Brooklyn99滿好看的XDDD)

不過今天一早起來,我馬上想到如果delete的stack frame不能做,那何不用一個不太會動到的stack frame上呢?

於是我把目標放準在handler的ebp - 0x22上,於是......就成功喇~~~可喜可賀可喜可賀

我的exploit:


看到一種作法比較特殊,該作者跟我一樣都是改ebp,不一樣的是我讓ebp改到stack我能操控的地方擺system和sh,而他則是把ebp改為atoi_got + 0x22,這是因為在handler這個stack frame中,存輸入的buf在ebp - 0x22的地方,所以當read(0, buf, 21)的時候實際上是用ebp - 0x22當參數傳入的,可以從下面看到:
修改後就會變成:read(atoi_got + 0x22 - 0x22),這樣就可以順利傳入system,至於sh呢,可以順勢寫在後面,這樣下面的atoi會以buf當參數來看的話會看成:
atoi("\xad\xde\xef\xf7;sh\x00")
※分號前面那串假設是system真正地址

依據command injection前面辨別不出會報錯然後繼續執行分號後面的,所以可以拿到shell沒問題!

覺得這種方法比我的優雅多了XDD然後看了一些writeup,大家好像都用這種方法......難道我是異類嗎QAQQQ

沒有留言:

張貼留言