从国赛想到的一些php绕过注释符trick

从国赛衍生出来的一些php绕过注释符trick

首先是在很早之前我在XYCTF出过的一道题,牢牢记住,逝者为大,题目代码是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
highlight_file(__FILE__);
function Kobe($cmd)
{
if (strlen($cmd) > 13) {
die("see you again~");
}
if (preg_match("/echo|exec|eval|system|fputs|\.|\/|\\|/i", $cmd)) {
die("肘死你");
}
foreach ($_GET as $val_name => $val_val) {
if (preg_match("/bin|mv|cp|ls|\||f|a|l|\?|\*|\>/i", $val_val)) {
return "what can i say";
}
}
return $cmd;
}

$cmd = Kobe($_GET['cmd']);
echo "#man," . $cmd . ",manba out";
echo "<br>";
eval("#man," . $cmd . ",mamba out");

上面的代码在限制字数内能执行代码,当时我给出的解是用换行符进行绕过也就是%0a

在比赛比完之后我就想还有没有其他绕过的方式…

ciscn2024华东南国赛WEB-粗心的程序员

这题在扫出文件泄露之后,关键的漏洞代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
error_reporting(0);
include "default_info_auto_recovery.php";
session_start();
$p = $_SERVER["HTTP_X_FORWARDED_FOR"]?:$_SERVER["REMOTE_ADDR"];
if (preg_match("/\?|php|:/i",$p))
{
die("");
}
$time = date('Y-m-d h:i:s', time());
$username = $_SESSION['username'];
$id = $_SESSION['id'];
if ($username && $id){
echo "Hello,"."$username";
$str = "//登陆时间$time,$username $p";
$str = str_replace("\n","",$str);
file_put_contents("config.php",file_get_contents("config.php").$str);
}else{
die("NO ACCESS");
}

那么我们要绕过的地方就在这里

1
$str = "//登陆时间$time,$username $p";

我们能看到\n被过滤了,那么我们还有什么其他办法能绕呢

方法1 \r

\r (回车) 和 \n (换行) 是在计算机中用于都表示行终止符的控制字符。

  1. \n:
    • 在 Linux 以及编程语言中,\n 表示行的结束,在这些系统中,\n 会将光标移动到下一行的开头。
  2. \r:
    • 在早期的系统和编程语言中,\r 表示将光标移到当前行的开头,而不移动到下一行。
    • 在 Windows 系统中,行终止符通常由 \r\n 组合表示。\r 使光标回到行首,\n 将光标移动到下一行。

那么假设我们有这么一串字符串

1
Hello \rWorld

在大多数现代环境中,回显则会是

1
World

因为 \r 将光标移回行首,随后 World 覆盖了 Hello

我们在python中进行实验发现是符合的

1
2
3
4
5
$ python

>>> print("hello \rworld")
world
>>>

而在我们神奇的php中呢

1
2
<?php
echo "hello \rworld";

则是回显

1
2
hello 
world

那么我们在php中我们便可以用\r代替换行符

方法2 ?>

某一天我在写wp的时候,准备把wp的代码写上注释再跑一遍

1
2
3
<?php
eval(base64_decode("Pz48P3BocCBwaHBpbmZvKCk7Pz4="));
//?><?php phpinfo();?>

发现phpinfo();运行了两次,同时在vscode里面,注释后面的代码是高亮状态,在注释后面的字符为什么会被解析执行呢

简单测试后了解到了

PHP解析器在处理注释时并没有完全忽略注释内容,而是会在注释内容中寻找特定的字符序列,例如 ?>。这是因为PHP解析器在扫描代码时,会优先处理PHP标签的打开和关闭,这些标签的优先级高于注释的处理

那么我们就可以用这个方法闭合掉前面的注释符然后再开一个新的标签进行执行。