融贯杯 writeup
学长闲的没事干 给学弟出题 顺便给外校人员也做做 就诞生了本次的融贯杯
然后我被拉过来出题 出了19道web和9道misc 写下我的解题思路
整体难度不是很大 题目质量还可以,有些题目是搬运或者稍加修改。
WEB>
1.代码的秘密
题目如下:
打开源码发现一段js代码
在本地运行js代码 获得flag
2.本地访问
题目如下:
题目提示说要本地访问 因此想到用X-Forwarded-For构造ip
尝试访问后发现源代码:
第一层绕过后 要求我们用User-Agent伪造admin
访问后绕过判断
这里要我们使用post传入参数password 当password为admin123时即可拿到flag
访问得到flag:
3.密码爆破
题目如下:
结合题目提示要求我们爆破密码 并且密码为5位数字
这里可以用python写脚本 或者用 burpsuite 进行爆破 用burpsuite更快一点
python脚本如下:
import requests
def getpasswd():
ls = []
for i in range(10000,100000):
ls.append(i)
return ls
def flag():
url = "http://47.96.153.252:28003/"
for i in getpasswd():
data = {'password':i}
http=requests.post(url,data=data)
if "密码错误" in http.text:
print('[-]%s pass'%i)
pass
else:
print('[+]%s'%i)
break
flag()
burpsuite需抓包 然后进行Intruder爆破
得到密码32767 解得即可。
4.运维失误
题目如下:
进入题目发现无权访问 结合简介提示找网站备份文件 可以判断www.zip www.tar.gz robots.txt 等等。
得到源码文件
index.php:
这里要我们传入username和password参数 然后账号密码是不知道的 要经过md5验证才能拿到flag
再看74037e0c.php
得到账号密码 传入username和password即可拿到flag
5.时间穿梭
题目如下:
点击题目超链接 却被重定向到另一个页面
猜测题目用了header重定向 这里用burpstuie拦截
开启拦截 点击超链接
发送到repeater
得到flag
6.狡猾的前端
题目如下:
提示我们flag就在源码里 尝试用f12查看
几乎能查看源码的键都被js过滤了 这里可以用postman查看
这里非预期解是可以通过多次按f12或者其他键 可以卡出源代码
7.Ez_Bypass
题目如下:
先看源代码:
提示我们传两个参数 func 和 cmd
传入得到源码
代码审计一番过后 大致了解了题目使用call_user_func函数 从用户传入的函数和参数进行执行
这里第一层是绕过过滤函数
第二层是过滤flag关键词
绕过过后即可执行命令
这里有hint 先看hint
传入/?func=&cmd=&hint
提示先用scandir找flag 然后用system一把梭
因为使用print_r所以结果会以数组返回 导致我们可以用scandir看任意路径文件
传入/?func=scandir&cmd=/
找到flag
然后用system执行命令。
这里因为flag被过滤了 结合题目简介提示,我们可以用linux的特性绕过。
linux下可以定义一个变量为一个字符串 然后引用这个变量
因此我们可以定义多个变量 然后拼接绕过flag过滤
传入/?func=system&cmd=a='fl';b='aggggHere';cat /$a$b
8.nizhuansiwei
题目如下:
题目主要是两层绕过
首先file_get_contents读取到的文件内容要为welcome to the wzzctf一般来说是不可能的
结合题目提示 用data://绕过
这里是要用data://伪协议构造文件内容
先将内容进行base64
传入/?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgd3p6Y3Rm
即可绕过第一层
然后需要我们传入一个反序列化后的password的值 要为hacker 即可得到flag
现在本地测试
输入password=s:6:”hacker”; 即可
9.某职专后台系统
题目如下:
一个登录平台 结合题目提示存在高危漏洞 猜测是SQL注入漏洞
先用万能密码试试
直接进入了 但是没有flag 此题为回显型SQL 因此尝试爆数据库 爆表 拿flag
三个字段
爆数据库:
1' union select 1,database(),3 #
爆表:
1’ union select 1,table_name,3 from information_schema.tables where table_schema=database()#
得到表flag
然后再查字段名
爆字段:
1' union select 1,column_name,3 from information_schema.columns where table_schema=database() and table_name='flag'#
字段名也是flag 最后直接查询就可以了
payload:
1' union select 1,flag,3 from website.flag #
10.你传你马呢
题目如下:
文件上传题目
随便上传个php文件
报错,这里error_log记录的是文件的MIME值 猜测题目是检测文件MIME值 而图片的MIME是白名单
所以先上传个图片 然后再把文件内容和后缀改为php即可。
先写个马
把后缀改为jpg
先用burpsuite开启拦截 然后上传图片。
后缀改为php上传
访问木马蚁剑连接 或者直接传参都可以
11.Baby_Ping
题目如下:
一个ping功能的平台 要想到使用ping的时候肯定是在靶机中运行 然后我们可以用;隔开执行多个命令
先试试1.1.1.1;ls
成功执行 直接看根目录下的flag
12.Baby_MD5
题目如下:
先输入?game开始
得到源码:
题目注释也提示的很明显了 需要绕过三层 分别为数组绕过 0e绕过 原值绕过
第一层:
需要我们传入两个值val1和val2两个值不同 但是它们的md5值要相同
这里考察的点就是用数组绕过,php中因为数组的值不能被md5处理,则返回NULL,导致相等。
本地测试如下:
可以看到两个值为空值 php中空值相等 且两值相等 所以绕过。
/?game&val1[]=1&val2[]=2
第二层:
这里也是要我们传两个不同的值 且MD5值相同 不同的是这里传入的值必须为string类型 不能为数组
这里考察的是0e绕过 原理是两个值的md5开头为0e php中0e开头的字符串在参与比较时 会被当做科学计数法 结果转换为0 因此绕过
一些绕过值:
QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
传入任意两个即可。
/?game&val1[]=1&val2[]=2&val3=QNKCDZO&val4=240610708
第三层:
这里要我们传入的值等于其md5的值 是原值绕过
记录一个值:
0e215962017 的 MD5 值也是由 0e 开头,在 PHP 弱类型比较中相等
所以post传入即可拿到flag
13.套娃
题目如下:
先看源代码
substr_count() 函数计算子串在字符串中出现的次数
$_SERVER['QUERY_STRING']
例如:
http://localhost/aaa/index.php?p=222&q=333
结果:
$_SERVER['QUERY_STRING'] = “p=222&q=333”;
因此想要绕过我们传入的参数得没有_下划线 但是我们传参又必须要有w_z_z_c
下划线的绕过我们可以用 . 或者 空格 来代替这个符号
后面的绕过正则只需要用%0a截断即可
payload:/?w z z c=23333%0A
或/?w.z.z.c=23333%0A绕过
14.异或的马
题目如下:
这是通过异或写的一段木马 只要看懂代码就可以执行了。
可以直接用php执行。或者用python写 这里php方便一点
可以看到木马大致为assert($_GET['H@ck'])
连接方式为get
密码为H@ck
payload:/?H@ck=system(%27cat%20/flag%27)
15.字符?正则?
题目如下:
这里我们传入的id只要符合正则匹配就可以拿到flag
这个正则有点复杂 慢慢分析:
“/key.*key.{4,7}key:/./(.*key)[a-z][[:punct:]]/i”
/ /是定界符;
key,直接使用,id=key
.是元字符,表示除了换行符的任意一个字符,就取a好了,id=keya
*是量词,表示前一个元字符a的数量0个或多个,即{0,}。取零个,id=key
key,直接使用,id=keykey
.取a,id=keykeya
{4,7}是量词,表示前一个元字符a的数量为4到7,取4个,id=keykeyaaaa
key,直接用,id=keykeyaaaakey
:也直接用,id=keykeyaaaakey:
/即/,\防止转义,id=keykeyaaaakey:/
.取a,id=keykeyaaaakey:/a
/即/,id=keykeyaaaakey:/a/
(.*key)是一个分组,.取a,星号取零个,key直接用,id=keykeyaaaakey:/a/key
[a-z]任取一个a-z的小写字母,取a,id=keykeyaaaakey:/a/keya
[[:punct:]]表示任取一个标点符号,取:,id=keykeyaaaakey:/a/keya
i为模式修饰符,表示不区分大小写
所以得到payload为:
?id=keykeyaaaakey:/a/keya:
16.Easy_Ping
题目如下:
先让我们传入参数ip
又是ping题 尝试用;来执行命令
成功执行,尝试cat /flag
发现空格被过滤 可以用$IFS$9绕过空格
flag被过滤
尝试先看源码。
得到源码:
这里把空格 一些特殊符号 bash 和flag过滤了
这里利用linux变量特性绕过
这里没绕过正则匹配 如果先写fl 再写ag 还是和正则匹配上的
把fl 和 ag 反一下就可以了
payload:/?ip=1.1.1.1;a=ag;b=fl;cat$IFS$9$b$a.php
17.闪电五连鞭
题目如下:
第一个判断:
当没有用GET方法传入flag时,会显示Click here的链接。
点击链接会用GET方法传入一串字符串$exam,后面是当前时间的一串sha1哈希值。
第二个判断:
这里要传入的flag值为例子exam的长度
先点超链接看例子
用python看下长度:
长度为49
我们可以用垃圾字符填充flag值 如[代码];1*n;这种方式
第三个判断:
过滤了一堆字符`’”‘.‘\‘(‘)‘[‘]‘_’flag’echo’print’require’include’die’exit
第四个判断:
判断传入flag的值等于flag值的哈希值,正确就输出flag。用的是严格的三个等号的比较,flag都不知道,哈希值更不可能知道(===强相等,类型和值都要相等),
但存在eval($_GET['flag'])可以任意代码执行
尝试绕过过滤:
echo被过滤了,用php短标签进行输出;
flag被过滤了,用先赋其他值,再修改的方法绕过
当php开启短标签后,
能正常解析类似于这样形式的php文件: phpinfo() ?>
并且可以使用<?=$a?>的形式输出
为了使payload长度与$exam长度相等,在代码间加入无意义的语句。
构造payload:/?flag=$a=blag;$a{0}=f;111111111111111111111;?>=$$a;?>
18.PHPGame
题目如下:
先看源码:
先传参 然后开始。
题目源码如下:
<html>
<!--if($_REQUEST['mode']!="begin"){
die("Welcome PHP Games!");
}-->
</html>
<?php
error_reporting(0);
include 'fl4g.php';
if($_REQUEST['mode']!="begin"){
die("PHP Games!");
}else{
show_source(__FILE__);
class last_task{
var $left;
var $middle;
var $right;
}
$a=$_GET['a'];
$b=$_GET['b'];
if($a==$b){
die("wrong way");
}else{
if(md5($a)!==md5($b)){
die("need a little magic");
}else{
if($_POST['token']){
$token = unserialize($_POST['token']);
if($token['user']=="user"&&$token['pass']=="pass"){
$flag=$_POST['flag'];
if($flag){
$flag = unserialize(urldecode($flag));
$flag->middle = $fl4g;
if($flag->middle===$flag->left&&$flag->middle===$flag->right){
echo "this is your flag ".$flag->middle;
}else{
die("one more step");
}
}else{
die("don't give up");
}
}else{
die("Not a valid token");
}
}else{
die("give me the token");
}
}
}
}
?> wrong way
1、MD5弱比较绕过
这里是要传入的变量a和变量b一样 并且md5值不能一样。
这里考察的点就是用数组绕过,php中因为数组的值不能被md5处理,则返回NULL,导致相等。
本地测试如下:
因此第一层用/?mode=begin&a[]=1&b[]=2 绕过
2、数组反序列化
这里要传一个数组,还得是反序列化,在本地构造一个就可以了。
a:2:{s:4:”user”;s:4:”user”;s:4:”pass”;s:4:”pass”;}
成功绕过。
3.PHP反序列化浅拷贝
重点来了,,这里是最难的部分。
这里的意思是传一个反序列化后的值。然后要使last_task类中的left和right一定要等于$middle的值(这里middle的值是fl4g.php中的$fl4g变量) 也就是说能绕过就可以得到flag了。
因为绕过if判断后输出的值也是middle的值,而middle的值就是flag,所以我们不能改变middle的值。但是又得让left和right的值为middle的值,显然我们不知道flag是做不到的,因此这里考察的一个知识点就是PHP浅拷贝。
参考文章https://blog.csdn.net/crisprx/article/details/104457047 师傅讲的很细,这里概述一下。
先说一下深拷贝和浅拷贝通俗理解
深拷贝:赋值时值完全复制,完全的copy,对其中一个作出改变,不会影响另一个
浅拷贝:赋值时,引用赋值,相当于取了一个别名。对其中一个修改,会影响另一个
举个例子:(这里只做浅拷贝的例子)
(网站回显)
而这道题要用到'&' 来浅拷贝
再来个李子:
这里的知识点是引用传递。在这个例子中,将$a为crispr copy,$a前添加& 而$b又等于$a,然后又改变了$b的值,导致$a的值改变了。
参考:https://www.php.net/manual/zh/language.references.pass.php
所以我们的payload为:
或者:
这里将left和right的值取&$middle的值 然后再将值序列化传入即可。
O:9:”last_task”:3:{s:4:”left”;N;s:6:”middle”;R:2;s:5:”right”;R:2;}
传入flag post值 得到flag
19.应可鲁德
题目如下:
先是一个登陆页面,然后随便输入个id进去。如下:
点击超链接,发现url明显的是文件包含。
尝试读取默认文件 /etc/passwd
成功读取到了。说明这是一个通过get传参的include函数。
尝试读取flag一把梭。
无果
先慢慢来,看源码先。
这里用php://filter伪协议读取文件
构造payload:php://filter/read=convert.base64-encode/resource=index.php
index源码如下:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<form action="action.php" method="POST">
please input your name:
<input type="text" name="name" >
<input type="submit" value="Submit">
</form>
</body>
</html>
再看下action.php的文件内容
action源码如下:
<?php
session_start();
error_reporting(0);
$name = $_POST['name'];
if($name){
$_SESSION["username"] = $name;
}
include($_GET['file']);
?>
<!DOCTYPE html>
<html>
<div>
<a href="action.php?file=1.txt">ctf推荐书籍</a>
<a href="action.php?file=2.txt">ctf刷题平台</a>
</div>
</html>
这里很明显就是session包含。
在action.php中代码的这一块:
$name = $_POST['name'];
if($name){
$_SESSION["username"] = $name;
}
其原理是:
在我们在首页(index.php)通过post传参传入了id后会发送到action.php 在action.php中会把用户名保存为传入的post值
而这个post值是可控的。因此我们只要传入 一句话进去,再通过session
会创造一个临时文件,我们访问临时文件就可以实现任意代码执行了。接下来就懂得都懂。
php的 session文件的默认存放位置大致如下
/var/lib/php/sess_PHPSESSID
/var/lib/php5/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID
先id传个
访问:/action.php?file=php://filter/read=convert.base64-encode/resource=/tmp/sess_1c87b143947ceb5dac0b2adf082d0aab
然后我们直接访问 /action.php?file=/tmp/sess_1c87b143947ceb5dac0b2adf082d0aab
到这里就简单了,然后我们再写个一句话木马进去
传入?file=/tmp/sess_c2ae0bc438de4b10b87b791a7514a375&c=system('ls /');
(注意这里多个传参要用&拼接)
最后cat /fl444444444g就可以了
MISC>
1.无法达到的深度
题目附件:
结合题目和简介 (深度) 猜测通过改图片高度来拿flag
图片属性:
winhex打开图片分析
高度628的hex值为0274 通过winhex搜索
这里左边的是高度 右边的是宽度
把0274改高 比如改为0500 保存:
图片有文字提示 再改高点 直接改为 2F00(约10000)
得到flag
2.五步飞扬
题目附件:
第一步:
ASCII:
102 108 97 103 123
用python解
解得 flag{
第二步:
URL:
%5Cu0063%5Cu0034%5Cu0038%5Cu0032%5Cu0035%5Cu0031%5Cu0035%5Cu0030
url解码得到 c4825150
得到c4825150
第三步:
摩斯电码
-….- . —-. ..-. —-. —– —– -.-. —–
在线网站解一下即可。
得到-e9f900c0
第四步:
BrainFuck解码
+++++ +[->+ +++++ <]>++ +++++ ++.<+ +++++ +[->+ +++++ +<]>+ +++++ .–.+
+..<+ +++++ [->– —-< ]>— —– .—- —-. <++++ +++[- >++++ +++<]
>++++ +.<++ +++++ [->– —– <]>– –.++ .<
得到-dbdd80f13
第五步:
base系列(base64->base32->base16)
R1UyRE1PQldIRTNUR01SUUdZNFRPTVpTR0EzVFNOU0dHNDJUT01SU0dBM0RNTlNER1lZVE1OWlRJRVpFSU5SV0dZMkRHTUJUR0VaVE9NWlRHWVpET1JBPQ==
直接用ciphey一把梭:
得到:-fd0173b}
组合flag 得到flag{c4825150-e9f900c0-dbdd80f13-fd0173b}
3.爆破鬼才
题目附件:
题目说是密码爆破 且为四位数字 用ARCHPR爆破
将压缩包拖入即可。
得到密码为8964 用密码打开文本即可得到flag
flag{657ef479be76fe227ce09f9dd22c2cd8}
4.九层妖塔
(此题搬运自DASCTF魔法世界 《闯入魔塔的魔法少女》)
题目附件:
预期解是用swf逆向即可 当然玩五十层魔塔也可以。。
用Flash Decomplier反编译工具打开
使用文件查找功能
直接搜索flag
在DoAction找到flag字段
转到DoAction 然后用ctrl+f快速查找 搜索flag
得到flag
DASCTF{23dvkjzr3juboiavztbncaxftfpyq5gz}
5.艾克赛斯
题目附件:
先看encode.py
这里先将flag的文本的每一个字符读取 将每一位ascii码进行-1操作
然后再把拼接起来的新的字符串作为十进制写到密文中。
密文如下:
8785377975578074175091449592699820502541930703609541378188644326830861555987356326396428107299197220
对应写解密脚本即可。
先将密文转为十六进制
这里再将ascii码分隔一下 然后再一一转为字符串即可
最终脚本如下:
def decode():
ciphey_text=8785377975578074175091449592699820502541930703609541378188644326830861555987356326396428107299197220
print(hex(ciphey_text))
#0x101107961021225548535199100999751545549984947505696495149549899475448501011015649124
list=[101,107,96,102,122,55,48,53,51,99,100,99,97,51,54,55,49,98,49,47,50,56,96,49,51,49,54,98,99,47,54,48,50,101,101,56,49,124] ###分离ascii码
flag=""
for i in list:
flag += chr(i+1)
print(flag)
decode()
运行得到flag
flag{8164dedb4782c2039a2427cd0713ff92}
6.lsp隐写
题目附件:
一张图片 不难想到此题为lsb隐写 标题也提示了 将图片拖入stegsolve中
进行通道分析:
将红绿蓝三个通道选为最低位 然后bit order选为lsb
在文件头部发现504B 这是压缩包的文件头
选择Save Bin到文本中
得到十六进制数值 然后将这段数据通过winhex写到压缩包中
504B030414000000080053A58353AADB061F360000003400000008000000666C61672E7478744B36CE294DF128A9F0ADF2AA4A7649A9F20D09ABF0AB8A344DAA8A3448CACAAE4ACE0AAAF40B4937F6CD7235F00BC936F2CD33B00500504B0102140014000900080053A58353AADB061F3600000034000000080024000000000000002000000000000000666C61672E7478740A0020000000000001001800DAEE244043E8D7011871A34643E8D701FCD9203D43E8D701504B050600000000010001005A0000005C0000000000
保存后 发现是文件加密 这里是伪加密
将0900改为0000即可。
打开文本 发现一段base64数据
在线解密一下
发现又是rot13 再解一下
得到flag
flag{d32fc7f15d769b64a93e4e5872145962}
7.异或与非
题目附件:
加密脚本如下:
[+]Your Ciphertext: ['f', '
‘, ‘
‘, ‘’, ‘’, ‘’, ‘S’, ‘’, ‘’, ‘P’, ‘V’, ‘’, ‘’, ‘‘, ‘
‘, ‘’, ‘’, ‘T’, ‘', ‘
‘, ‘’, ‘’, ‘ ’, ‘’, ‘V’, ‘V’, ‘Q’, ‘S’, ‘’, ‘P’, ‘S’, ‘’, ‘’, ‘’, ‘ ‘, ‘‘, ‘ ’, ‘I’]
审计代码:
首先将flag文本内容读出 然后创建了列表encode_flag 并添加flag的第一个字符
然后遍历flag字符串 将每一位字符与上一位字符的ascii码进行异或 转成字符
最后将结果打印出来
大致读懂代码后 根据print出来的东西写解密脚本
脚本如下:
def decode():
str=['f', '', '', '', '', '', 'S', '', '', 'P', 'V', '', '', '', '', '', '', 'T', '\', '', '', '', '