^

简单开发一个CTF平台

取名为Un1kCTF吧,被喷就改名。肯定干不过ctfd,但是就是想写着玩。

这次和vaalacat一起开发,我负责做平台的前后端,他负责做动态靶机的有关处理。

本文就作为开发进度文,也顺便督促自己做点东西出来。

2022-05-04

感谢bugku提醒。之前未在文章、网站注明前端主题来源。


目前只是因为主题好用 符合本人审美 并且前端开发比后端开发更繁琐 所以暂时使用了相关的布局

后期如若公司使用源码系统将会单独找美工开发 或者会更换布局 尽可能与bugku官方有差异

不过目前只是开发环境测试 并不会共享源代码传播运行环境

再次感谢bugku官方的提醒

2022-04-23

基本信息配置模块


后面可能还需要加其他选项卡 比如邮箱配置、登录配置、权限配置等等,大致demo先做咯

用户表



已解赛题后期根据api来操作,关闭添加时候操作就可以了

题目列表



先按照静态题目来写  后面需要绑定一下模型 就可以做动态分值、动态靶机的设置了

题目分类关联了 题目分类表 可以下拉指定

2022-04-24

解决多表关联显示问题


原来只能够显示1,2这样的id 需要通过left join 创建虚拟字段 拿到id对应的挑战名

记录一下关联的sql语句


2022-04-25



并根据积分进行排名 以及根据后台添加的题目 显示最新添加的9个


编写轮播图功能



接入公告推送与文章阅读



配置文件状态与平台状态同步生效



2022-04-25

编写题目展示模块


可根据用户选择切换分类


公告、题目做了分页

题目增加提示和writeup两个字段 当后台模式为比赛模式 不显示相关writeup


不做团队模式了 太麻烦了 累了

接着只要做flag提交 后台数据联动修改 用户登录 以及把控相关漏洞即可。

2022-04-26

今天把动态靶机做了 用户可以创建靶机 以及销毁容器



今天学到的东西

当用jquery前端追加html代码的时候 追加的代码无法绑定事件

这个时候需要

$("body").on("click", "#createScene", function() {
//code
}

来绑定到相关操作 由于销毁后 按钮会还原成创建靶机 所以两个事件都需要用这个方法 也不会冲突报错

配置用户只能创建一个动态靶机 


刷新界面后 只要该用户下存在未销毁场景 会覆盖到web赛题



当用户开两个界面时 企图绕过前端限制


通过后端用户解决赛题的列表 前端动态渲染


根据已解答赛题 限制提交flag


2022-04-27

增加用户登录功能 注册暂时没做


首页赛题攻克显示



2022-04-28

配置用户个人中心  并配置后台数据图用于统计


配置用户个人设置功能


并check了越权等漏洞是否存在 修复一个xss漏洞

增加pwn题的动态靶机部署 mode选择direct


优化前端用户信息显示菜单


2022-04-30

学习sql语句find_in_set


通过语句

SELECT * FROM `cd_chanllenge` WHERE find_in_set(chanllenge_id,(SELECT chanllenge_id from cd_userinfo where userinfo_id =19))

就可以定位到用户解决赛题所对应的所有题目记录

用户所解赛题是以题目id进行排列的,例如1,2,3,4 通过 find_in_set 就可以找到对应的记录 但是不能用in

原因是用in时 当查询的记录是字符串 就会默认转换成int 取第一个数值 当用户做了四题 他也只显示1题

之后只需要试用sum value就可以拿到总分了


但是这并不能实现我的目的

我们的逻辑是 通过用户的所解赛题字段 去表chanllenge找id 然后通过计算后 进行排序 上面我们只是指定了用户id才知道用户的分数

显然 我们都不知道排序情况  并且这个语句只能查出总分 以及对应id 如果是通过遍历用户id 在排序 拿代码太不够简单了

于是重新学习了下 left join 具体的解决思路如下:

1.通过left join 把用户表设置为主表 题目表设置为副表

2.通过find_in_set 函数,通过题目表的chanllenge_id 去用户表的chanllenge_id 进行查询 例如用户解决了四道赛题 那么 会显示四条记录 用户信息的字段都是一样的 无非是聚合的题目信息分别为 四个他所解赛题的信息

3.之后通过nickname 进行groupby 拿到sum(value)

4.通过sum(value) 进行desc排序

语句如下

select nickname,sum(value) from cd_userinfo a left join cd_chanllenge b on find_in_set(b.chanllenge_id,a.chanllenge_id) group by nickname order by sum(value) desc


没想到第一次翻数据库的书居然是写代码的时候 上课都在玩游戏T T

但是这还是不太行 比如我给用户设置了status 给题目也设置了status 我们可不可以弄一个 只有题目有效 和用户正常的状态下 才显示在排行榜 并设置分数呢?

所以进一步优化我们的sql语句

select nickname,sum(value) as total from cd_userinfo a left join cd_chanllenge b on find_in_set(b.chanllenge_id,a.chanllenge_id) where a.status =1 and b.status =1 group by nickname order by sum(value) desc limit 0,10

这里 进行查询的时候我们需要设置为将nickname和sum设置为查询字段,加上判断条件。a代表userinfo表,b代表题目表,只有两个字段都是1代表都正常的时候,才进行聚合。

前面我们的语句把总分as成count 发现出问题了 原来是表里本来就有count,无法覆盖。

最后排行榜显示成功了 不需要额外给数据表加字段 并且可以实时显示总分 (之前的处理逻辑太蠢了 每次用户做题的时候更新总分、添加用户更新总分 再去进行排序 很蠢)


这也很好的为我们 去除了无分数的用户、当后台题目分值修改后动态修改总分 真是他妈的一举多得 前面的语句还会显示用户名 但是分数为null

设置题目动态flag模式 防止作弊


每个用户对应动态靶机的flag不一样 并且生成flag的算法无法被破解


2022-05-04

新增 语句排序号


优化sql语句 使得内容出现 排序号 而不是mysql每一行取值后渲染

select *,(@i:=@i+1) as i from (select nickname,sum(value) as total,team,gravatar from cd_userinfo a left join cd_chanllenge b on find_in_set(b.chanllenge_id,a.chanllenge_id) where a.status =1 and b.status =1 group by nickname order by sum(value) desc limit 0,10) data,(select @i:=0) t

2022-05-06

假期结束 继续优化

增加赛事标签与选择




前端赛事信息布局根据ctf配置中的当前赛事动态修改


并会自行根据时间判断 是否结束 和是否进行 动态修改状态

增加全题显示配置 (开启代表 用户可以做任何赛事的赛题 任何比赛的赛题)

关闭则表示 只能做当前赛事赛题


关闭



关闭则 只会显示本次比赛下的题目 并且其他赛事的题目无法提交flag或者访问题目信息

接入 RSA流量加密


全平台接入 防止爆破flag、爆破密码、爆破验证码

并设置开关按钮来动态控制是否开启rsa加密


防止因为人数过多 造成更大的加解密数据传输成本 

2022-05-07

websocket接入 短消息

调用gateway 使用非轮询方式向指定用户、全体登录用户、全体连接设备推送消息


具体可见另一篇文章


接着就是写定向推送用户信息 和登录用户入组的功能编写了 就不贴图了

总结

至此 Un1kCTF1.0 实训平台就开发完毕了

开发周期:2022-04-23 - 2022-05-07 差不多两个礼拜

功能实现如下:

1.动态靶机(动态flag)实现赛题部署

2.基本的登录注册做题功能

3.websocket接入的短消息提醒

4.赛事选择与模式选择

需要完善的功能:

1.反作弊烽火台

2.动态靶机信息完善 加入自动销毁与手动销毁

3.动态靶机绑定域名

4.个人中心功能完善 

5.团队功能丰富 接入密码等

....

感谢vaalacat做的动态靶机部分的功能 如果没有你 平台会逊色很多 你真是太牛逼了

感谢bugku平台编写如此好的前端ui供我直接借鉴与使用 让我少走了很多弯路  后期会持续调整布局 或者干脆让公司找个前端重新写 不会与bugku雷同发布

感谢sweetpotato做的图片 真的太漂亮了 给我的平台润色不少

感谢女朋友一直陪伴我写代码