I春秋第四季CTF-Web-Writeup(部分)
因為比較菜,Web當時只做出了四題…所以只有部分wp
全部的wp官方鏈接:https://bbs.ichunqiu.com/thread-55360-1-1.html,https://bbs.ichunqiu.com/thread-55362-1-1.html
第一題:PHP反序列化
題目總共有三個php文件
第一個:index.php
第二個:show.php
第三個:user.php
題目:http://120.55.43.255:24719,進去后沒有看見任何東西
我們查看源代碼:發現了一個鏈接
接下來,我們訪問該鏈接,看看有什么
哦?那我們再看看user.php里有什么,什么都沒有
接下來使用php偽協議分別獲取index.php、show.php、user.php
payload:
獲得的index.php經過bse64加密的源碼:
PGh0bWw+DQogICAgPHRpdGxlPldoZXJlPC90aXRsZT4NCiAgICANCjw/cGhwDQogICAgZXJyb3JfcmVwb3J0aW5nKDApOw0KICAgIGlmKCEkX0dFVFtmaWxlXSl7ZWNobyAnPGEgaHJlZj0iLi9pbmRleC5waHA/ZmlsZT1zaG93LnBocCI+PC9hPic7fQ0KICAgICRmaWxlPSRfR0VUWydmaWxlJ107DQogICAgaWYoc3Ryc3RyKCRmaWxlLCIuLi8iKXx8c3RyaXN0cigkZmlsZSwidHAiKXx8c3RyaXN0cigkZmlsZSwiaW5wdXQiKXx8c3RyaXN0cigkZmlsZSwiZGF0YSIpKXsNCiAgICAgICAgZWNobyAiTkFOST8iOw0KICAgICAgICBleGl0KCk7DQogICAgfQ0KICAgIGluY2x1ZGUoJGZpbGUpOw0KPz4NCjwvaHRtbD4NCg==解碼后如下:
<html><title>Where</title><?phperror_reporting(0);if(!$_GET[file]){echo '<a href="./index.php?file=show.php"></a>';}$file=$_GET['file'];if(strstr($file,"../")||stristr($file,"tp")||stristr($file,"input")||stristr($file,"data")){echo "NANI?";exit();}include($file); ?> </html>同理:
- show.php的源代碼
- user.php的源代碼
這幾個源代碼一看,根據user.php可以看出,原來是和反序列化有關
__destruct()魔術方法就是在程序執行結束后,執行該函數
__wakeup()魔術方法是和unserialize共同存在的,執行unserialize()時,會先調用__wakeup函數,所以上面的代碼,在執行unserialize(KaTeX parse error: Expected group after '_' at position 12: cmd)時。會優先執行_?_wakeup函數,但要注意的…cmd要是經過序列化過的數值。
解題思路:
這題的思路就是,把eval函數用起來,不僅僅是簡單地跳過__wakeup函數,還要執行__destruct函數,所以我們需要將序列化后的函數修改一番,既可以繞過__wakeup,又可以調用__destruct函數,執行系統命令
首先,進行序列化
代碼:
由于報錯了,反正我們也是要修改$warn的值,這里我們暫且可以給他一個""
代碼:
這時,convent對象就被我們序列化了,序列化后的值如下
這里的序列化表示對象名叫convent,屬性有1個,名稱為warn,值為""
這里我們需要繞過__wakeup的話,將O:7:“convent”:1:{s:4:“warn”;s:0:"";}中的1改為大于1的數,即可完成繞過__wakeup函數,想要執行__destruct函數,就要反過來用反序列化了。
根據源碼中eval(this?>warn)可知,也就是執行this->warn)可知,也就是執行this?>warn)可知,也就是執行warn,所以,我們需要修改屬性warn的值,下面是payload(注意還要繞過__wakeup的)
這里"convent"后面的3用來繞過__wakeup函數,將warn的值修改為了system(‘ls’);,POST提交cmd時,是如下流程:
$cmd =O:7:"convent":3:{s:4:"warn";s:13:"system('ls');";}; unserialize(O:7:"convent":3:{s:4:"warn";s:13:"system('ls');";}); 此時的warn屬性的值為:system('ls'); 執行covent,因為繞過了__wakeup,就不執行__wake函數了,直接執行__destruct函數: eval(warn的屬性值),也就是eval(system('ls');)注意!!!POST提交payload時,不需要對payload使用引號,如下所示是錯誤的
cmd=‘O:7:“convent”:3:{s:4:“warn”;s:13:“system(‘ls’);”;}’
使用bp進行截斷發送:
因為dsuhhjfdgjhaskjdkj.txt和Index,php在同一目錄下,我們使用URL訪問它
參考文章:http://p0desta.com/2018/04/01/php反序列化總結/
https://www.freebuf.com/column/202607.html
第四題:偽隨機數與eval函數拼接
題目:
源碼:
審計源碼,總共有兩個可利用點,一個是mt_srand()函數,還有一個是eval( “var_dump($a);”)
一開始直接使用的如下payload:
還是沒有顯示,看來必須要$key == $true_key才會執行eval函數了
最后正確的payload:
http://120.55.43.255:27189/?hello=1);print_r(file("./flag.php")&seed=12345&key=162946439
解題知識:
綜合分析源代碼后,我們知道,需要最終執行eval函數,執行自己想要的代碼,那么,首先執行eval函數的前提就是$key == $true_key,成功輸出Key Confirm,才能執行eval()函數,其次就是我們需要對源碼中eval函數的內容進行拼接,執行我們想要的命令,因為它存在一個var_dump()函數
mt_rant():生成隨機數
mt_srant(seed):根據seed):根據seed):根據seed種子,然后再通過mt_rant()生成隨機數
例如:
如果將代碼改為如下所示:
<?php mt_srand(12345); echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; echo mt_rand()."<br/>"; ?> 輸出: 162946439 247161732 1463094264 1878061366 394962642我們發現根據我們指定的種子,生成的數都是固定的,正如第一個一樣,只要你指定mt_srand()括號里的種子為12345,那么它輸出的隨機數,我們就能知道是什么,本題如下
mt_srand(12345);//設置種子為12345 $true_key = mt_rand();//根據種子12345生成一個隨機數,我們知道,這第一個隨機數肯定是162946439 if ($key == $true_key){//這里我們進行GET請求時將$key的值設為162946439,最后就是162946439==162946439,成功執行if語句eval函數內容拼接
eval( "var_dump($a);"); hello是接受參數的變量,接下來就是構建hello變量,也就是上面代碼中的$a,使其能夠閉合var_dump,利用print_r輸出 首先閉合var_dump:$_GET[hello]=$a=1); eval("var_dump(1);)"); //多出來的第一個括號準備和后面print_r的第一個括號閉合,下面藍色表示我們構造的值 第二步構建print_r:print_r(file("./flag.php")); 構建的URL觸發的 eval操作為 eval("var_dump(1);print_r(file("./flag.php"))"); URL構建結束,最終的payload: http://120.55.43.255:27189/?hello=1);print_r(file("./flag.php")&seed=12345&key=162946439注:
echo是PHP語句, print和print_r是函數,語句沒有返回值,函數可以有返回值(即便沒有用) print只能打印出簡單類型變量的值(如int,string) print_r可以打印出復雜類型變量的值(如數組,對象) file() 函數把整個文件讀入一個數組中。 與 file_get_contents() 類似,不同的是 file() 將文件作為一個數組返回。數組中的每個單元都是文件中相應的一行,包括換行符在內。 如果失敗,則返回 false。語法 file(path,include_path,context) 參數 描述 path 必需。規定要讀取的文件。 include_path 可選。如果也想在 include_path 中搜尋文件的話,可以將該參數設為 "1"。 context 可選。規定文件句柄的環境。 context 是一套可以修改流的行為的選項。若使用 null,則忽略。 說明 對 context 的支持是 PHP 5.0.0 添加的。返回的數組中每一行都包括了行結束符,因此如果不需要行結束符時還需要使用 rtrim() 函數。 提示和注釋 注釋:從 PHP 4.3.0 開始,可以用 file_get_contents() 來將文件讀入到一個字符串并返回。 注釋:從 PHP 4.3.0 開始,file() 可以安全用于二進制文件。 注釋:如果碰到 PHP 在讀取文件時不能識別 Macintosh 文件的行結束符,可以激活 auto_detect_line_endings 運行時配置選項。因為使用了file函數,所以最后輸出只能使用print_r打印出數組,這個需要注意
注:一開始我是使用的GET請求,然后使用bp抓包,發送到repeater,修改數據為POST,有時這樣不可行,無法返回正確的數據。所以我們需要注意以下幾個方面,如果你一開始由GET改用POST之后,要注意,POST值的下方不能有空的一行,我之前就是這個問題,我抓到的包發送到repeater后,最后一行數據下面本就空著兩行,我又多按了一個回車,變成數據下面一個空行(這是必須的)、POST值、POST值下面一個空行(這是不必要的,存在只會使代碼無法正常執行)導致死活都無法正確執行代碼。
另外,Content-Length它會自己修改,不用特意改它,實在不行,刪了就行,它會根據你的POST請求自動生成。
如果這樣POST提交還是失敗還不行,那就乖乖的先進行POST請求,然后再抓包修改。
一個小貼士,了解就好:在HTTP協議中,Content-Length用于描述HTTP消息實體的傳輸長度the transfer-length of the message-body。在HTTP協議中,消息實體長度和消息實體的傳輸長度是有區別,比如說gzip壓縮下,消息實體長度是壓縮前的長度,消息實體的傳輸長度是gzip壓縮后的長度。所以,有時候我們可以根據length的值大致判斷我們所提交的數據是否按照我們要求的參數進行提交(Content-Length一般代表著GET或POST請求值的長度,因為存在gzip,所以只能粗略判斷)
參考文章:
https://www.cnblogs.com/zaqzzz/p/9997855.html
https://segmentfault.com/a/1190000016750234?utm_source=tag-newest
第七題:輸出流和反序列化
題目:訪問http://120.55.43.255:28119后出現下圖所示
我們查看網頁源代碼:
一眼看去,我們首先要傳參使得$user=admin,這里使用了file_get_contents()函數,那么我們怎樣讓$user===admin呢? file_get_contents是將一個文件讀入字符串中,這里是將$user讀入字符串r中,在這里,我們想要file_get_contents($user,'r')===admin,怎么搞呢?使用php://input封裝協議,它就是用來獲取POST數據的 舉例:
<?php $d = file_get_contents('php://input'); echo "獲得到的POST數據是:".$d; echo "<br/>"; @eval($d); ?>下面是我搭的一個環境做得測試:
測試系統命令:
在hackbar中使用POST提交數據,使用POST提交時需要注意,要在提交的數據前面加上變量,就像上圖中的xx,因為不知道是我hackbar的原因還是其他原因,不加變量就無法Execute,好了,hackbar是好是壞我們暫且不管,有問題就要解決。當我們使用上圖方法進行提交時,使用變量進行POST提交后,再使用bp進行抓包修改,刪除變量和等于號,然后再提交,這樣就可以了。雖然繞了一圈,但總比拿不到flag好!
使用bp抓包圖:
瀏覽器顯示:
總結:由此可見,php://input封裝協議,是獲取我們POST提交的原始數據,你提交啥,我就獲取啥
好了,繼續進入正題,題目中的pass參數是干嘛用的呢?看了一眼源代碼,我們使用php://input封裝協議配合file參數使用php偽協議獲取index.php、class.php的源碼信息
payload:
如下圖
將base64進行解密,得到index.php源碼:
按照同樣的方法,獲取class.php
class.php源碼:
已經全部的到源碼,一掃而過,覺得和反序列化有關,那么我們再來看看index.php、class.php
分析代碼:
好了,再index.php頁面下,我們繼續構造payload
這里存在一個反序列化,并且這個$pass是可控的,那么我們可以利用反序列化獲取一些敏感信息(雖然沒有eval函數,但有echo,可以修改反序列話數據,配合php偽協議,base64加密輸出fffffflag.php)
我們先將上面的類實例化一個對象,進行序列化
如上圖所示,file的值為NULL,那么我們修改file的值,改為我們自己想要的,我們想要執行
那么就將序列化后的值就改為下面所示:
O:4:"Read":1:{s:4:"file";s:62:"php://filter/read=convert.base64-encode/resource=fffffflag.php";}這個Read類序列化過后,將被序列化的值修改后,當它執行unserialize反序列化時,就會執行php://filter/read=convert.base64-encode/resource=fffffflag.php
這里最后的payload是
bp圖:
將base64解碼后得到flag
第十題:strcmp漏洞和命令執行
題目如下:
發現了網頁源代碼的提示:
這里考到的是strcmp()函數漏洞
只有當if(0==0),才會執行if語句,使用文件包含
strcmp()函數漏洞介紹:
注:這一個漏洞適用與5.3之前版本的php 我們首先看一下這個函數,這個函數是用于比較字符串的函數
int strcmp ( string $str1 , string $str2 ) 參數 str1第一個字符串。str2第二個字符串。如果
str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果兩者相等,返回 0。
strcmp()函數期望傳入到它當中的數據是字符串類型,但是如果我們傳入不合法的字符串類型的數據,這個函數將會有怎么樣的行為呢?實際上,當這個函數接受到了不合法的字符串類型時,這個函數將發生錯誤,但是在5.3之前的php中,顯示了報錯的警告信息后,將return
0 !!! 也就是雖然報了錯,但卻返回0。php官方在后面的版本中修復了這個漏洞,使得報錯的時候函數不返回任何值。
那么,如何繞過呢?
只要我們$_POST[‘password’]是一個數組或者一個object即可,這兩種是字符串,但它們是不合法的字符串,但又如何上傳一個數組呢?請看下面
php為了可以上傳一個數組,會把上傳的變量結尾帶一對中括號當作數組上傳,例如:password[]=xx,上傳變量名為password的數組,其數組中的值為xx
登陸成功payload(POST提交):等于號后面的值可以自己隨意設置
password[]=1stPeak
獲取php源碼payload:
獲取index.php
base64解碼:
獲取ping.php源碼:
payload:
base64解碼:
ping.php的源碼是修改的DVWA High級別的源碼,將"| “改成了”|",更加嚴謹
Payload(以下兩種在bp中都可用,在hackbar中第二種不可用):
或
%0a(表示換行,a不區分大小寫,在Linux下使用,linux,linux,linux!!!)介紹:
參考:
https://www.webshell.cc/4362.html
https://www.xuebuyuan.com/431420.html
https://www.freebuf.com/articles/web/129607.html
https://www.cnblogs.com/wangyuyang1016/p/11999986.html
總結
以上是生活随笔為你收集整理的I春秋第四季CTF-Web-Writeup(部分)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超级课程表有哪些功能(超级玛丽小游戏)
- 下一篇: 中国农业银行app怎么添加银行卡(《中国