一、SQL注入原理:
注入:通过GET / POST 方式把恶意的语句插入到原来的代码中,导致恶意的语句被执行。
SQL 注入:攻击者探测出开发者编程过程中的漏洞,利用这些漏洞,将一种将恶意的SQL代码插入或添加到应用(用户)的输入参数的攻击,巧妙的构造SQL语句,对数据库系统的内容进行直接检索或修改。
SQL注入的前提条件:
- 用户输入(参数)可控。
- 数据(参数)带入到后端的数据库中进行查询
二、SQL注入流程:
(1)信息收集:
- 数据库类型 查看sql注入页面 是否报错,来判断数据库类型
- 数据库版本 函数: version()、@@version
- 数据库用户 user() 、 system_user
- 数据库权限 —is-dba 查看数据库是否是高权限
收集的信息还有很多
(2)数据库数据获取: 1. 暴力破解 2. 通过语句查询
- 获取库信息
2. 获取表信息
3. 获取列信息
4. 获取数据
access 只有表,通过暴力破解,通过表再去获取(3)权限提升:
- 执行命令 SQL Server SA提权、mysql UDF、MOF提权
2. 读文件 读中间件配置文件,该数据库配置文件
3. 写文件 写webshell 到网站
三、关于MySQL数据库的user表段
MySQL 无论是4.x 还是 5.x 都有一个独立的数据库,名字就叫 ”mysql“ ,当中有很多数据表,保存MySQL的各种设置参数。其中user表段设置了MySQL中数据库用户的部分信息。
user表段中,user字段为用户登录名,可以有相同的名字重复
MySQL 5.7.6 以后版本将原来的 pasword 字段修改为 authentication-string,
authentication_string 字段为登录密码哈希,是40位的密码,类似于MD5,可以在md5 在线破解网站进行破解。
host 字段设置的是这个用户可以在哪些机器上登录,如果为localhost表示只能本机登录,host可以是数据库IP 也可以是数据库服务器的名称,若host为 ” localhost ” 不一定表示没有希望,如果服务器某个网站装有 phpmyadmin 这个软件的话,是可以利用的。
file_priv字段规定了这个用户是不是可以读取硬盘里的文件,设置为Y表示允许,设置为N表示禁止。
四、常用的一些函数
user() :数据库的用户,格式为 user@server ,例如 root@localhost 通常最高管理账户为root ,服务器以 localhost 也就是本地居多,也可以是服务器名例如 mysqldbserver,也可以是IP 例如 192.168.100.111。所有的 user 都会在mysql 数据库中的user表段中记录,用于设置权限等。
current_user() 当前用户名,当前登陆的用户具有什么权限的话。
database() : 当前数据库名,网站建设者任意给予的数据库的名称
- version() / @@version;: 当前使用的数据库的版本,一般为4.x、5.x或者版本更高。
- @@datadir: 数据路径。数据库存储数据总要有个路径存放数据,就是这里
- session_user() 链接数据库的用户名
- @@version_comment 数据库服务器的信息
- @@basedir mysql安装路径
- @@version_compile_os 操作系统版本
- @@version_compile_machine 查看机器的型号
hex() 和 unhex() : 有一些注入点由于数据库对数据字段的类型定义,可能不支持UNION 来显示不同类型的内容,所以使用hex对数据进行hex编码,或者直接将数据进行hex转码后,输入hex转码后的内容。
- load_file: 这是mysql 以文本的形式读取文件的参数。
例如 linux 系统的网站 load_file(‘etc/passwd’) 或者 windows 系统的网站 load_file(‘c:\boot.ini’)。这个参数可以用的前提是,user() 用户在mysql.user表中的字段为 file_priv 设置为Y,查看是否有写入权限。需要注意的是,如果是windows 系统,保险起见将路径设置为双斜杠,因为双斜杠在计算机语言中是单斜杠的意思,如果为单斜杠。例如 d:\table ,那么这个路径中的 \t 就会解析成键盘上的 table 键, \n\r 类似。 很多时候php的网站的 gpf 会设置为ON ,(对特殊字符进行转义,将单引号 自动修改为 \’) 那么 load_file(’c:\boot.ini’) 就会变成 load_file(\’c:\\boot.ini\’) 出现语法错误,得不到结果。解决的方法就是对 c:\boot.ini 进行hex编码,输入hex转码得内容。
注意: secure_file_priv 必须为空,不能为NULL,否则不能去读文件的内容
secure-file-priv参数是用来限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()传到哪个指定目录的。
- ure_file_priv的值为null ,表示限制mysqld 不允许导入|导出
- 当secure_file_priv的值为/tmp/ ,表示限制mysqld 的导入|导出只能发生在/tmp/目录下
- 当secure_file_priv的值没有具体值时,表示不对mysqld 的导入|导出做限制
如何查看secure-file-priv参数的值:
show global variables like ‘%secure%’;
- into outfile:将查询结果输出保存到一个文件中
<br />/
``` select ‘<?php phpinfo(); ?>’ into outfile “C:\phpStudy\MySQL\bin\1.php”;
select * from student into outfile ‘C:/phpStudy/MySQL/bin/test.php’;
需要注意的点:
1. outfile 可导出多行,并会在每⾏的结束加上换⾏符<br />如果test表中的内容有多行<br />![](https://cdn.nlark.com/yuque/0/2021/png/1442084/1614525075490-1c25f002-d424-4090-8d71-915714c0d21e.png#align=left&display=inline&height=48&margin=%5Bobject%20Object%5D&originHeight=48&originWidth=186&size=0&status=done&style=none&width=186)<br />导出效果<br />![](https://cdn.nlark.com/yuque/0/2021/png/1442084/1614525075522-d712747a-b6d6-4690-b38c-7315c57f5e0b.png#align=left&display=inline&height=36&margin=%5Bobject%20Object%5D&originHeight=36&originWidth=143&size=0&status=done&style=none&width=143)
1. outfile 将数据写到文件里时有特殊的格式转换<br />`a\naa\raaaa`写入时`\n`被转义,并且文件末尾加了一个新行<br />![](https://cdn.nlark.com/yuque/0/2021/png/1442084/1614525075481-4ba4cdc4-a2c2-4734-af80-6953836db350.png#align=left&display=inline&height=143&margin=%5Bobject%20Object%5D&originHeight=143&originWidth=548&size=0&status=done&style=none&width=548)<br />导致写shell时要注意特殊字符
1. outfile 的路径不能是0x开头或者char转换以后的路径,只能是引号包裹的路径<br />导致写shell时无法通过hex编码或char()来bypass引号转义等
1. 文件不能覆盖写入,所以写入文件必须为不存在
SELECT <?php phpinfo() ?> into outfile '路径': 前提是gpf设置为off,有注入点,权限很大,file_priv为Y,知道网站的真实路径。
- dumpfile
select ‘<?php phpinfo(); ?>’ into dumpfile “C:\phpStudy\MySQL\bin\1.php”; select * from student into outfile ‘C:/phpStudy/MySQL/bin/test.php’; ``` 需要注意的点:
- dumpfile 只能导出一行
- dumpfile 在写⽂件时会保持⽂件的原⽣内容/原数据格式,适合写二进制文件,如exe文件,udf提权的dll文件
- dumpfile 的路径不能是0x开头或者char转换以后的路径
- 文件不能覆盖写入,所以写入文件必须为不存在
- 导入语句load data infile()读文件
条件:
- 所读文件的绝对路径
- secure_file_priv 的值非NULL或包含了所读文件的绝对路径
- mysql服务有对所读文件的读权限
- mysql连接用户有FILE权限/如果指定LOCAL关键词则无需FILE权限
- 如果是mysql8,需要
SET GLOBAL local_infile=1;
<br />
load data infile()将所读文件内容存储到表中load data [local] infile '/etc/passwd' into table result;
如果指定LOCAL关键词,则表明从客户端的主机上按路径读取文件,适合站库分离,无需FILE权限。
路径获取常见方法:
报错显示,遗留文件,漏洞报错,平台配置文件,爆破等
五、 MySQL字符串拼接和字符串截取函数
(1)concat
- select concat(id,’|’,username,’|’,password) from users; 每个字段必须指定分隔符,去拼接字符串
(2)concat_ws
- select concat_ws(‘|’,id,username,password) from users; 用固定的分隔符去拼接id,username,password。
(3) group_concat
- select group_concat(‘\n’,username) from users; \n (
浏览器)换行 去拼接字符串
(4)substr 截取函数
select substr((select username from users limit 0,1),1,2);
limit m,n 函数是从m行开始查m+n行。 substr 从第一位开始截取两位
(5)mid 函数
select substr((select username from users limit 0,1),1,2);
从第二个字母截取三个字段
(6)left 函数
- select left(‘Avenue’,3); 从左截取两位
(7)right 函数
- select right(‘Avenue’,2); 从右截取字符串个数
(8)locate 函数
locate(substr,str,pos):返回字符串1在字符串2中第一次出现的位置,从位置pos开始算起;
如果返回0,表示从pos位置开始之后没有了,如果返回值 大于0,表示有。
由于这函数的用法,不能结合ascii或者ord来使用,只能结合if来使用,下面来操作一下。
select locate(‘security’,’1234security’); 返回第一个字符串首次在第二个字符串出现得位置
(9)ascii、ord 函数
返回指定的ASCII字符对应的值
- select ascii(‘a’);
- select ord(‘a’);
(10)char 函数
返回指定数字对应的ascii码字符函数:
select char(97);
(11)length、count 函数
计算长度、数量的函数
- select length(database()); 查询数据库的长度
- select count(*) from users; users表里13条数据。