Featured image of post 2025春秋杯夏季赛wp

2025春秋杯夏季赛wp

2025春秋杯夏季赛wp

eccccc

  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
from hashlib import sha256
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from Crypto.Util.number import inverse, isPrime
from math import isqrt

# EC 椭圆曲线阶
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141

# 签名信息
r1 = 18507930132802310344248699822628576170242868593944128167302942018134209256936
s1 = 23965013559564325260453725916491832279556345092147805659950905735422363429946
m1 = b'32748923ur8934u893ygf893h34t3453453'

r2 = 61645219796227967861807301237829197706412124807702206247291322591426944615554
s2 = 84283844402102709520391794221564573160907887711307574424747605446691209453247
m2 = b'ehfw9h8r039u82678ifjewf9024r2323423'

h1 = int.from_bytes(sha256(m1).digest(), 'big')
h2 = int.from_bytes(sha256(m2).digest(), 'big')

s1_inv = inverse(s1, n)

# 构造二次模方程
A = (s2 * 7 * pow(s1_inv, 2, n)) % n
B = (s2 * 3 * s1_inv) % n
C = (s2 * 11) % n

h1sq = pow(h1, 2, n)
r1sq = pow(r1, 2, n)
term1 = (A * h1sq) % n
term2 = (2 * A * r1 * h1) % n
term3 = (A * r1sq) % n
term4 = (B * h1) % n
term5 = (B * r1) % n

const_right = (term1 + term4 + C) % n
linear_right = (term2 + term5) % n
quad_right = term3

# 左右相减后得到二次方程:
# d^2 * quad_right + d * (linear_right - r2) + (const_right - h2) ≡ 0 mod n

a = quad_right
b = (linear_right - r2) % n
c = (const_right - h2) % n

# 求模 n 意义下的二次同余 a*d^2 + b*d + c ≡ 0 (mod n)

def modular_sqrt(a, p):
    """Tonelli-Shanks algorithm: solve x^2 ≡ a mod p"""
    if pow(a, (p - 1) // 2, p) != 1:
        return None  # no square root exists

    if p % 4 == 3:
        return pow(a, (p + 1) // 4, p)

    # Find Q and S with p-1 = Q * 2^S
    q = p - 1
    s = 0
    while q % 2 == 0:
        q //= 2
        s += 1

    # Find z which is a quadratic non-residue
    for z in range(2, p):
        if pow(z, (p - 1) // 2, p) == p - 1:
            break

    m = s
    c = pow(z, q, p)
    t = pow(a, q, p)
    r = pow(a, (q + 1) // 2, p)

    while t != 1:
        i = 1
        t2 = (t * t) % p
        while t2 != 1:
            t2 = (t2 * t2) % p
            i += 1
            if i == m:
                return None
        b = pow(c, 1 << (m - i - 1), p)
        m = i
        c = (b * b) % p
        t = (t * c) % p
        r = (r * b) % p
    return r

def solve_quadratic_mod(a, b, c, p):
    """Solves a*d^2 + b*d + c ≡ 0 mod p"""
    a_inv = inverse(a, p)
    b_ = (b * a_inv) % p
    c_ = (c * a_inv) % p

    # Solve d^2 + b_*d + c_* ≡ 0
    discriminant = (b_ * b_ - 4 * c_) % p
    sqrt_d = modular_sqrt(discriminant, p)
    if sqrt_d is None:
        return []

    root1 = (-b_ + sqrt_d) * inverse(2, p) % p
    root2 = (-b_ - sqrt_d) * inverse(2, p) % p
    return [root1, root2]

# 解出 d 的可能值
roots = solve_quadratic_mod(a, b, c, n)

# 解密尝试
for d in roots:
    key = sha256(str(d).encode()).digest()
    ct = bytes.fromhex("a713d56a102ac904da8baa66deaedcdbb754cd8bc94bf4b45e708d611b53ef92af03e9c20c8c8383f9c6c709f99c709d")
    try:
        cipher = AES.new(key, AES.MODE_ECB)
        flag = unpad(cipher.decrypt(ct), 16)
        print(f"[+] Found d = {d}")
        print(f"[+] FLAG = {flag}")
        break
    except:
        continue

image-20250713113147721

ez_ruby

 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
require "sinatra"
require "erb"
require "json"

class User
    attr_reader :name, :age

    def initialize(name="oSthinggg", age=21)
        @name = name
        @age = age
    end

    def is_admin?
        if to_s == "true"
            "a admin,good!give your fake flag! flag{RuBy3rB_1$_s3_1Z}"
        else
            "not admin,your "+@to_s
        end
    end

    def age
        if @age > 20
            "old"
        else
            "young"
        end
    end


    def merge(original, additional, current_obj = original)
        additional.each do |key, value|
            if value.is_a?(Hash)
            next_obj = current_obj.respond_to?(key) ? current_obj.public_send(key) : Object.new
            current_obj.singleton_class.attr_accessor(key) unless current_obj.respond_to?(key)
            current_obj.instance_variable_set("@#{key}", next_obj)
            merge(original, value, next_obj)
            else
            current_obj.singleton_class.attr_accessor(key) unless current_obj.respond_to?(key)
            current_obj.instance_variable_set("@#{key}", value)
            end
        end
        original
    end
end

user = User.new("oSthinggg", 21)


get "/" do  
    redirect "/set_age"
end

get "/set_age" do
    ERB.new(File.read("views/age.erb", encoding: "UTF-8")).result(binding)
end

post "/set_age" do
    request.body.rewind
    age = JSON.parse(request.body.read)
    user.merge(user,age)
end

get "/view" do 
    name=user.name().to_s
    op_age=user.age().to_s
    is_admin=user.is_admin?().to_s
    ERB::new("<h1>Hello,oSthinggg!#{op_age} man!you #{is_admin} </h1>").result
end     

一眼ruby的erb模板注入,污染@to_s就行,然后查看view路由

image-20250713144024300

image-20250713144043766

奶龙牌密码

题目的流程如下

  1. 生成两个$p+1$光滑的素数
  2. 用相同的两个密钥key1,key2进行两次DES加密,这两个key是自己可以控制的
  3. 然后检验DES的密文是否为素数,如果两个都是素数,就相乘作为RSA的模
  4. 进行Paillier同态加密,并给出noise ^ noise >> 16
$$ if \quad i \in [0,16)\\ c_i = m_i\\ if \quad i \ge 16\\ c_i = m_i \otimes m_{i-16} $$

由于$m_0$~$m_{15}$是已知的,所以后面的很容易就恢复了,恢复noise之后根据同态加密的性质,enc_flag = (c - noise) % n

由于DES的密钥可控,我们可以输入两个弱密钥,使得cp = p,cq = q,这样的$n$就可以利用一个$p + 1$光滑的板子分解,然后解RSA即可

 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
from Crypto.Util.number import *
from itertools import count
from gmpy2 import *
from pwn import *

def recover_noise(cnoise):
    bin_cnoise = list(map(int,bin(cnoise)[2:]))
    noise = bin_cnoise[:16]
    for i in range(16,len(bin_cnoise)):
        noise.append(bin_cnoise[i] ^ noise[i-16])
    return int(''.join(map(str,noise)),2)

def mlucas(v, a, n):
    v1, v2 = v, (v ** 2 - 2) % n
    for bit in bin(a)[3:]: v1, v2 = ((v1 ** 2 - 2) % n, (v1 * v2 - v) % n) if bit == "0" else (
        (v1 * v2 - v) % n, (v2 ** 2 - 2) % n)
    return v1

def primegen():
    yield 2
    yield 3
    yield 5
    yield 7
    yield 11
    yield 13
    ps = primegen()  # yay recursion
    p = ps.__next__() and ps.__next__()
    q, sieve, n = p ** 2, {}, 13
    while True:
        if n not in sieve:
            if n < q:
                yield n
            else:
                next, step = q + 2 * p, 2 * p
                while next in sieve:
                    next += step
                sieve[next] = step
                p = ps.__next__()
                q = p ** 2
        else:
            step = sieve.pop(n)
            next = n + step
            while next in sieve:
                next += step
            sieve[next] = step
        n += 2

def ilog(x, b):  # greatest integer l such that b**l <= x.
    l = 0
    while x >= b:
        x /= b
        l += 1
    return l

def attack(n):
    for v in count(1):
        for p in primegen():
            e = ilog(isqrt(n), p)
            if e == 0:
                break
            for _ in range(e):
                v = mlucas(v, p, n)
            g = gcd(v - 2, n)
            if 1 < g < n:
                return int(g), int(n // g)  # g|n
            if g == n:
                break
            
key1 = '011F011F010E010E'
key2 = '1F011F010E010E01'
context.log_level = 'debug'
sh = remote("101.201.151.28",30753)
sh.recvuntil(b"Welcome to My cryptosystem, can you find the vulnerability of this cryptosystem and get the flag?\n")
sh.sendlineafter(b"input your key1: ",key1.encode())
sh.sendlineafter(b"input your key2: ",key2.encode())
c = eval(sh.recvline().strip().decode().split('=')[-1])
cnoise = eval(sh.recvline().strip().decode().split('=')[-1])
n = eval(sh.recvline().strip().decode().split('=')[-1])

p, q = attack(n)
print(f"p = {p}")
print(f"q = {q}")
noise = recover_noise(cnoise)
print(f"noise = {noise}")
cm = (c - noise) % n
m = pow(cm,inverse(65537,(p-1)*(q-1)),n)
print(long_to_bytes(m))

image-20250713162234186

e_misc

直接爆破密码

image-20250713155709407

hex文件丢给ai分析

image-20250713163259760

pypy

拿到源码丢给ai,py3.8环境运行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def main():
    import inspect, hashlib, marshal, builtins, subprocess, sys, platform
    assert platform.python_version() == "3.8.0" and platform.system() == "Windows"
    anti = b'\xe3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00@\x00\x00\x00sp\x00\x00\x00d\x00d\x01l\x00Z\x00d\x00d\x01l\x01Z\x01d\x00d\x01l\x02Z\x02e\x02\xa0\x03\xa1\x00Z\x04d\x02d\x03\x84\x00e\x01_\x05d\x04d\x03\x84\x00e\x01_\x06e\x02\xa0\x07\xa1\x00e\x00_\x08e\x02\xa0\x07\xa1\x00e\x00_\te\x04e\x00j\x08_\ne\x02\xa0\x03\xa1\x00e\x00j\t_\ne\x00\xa0\x0b\xa1\x00d\x01k\x03rld\x01Z\x04d\x01S\x00)\x05\xe9\x00\x00\x00\x00Nc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00O\x00\x00\x00s\x04\x00\x00\x00d\x00S\x00\xa9\x01N\xa9\x00\xa9\x02\xda\x04args\xda\x06kwargsr\x03\x00\x00\x00r\x03\x00\x00\x00\xfa\t.\\anti.py\xda\x08<lambda>\x03\x00\x00\x00\xf3\x00\x00\x00\x00r\x08\x00\x00\x00c\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00O\x00\x00\x00s\x04\x00\x00\x00d\x00S\x00r\x02\x00\x00\x00r\x03\x00\x00\x00r\x04\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x07\x00\x00\x00r\x08\x00\x00\x00\x04\x00\x00\x00r\t\x00\x00\x00)\x0c\xda\x03sys\xda\x08builtins\xda\x02io\xda\x07BytesIOZ\x08debugger\xda\x05print\xda\x04open\xda\x08StringIO\xda\x06stdout\xda\x06stderr\xda\x06buffer\xda\x08gettracer\x03\x00\x00\x00r\x03\x00\x00\x00r\x03\x00\x00\x00r\x07\x00\x00\x00\xda\x08<module>\x01\x00\x00\x00s\x12\x00\x00\x00\x18\x01\x08\x01\n\x01\n\x01\n\x01\n\x01\x08\x01\x0c\x01\x0c\x01'
    exec(marshal.loads(anti))
    # 生成flag(保留源码)
    flag = "flag{" + hashlib.md5((str((lambda x: [dir(_) for _ in x])
                                      (dict({**locals(), **globals()}).values())).encode() +
                                  b'def main():\n    import inspect, hashlib, marshal,builtins,subprocess,sys,platform\n    assert platform.python_version()=="3.8.0" and platform.system()=="Windows"\n    anti=b\'\\xe3\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00@\\x00\\x00\\x00sp\\x00\\x00\\x00d\\x00d\\x01l\\x00Z\\x00d\\x00d\\x01l\\x01Z\\x01d\\x00d\\x01l\\x02Z\\x02e\\x02\\xa0\\x03\\xa1\\x00Z\\x04d\\x02d\\x03\\x84\\x00e\\x01_\\x05d\\x04d\\x03\\x84\\x00e\\x01_\\x06e\\x02\\xa0\\x07\\xa1\\x00e\\x00_\\x08e\\x02\\xa0\\x07\\xa1\\x00e\\x00_\\te\\x04e\\x00j\\x08_\\ne\\x02\\xa0\\x03\\xa1\\x00e\\x00j\\t_\\ne\\x00\\xa0\\x0b\\xa1\\x00d\\x01k\\x03rld\\x01Z\\x04d\\x01S\\x00)\\x05\\xe9\\x00\\x00\\x00\\x00Nc\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\x00\\x00O\\x00\\x00\\x00s\\x04\\x00\\x00\\x00d\\x00S\\x00\\xa9\\x01N\\xa9\\x00\\xa9\\x02\\xda\\x04args\\xda\\x06kwargsr\\x03\\x00\\x00\\x00r\\x03\\x00\\x00\\x00\\xfa\\t.\\\\anti.py\\xda\\x08<lambda>\\x03\\x00\\x00\\x00\\xf3\\x00\\x00\\x00\\x00r\\x08\\x00\\x00\\x00c\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x00\\x00\\x01\\x00\\x00\\x00O\\x00\\x00\\x00s\\x04\\x00\\x00\\x00d\\x00S\\x00r\\x02\\x00\\x00\\x00r\\x03\\x00\\x00\\x00r\\x04\\x00\\x00\\x00r\\x03\\x00\\x00\\x00r\\x03\\x00\\x00\\x00r\\x07\\x00\\x00\\x00r\\x08\\x00\\x00\\x00\\x04\\x00\\x00\\x00r\\t\\x00\\x00\\x00)\\x0c\\xda\\x03sys\\xda\\x08builtins\\xda\\x02io\\xda\\x07BytesIOZ\\x08debugger\\xda\\x05print\\xda\\x04open\\xda\\x08StringIO\\xda\\x06stdout\\xda\\x06stderr\\xda\\x06buffer\\xda\\x08gettracer\\x03\\x00\\x00\\x00r\\x03\\x00\\x00\\x00r\\x03\\x00\\x00\\x00r\\x07\\x00\\x00\\x00\\xda\\x08<module>\\x01\\x00\\x00\\x00s\\x12\\x00\\x00\\x00\\x18\\x01\\x08\\x01\\n\\x01\\n\\x01\\n\\x01\\n\\x01\\x08\\x01\\x0c\\x01\\x0c\\x01\'\n    exec(marshal.loads(anti))\n    flag = "flag{" + hashlib.md5((str((lambda x: [dir(_) for _ in x])\n                      (dict({**locals(), **globals()}).values())).encode() +\n                  inspect.getsource(main).encode())).hexdigest() + "}"\n    if input() == flag:\n        subprocess.Popen(\'calc.exe\')\n')).hexdigest() + "}"
    # 关键:用原始文件操作写入flag
    subprocess.run(f'echo "{flag}" > D:\\flag.txt', shell=True)
    if input() == flag:
        subprocess.Popen('calc.exe')
if __name__ == "__main__":
    main()

然后conda 起一个环境跑

image-20250713170812232

结果保存在flag.txt了

image-20250713170834906

easy_misc

解压得到一堆txt

看到最后一个txt是504B开头,直接上脚本逆序拼接

 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
import os
import re
from pathlib import Path

def extract_number(filename):
    """
    Extract the numerical part from the filename (excluding .txt) for sorting.
    Returns a large negative number if no digits are found to push such files to the end.
    """
    match = re.search(r'(\d+)\.txt$', filename)
    return int(match.group(1)) if match else -float('inf')

def merge_txt_files_by_number_desc(input_folder, output_file):
    """
    Merge all .txt files in the specified folder into a single output file,
    sorted by the numerical value in filenames in descending order (e.g., 127599.txt to 1.txt).
    
    Args:
        input_folder (str): Path to the folder containing .txt files
        output_file (str): Path to the output file where contents will be saved
    """
    try:
        # Convert input_folder to Path object
        folder_path = Path(input_folder)
        if not folder_path.is_dir():
            print(f"Error: {input_folder} is not a valid directory.")
            return
        
        # Collect all txt files
        txt_files = []
        for root, _, files in os.walk(folder_path):
            for file in files:
                if file.endswith('.txt'):
                    txt_files.append(Path(root) / file)
        
        # Sort files by numerical value in filename in descending order
        txt_files.sort(key=lambda x: extract_number(x.name), reverse=True)
        
        # Open output file in write mode
        with open(output_file, 'w', encoding='utf-8') as outfile:
            for file_path in txt_files:
                try:
                    # Read each txt file
                    with open(file_path, 'r', encoding='utf-8') as infile:
                        content = infile.read()
                        # Write content to output file
                        outfile.write(content)
                        # Add a newline between files for clarity
                        outfile.write('\n')
                except UnicodeDecodeError:
                    print(f"Warning: Could not decode {file_path}, skipping.")
                except Exception as e:
                    print(f"Error reading {file_path}: {e}")
        
        print(f"Successfully merged {len(txt_files)} txt files to {output_file}")
        
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    # Example usage
    input_folder_path = "1"  # Replace with your folder path
    output_file_path = "merged_output.txt"    # Output file name
    merge_txt_files_by_number_desc(input_folder_path, output_file_path)

然后拖到010里面改后缀为zip,解压得到一张图片

image-20250713171820728

后来群里师傅聊到是猫脸变换,这里上爆破工具

https://github.com/Alexander17-yang/Anrold-break/releases/tag/arnold2.0

尝试爆破了好久也没出

Licensed under 9u_l3
使用 Hugo 构建
主题 StackJimmy 设计