S3C2021-部分WriteUp
前言
2021年S3C CTF结束了(S3C CTF是学校工作室举办的,为了招新)
本WP只包含本人出的题,题目提供docker-compose包。
尝试了一下运维比赛,还好没有出说什么大问题
题目
出题时已经考虑题目尽量往简单,但是没有一道是原题,是我对自己的知识的梳理而出的,绝对原创
水平有限,第一次出题,若发现问题欢迎指出,非常感谢
WEB
环境大多为PHP7.0+PHP-FPM+Nginx,最后一题为Python Flask
学霸题,数正方体 | 动态 | 100分 | @1x
想考察python requests包的基本使用
侧信道攻击 | 动态 | 496分 | @1x
考察思维和观察能力
解压小游戏 | 动态 | 100分 | @1x
想考察Web技术了解和JavaScript脚本运行流程分析
私人图片库 | 动态 | 275分 | @1x
考察SQL之万能密码、简单文件上传(一句话木马及工具的利用)
查询-1 | 血分 | 350分 | @1x
考察SQL注入之联合查询注入
popchain | 血分 | 400分 | @1x
PHP魔术方法和简单popchain构造
安全知识学习(未上线,不提供)
传参json与重放攻击
MISC
黑阔入侵 | 动态 | 100 | BY@1x
Wireshark的基本使用
Call me | 动态 | 304 | BY@1x
分析找规律、ANSCII码与字符Pyhton程序理解
Re
(C程序)
在 windows下由GCC编译
拒绝手算 | 动态 | 500 | BY@1x
基本逆向
(Mobile)
由Android Studio构建-Java
简单apk | 动态 | 275 | BY@1x
APK反编译工具的使用
APK1 | 动态 | 496 | BY@1x
Java程序阅读与理解
详解
学霸题,数正方体
题目的docker-compose文档提供下载(若不清楚如何使用,请看文末):
/static/post/s3cctf2021/ext/zfx.tar.gz
正方体的数量是随机产生的,而且时间有限制,要求在两秒之内回答正确的正方体数量
服务端部分程序如下
1 | $_SESSION['CREATED'] = time(); |
完全可以设一个非常大的随机数范围,但是这里只设置如下,
所以完全可以被数出来或者一直尝试一个数字而撞出来
1 | $lifeTime = 2; |
正经做法如下
观察HTML的Form表单部分
可得知为POST传参,参数有两个,
一个是代表正方体数量的cube_num,
而另外一个是不那么明显的submits参数,要注意此参数值为submit
1 | <form action="index.php" method="post"> |
后端部分代码如下(下面的代码并不完整,贴出来只是为了方便理解)
(若不想看可以跳过此步)
1 | $get_val0 = $_POST["cube_num"]; |
因此可以编写程序进行自动提交
(程序为python3)
1 | import requests |
侧信道攻击
之前看过一些较为久远但十分有趣的攻击案例,例如由于密码验证系统的设置缺陷,利用时间信息可以强行猜出较长位数的密码,
不信的的话,且看下面,这道题将做一个小小示范
题目的docker-compose文档提供下载(若不清楚如何使用,请看文末):
/static/post/s3cctf2021/ext/cexindao.tar.gz
当访问题目,将会看到以下PHP代码
1 | <?php |
注意到BF算法的函数中的
1 | usleep(50000); |
理解程序之后可以知道,当某位字符与目标字符不匹配,将会延时50毫秒
不妨打开F12的浏览器调试工具,输入一位字母或数字尝试
正确与错误密码的响应时间差别较大
这样就能一位一位地将密码试出
若不愿手动尝试,提供自动尝试的python程序
1 | import requests |
解压小游戏
一个很简单的小游戏
虽然通关就给flag,但是正经做法请看如下
题目的docker-compose文档提供下载(若不清楚如何使用,请看文末):
/static/post/s3cctf2021/ext/xiaoyouxi.tar.gz
分析得知此游戏为静态的
既然游戏到38关会给flag,那么应该存在相关的判断程序,所以需要关注相应的JavaScript文件
考虑到招新赛不会太难,接下来基于不同情况通常有两种做法
做法一:
找到相应js文件,判断的程序被加密—>找到游戏判断通关的语句进行修改,直接通关拿flag
做法二:
找到相应js文件,判断的程序未加密—>直接拿flag
本题基于做法二
打开游戏界面再按F12打开调试器,转到network选项卡
刷新界面,此时可以看到加载的文件
对文件类型进行排序,再排除掉一些没有存在服务器上的文件,就剩下下面两个js
打开common.js发现与游戏处理关系不大,排除
再打开fra.js,发现就是游戏的处理相关
仔细看,跟随游戏的处理、调用,可以找到
或者如果能猜到有弹窗告诉flag,可以直接搜索alert(这里做了处理,搜s3c搜不到flag)
私人图片库
主要考察对一句话木马的理解,顺便提供一次入侵的机会
题目的docker-compose文档提供下载(若不清楚如何使用,请看文末):
/static/post/s3cctf2021/ext/sirentuku.tar.gz
本题登陆密码19位,爆破不可能完成
因为网页源带代码已经给了提示,箭头所指处为sql语句(数据库为MYSQL),
容易知道万能密码可绕过登录
部分后端程序如下(若不想看可以跳过此步)
1 | $cannot = array("-- ", "delete", ";", "drop", "group_concat(", "join", "insert", "into", "outfile", "~", "concat(", "updatexml", "extractvalue", "create", "alter", "desc", "concat_ws(", "update", "rename", "*", "/*", "*/", "()", "length", "rand(", "floor(", "sleep(", "benchmark(", "ascii(", "rpad(", "load_file(", "repeat(", "rlike", "get_lock(", "substr(", "mid", "regexp", "^", "like"); |
万能密码只需要在网上随便找一句类似于1’or ‘’=’即可
登录进去是一些图片展示,如果能看到右上角的上传图片,距离获取flag仅有两步之遥
如果有尝试过上传,可以知道仅允许上传图片
为了入侵服务器,需要上传一句话木马
此时结合提示可以得知容易绕过
可知仅过滤MIME类型,未有对文件后缀名进行过滤,
而MIME类型由浏览器判断后缀名得来,因此可以直接抓包修改
部分后端程序如下(若不想看可以跳过此步)
1 |
|
使用的一句话木马如下
此题有两种方法,
一种方法是先上传一句话木马.php再使用brup suite抓包更改MIME类型为image/jpeg,最简单
另外一种是制作图片马,即图片与一句话木马合成(图片木马),抓包后改为php后缀,就不必修改MIME,提交即可上传成功
至于为什么需要php为后缀,因为这台服务器上被设置成了只有.php后缀的文件才能当做php脚本解释
(web服务器用的是nginx,且设置了只解释.php后缀的文件)
这里只讲方法一
方法一
直接上传一句话木马,按下上传时抓包
更改Content-type(代表MIME类型),上传成功
打开蚁剑(中国菜刀也行)新建连接,填上前面的图上一句话木马的信息
打开文件管理
来到web目录,可以看到提示
获取flag
查询-1
这题没有什么难度,只要稍懂SQL语句以及能找到一篇比较详细的联合查询注入教程,即可完成
基本上没有过滤联合查询注入需要的语句
题目的docker-compose文档提供下载(若不清楚如何使用,请看文末):
/static/post/s3cctf2021/ext/check-1.tar.gz
写了一篇有关SQL注入的博客,感兴趣可以来康康:SQL注入常用姿势
过滤程序如下(用正则可能会好一些,这里是利用字符串查找)
1 | $cannot = array("-- ", "delete", ";", "drop", "group_concat(", "join", "insert", "into", "outfile", "~", "concat(", "updatexml", "extractvalue", "create", "alter", "desc", "concat_ws(", "update", "rename", "*", "/*", "*/", "()", "length", "rand(", "floor(", "sleep(", "benchmark(", "ascii(", "rpad(", "load_file(", "repeat(", "rlike", "get_lock(", "substr(", "mid", "regexp", "^", "like"); |
题目已经提示叫尝试id 0-5,那就查查试试看
到id为3时得到一个有用的提示,叫尝试联合查询
到id为5时提示flag就在名字叫做flag的表里面
下面是解题思路
1 | 0'order by 3# |
或者运行下面的程序获取flag
1 | import requests, time |
运行截图如下
popchain
简单的PHP POP链构造
题目的docker-compose文档提供下载(若不清楚如何使用,请看文末):
/static/post/s3cctf2021/ext/popchain.tar.gz
进入题目,可以见到以下程序
1 |
|
程序大意是通过GET获取参数pop的值,base64解码后再反序列化
构造程序如下即可完成解题
1 |
|
最后提交生成的base64字符串
1 | http://题目地址/?pop=Tzo5OiJzdG9wX2N0cmwiOjE6e3M6NDoiY3RybCI7Tzo3OiJzZXR0aW5nIjoyOntzOjc6ImN0cmxfbWUiO047czozOiJzZXQiO086NjoibG9nZ2VyIjozOntzOjM6InN0ciI7Tzo3OiJzZXR0aW5nIjoyOntzOjc6ImN0cmxfbWUiO047czozOiJzZXQiO2k6MTt9czo0OiJpbmZvIjtOO3M6NDoiZnVuYyI7TzoxMzoidXNlcl9mdW5jdGlvbiI6MTp7czo1OiJ2YWx1ZSI7czoyODoibHMgLztlY2hvICI8YnIgLz4iO2NhdCAvZmxhZyI7fX19fQ== |
其它诸如构造POP链可以康康:
安全知识学习
无
黑阔入侵
这题是为了给大家了解wireshark的简单使用而出的
有两种解法,先讲wireshark的使用
附件:
/static/post/s3cctf2021/ext/1.pcapng
解法一:
一般先关注http流量,因为比较好找
打开流量文件后在下图所示处输入http即可看到所有http流量
找到不是404状态的带有flag字样的东西
为了获取这个文件,需要追踪http流
这里已经获取到了flag
如果flag没有在这里明文显示呢?
可以尝试获取黑阔得到的文件
将格式换成“原始数据”
选中红色部分,按下退格键删除
可以看到红色部分变成了灰色,此时按下下图中的黑色箭头所示按钮
因为这个流名字就叫flagflag.zip,所以这里保存为zip文件
解法二:
使用010Editor或winhex,直接打开,搜索s3c
Call me
附件:
/static/post/s3cctf2021/ext/flag.zip
附件给的是一种使用二进制实现自制编码的方法
要对这种编码进行解码,可以以LX(两个大写字母)开头,将字符串分为组,根据”!”为0,”?”为1来转成二进制
再转ASCII,即可获取flag
感兴趣可以来康康这个:自制一个简单的编码方法
解题程序如下
1 | flag = "LX?Lx?Lx?Lx!Lx!Lx?Lx?LX?Lx?Lx!Lx!Lx?Lx?LX?Lx?Lx!Lx!Lx!Lx?Lx?LX?Lx?Lx?Lx?Lx!Lx?Lx?LX?Lx?Lx?Lx!Lx!Lx!Lx!LX?Lx!Lx!Lx?Lx?Lx!Lx!LX?Lx?Lx!Lx!Lx?Lx!Lx?LX?Lx?Lx!Lx?Lx!Lx!LX?Lx?Lx?Lx!Lx!Lx?Lx?LX?Lx!Lx!Lx!Lx?Lx!Lx?LX?Lx!Lx?Lx?Lx?Lx?Lx?LX?Lx?Lx!Lx!Lx!Lx?Lx?LX?Lx!Lx!Lx!Lx!Lx!Lx?LX?Lx?Lx!Lx?Lx?Lx!Lx!LX?Lx?Lx!Lx?Lx?Lx!Lx!LX?Lx!Lx?Lx?Lx?Lx?Lx?LX?Lx!Lx!Lx?Lx?Lx!Lx?LX?Lx?Lx!Lx!Lx?Lx?LX?Lx!Lx?Lx?Lx?Lx?Lx?LX?Lx!Lx!Lx?Lx?Lx!Lx!LX?Lx!Lx?Lx?Lx!Lx!Lx!LX?Lx?Lx?Lx?Lx?Lx!Lx?" |
拒绝手算
需要一些耐心
提供文件下载
/static/post/s3cctf2021/ext/re.exe
IDA打开
可以见到一堆加密后的东西
程序逻辑:程序接受输入的flag,加密后再与存储的数据进行比较,若相同,则输入的字符串为正确flag
跟进程序,发现经过两段加密
找到这两个函数
enc1大意是
第一个for循环
循环0-255为i,a1也就是索引空间为256的一个数组,以i为索引存入i
a2也就是密钥,即上图的Str变量,即‘abcdefghij’,i%10为索引循环读取a2存入v4
第二个while循环
还是0-255为j,v5存的其实是a1以j%5为索引的值
v6存的是 以j为索引读取v4加上v5加56,v4变量就是上面那个for循环中,以0-9为周期循环存着密钥的v4
最后处理a1,a1基地址加上6再加上j%249,指针指向其值,加上v6
第三个for循环
循环0-255为j
a1基地址加上j来指针访问其值,赋值为指针访问a1基地址加上j+56得到的值再%256
enc2应该比enc1好理解
第一个循环
以密钥长度决定i到多大结束,也就是到255会break掉
v5以i为索引存入i%5
第二个循环
仍然以密钥长度决定i到多大结束,还是到255会break掉
这里的Str是经过enc1加密后的数组,与a2也就是密钥字符串,读取(v5[i]+i)%10后作为a2索引,得到a2里的值进行异或操作
最后一个疑点
回到main函数,发现v9的最大索引数字是245
既然循环都以0-255,但密文只有0-245怎么办?
只需在后面的位置填0,因为编译器分析索引为245以后的值用不上,给优化掉了
1 | [-54, 15, -8, -47, 28, -1, -19, 53, 19, -6, -8, 60, 48, -26, -2, 63, -37, 33, 25, -13, -21, -10, 43, -22, -68, 4, -13, 43, -35, -69, 1, -82, 56, -40, -74, -63, -5, 4, -23, -75, -42, 17, 80, 15, -22, 37, 17, 80, 15, -22, 37, 31, 90, 21, -28, 47, 31, 90, 21, -28, 47, -27, 44, 27, -2, 57, -27, 44, 27, -2, 57, -13, 54, -31, -56, 3, -13, 54, -31, -56, 3, -7, 56, -9, -62, 13, -7, 56, -9, -62, 13, -57, 2, -3, -36, 23, -57, 2, -3, -36, 23, -51, 20, -61, -42, -31, -51, 20, -61, -42, -31, -37, 30, -55, -96, -21, -37, 30, -55, -96, -21, -95, -32, -33, -70, -11, -95, -32, -33, -70, -11, -81, -22, -91, -76, -1, -81, -22, -91, -76, -1, -75, -4, -85, -114, -55, -75, -4, -85, -114, -55, -125, -58, -79, -104, -45, -125, -58, -79, -104, -45, -119, -56, -121, -110, -35, -119, -56, -121, -110, -35, -105, -46, -115, 108, -89, -105, -46, -115, 108, -89, -99, -92, -109, 102, -79, -99, -92, -109, 102, -79, 107, -82, -103, 112, -69, 107, -82, -103, 112, -69, 113, -80, 111, 74, -123, 113, -80, 111, 74, -123, 127, -70, 117, 68, -113, 127, -70, 117, 68, -113, 69, -116, 123, 94, -103, 69, -116, 123, 94, -103, 83, -106, 65, 40, 99, 83, -106, 65, 40, 99, 89, -104, 87, 34, 109, 89, -104, 0, 0, 0, 0, 0, 0, 0, 0] |
解题程序如下
1 | enc_flag = [-54, 15, -8, -47, 28, -1, -19, 53, 19, -6, -8, 60, 48, -26, -2, 63, -37, 33, 25, -13, -21, -10, 43, -22, -68, 4, -13, 43, -35, -69, 1, -82, 56, -40, -74, -63, -5, 4, -23, -75, -42, 17, 80, 15, -22, 37, 17, 80, 15, -22, 37, 31, 90, 21, -28, 47, 31, 90, 21, -28, 47, -27, 44, 27, -2, 57, -27, 44, 27, -2, 57, -13, 54, -31, -56, 3, -13, 54, -31, -56, 3, -7, 56, -9, -62, 13, -7, 56, -9, -62, 13, -57, 2, -3, -36, 23, -57, 2, -3, -36, 23, -51, 20, -61, -42, -31, -51, 20, -61, -42, -31, -37, 30, -55, -96, -21, -37, 30, -55, -96, -21, -95, -32, -33, -70, -11, -95, -32, -33, -70, -11, -81, -22, -91, -76, -1, -81, -22, -91, -76, -1, -75, -4, -85, -114, -55, -75, -4, -85, -114, -55, -125, -58, -79, -104, -45, -125, -58, -79, -104, -45, -119, -56, -121, -110, -35, -119, -56, -121, -110, -35, -105, -46, -115, 108, -89, -105, -46, -115, 108, -89, -99, -92, -109, 102, -79, -99, -92, -109, 102, -79, 107, -82, -103, 112, -69, 107, -82, -103, 112, -69, 113, -80, 111, 74, -123, 113, -80, 111, 74, -123, 127, -70, 117, 68, -113, 127, -70, 117, 68, -113, 69, -116, 123, 94, -103, 69, -116, 123, 94, -103, 83, -106, 65, 40, 99, 83, -106, 65, 40, 99, 89, -104, 87, 34, 109, 89, -104, 0, 0, 0, 0, 0, 0, 0, 0] |
源程序如下
1 |
|
简单apk
附件:
/static/post/s3cctf2021/ext/app-release.apk
反编译后打开com.example.myapplication/MainActivity即可看到flag
反编译软件可以用jadx-gui
APK1
附件:
/static/post/s3cctf2021/ext/app-release1.apk
反编译后打开com.example.myapplication/MainActivity,
可以看到程序获取了用户输入后将值传入到了re_me()
同时可以发现有个奇怪的类叫re_me
打开研究一下就能写出逆向程序
解题程序
1 | test = [14,114,95,36,86,62,67,246,214,20,44,54, |
dockers-compose编译镜像
此部分将引导docker-compose的简单使用
安装docker组件
先确定docker-compose是否已经安装
(一般windows上的docker软件会把docker-compose一同安装)
(在Centos上,docker-compose可能需要单独安装)
1 | docker-compose --version |
Ubuntu可直接安装
1 | sudo apt install docker-compose |
解压与释放
若已安装,则对在本文下载的文件进行解压
确定终端处于下载的.tar.gz文件所处的目录
对.tar.gz文件进行释放操作
命令类似如下
1 | tar -xvzf 文件名 |
进入释放后的目录
1 | ls |
1 | cd 目录名 |
修改配置(若无需修改,跳过此步)
终端界面可以使用nano、vim等,图形界面直接右键文本编辑
推荐使用nano
1 | nano 文件名 |
箭头所指处为映射IP,8089改成你想修改的端口即可
修改完成使用ctrl+x退出
输入yes即可保存
编译镜像
确定已经在释放的目录
1 | sudo docker-compose build |
如果卡在此步可进行换源
换源
1 | nano /etc/docker/daemon.json |
输入
1 | { |
重启docker
1 | service docker restart |
继续编译
启动容器
1 | sudo docker-compsoe up -d |
正常运行
1 | sudo docker ps |
删除容器
1 | sudo docker-compsoe down |
尾声
谢谢你看到这里
EOF