CTF复习-PHP代码简单审计

1
2
3
4
5
6
7
8
9
10
11
12
13
function is_trying_to_hak_me($str)
{
$blacklist = ["' ", " '", '"', "`", " `", "` ", ">", "<"];
if (strpos($str, "'") !== false) {
if (!preg_match("/[0-9a-zA-Z]'[0-9a-zA-Z]/", $str)) {
return true;
}
}
foreach ($blacklist as $token) {
if (strpos($str, $token) !== false) return true;
}
return false;
}

整个函数顾名思义,进行输入检测,判断是否是黑客行为,要使函数返回false即可绕过这个输入检测。

定义了一个黑名单:

1
$blacklist = ["' ", " '", '"', "`", " `", "` ", ">", "<"]

黑名单:单引号+空格、空格+单引号、双引号、反引号、反引号+空格、空格+反引号、<、>

  1. 过滤单引号和空格的组合,通常是为了防止类似**’ or ‘1’ = ‘1’**这种类似的注入
  2. 双引号通常用于Sql语句闭合字符串
  3. 反引号一般用于包裹MySql表名或字段名,也可用于命令执行
  4. 两个尖括号通常用于php代码或者xss的payload
1
2
3
4
5
if (strpos($str, "'") !== false) {
if (!preg_match("/[0-9a-zA-Z]'[0-9a-zA-Z]/", $str)) {
return true;
}
}

前面的过滤并非是把单引号直接打死,而是禁止单引号与空格的组合,在这串代码里面,就对单引号作了更严格的过滤

preg_match函数会拿着前面的正则表达式在**$str**变量里面匹配,也就是说可以用单引号,但是单引号前后必须有数字或者字母

继续审计

1
2
3
4
5
6
7
8
9
10
11
12
$db = new SQLite3("/var/db.sqlite");
$result = $db->query("SELECT * FROM users WHERE username='$user'");
if ($result === false) die("pls dont break me");
else $result = $result->fetchArray();
if ($result) {
$split = explode('$', $result["password"]);
$password_hash = $split[0];
$salt = $split[1];
if ($password_hash === hash("sha256", $pass.$salt)) $logged_in = true;
else $err = "Wrong password";
}
else $err = "No such user";

实例化一个 SQLite3 对象,连接到服务器路径 /var/db.sqlite 的数据库文件

需要让输入的$user插入sql语句中能够正确返回

注意两个点:语句整体正确和注释符号正确

对于输入的result值里面提取到password,将’$’左边作为password的hash值,右边作为盐值

将password处输入的pass与盐值拼接进行sha256计算,如果等于输入的password_hash,则会通过验证

这里面就不能用#,需要用—或者–+

user传入admin’union select 1,’49d180ecf56132819571bf39d9b7b342522a2ac6d23c1418d3338251bfe469c8$7’–+

pass传入6

49d180ecf56132819571bf39d9b7b342522a2ac6d23c1418d3338251bfe469c8为67的sha256计算值,此时返回$logged_in为true