注入点在表名处的SQL注入

刚好前段时间看到过相关文章,并且碰到了类似环境,在此记录一下

案例

代码大概如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
include "config.php";
$table = $_GET[a];
$conn = new mysqli($servername, $username, $password,$dbname);

$sql = "SELECT * FROM ns_$table where uid=1";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo $row['member_name'];
}
}
$conn->close();
?>

注入点在表名处,如果表名不存在的话后续将无法进行,所以要先猜测下表名~ 表名可以根据实际情况进行猜测,例如这里我用的是一个商城的数据库,那大概会有member或者account之类的表名,可以爆破下
image-20200118215425632

当表名为member时有数据返回,好嘞,现在找到表了可以进行注入了,直接跟注入语句并把后面内容注释掉即可。 有些时候情况可能会有些复杂,例如

1
SELECT * from ns_member where member_name=(select user_name from sys_$table limit 0,1)

真实情况可能会更加复杂,注释的话很有可能会出现错误,这种情况下如果有报错信息可以采取报错注入,没有的话可能要慢慢猜了吧(大概)

探索

表名完全可控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "config.php";
$table = $_GET[a];
$conn = new mysqli($servername, $username, $password,$dbname);

mysql_query("desc $table") or die;
$sql = "SELECT * FROM $table where uid=1";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo $row['member_name'];
}
}
$conn->close();
?>

首先看下Mysql中desc的语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{EXPLAIN | DESCRIBE | DESC}
tbl_name [col_name | wild]
{EXPLAIN | DESCRIBE | DESC}
[explain_type]
{explainable_stmt | FOR CONNECTION connection_id}


explain_type: {
EXTENDED
| PARTITIONS
| FORMAT = format_name
}
format_name: {
TRADITIONAL
| JSON
}
explainable_stmt: {
SELECT statement
| DELETE statement
| INSERT statement
| REPLACE statement
| UPDATE statement
}

image-20200118215437025
So 我们可以使用报错注入
image-20200118215448787

表名不完全可控且desc中有`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "config.php";
$table = $_GET[a];
$conn = new mysqli($servername, $username, $password,$dbname);

mysql_query("desc `ns_$table`") or die;
$sql = "SELECT * FROM ns_$table where uid=1";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo $row['member_name'];
}
}
$conn->close();
?>

上面也提到过这个👇

1
2
{EXPLAIN | DESCRIBE | DESC}
tbl_name [col_name | wild]

image-20200118215511141

默认情况下,描述显示有关 table 中所有列的信息。 col_name,如果给定,则是 table 中列的 name。在这种情况下,该语句仅显示指定列的信息。 wild,如果给定,则是 pattern string。它可以包含 SQL %和_通配符。在这种情况下,语句仅显示名称与 string 匹配的列的输出。除非 string 包含空格或其他特殊字符,否则无需将 string 括在引号内。

为table列的name时

image-20200118215529313

随意的时候

image-20200118215541205

但是当`出现在select 语句中时
image-20200118215552911

当我们加两个`后,第一个语句就成了

1
desc `ns_member```;

第二个则为

1
SELECT * FROM ns_member`` where uid=1

只要在第二个`后注入即可

表名不完全可控且SELECT有`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "config.php";
$table = $_GET[a];
$conn = new mysqli($servername, $username, $password,$dbname);

mysql_query("desc ns_$table") or die;
$sql = "SELECT * FROM `ns_$table` where uid=1";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo $row['member_name'];
}
}
$conn->close();
?>

如果像上面的情况一样使用`会变成什么样呢?
image-20200118215606017

MySQL会将`内的所有字符当作一个表,对于这种情况大概无解

表名不完全可控且都有`

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
include "config.php";
$table = $_GET[a];
$conn = new mysqli($servername, $username, $password,$dbname);

mysql_query("desc `ns_$table`") or die;
$sql = "SELECT * FROM `ns_$table` where uid=1";
$result = $conn->query($sql);

if ($result->num_rows > 0) {
while($row = $result->fetch_assoc()) {
echo $row['member_name'];
}
}
$conn->close();
?>

同上Orz

参考链接:

https://www.docs4dev.com/docs/zh/mysql/5.7/reference/explain.html#explain-%E8%AF%AD%E6%B3%95

http://www.yulegeyu.com/2017/04/16/%E5%BD%93%E8%A1%A8%E5%90%8D%E5%8F%AF%E6%8E%A7%E7%9A%84%E6%B3%A8%E5%85%A5%E9%81%87%E5%88%B0%E4%BA%86Describe%E6%97%B6%E7%9A%84%E5%87%A0%E7%A7%8D%E6%83%85%E5%86%B5%E3%80%82/