• HWS-2022 夏令营线上赛 WP


    本次比赛的全部题目附件(点击进入下载链接
    在这里插入图片描述
    PS:比赛结束时,排名已经第五了(估计等一二三血一加成,就掉到第十名去了)不过回味一下我第二名的巅峰时刻哈哈哈(跑…ε=ε=ε=(~ ̄▽ ̄)~
    在这里插入图片描述

    一、硬件(Crypto侧信道)

    ① 硬件(Crypto侧信道)-Read&Solve

    1. 参考了 CTF Wiki 的低高位取 01,得到侧信道电位频率为:1010110100101100
    2. 考虑到可能是二进制,转成十进制,再转成十六进制即可得到 FLAG

    img
    在这里插入图片描述

    得到 FLAG 为 ad2c

    ② 硬件(Crypto侧信道)-足够安全

    1. 参考了 Google 2022 CTF 的 ELECTRIC MAYHEM CLS 的 WP,参考博客:Google CTF writeup(kurenaif)
    2. 确认了 firmware 中的 aes.c 的 sbox 并没有修改之后,就知道可以套代码了
    3. 只需要将 traces.json 改成题目的就行了
    import json
    import numpy as np
    import matplotlib.pyplot as plt
    import scipy.io as sio
    from Crypto.Cipher import AES
    import binascii
    import sys
    
    humming = [bin(n).count("1") for n in range(256)]
    
    json_open = open('traces.json', 'r')
    json_load = json.load(json_open)
    
    sbox = (0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
            0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
            0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
            0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
            0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
            0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
            0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
            0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
            0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
            0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
            0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
            0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
            0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
            0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
            0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
            0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
            0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
            0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
            0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
            0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
            0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
            0xb0, 0x54, 0xbb, 0x16)
    
    
    def addkey_subbytes(pt, guesskey):
        return sbox[pt ^ guesskey]
    
    
    N = len(json_load)
    
    print(N)
    # print(json_load[0]['pt'])
    # print(json_load[0]['ct'])
    # print(json_load[0]['pm'])
    
    bestguess = [0] * 16
    data_start = 0
    data_end = 1800
    NUM_POINTS = data_end - data_start
    NUM_TRACES = len(json_load)
    traces = []
    
    for pt_ct_pm in json_load:
        traces.append(pt_ct_pm['pm'][data_start:data_end])
    
    for k_idx in range(16):  # determine key index
        cpaoutput = [0] * 256
    
        # follow valiables may not be need
        maxcpa = [0] * 256
        bestcor = 0
        bestkey = 0
    
        for kguess in range(256):  # determine word key candidate
            sumnum = np.zeros(NUM_POINTS)
            sumden1 = np.zeros(NUM_POINTS)
            sumden2 = np.zeros(NUM_POINTS)
    
            hyp = np.zeros(NUM_TRACES)
    
            for t_idx in range(NUM_TRACES):  # hypothesis hamming weight
                hyp[t_idx] = humming[addkey_subbytes(json_load[t_idx]['pt'][k_idx],
                                                     kguess)]
    
            h_mean = np.mean(hyp, dtype=np.float64)
            t_mean = np.mean(traces, axis=0, dtype=np.float64)
    
            assert 0 < h_mean and h_mean < 8, "meanh is not between 0 and 8"
            assert len(t_mean) == NUM_POINTS, "meant is less than trace points"
    
            cors = []
    
            for t_idx in range(NUM_TRACES):
                hdiff = (hyp[t_idx] - h_mean)
                tdiff = traces[t_idx] - t_mean
    
                sumnum = sumnum + (hdiff * tdiff)
                sumden1 = sumden1 + hdiff * hdiff
                sumden2 = sumden2 + tdiff * tdiff
    
            cpaoutput[kguess] = sumnum / np.sqrt(sumden1 * sumden2)
    
            maxcpa[kguess] = max(abs(cpaoutput[kguess]))
    
        bestguess[k_idx] = np.argmax(maxcpa)
        print("[+] best guess key [{0}] is {1:02x} (score: {2})".format(
            k_idx, bestguess[k_idx], maxcpa[bestguess[k_idx]]))
    
    # strkey = ''.join(map(chr, bestguess))
    # print(strkey)
    print(bestguess)
    b = ""
    for i in bestguess:
        b += str(hex(i))[2:]
    print(b) # FLAG
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108


    得到 FLAG 为 26783472458169352098699180565216

    二、MISC

    ① 最伟大的作品

    1. 一通操作发现没有用,结果放大声音一听歌才发现,原来是钢琴声
    2. 在线钢琴模拟器网站复刻听到的钢琴声音,得到目标音符为:badbadcabbage

    得到 FLAG 为 badbadcabbage

    ② random

    1. 首先根据 made 代码,判断出:只要得出 r3 的原始序列即可知道 FLAG
    2. getpixel 函数的作用是获取坐标的像素值,putpixel 函数的作用是设置坐标的像素值
    3. 根据 cat3.putpixel((i, j), pix[2] ^ r3[i * y + j]) 可知 1.png 的 p3 像素最后会变成 xx.png 的 p3 像素,即可以写出 pix1[2]^num == pix2[2],num 代表随机后的 r3 序列
    4. 要获得 r3 序列才能得到 FLAG,经过测试,只有在 made 代码中进行 shuffle,才能得到与其一样的排列序列,所以我自己设 temp = [0, 1, …, 27917] 共 27918 个元素的序列进行 shuffle,得到的随机序列放进 wp 的代码中,再进行逆 shuffle,并对 r3 进行逆,即可得到 FLAG
    import random
    from PIL import Image
    from hashlib import md5
    from Crypto.Util.number import long_to_bytes as n2b
    
    # 随机序列
    temp = [19413, 5017, 7689, ...,21804, 2197, 3115]
    print(len(temp))
    
    random.seed(793211)
    
    cat = Image.open('1.png')
    cat1 = Image.new('L', cat.size)
    cat2 = Image.new('L', cat.size)
    cat3 = Image.new('L', cat.size)
    
    catt = Image.open('xx.png')
    catt1 = Image.new('L', catt.size)
    catt2 = Image.new('L', catt.size)
    catt3 = Image.new('L', catt.size)
    
    x, y = cat.size
    bits = x * y
    
    r3 = [-1] * 27918
    
    for i in range(x):
        for j in range(y):
            pix1 = cat.getpixel((i, j))
            pix2 = catt.getpixel((i, j))
            for num in range(256):
                if(pix1[2]^num == pix2[2]):
                    r3[i*y+j] = num
                    break
            # cat3.putpixel((i, j), pix[2] ^ r3[i * y + j])
    
    result = [-1] * 27918
    for i in range(27918):
        result[temp[i]] = r3[i]
    
    flag = ""
    for i in range(28):
       flag+=chr(result[i])
    print(flag)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44


    得到 FLAG 为 lovely_cat_with_random

    ③ What’s this

    1. 使用在线工具反编译无果,使用 stegosaurus 也无果,于是谷歌搜索针对 pyc 的工具
    2. 通过查阅,发现可以使用命令 uncompyle6 flag.pyc 反编译,于是我得到第一份源代码
    3. 由于列表元素过大,且众多奇怪变量,怀疑是混淆代码,对第一份源代码运行,并储存二进制文件
    4. 查看二进制文本,发现又是混淆代码,重复上一步操作,储存至新的二进制文件
    5. 再查看二进制文本,发现又是混淆代码,重复上一步操作,储存至新的二进制文件
    6. 最后终于在新的二进制文件中,得到 FLAG
    # 储存至二进制文件的代码
    
    with open("flag",'wb') as ff:
        ff.write(bytearray(f)
    
    • 1
    • 2
    • 3
    • 4
    marshal.dumps 的作用是数据序列化到二进制文件中
    marshal.loads 的作用是加载二进制文件序列化中的数据
    详细可查阅此处:https://www.jb51.net/article/55645.htm
    
    • 1
    • 2
    • 3

    PS:注意混淆时不能替换变量名,容易出错

    由于文件过大,仅展示部分混淆代码,如下:

    • 第一份混淆代码
    # whatisthis.py
    
    import marshal
    import numpy as np
    c = [235, 26, 15, ..., 14, 14, 18, 7]
    remind = "Don't try to reverse this python script. You will be disappointed about it "
    a = '475'
    np.random.seed(np.sum([ord(b) for b in a]))
    for b in range(len(c)):
        c[b] ^= np.random.randint(27)
    else:
        exec(marshal.loads(bytearray(c)))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 第二份混淆代码
    # next.py
    
    import marshal
    a = [225, 217, 139, ..., 210, 108, 12, 14]
    def b(key):
        c = list(range(256))
        d = 0
        for e in range(256):
            d = (d + c[e] + ord(key[e % len(key)])) % 256
            c[e], c[d] = c[d], c[e]
        return c
    def f(p):
        g = b('h0lyduck')
        h = []
        e = d = 0
        for i in p:
            e = (e + 1) % 256
            d = (d + g[e]) % 256
            g[e], g[d] = g[d], g[e]
            j = (g[e] + g[d]) % 256
            k = g[j]
            h.append(i ^ k)
        return h
    exec(marshal.loads(bytearray(f(a))))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 第三份混淆代码(太长不展示了)

    得到 FLAG 为 Wow_Y0o0U_@re_MaSt3r_0F_Not_d3f1neD

    三、Crypto

    ① HWS-easyRSA

    1. 模板题,参考博客:ctf之lcg算法中的lcg-4
    2. 改几个参数即可得到 FLAG
    from Crypto.Util.number import long_to_bytes
    
    n =  31893593182018727625473530765941216190921866039118147474754069955393226712079257707838327486268599271803
    output =  [
        25820280412859586557218124484272275594433027771091486422152141535682739897353623931875432576083022273940,
        24295465524789348024814588142969609603624462580932512051939198335014954252359986260009296537423802567677,
        14963686422550871447791815183480974143372785034397446416396172429864269108509521776424254168481536292904
    ]
    
    MMI = lambda A, n,s=1,t=0,N=0: (n < 2 and t%N or MMI(n, A%n, t, s-A//n*t, N or n),-1)[n<1] #逆元计算
    a=(output[2]-output[1])*MMI((output[1]-output[0]),n)%n
    ani=MMI(a,n)
    b=(output[1]-a*output[0])%n
    seed = (ani*(output[0]-b))%n
    plaintext=seed
    print(long_to_bytes(plaintext))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述
    得到 FLAG 为 e4syRsa1snotdifficult5996642D0A7415EF

  • 相关阅读:
    图像处理之图像质量评价指标PSNR(峰值信噪比)
    生物领域简单调研
    vue+ts vite环境项目取不到process 解决方法
    程序调试技巧
    uniapp项目+SSM实现的安卓的掌上校园系统
    CS144 计算机网络 Lab1:Stream Reassembler
    Mac M3 Pro 安装 Zookeeper-3.4.6
    阅读论文Parallel Instance Query Network for Named Entity Recognition
    服务器访问速度
    正则表达式
  • 原文地址:https://blog.csdn.net/CourserLi/article/details/126110105