MoeCTF-2024-wp

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!!}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

巅峰赛2000分以下是巅峰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值