[BJDCTF 2020]encode

考点:RC4加密,base64加密

解题步骤:

先使用工具进行去壳处理,使用ida打开,可以得知输入的字符先进行了base64换表加密(20行)

,又进行了异或处理(24行),最后进行了RC4加密(25行)

[BJDCTF 2020]encode_第1张图片

 RC4解密脚本:

# 解密脚本
base64_table = [0xE8,0xD8,0xBD,0x91,0x87,0x1A,0x01,0x0E,0x56,0x0F,0x53,0xF4,0x88,0x96,0x82,0xF9,0x61,0x42,0x0A,0xF2,0xAB,0x08,0xFE,0xD7,0xAC,0xFD,0x5E,0x00]
username = b"Flag{This_a_Flag}"

def rc4(key,data):
    S = list(range(256))
    j =0
    out = []
    for i in range(256):
        j = (j + S[i] + key[i % len(key)]) % 256
        S[i],S[j] = S[j], S[i]
    i = j = 0
    for t in data:
        i = (i + 1) % 256
        j = (j + S[i]) % 256
        S[i], S[j] = S[j], S[i]
        out.append(t ^ S[(S[i] + S[j]) % 256])
    return out

retval = rc4(username, base64_table)
new_table = "".join([chr(t) for t in retval])
for x in new_table:
    print(ord(x),end=",")
35,21,37,83,8,26,89,56,18,106,57,49,39,91,11,19,19,8,92,51,11,53,97,1,81,31,16,92

异或解密:

a = [35,21,37,83,8,26,89,56,18,106,57,49,39,91,11,19,19,8,92,51,11,53,97,1,81,31,16,92]
key = "Flag{This_a_Flag}"
length = len(key)
for i in range(len(a)):
    a[i] ^= ord(key[i%length])
for i in a:
    print(chr(i),end="")

 eyD4sN1Qa5Xna7jtnN0RlN5i8lO=

base64解密:

[BJDCTF 2020]encode_第2张图片

RC4加密(结合本题进行分析):

特点:对明文使用同一个密钥异或两次最后得到的是原文

1、先初始化状态向量S(256个字节,用来作为密钥流生成的种子1)

按照升序,给每个字节赋值0,1,2,3,……,254,255

在sub_8048CC2函数中可以看见(第14行),[BJDCTF 2020]encode_第3张图片

 2、初始密钥(由用户输入)长度任意

如果输入长度小于256个字节,则进行轮转,直到填满

例如输入密钥的是1,2,3,4,5   ,  那么填入的是1,2,3,4,5,1,2,3,4,5,1,2,3,4,5........

由上述轮转过程得到256个字节的向量T(用来作为密钥流生成的种子2)

[BJDCTF 2020]encode_第4张图片

 3、开始对状态向量S进行置换操作(用来打乱初始种子1)

按照下列规则进行

从第零个字节开始,执行256次,保证每个字节都得到处理

[BJDCTF 2020]encode_第5张图片

 这样处理后的状态向量S几乎是带有一定的随机性了

4、密钥流的生成与加密

[BJDCTF 2020]encode_第6张图片

//代码实现
#include
#include
 
#define SBOX_LEN 256
 
#define rc4_encrypt rc4_crypt
#define rc4_decrypt rc4_crypt
 
static inline void swap_uchar(unsigned char *puc_x, unsigned char *puc_y)
{
    *puc_x = *puc_x ^ *puc_y;
    *puc_y = *puc_x ^ *puc_y;
    *puc_x = *puc_x ^ *puc_y;
}
 
void hexdump(unsigned char *puc_data, int length)
{
    int i = 0;
 
    for (i = 0; i < length; i++) {
        printf("%02X", puc_data[i]);
        if (i && (i + 1) % 16 == 0) {
            putchar('\n');
        }
    }
    printf("\n");
}
 
/**
 * 利用Key生成S盒
 * the Key-Scheduling Algorithm
 */
static void rc4_ksa(unsigned char *puc_sbox, unsigned char *puc_key, int key_length)
{
    int i = 0;
    int j = 0;
    char tmp[SBOX_LEN] = {0};
 
    for (i = 0; i < SBOX_LEN; i++) {
        puc_sbox[i] = i;
        tmp[i] = puc_key[i % key_length];
    }
 
    for (i = 0; i < SBOX_LEN; i++) {
        j = (j + puc_sbox[i] + tmp[i]) % SBOX_LEN;
        swap_uchar(&puc_sbox[i], &puc_sbox[j]); //交换puc_sbox[i]和puc_sbox[j]
    }
}
 
/**
 * 利用S盒生成密钥流
 * The pseudo-random generation algorithm(PRGA)
 */
static void rc4_prga(unsigned char *puc_sbox, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
    int i = 0;
    int j = 0;
    int t = 0;
    unsigned long k = 0;
 
    for (k = 0; k < ul_data_length; k++) {
        i = (i + 1) % SBOX_LEN;
        j = (j + puc_sbox[i]) % SBOX_LEN;
        swap_uchar(&puc_sbox[i], &puc_sbox[j]);
        t = (puc_sbox[i] + puc_sbox[j]) % SBOX_LEN;
        /* 为了更清晰理解rc4算法流程,此处保存keystream,不直接进行XOR运算 */
        puc_key_stream[k] = puc_sbox[t];
    }
}
 
/* 加解密 */
void rc4_crypt(unsigned char *puc_data, unsigned char *puc_key_stream, unsigned long ul_data_length)
{
    unsigned long i = 0;
 
    /* 把PRGA算法放在加解密函数中可以不需要保存keystream */
    for (i = 0; i < ul_data_length; i++) {
        puc_data[i] ^= puc_key_stream[i];
    }
}
 
int main(int argc, char *argv[])
{
    unsigned char sbox[SBOX_LEN] = {0};
    char key[SBOX_LEN] = {"abcdefghijklmnopqrstuvwxyz"}; //秘钥内容随便定义
    char data[512] = "[email protected] lvfvr#9527";
    unsigned char puc_keystream[512] = {0};
    unsigned long ul_data_length = strlen(data);
 
    printf("key=%s, length=%d\n\n", key, strlen(key));
    printf("Raw data string:%s\n", data);
    printf("Raw data hex:\n");
    hexdump(data, ul_data_length);
 
    /* 生成S-box */
    rc4_ksa(sbox, (unsigned char *)key, strlen(key));
 
    /* 生成keystream并保存,S-box也会被更改 */
    rc4_prga(sbox, puc_keystream, ul_data_length);
 
    printf("S-box final status:\n");
    hexdump(sbox, sizeof(sbox));
 
    printf("key stream:\n");
    hexdump(puc_keystream, ul_data_length);
 
    /* 加密 */
    rc4_encrypt((unsigned char*)data, puc_keystream, ul_data_length);
 
    printf("cipher hexdump:\n");
    hexdump(data, ul_data_length);
 
    /* 解密 */
    rc4_decrypt((unsigned char*)data, puc_keystream, ul_data_length);
 
    printf("decypt data:%s\n", data);
 
    return 0;
}

参考:

https://www.cnblogs.com/gambler/p/9075415.html

你可能感兴趣的:(CTF_RE做题笔记,算法,安全,密码学)