内容纲要

做了一下 XCTF 4th-CyberEarth 的 ICS-02 , 记录一下 WriteUp


工控云管理系统 , 点击云平台文档管理中心 .

点击提示 , 告诉你在文档中可以找到有用的信息

点击下载文档 , 会下载一个 download.php 文件

但事实上这并不是一个 PHP 文件 , 使用xxd 打开会发现这是一个 PDF 文件

PDF 文件头格式为 : 0x25 0x50 0x44 0x46

然后就是查看 PDF 文件内容 ,但并没有找到什么恶意代码( /javascript , /JS ... ) , 所以猜测这个 PDF 文件是个幌子 ,使用 BurpSuite 抓包


BurpSuite 抓包

  1. 点击 paper 后页面以 GET 方式请求 download.php 页面

这里提示了 SSRF , 非常关键!但还是要检查一下是否存在任意文件下载等漏洞

修改 GET 参数值 , 发现**该参数值实际上是要下载的 PDF 文件名 ,并且常规的截断方式无法使用 , 猜测这里仅能下载 PDF 文件 .

  1. 回到 SSRF 这个关键点 , download.php 页面可以发起请求 , 但仅有这个页面还不够 , 需要其他信息

    dirsearch 扫描一下目标站点是否存在某些敏感文件

    发现一个 /secret 目录 , 打开后内容如下所示

    该目录下存在两个文件 : secret.phpsecret_debug.php

    1. secret_debug.php

      页面提示当前 IP 地址无权访问 secret_debug.php ,修改 XXF 后依旧无法访问 , 猜测后端是使用 $_SERVER[REMOTE_ADDR] 的方式来获取用户 IP 地址的 .

      但是问题不大 ,因为我们有 SSRF , 可以通过 download.php 页面来发起请求 , 这样请求的IP地址就合法了.

    2. secret.php

      首先进入一个选择页面

      通过 GET 请求向下一个页面发送数据 , 因为这里是单项选择后提交 , 所以参数的值好像都是写死的( 不是 Y 就是 N ) , 没什么利用点

      然后是一个填空页面

      随意填写后提交数据

      再次提交后返回报错信息

      这条报错怎么看怎么像 MySQL 的报错信息 ... 并且根据返回信息 " Confirm that the following data is correct so we know it was stored correctly in our database. " , 可以判断这里肯定连接了数据库 ,那么很有可能存在 SQL 注入漏洞 .


SQL Injection

我在SQL注入时遇到了不少麻烦 , 现在回想一下感觉还是要先把思路理清楚

  1. 后台是怎么执行SQL语句的?

    根据页面的返回结果 , 我们可以看出这里执行了两个SQL操作 . 首先 , 将GET请求获得的数据存入数据库 , 然后再检索数据库 , 返回 Name 和 DoB 的数据( 不确定 )

    存入数据库时需要使用 INSERT 语句 . 可以写个Demo ,假设原表是这样创建的

    正常插入数据是这样的

    如果插入重复数据 ,会出现题目中的报错信息

    如果插入的列多余已设置的列 , 同样会报错

    一般使用注释 /*-*/ 来注入我们想要的信息

    这样数据返回时就可以返回指定的执行结果了

    1. 生成 Payload

    本题的考点就如上面所示 , 通过 INSERT 语句插入 Payload

    那么 Payload 究竟如何构造呢 ? 构造的 Python 脚本如下所示

    该脚本被放在文章末尾

    将输出的 Payload 放入浏览器执行后 , 返回结果如下

    说明这里页面仅仅是将用户输入的数据打印在页面上 ,而并没有返回数据库查询的结果 ,这里的数据不是 SELECT 语句返回的 !


SSRF

那么到底有没有地方能得到 SELECT 语句的返回结果呢 ? 其实 secret.php 的注释中给出了提示

还有个没权限访问的 secret_debug.php 页面没用到 .

要访问 secret_debug.php 页面需要 SSRF ,也就需要用到 download.php 页面

但是在 download.php 页面请求 secret_debug.php 时 , 发现页面还是返回 PDF 文件不存在的错误 .

那么是否这里的响应与GET参数有关呢 ? 重新构造 Payload .

将 IP 地址设置为 127.0.0.1 后 , 将输出的 Payload 放入 Burpsuite 中作为 dl 参数的值

这里有个需要注意的点

  • 若将 Payload 直接放入 URL 中 ,BurpSuite 可能会错误的解析参数 , 如下

    • 建议直接在 Params 选项卡里添加 Payload

然后发送请求 , 即可拿到当前数据库的 version 信息

SQL注入成功 !


拿到 Flag

因为已经找到了利用点 , 所以拿到 Flag 就非常容易了

  1. 拿到当前数据库

    Payload : database()

    当前数据库为 : ssrfw

  2. 拿到当前数据库中的表

    因为空格会在URL编码中产生歧义 , 因此 SQL Payload 中尽量不要使用空格~

    并且Payload 中的 Select 语句相当于一个子查询 , 因此使用括号包围 Payload

    Payload : SELECT(GROUP_CONCAT(table_name))FROM(information_schema.tables)WHERE(table_schema)='ssrfw'

    发现有两张表 : cetcYssrfusers

  3. 拿到 cetcYssrf 表中的字段

    Payload : SELECT(GROUP_CONCAT(column_name))FROM(information_schema.columns)WHERE(table_name)='cetcYssrf'

  4. 拿到 Flag !

    Payload : SELECT(GROUP_CONCAT(secretName,0x3a,value))FROM(ssrfw.cetcYssrf)

    成功拿到 Flag !


总结

这道题还是花费了我多时间的 , 我比较菜还没怎么见过 SSRF 的题目 , 从这道题上学到了很多东西 .

很多看起来很复杂的问题只要耐心分析 ,就能找到突破点~

最后附上最终的测试脚本

最后修改日期:2019年9月12日

作者

留言

撰写回覆或留言

发布留言必须填写的电子邮件地址不会公开。