[0CTF 2016]piapiapia之愚見

今天在buuctf上嘗試了一下[0CTF 2016]piapiapia之愚見這個(gè)題目,點(diǎn)進(jìn)去之后是登錄界面和一張貓的動(dòng)圖,進(jìn)行了爆破和簡單的注入嘗試,掃描了一下目錄,一無所獲。

在網(wǎng)上看了看大佬的wp,發(fā)現(xiàn)有www.zip源碼泄露(個(gè)人認(rèn)為嚴(yán)格意義上不算泄露),不同掃描器內(nèi)的字典也不一樣,據(jù)說能在本題中掃描出來的有dirmap、dirsearch、nikto,我偷懶直接將源碼下載下來進(jìn)行審計(jì)。

代碼量并不大,比較友好,按照所學(xué),先看config.php,再是class.php,


config.php

我們要有一個(gè)意識(shí):這是我們下載下來的源碼,并非真正的服務(wù)端運(yùn)行的源碼,本地搭建做題環(huán)境時(shí)要改成自己的用戶名、密碼之類,在服務(wù)端docker的主機(jī)里,$flag變量應(yīng)該存的就是我們要的flag。

繼續(xù)審計(jì)代碼,我們可以發(fā)現(xiàn)在class.php中有本題關(guān)鍵的兩個(gè)類和相關(guān)函數(shù),其中的函數(shù)寫的較為全面(增改查都涉及)、認(rèn)真(變量有單引號(hào)保護(hù)且過濾了單引號(hào)和一些關(guān)鍵詞),若想注入恐怕需要費(fèi)點(diǎn)功夫,其余的php文件亮點(diǎn)不多、比較平常,但還有三個(gè)點(diǎn)需要注意:

一是update.php里有一個(gè)序列化操作,與之對(duì)應(yīng)的有一個(gè)反序列化操作,在注入可能不好用的情況下,這很有可能是本題的關(guān)鍵;


update.php 此處的serialize($profile)將會(huì)存入數(shù)據(jù)庫


profile.php 此處從數(shù)據(jù)庫中取出序列化的$profile

二是update.php里對(duì)傳入的變量做了簡單的檢查,


這里比較有意思的是,前兩個(gè)是沒有按相應(yīng)規(guī)則匹配到文本則執(zhí)行die()函數(shù),也就是說無論preg_match()返回值為0或null或false皆會(huì)die出,而第三個(gè)檢查則不是這樣,是如果匹配到非字母數(shù)字或nickname長度大于10則die出,這里我們就可以操作了,控制nickname為一個(gè)數(shù)組,這樣的話兩個(gè)判斷條件為false或NULL,故不會(huì)die出。



可以想象這是出題人故意設(shè)計(jì)的,否則為什么不接著前兩個(gè)if判斷的格式寫。由此看來,nickname為我們可以較為完全的控制、利用的變量。

三是有profile.php的功能是展示文件,說是展示,實(shí)為讀取,


剛才我們?cè)赾onfig.php里想到要讀取服務(wù)端上config.php的源碼,而這里是整個(gè)題目里唯一的可以讀取文件的點(diǎn)。

現(xiàn)在我們有個(gè)大體思路了,update.php中有一個(gè)$profile數(shù)組變量,這個(gè)數(shù)組里有$phone, $email, $nickname, $photo幾個(gè)變量,序列化后以profile字段存入數(shù)據(jù)庫,而我們?nèi)绻芸刂苝hoto變量為"config.php",則能在訪問profile.php時(shí)獲得base64編碼之后的config.php源碼。

下面問題來了,怎么控制$photo?


update.php中的文件上傳為$photo變量唯一的來源,無法實(shí)際利用,到了這里如果不知道本題想考的知識(shí)點(diǎn)——PHP序列化長度變化導(dǎo)致字符逃逸,我們就可以放棄了。

閱讀了諸位大佬的wp后(沒辦法,太菜了),再經(jīng)過動(dòng)手實(shí)踐,我對(duì)這個(gè)知識(shí)點(diǎn)有了一定的理解,和大家分享一下。

大佬說:看過PHP的底層代碼后,發(fā)現(xiàn)PHP反序列化中值的字符讀取多少其實(shí)是由表示長度的數(shù)字控制的,而且只要整個(gè)字符串的前一部分能夠成功反序列化,這個(gè)字符串后面剩下的一部分將會(huì)被丟棄,舉個(gè)例子:





這樣很正常,下面我們引出知識(shí)點(diǎn)。



我們可以看到,原來的字符串Northind內(nèi)被填充了幾個(gè)字符串,先是 """ 三個(gè)雙引號(hào),再是正常結(jié)尾時(shí)需要有的 ";} 三個(gè)字符,在PHP進(jìn)行反序列化時(shí),由字符串初始位置向后讀取8個(gè)字符,即使遇到字符串分解符單雙引號(hào)也會(huì)繼續(xù)向下讀,此處讀取到 North""" ,而后遇到了正常的結(jié)束符,達(dá)成了正常反序列化的條件,反序列化結(jié)束,后面的 ind";}? 幾個(gè)字符均被丟棄。

借用大佬的一個(gè)例子(https://www.cnblogs.com/litlife/p/11690918.html),簡單分享一下這個(gè)知識(shí)點(diǎn)的應(yīng)用



這里的username我們可控,bad_str函數(shù)會(huì)把反序列化后的字符串中的單引號(hào)替換“no”,我們做個(gè)分析,嘗試著修改該用戶的簽名,用到的當(dāng)然是本題的知識(shí)點(diǎn),


我們要記住一點(diǎn),我們的字符串是在某變量被反序列化得到的字符串受某函數(shù)的所謂過濾處理后得到的,而且經(jīng)過處理之后,字符串的某一部分會(huì)加長,但描述其長度的數(shù)字沒有改變(該數(shù)字由反序列化時(shí)變量的屬性決定),就有可能導(dǎo)致PHP在按該數(shù)字讀取相應(yīng)長度字符串后,本來屬于該字符串的內(nèi)容逃逸出了該字符串的管轄范圍,輕則反序列化失敗,重則自成一家成為一個(gè)獨(dú)立于原字符串的變量,若是這個(gè)獨(dú)立出來的變量末尾是個(gè) ";} ,則可能會(huì)導(dǎo)致反序列化成功結(jié)束,后面的內(nèi)容也就被丟棄了。此處能逃逸的字符串的長度由經(jīng)過濾后字符串增加的長度決定,如上圖第四個(gè)語句,@號(hào)內(nèi)就是我們要逃逸出來的字符串,長度為33,百分號(hào)內(nèi)為我們輸入的username變量,要想讓@號(hào)內(nèi)的字符串逃逸,就需要原來的字符串增長33,這樣的話@號(hào)內(nèi)的字符串被擠出,username的正常部分和增長的部分正好被PHP解析為一整個(gè)變量,@號(hào)內(nèi)的內(nèi)容就被解析為一個(gè)獨(dú)立的變量,而且因?yàn)樗淖詈笥?";} ,使反序列化成功結(jié)束。

為了增長33,我們需要username里加入33個(gè)單引號(hào),它們會(huì)被替換為33個(gè)no,使長度增加33,由此以來,上圖中x的值也可以確定了,輸入的username即為Northind'''''''''''''''''''''''''''''''''";i:1;s:18:"Today is Northind!";},x為它的長度(74),所以我們最后得到的字符串為:

a:2:{i:0;s:74:"Northind'''''''''''''''''''''''''''''''''"(注意最后這里是個(gè)雙引號(hào));i:1;s:18:"Today is Northind!";};i:1;s:15:"Today is Mondy!";}



我們可以看到,在這個(gè)反序列化字符串被過濾后,里面的單引號(hào)全部被替換為“no”,使"Northind"+"no"*33的長度之和等于74,配合上我們傳入的",滿足PHP反序列化的條件之一,后面的";i:1;s:18:"Today is Northind!";}先閉合了一個(gè)變量的正確格式,又寫入了一個(gè)變量正確格式,最后閉合了一個(gè)反序列化操作。該擠出的被擠出逃逸了,該丟棄的丟棄了,任務(wù)也完畢了。這是我們的分析,接下來實(shí)際傳個(gè)username變量進(jìn)去看看,


可以發(fā)現(xiàn),成功修改了簽名。

下面回到piapiapia這個(gè)題,既然要用到反序列化長度逃逸,必然是先把變量序列化,然后進(jìn)行過濾,在過濾的過程中把某個(gè)關(guān)鍵詞替換成了長度更長的關(guān)鍵詞,導(dǎo)致長度加長,最終引起逃逸,而在class.php中,我們可以看到:


我們只有傳入的字符串中有'where'關(guān)鍵字,被替換為'hacker'關(guān)鍵字,才會(huì)讓長度加一,否則長度不變。在這里眼尖的大佬直接就看出端倪了,而我水平著實(shí)有限,不讀讀大佬的博客是真看不出來。

下面我們來分析piapiapia這個(gè)題應(yīng)該怎樣構(gòu)造字符串,

經(jīng)過本地調(diào)試,我們可以知道,正常情況下,原始的$profile字符串為 (此處已經(jīng)將nickname以數(shù)組類型傳參):

a:4:{s:5:"phone";s:11:"66666666666";s:5:"email";s:10:"111@qq.com";s:8:"nickname";a:1:{i:0;s:5:"kendo";}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}

因?yàn)槲覀兿氚裵hoto改為config.php,我們目的字符串的前身可知矣(為了看著方便還是把可控部分的雙引號(hào)改為%):

a:4:{s:5:"phone";s:11:"66666666666";s:5:"email";s:10:"111@qq.com";s:8:"nickname";a:1:{i:0;s:5:%kendo";}s:5:"photo";s:10:"config.php";}%;}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}

我們要逃逸的部分為";}s:5:"photo";s:10:"config.php";},長度為34,需要在nickname[0]里添加34個(gè)where才能被成功逃逸。

我們可以構(gòu)造構(gòu)造,并在本地試著反序列化看看能否輸出有效信息,


所以我們的目標(biāo)字符串為:

a:4:{s:5:"phone";s:11:"66666666666";s:5:"email";s:10:"111@qq.com";s:8:%nickname";a:1:{i:0;s:204:"34個(gè)where";}s:5:"photo";s:10:"config.php";}%;}s:5:"photo";s:39:"upload/f3ccdd27d2000e3f9255a7e3e2c48800";}

為了方便好看還是將可控部分的雙引號(hào)改為%,

然后簡單的復(fù)制了profile的代碼和filter函數(shù),建了個(gè)PHP文件,



輸出中有base64編碼的內(nèi)容,解碼即為config.php

結(jié)果看來,已經(jīng)可以成功讀取本地的config.php,接下來的內(nèi)容不難,在docker上訪問register.php,注冊(cè)用戶,在update.php里輸入一定的字符,抓包,


將nickname那里改為nickname[],(根據(jù)直覺這么改就能傳數(shù)組,實(shí)際也確實(shí)是這樣),再將他的值改為我們構(gòu)造的字符串中%內(nèi)部分,



頁面有warning是因?yàn)槲覀兊膎ickname為數(shù)組類型,但無傷大雅,訪問profile.php,查看源代碼,



將這個(gè)內(nèi)容base64解碼,就能讀取服務(wù)端的config.php,得到flag。

幾點(diǎn)心得體會(huì):

1.掃描器之間也有些差別,有的掃描器確實(shí)是掃不出來,這就讓我們不得不多備一兩個(gè)掃描器;

2.還是要多動(dòng)手,多去實(shí)踐才能弄懂;

3.先發(fā)散找思路,再縮小范圍,最后去嘗試;

4.我對(duì)PHP底層的東西的了解為0,日后有機(jī)會(huì)一定要多多了解。

大膽應(yīng)無懼,雄心誓不回

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、Python簡介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡介】: Python 是一個(gè)...
    _小老虎_閱讀 6,353評(píng)論 0 10
  • ORA-00001: 違反唯一約束條件 (.) 錯(cuò)誤說明:當(dāng)在唯一索引所對(duì)應(yīng)的列上鍵入重復(fù)值時(shí),會(huì)觸發(fā)此異常。 O...
    我想起個(gè)好名字閱讀 6,016評(píng)論 0 9
  • 官網(wǎng) 中文版本 好的網(wǎng)站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,727評(píng)論 0 5
  • 常用模塊 認(rèn)識(shí)模塊 什么是模塊 什么是模塊? 常見的場(chǎng)景:一個(gè)模塊就是一個(gè)包含了python定義和聲明的文件,文...
    go以恒閱讀 2,171評(píng)論 0 6
  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個(gè)線程,因...
    小菜c閱讀 7,380評(píng)論 0 17

友情鏈接更多精彩內(nèi)容