呜呜呜,自闭了,SM4的侧信道攻击肝了2天,啃了几篇论文,敲了几百行代码,算出来还是错的,没打过OI,优化算法太痛苦了
ps:经过HWS群里的@JZAX大佬指点,终于复现了SM4的侧信道攻击
硬件(Crypto侧信道)
Read&Solve
RSA侧信道,根据CTFWiki的图,直接对着波形提取二进制转hex提交
足够安全
AES侧信道,github上可以搜到一个项目(https://github.com/wlmnzf/CPA)
自己改改脚本把json的数据扔进去即可
MISC
最伟大的作品
听一下可以听出来是由不同音调组成,找个在线网站翻译下(https://bideyuanli.com/pp)
把数字前对应的字母连起来提交即可
random
random的size固定,然后按照顺序生成加密时的伪随机数,flag所在位置替换为从\x00到\x27,就可以获得打乱后flag每个字符的顺序,恢复即可
# from flag import FLAG
import random
from PIL import Image
from hashlib import md5
from Crypto.Util.number import long_to_bytes as n2b
random.seed(793211)
def pbl(bits):
num = random.getrandbits(bits)
bins = []
while num:
bins.append(num & 1)
num >>= 1
while len(bins) != bits:
bins.append(0)
return bins
cat = Image.open('1.png')
catx = Image.open('xx.png')
x, y = cat.size
bits = x * y
r1, r2 = pbl(bits), pbl(bits)
fake_flag=b''
for i in range(28):
fake_flag+=n2b(i)
r3 = fake_flag+n2b(random.getrandbits((bits - 28) * 8))
r3 = list(r3)
random.shuffle(r3)
flag=[0 for _ in range(28)]
i=0
j=0
for i in range(x):
for j in range(y):
pix = cat.getpixel((i, j))
pixx = catx.getpixel((i, j))
if r3[i * y + j]!=(pix[2] ^ pixx[2]):
flag[r3[i * y + j]]=pix[2] ^ pixx[2]
for i in flag:
print(chr(i),end='')
What's this
先用uncompyle6反编译出py文件,查看py文件可知,其每次会在程序最后执行一个新的程序。把源代码改一下,把每次要执行的代码给输出到另一个文件里,套了几层娃,最后输出的文件里面有flag明文
CRYPTO
HWS-easyRSA
LCG,找个脚本解一下就行
from gmpy2 import gcd
from Crypto.Util.number import *
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))
RE
re1
很明显的XXTEA加密,把密文密钥提出来,解密一下
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define DELTA 0x9e3779b9
#define MX \
(((z >> 5 ^ y << 2) + (y >> 3 ^ z << 4)) ^ \
((sum ^ y) + (key[(p & 3) ^ e] ^ z)))
uint32_t cipher[] = {
0x10BD3B47, 0x6155E0F9, 0x6AF7EBC5, 0x8D23435F, 0x1A091605, 0x0D43D40EF, 0x0B4B16A67, 0x6B3578A9 ,0x0
};
uint32_t *xxtea_uint_decrypt(uint32_t *data, size_t len, uint32_t *key)
{
uint32_t n =
(uint32_t)len - 1;
uint32_t z, y = data[0], p, q = 6 + 52 / (n + 1), sum = q * DELTA, e;
if (n < 1)
return data;
while (sum != 0)
{
e = sum >> 2 & 3;
for (p = n; p > 0; p--)
{
z = data[p - 1];
y = data[p] -= MX;
}
z = data[n];
y = data[0] -= MX;
sum -= DELTA;
}
return data;
}
int main()
{
uint32_t key[] = {0x1234, 0x2345, 0x4567, 0x6789};
xxtea_uint_decrypt(cipher, 8, key);
printf("%s", &cipher);
}
re2
可以看到有个TLSCallback函数,异或了一块数据块后将其作为代码执行,把debug_break给patch掉,然后动调可以发现是RC4加密,加密前异或了0x48
找个在线网站解密一下
re3
apk拖入GDA逆向,可以在入口处找到以下检查函数,tran函数用于将输入的10进制数三位一组,转换为2字节36进制存储,因为check在libc里,接下来去逆向libc
libc里的Java_com_example_ctf_MainActivity_check函数没什么用处,对sure_flag交叉引用找到检查函数sub_D060
红框处代码因为wsl环境不方便装模拟器调试,所以拖出来用c调,可以发现功能是将36进制数转换为16进制数
下面是rsa加密函数,m是我们的输入,n和e分别是73AA和73A3,c是sure_flag,加密后进行比较。识别rsa加密函数可以根据rsa的特征,常见代码如下:
static int public_block_operation(uint8_t *out, uint32_t *out_len, uint8_t *in, uint32_t in_len, rsa_pk_t *pk)
{
uint32_t edigits, ndigits;
bn_t c[BN_MAX_DIGITS], e[BN_MAX_DIGITS], m[BN_MAX_DIGITS], n[BN_MAX_DIGITS];
bn_decode(m, BN_MAX_DIGITS, in, in_len);
bn_decode(n, BN_MAX_DIGITS, pk->modulus, RSA_MAX_MODULUS_LEN);
bn_decode(e, BN_MAX_DIGITS, pk->exponent, RSA_MAX_MODULUS_LEN);
ndigits = bn_digits(n, BN_MAX_DIGITS);
edigits = bn_digits(e, BN_MAX_DIGITS);
if(bn_cmp(m, n, ndigits) >= 0) {
return ERR_WRONG_DATA;
}
bn_mod_exp(c, m, e, edigits, n, ndigits);
*out_len = (pk->bits + 7) / 8;
bn_encode(out, *out_len, c, ndigits);
// Clear potentially sensitive information
memset((uint8_t *)c, 0, sizeof(c));
memset((uint8_t *)m, 0, sizeof(m));
return 0;
}
把c,n,e提取出来解密出m,然后逆tran转为我们的输入,脚本如下:
from Crypto.Util.number import *
import gmpy2
n=0x7019325B70F4A2F26E921102A0206DE415CAEB535CD4EC9D23D6608630DD00A9DB5DB8FAEF4621CCB2E775844C7447A1A843EBAC03ECA6F329FEABCD6560B80AACF7A54A298548827C9D75E1450FCF7E53DAC37C0F7FD25D509C342C23BDA0619504B28EC903C56C87
p=1475203612633975218848450285487339190962027688336790188873776418606441616307026173067
q=1475203612633975218848450285487339190962027688336790188873776418606441616307046219549
r=1475203612633975218848450285487339190962027688336790188873776418606441616307129708089
e=0x10001
c=bytes_to_long(b"I am sure it is fl4g")
phi=(p-1)*(q-1)*(r-1)
d=gmpy2.invert(e,phi)
m=gmpy2.powmod(c,d,n)
s=hex(m)[2:]
for i in range(len(s)//2):
print('%03d'%(int(s[i*2:i*2+2],16)),end="")
输出直接md5加密即为flag
Comments | 1 条评论
博主 12
orz