玄机靶场挑战【2024铁人三项决赛CTFMISC-aesweblog】,看到排第一的大佬,我的二血瞬间感觉不香了
本文最后更新于 36 天前,其中的信息可能已经有所发展或是发生改变。

宣传了好几天的玄机靶场,本周末终于有空了,找了一道当下最新的题目,直接开整。

两个小时后,首战告捷,成功拿下二血。

结果,瞄了一眼一血,瞬间不香了,这家伙,三十秒,真男人呀…… 难不成这题有特殊解法?这速度,Ctrl + F 直接搜 flag ?

没搞明白,先简单地分享一下我自己常规的解题思路吧,如果后面发现有特殊解法,再做补充。

01 题目简介

我辛辛苦苦采用apache+sqlite3+python搭建的MIS环境,好像存在很多漏洞,昨天发生数据泄露事件了,攻击者把我的旗帜拿走了。幸好Web日志还在,帮我分析一下,哪些flag被盗,我只关注flag1和flag6。注意:本题目的flag为flag1+flag6的组合。组合方式举例为:将flag1{aaa}和flag6{bbbbb}组合为最终的flag{aaa-bbbbb}

02 分析题目

从题目简介中,可以了解到,此题的目标简而言之就是从存留的 Web 日志文件中,分析并找出flag1 和 flag6,组合成最终 flag。

03 分析附件

下载题目附件,是一个 zip 包,解压,可以看到一个名为access_access.log 的日志文件和一个名为initsecretandflagdata.py的 python 脚本文件。

根据文件名,大致可以了解到,access_access.log 应该就是题目中所说的 Web日志文件;而 initsecretandflagdata.py 看上去是对 flag 文件进行加密处理的脚本。

也就是说,我们从日志中分析到的 flag 文件很可能是一个密文,还需要根据这个加密脚本进行恢复。

04 分析日志文件

打开日志文件(嚯,还挺大),滚动条随便往中间位置拉一拉,很明显,这是一个SQLMAP 盲注日志。

为什么说很明显,往下看…

****话说,如果连 SQL 盲注是什么都不知道的,建议先去百度一下再来继续看。


  1. 日志中充满大量的 SELECT、AND 等 SQL 关键字,基本可以肯定这是 SQL 注入攻击日志;

  2. 日志末尾的 sqlmap/1.8.4.5#dev 字样,这是经典的 SQL 注入工具 – sqlmap 扫描的特征,甚至还包含了版本号;

  3. 日志中充满了大量的 %20、%29、%3E 等类似字符,这是 GET 请求时对特殊符号的 HTML 编码;

4.日志中有大量的 SUBSTR、CHAR 等字符,这就是典型的 SQL 盲注的特征;

  1. 日志中每条信息都包含 200 196 或 200 341 字样,其中 200 为请求成功状态码,那么 196 和 341 应该为响应包长度,只有这两种长度,所以大概率其中一个为“成功”,另一个为“失败”。

处理日志,恢复数据

捋清思路,确定接下来的行动方向

日志共计有 6W 多行,太多了,必须考虑写脚本分析。

Step1:HTML 编码看的眼花缭乱,首先考虑将 HTML 编码还原,最起码可以更直观的看到 SQL 语句;

Step2: 编码还原之后,日志看上去将会直观很多,然后再写个脚本,提取出日志中涉及到的所有数据库、数据表、数据表字段。大致了解一下数据库的表结构;

Step3: 得到表结构后,猜测应该会有 flag 表或者 flag 字段(根据之前的推测,应该是个密文),有可能还会有密钥之类的东西;

Step4:写脚本,恢复需要用到的字段数据,如题的 flag1 和 flag6。

开始行动,解码日志

▲ 对日志解码重新输出到 access_unquote.log

▲ 处理之后,日志文件中的 SQL 语句直观了很多

再写脚本,提取数据库结构

先随便拉出来两条日志,如下:

172.21.0.2:80 172.21.0.1 - - [25/Apr/2024:10:14:25 +0000] "GET /cgi-bin/customerdetail.py?name=admin' AND SUBSTR((SELECT COALESCE(username,CHAR(32)) FROM secrets LIMIT 20,1),6,1)>CHAR(96) AND 'jffp'='jffp HTTP/1.1" 200 341 "-" "sqlmap/1.8.4.5#dev (https://sqlmap.org)" "-"
172.21.0.2:80 172.21.0.1 - - [25/Apr/2024:10:14:25 +0000] "GET /cgi-bin/customerdetail.py?name=admin' AND SUBSTR((SELECT COALESCE(username,CHAR(32)) FROM secrets LIMIT 20,1),6,1)>CHAR(112) AND 'jffp'='jffp HTTP/1.1" 200 196 "-" "sqlmap/1.8.4.5#dev (https://sqlmap.org)" "-"

根据 SQL 注入原理,还原完整的 SQL 结构,大致看一眼,SELECT COALESCE 内的应该是字段名,FROM 后的是表名。

select 1 from tmp where name = 'admin' AND SUBSTR((SELECT COALESCE(username,CHAR(32)) FROM secrets LIMIT 20,1),6,1)>CHAR(96) AND 'jffp'='jffp'

借用正则表达式直接提取字段名和表名,并整理格式输出。

▲ 正则表达式提取表名、列名

可见,共涉及 3 个数据表,字段分别如下:

secrets: id/datetime/passphrase/username
user_flag: username/flagvalue/id/note/encrypted/flagname/datetime
customers: city/state/username/contract/address/id/phone/zip

继续写脚本,恢复所需数据

在上一步还原的 SQL 基础上,进一步分析一下这个 SQL 语句具体做了什么?

select 1 from tmp where name = 'admin' AND SUBSTR((SELECT COALESCE(username,CHAR(32)) FROM secrets LIMIT 20,1),6,1)>CHAR(96) AND 'jffp'='jffp'

可以看到,where 条件中有三个子条件,分别是

· name = ‘admin’

· SUBSTR((SELECT COALESCE(username,CHAR(32)) FROM secrets LIMIT 20,1),6,1)>CHAR(96)

· ‘jffp’=’jffp’

这三个条件的 AND 结果相应长度为 341,具体为 TRUE 还是 FALSE?重点其实取决于第二个条件(第一个条件恒为 TRUE,第三个条件恒为 TRUE)。

我猜肯定会有人疑惑

第三个条件 ‘jffp’=’jffp’ 恒为 true 可以理解,但是第一个条件 name=’admin’ 凭什么说它恒 true,有证据吗?

其实很简单,仔细看上面第三步中拉出来的两条日志,既有 response 为 341 的,也有 response 为 196 的,这是三个 AND 条件,所以必然有三个条件同为 TRUE 的场景,而 name 一直都是 ‘admin’,所以 name=’admin’ 是恒 true 的,否则就只会出现 341 或者 196,而不是同时出现这两种响应。

接下来,详细分析第二个条件:

将条件二拆分成两部分:

  1. SELECT COALESCE(username,CHAR(32)) FROM secrets LIMIT 20,1

  2. SUBSTR(第一段),6,1)>CHAR(96)

先来看第一段:

COALESCE 函数的作用是返回第一个非空参数;

32 是 空格的 ASCII 编码,所以 CHAR(32) 也就是空格;

LIMIT 20,1 意为跳过 20 行数据,选择 1 行数据,也就是第 21 行数据;

然后看第二段:

SUBSTR(xxx,6,1) 意思是截取 xxx 字符串的第 6 个字符

96 是字符 、的 ASCII 编码,其实这里本意并不是要使用 96,判断是否大于 96,其实是等同于是否大于等于 97,而 97 是小写字母 a 的 ASCII 码,同理 98 为 b,99 为 c

所以,整个 SQL 语句的意思就是:

查询 secrets 表的第 21 条数据的 username 值,如果存在,截取 username 的第 6 个字符,判断其 ASCII 码是否大于 96

▲ 上述示例日志附近的日志

以 secures 表第 21 条数据 username 值的第 6 个字符为例,分析红框区域这些日志(判断 username 的第 6 个字符)

step1: 该字符 > CHAR(96) 返回 341

step2:该字符 > CHAR(112) 返回 196

step3:该字符 > CHAR(104) 返回 341

step4: 该字符 > CHAR(108) 返回 196

step5:该字符> CHAR(106) 返回 341

step6:该字符> CHAR(107) 返回 341

step7: 结束,下一个

由此可以判断出

  1. SQLMAP 采用的是夹逼法来确认所选中的字符;

  2. 341 应该为 TRUE 的返回值,196 应该为 FALSE 的返回值;

  3. secures 表中第 21 条数据的 username 值的第 6 个字符 ASCII 码应该为 108,即小写字母 l

06 终极脚本,恢复数据

上一步中,我们已经分析清楚了日志表达的意思并且已经获取到了其中一条数据的某个字段的某个字母。

接下来,将上述思路使用代码实现,利用脚本来恢复所有数据。

思路:

  1. 使用正则表达式,提取 SQL 语句

  2. 同表同一条数据的同字段的同一个字符,获取最后一条日志,加一得到最终字符(因为日志是使用大于号判断)

  3. 同样的逻辑,循环处理下一个字符,下一个字段、下一条数据、下一张表

▲ 恢复数据脚本

▲ 数据恢复完成

07 整理题目所需的 flag1 和 flag6

Record 23 
- id: 120 
- datetime: 2024-04-25 00:14:05 
- username: admin 
- flagname: flag1 
- flagvalue: lTr01ZNX8R9xotVanrPtKiBjCfQD5U5dD+KLRPgjnQ4= 
- note: encrypted with aes128. associated key, iv & salt are derived from passphrase. 
- encrypted: 1 

Record 18 
- id: 115 
- datetime: 2024-04-25 00:14:04 
- username: Morningstar 
- flagname: flag6 
- flagvalue: PgH8ySWqsB1IJEradvOouNWEP5mpHZnu5e9ShkiS1LWLb81hRUjAZLD4zzzxO5Tn 
- note: encrypted with aes128. associated key, iv & salt are derived from passphrase. 
- encrypted: 1

从 note 描述中,可以看到,flagvalue 是 aes128 加密之后的,而 key、iv、salt 都是从 passphrase 派生。

果然不出所料,还记的最开始 zip 包里面那个加密脚本吗?

那正好,从 secures 中找到 flag 对应的 passphrase,它们都有共同的 name,正好对应起来。

Record 23 
- id: 120 
- datetime: 2024-04-25 00:14:05 
- flagname: flag1
- username: admin 
- passphrase: 7xjo0DHFsoF1Jrus

Record 18 
- id: 115 
- datetime: 2024-04-25 00:14:04 
- flagname: flag6
- username: Morningstar 
- passphrase: TJOC6+L+vTajLOGqfJMweoLFZqvJ

08 分析加密脚本,继续恢复数据

拿到了 flag 的密文 flagvalue 和密钥 passphrase,接下来,该着手分析加密原理,来恢复 flag 明文数据了。

代码并不多,找到核心的加密算法,注释写的写很详细。

▲ 原 zip 包中的加解密文件

拿到了 flag 的密文 flagvalue 和密钥 passphrase,接下来,该着手分析加解密代码,来恢复 flag 明文数据了。

代码并不多,找到核心的加密算法,注释写的写很详细。

大致的加密流程:

  1. 根据 passphrase 派生 salt 值

  2. 根据 passphrase 和 salt 派生 iv 值

  3. 使用 aes_cbc 对 original_flagdata 填充并加密(这就是我们最终需要逆推出来的原始 flag)

  4. 根据 passphrase 和 salt 使用 pbkdf2 算法派生密钥 key (需要一点点的密码学基础,不然可能会看不懂)

  5. 使用生成的 key 进行 aes_cbc 解密(What???加解密算法直接给出了,解密方法直接整理一下拿出来用不就行了,还分析个毛)

▲ 整理的解密脚本及运行结果

09 整理数据,提交 flag

从题目简介中,可以了解到,此题的主要目标,应该是从存留的 Web 日志文件中,分析并找出 flag1 和 flag6,组合成最终 flag。

根据上一步的运行结果:

flag1{e6f1573b9496a7f3}

flag6{a85bcfc646ff161c71e520e7cba3}

结合题目中的描述,将flag1{aaa}和flag6{bbbbb}组合为最终的flag{aaa-bbbbb}

所以,最终 flag 的为:

flag{e6f1573b9496a7f3-a85bcfc646ff161c71e520e7cba3}

▲ 提交 flag

▲ 成功拿下二血

10 结束

感谢阅读,如果你感觉本文对你有帮助,还请帮忙点点“在看”和“分享”,让更多的人看到。

如果您有什么建议或指正,请私信我。

完整的脚本代码及文件我已上传至网盘,公众号聊天窗口发送:“玄机靶场0527” 获取网盘链接。

学海无涯,回头是岸。 --- hola
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇