Crypto
1、Signin
考点:RSA
(1)正常的rsa解密
2、Big and small
考点:RSA
(1)低解密指数攻击
3、ez_hash
考点:hash
(1)简单的hash爆破
from hashlib import sha256
from tqdm import trange
hash_value = '3a5137149f705e4da1bf6742e62c018e3f7a1784ceebcb0030656a2b42f50b6a'
for i in trange(1000000):
tmp = sha256(("2100" + str(i).zfill(6)).encode()).hexdigest()
if tmp == hash_value:
print(f"{i = }")
4、More_secure_RSA
(1)题目:
from Crypto.Util.number import *
flag = b'moectf{xxxxxxxxxxxxxxxxx}'
m = bytes_to_long(flag)
p = getPrime(1024)
q = getPrime(1024)
n = p * q
e = 0x10001
c = pow(m, e, n)
print(f'c = {c}')
print(f'n = {n}')
r = getPrime(1024)
n = n * r=q*p*r
c = pow(m, e, n)
print(f'C = {c}')
print(f'N = {n}')
由于 ⟨n,N⟩ 已知,我们可以求出 r=N/n;考虑将 C 模 r,得到 C mod r=m^e modr;可以推导出m=m modr
from Crypto.Util.number import *
assert N1 % n1 == 0
r = N1//n1
assert isPrime(r)
fake_flag = b'moectf{????????????????????????}'
assert bytes_to_long(fake_flag) <= r
dr = inverse(e, r-1)
m = pow(C1,dr,r)
flag = long_to_bytes(m)
5、ezlegendre
考点:
经过欧拉判别法验证, aa 是 pp 的二次非剩余, 而 a+1a+1 是 pp 的二次剩余,我们给定的 ee 是一个奇数,根据勒让德符号可知,最后得到的cipertext[i],也会是相对应的二次剩余或者是二次非剩余,遍历一遍通过欧拉判法可以得到最终的结果。
from sage.all import *
from Crypto.Util.number import *
'''
p = 303597842163255391032954159827039706827
a = 34032839867482535877794289018590990371
ciphertext = [……]
'''
msg_bin = ''
for i in range(len(ciphertext)):
msg_bin += '1' if pow(ciphertext[i], (p - 1) // 2, p) == 1 else '0'
flag = long_to_bytes(int(msg_bin,2))
print(flag)
# Flag: moectf{minus_one_1s_n0t_qu4dr4tic_r4sidu4_when_p_mod_f0ur_equ41_to_thr33}
6、RSA_revenge
考点:rsa
(1)题目的核心代码是这个
def emirp(x):
y = 0
while x !=0:
y = y*2 + x%2
x = x//2
return y
通过代码,我们发现用这个函数生成的p和q他们在二进制上相反的,比如p是1010,那么q就是0101。除此之外,我们会发现p和q的低位乘起来就是n的低位。通过这些性质我们可以直接开始进行爆破。
from Crypto.Util.number import*
from gmpy2 import *
n = 141326884939079067429645084585831428717383389026212274986490638181168709713585245213459139281395768330637635670530286514361666351728405851224861268366256203851725349214834643460959210675733248662738509224865058748116797242931605149244469367508052164539306170883496415576116236739853057847265650027628600443901
c = 47886145637416465474967586561554275347396273686722042112754589742652411190694422563845157055397690806283389102421131949492150512820301748529122456307491407924640312270962219946993529007414812671985960186335307490596107298906467618684990500775058344576523751336171093010950665199612378376864378029545530793597
def blast(a, b, k):
if k == 256:
if a*b == n:
print((a,b))
return
for i in range(2):
for j in range(2):
a1 = a + i*(2**k) + j*(2**(511-k))
b1 = b + j*(2**k) + i*(2**(511-k))
if a1*b1 > n:
continue
if (a1+(2**(511-k)))*(b1+(2**(511-k))) < n:
continue
if ((a1*b1)%(2**(k+1))) != (n%(2**(k+1))):
continue
blast(a1, b1, k+1)
for i in range(2):
blast(i*(2**256), i*(2**256), 0)
p,q = (12119998731259483292178496920109290754181396164390285597126378297678818779092115139911720576157973310671490865211601201831597946479039132512609504866583931, 11660635291534613230423193509391946961264539191735481147071890944740311229658362673314192872117237108949853531941630122241060679012089130178372253390640871)
assert p*q == n
phi = (p-1)*(q-1)
e = 65537
d = pow(e,-1,phi)
m = pow(c,d,n)
print(long_to_bytes(m))
Reverse
1、dynamic
考点:XXTEA
(1)这其实是一个标准的XXTEA,当n>1的时候(也就是+12)的时候,是加密,-12就是解密。 所以这个程序其实在做一个事情:把内置的flag进行解密后又马上加密回去,所以我们只需要动态调试,找到解密后的flag即可
2、upx
考点:UPX
(1)正常的UPX脱壳;再拖入IDA,即可查看正确的flag
3、xor
考点:XOR
(1)简单的XOR操作
enc = [
73, 75, 65, 71, 80, 66, 95, 65, 28, 22,
70, 16, 19, 28, 64, 9, 66, 22, 70, 28,
9, 16, 16, 66, 29, 9, 70, 21, 20, 20,
9, 23, 22, 20, 65, 64, 64, 22, 20, 71,
18, 64, 20, 89
]
result = ''.join([chr(x ^ 0x24) for x in enc])
print(result)
4、逆向工程入门指北
考点:签到
(1)给了一个程序;运行就是flag
5、d0tN3t
考点:XOR
(1)给出的是dll文件;需要用dnSpy逆向分析:加密逻辑
(byte)((int)((byte)text[i] + 0x72 ^ 0x72) ^ i * i)
写出解密脚本即可
enc = [173, 146, 161, 174, 132, 179, 187, 234, 231, 244, 177, 161, 65, 13, 18, 12, 166, 247, 229, 207, 125, 109, 67, 180, 230, 156, 125, 127, 182, 236, 105, 21, 215, 148, 92, 18, 199, 137, 124, 38, 228, 55, 62, 164]
for i in range(len(enc)):
print(chr(((i*i ^ 114 ^ enc[i]) - 114) & 0xff), end='')
# moectf{7ce581d2-b2ab-4ceb-9bbe-435873083db6}
6、rc4
考点:rc4
(1)显然题目说了是Rc4,并且RC4_1s_4w3s0m3很可能是密钥,我们直接拿上面的HEX进行解密就出了
def rc4_init(key):
S = list(range(256))
j = 0
for i in range(256):
j = (j + S[i] + key[i % len(key)]) % 256
S[i], S[j] = S[j], S[i]
return S
def rc4_crypt(S, data):
i = j = 0
result = bytearray()
for byte in data:
i = (i + 1) % 256
j = (j + S[i]) % 256
S[i], S[j] = S[j], S[i]
result.append(byte ^ S[(S[i] + S[j]) % 256])
return bytes(result)
encrypted_data = bytes.fromhex('A71A68ECD82711CC8C9B16155CD2673E82ADCE75D4BC5756C28A52B86BD6CCF8A4BA722FE05715B92411')
key = b"RC4_1s_4w3s0m3"
S = rc4_init(key)
decrypted_data = rc4_crypt(S, encrypted_data)
print(decrypted_data.decode('utf-8', errors='replace'))
7、upx-revengekao
考点:魔改UPX
(1)魔改UPX;脱壳机无法正常脱壳;猜测可能修改了头部或者特征码
(2)这个程序直接upx -d是显示无法进行解压的,原因是UPX解压的时候会检测程序段名称是否为UPX0\UPX1这类的,但是我改成了vmp0,导致无法直接解压,我们使用010Editor打开后更改这个字符串也就可以解密;或者动态调试就能看到flag
8、xtea
考点:tea加密
(1)xtea加密,这里key是12个字节,先对前八个字节加密后,将加密后的后四个字节与后四个字节再次加密
(2)很明显了;需要将enc内容还原得到Key就是正确的flag
加密函数:非常明显的tea加密
(3)解密
from typing import List, Tuple
from struct import unpack
from ctypes import c_uint32
# 将字节数组转换为 32 位整数列表
def byte2dword(x: List[int]) -> List[int]:
if len(x) % 4 != 0:
if type(x) == bytes:
x += b'\x00' * (4 - (len(x) % 4))
else:
x += [0] * (4 - (len(x) % 4))
return [v[0] for v in (unpack('<I', bytes(x[i:i+4])) for i in range(0, len(x), 4))]
# XTEA 解密函数
def xtea_decrypt(
src: Tuple[int, int], key: List[int], delta: int = 0x9E3779B9, rounds: int = 32
) -> Tuple[int, int]:
l, r = c_uint32(src[0]), c_uint32(src[1])
sum = c_uint32(delta * rounds)
k = [c_uint32(key[0]), c_uint32(key[1]), c_uint32(key[2]), c_uint32(key[3])]
for _ in range(rounds):
r.value -= (((l.value << 4) ^ (l.value >> 5)) + l.value) ^ (
sum.value + k[(sum.value >> 11) & 3].value
)
sum.value -= delta
l.value -= (((r.value << 4) ^ (r.value >> 5)) + r.value) ^ (
sum.value + k[sum.value & 3].value
)
return (l.value, r.value)
# 将 32 位整数列表转换为字节数组
def dword2byte(x: List[int]) -> bytes:
result = []
if type(x) == int:
for j in range(4):
result.append((x >> j*8) & 0xff)
return bytes(result)
for i in range(len(x)):
for j in range(4):
result.append((x[i] >> j*8) & 0xff)
return bytes(result)
# 加密后的数据
enc = [0xA3, 0x69, 0x96, 0x26, 0xBD, 0x78, 0x0B, 0x3D, 0x9D, 0xA5, 0x28, 0x62]
# 密钥
key = [2, 0, 2, 4]
# 将字节数组转换为 32 位整数
dw1, dw2, dw3 = byte2dword(enc)
# 解密 (dw2, dw3)
dw2, dw3 = xtea_decrypt((dw2, dw3), key=key, delta=-0x33004445, rounds=32)
# 解密 (dw1, dw2)
dw1, dw2 = xtea_decrypt((dw1, dw2), key=key, delta=-0x33004445, rounds=32)
# 将 32 位整数转换回字节数组
original_data = dword2byte([dw1, dw2, dw3])
# 输出结果
print("解密后的原始输入:", original_data.decode('utf-8', errors='replace'))
9、xxtea
考点:xxtea
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[((p&3)^e)&0xff] ^ z)))
void btea(uint32_t* v, int n, const uint32_t key[4])
{
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) /* Coding Part */
{
rounds = 6 + 52 / n;
sum = 0;
z = v[n - 1];
do
{
sum += DELTA;
e = (sum >> 2) & 3;
for (p = 0; p < n - 1; p++)
{
y = v[p + 1];
z = v[p] += MX;
}
y = v[0];
z = v[n - 1] += MX;
} while (--rounds);
}
else if (n < -1) /* Decoding Part */
{
n = -n;
rounds = 6 + 52 / n;
sum = rounds * DELTA;
y = v[0];
do
{
e = (sum >> 2) & 3;
for (p = n - 1; p > 0; p--)
{
z = v[p - 1];
y = v[p] -= MX;
}
z = v[n - 1];
y = v[0] -= MX;
sum -= DELTA;
} while (--rounds);
}
}
int main() {
unsigned char enc[] = { 0x64,0xf5,0xe1,0x78,0xe1,0xf0,
0x35,0xa8,0x34,0xff,0x12,0x05,
0xfb,0x13,0xe9,0xb0,0x50,0xa3,
0xb9,0x89,0xb1,0xda,0x43,0xc9,
0x4f,0xc8,0xdb,0x01,0x20,0xdb,
0x16,0xaf,0xed,0x67,0x17,0x96
};
int r = 9;
unsigned char input_key[13] = "moectf2024!!"; // Adjusted size to fit 12 characters + null terminator
const uint32_t k[4] = { *((uint32_t*)input_key),*((uint32_t*)(input_key + 4)), *((uint32_t*)(input_key + 8)),0xccffbbbb };
btea(((uint32_t*)enc),-r,k);
//moectf{j9h8hg75nky6vhkslh5v5awibr4i}
//btea(((uint32_t*)input), -r, ((uint32_t*)input_key));
for (int i = 0; i < 36; i++) {
printf("%c",enc[i]);
}
return 0;
}
10、Just-Run-It
考点:四个可执行文件
(1)0x0.exe:先脱壳;得到第一部分:6257396c5933526d657a55355a6d45
(2)0x1.elf
运行得到第二部分
moectf2024@xdsec ~> cat /flag.1
324d444a6a4c5459794e4745744e44
(3)0x2.apk;安装并运行后
moectf2024@xdsec ~> cat /flag.2
42694e7930345954566a4c57557a4e
(4)0x3 riscv ELF64程序
尝试运行发现错误;linux下运行64elf文件需要安装qemu-user
qemu-riscv64 ./0x3.riscv64.elf
最后
6257396c5933526d657a55355a6d45324d444a6a4c5459794e4745744e4442694e7930345954566a4c57557a4e
bW9lY3RmezU5ZmE2MDJjLTYyNGEtNDBiNy04YTVjLWUzN
再加上最后0x3的WU1NzRjZjliOX0=
bW9lY3RmezU5ZmE2MDJjLTYyNGEtNDBiNy04YTVjLWUzNWU1NzRjZjliOX0=
base64 decode
# moectf{59fa602c-624a-40b7-8a5c-e35e574cf9b9}
11、TEA
考点:TEA
(1)最简单的TEA加密
解密
def decrypt(v, k):
v0, v1 = v
delta = 0x9e3779b9
sum_ = delta * 32
k0, k1, k2, k3 = k
for _ in range(32):
v1 -= ((v0 << 4) + k2) ^ (v0 + sum_) ^ ((v0 >> 5) + k3)
v1 &= 0xFFFFFFFF # Ensure 32-bit overflow
v0 -= ((v1 << 4) + k0) ^ (v1 + sum_) ^ ((v1 >> 5) + k1)
v0 &= 0xFFFFFFFF # Ensure 32-bit overflow
sum_ -= delta
return v0, v1
def main():
# Encrypted data
v = [0x284c2234, 0x3910c558]
# Key (converted from "base64xorteaxtea" to 4 uint32 values)
key = [
0x62617365, # "base"
0x78363478, # "x64x"
0x6f727465, # "orte"
0x61787465 # "axte"
]
# Decrypt the data
v0, v1 = decrypt(v, key)
# Format the flag
flag = f"moectf{{{v0:08x}-{v1 >> 16:04x}-{v1 & 0xFFFF:04x}-9c42-caf30620caaf}}"
print(flag)
if __name__ == "__main__":
main()
12、ezMAZE
考点:迷宫
(1)先脱壳;输入w、a、s、d来移动;最终到达目标位置 (75, 55) 以赢得游戏并获取 flag;现在就需要找到地图
__int64 __fastcall sub_140001190(int a1, int a2)
{
unsigned __int8 v3; // [rsp+0h] [rbp-28h]
if ( a1 > 80 || a2 > 56 || a1 < 1 || a2 < 1 )
return 1i64;
v3 = word_140005000[10 * a2 - 10 + (a1 - 1) / 8];
word_140005000[10 * a2 - 10 + (a1 - 1) / 8] = (1 << (7 - (a1 - 1) % 8)) | v3;
return ((int)v3 >> (7 - (a1 - 1) % 8)) & 1;
}
(2)找到地图之后按照main函数编写脚本拿到路径然后就可以得到flag
moectf{the_18446744024826406994_amazing_maze!!}