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


得到 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)


得到 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)
marshal.dumps 的作用是数据序列化到二进制文件中
marshal.loads 的作用是加载二进制文件序列化中的数据
详细可查阅此处:https://www.jb51.net/article/55645.htm

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)))
  • 第二份混淆代码
# 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))))
  • 第三份混淆代码(太长不展示了)

得到 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))

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值