刚好前段时间看到过相关文章,并且碰到了类似环境,在此记录一下
案例
代码大概如下所示
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之类的表名,可以爆破下
当表名为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 }
|
So 我们可以使用报错注入
表名不完全可控且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]
|
默认情况下,描述显示有关 table 中所有列的信息。 col_name,如果给定,则是 table 中列的 name。在这种情况下,该语句仅显示指定列的信息。 wild,如果给定,则是 pattern string。它可以包含 SQL %和_通配符。在这种情况下,语句仅显示名称与 string 匹配的列的输出。除非 string 包含空格或其他特殊字符,否则无需将 string 括在引号内。
为table列的name时
随意的时候
但是当`出现在select
语句中时
当我们加两个`后,第一个语句就成了
第二个则为
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(); ?>
|
如果像上面的情况一样使用`会变成什么样呢?
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/