1. 进入环境,查看页面
我的心情和这个图像一样懵逼,拿起dirsearch就是一顿乱扫。如图:
发现有register.php
2. 问题分析
- 登入register.php,注册相关账户并登录
- 直接吧usrname给显示出来了,也就是说,注册提交了usrname数据,然后又从数据库中查询了username并回显,那么问题就清晰了一丢丢,想办法通过username注入数据,在回显时候再执行。查了查相关的wp,这种方式叫做
二次注入
:
- 二次注入的原理,在第一次进行数据库插入数据的时候(注册时),仅仅只是使用了 addslashes 或者是借助 get_magic_quotes_gpc 对其中的特殊字符进行了转义,在写入数据库的时候还是保留了原来的数据,但是数据本身还是脏数据。
- 在将数据存入到了数据库中之后,开发者就认为数据是可信的。在下一次进行需要进行查询的时候(登录后),直接从数据库中取出了脏数据,没有进行进一步的检验和处理,这样就会造成SQL的二次注入。比如在第一次插入数据的时候,数据中带有单引号,直接插入到了数据库中;然后在下一次使用中在拼凑的过程中,就形成了二次注入。
- 思考注入点
注册过程中,我们尝试一下抓包,得到数据如图: - 发现三个关键字,email、username、password,最后回显的是username,那么我们需要对usrname进行注入,如何注入?参考大佬们的wp,说是让FUZZ,于是屁颠屁颠的去查如何FUZZ,使用Burpsuite,在此记录一下。
注意§符号,然后点击payloads,填入相关的符号,(网上有,此处仅仅测试),然后点击start attack
可以看到过滤了什么字符,如图:
- 如何构造?
看了看大佬的WP,翻译一下,就是通过使用0’+1+'0
作为用户名,在注册的时候,猜想使用sql语句插入到表中,如:
在插入中将0’+1+‘0
插入,取的时候,MySQL语言的一种特性,就是+
在MySQL中是作为运算符的,引用一幅图:
利用这个特性,我们可以构造payload:0’+ascii(substr((select * from flag),1,1))+‘0
这样我们就可以得到flag表(这个表名是猜的,一般CTF的注入题,如果不特别提示表名的话,表名都是flag)查询结果的第一个字符的ascii码,但是之前FUZZ时已经发现,被过滤,查询资料后发现可以用from * for *
代替,所以我们的最终payload为0’+ascii(substr((select * from flag) from 1 for 1))+'0
。
*(PS:这点大佬的WP写出了from * for 的原因很棒,很多我看了都不知道为什么,就很难学)
不过我还是不懂,为什么就这么敢断定数据库表是flag,而且能想到利用二次注入,拿到flag的每位ascii做运算回显出来,然后拿到回显的前端数据又将其反ascii化,真尼玛牛逼。。。
- 使用脚本子跑起来(代码已注释)
解释一下代码中几个点:
python格式化输出可以参考链接:PYTHON 中的"%s" %占位符用法
为什么要去匹配< span class=“user-name”>
?如图:
(.*?)
表示使用的正则匹配的非贪婪模式!目的是匹配到第一个内容就停止了。
3. 总结
- 考察sql注入
- MySQL中的特殊字符+
- sql中的内置函数绕过检测
- 脚本使用
- 正则匹配和转码解码操作
参考博客:
太尼玛难了,好绕啊。。。全程参考wp,要被虐哭了!如有问题,欢迎探讨。