2024全国大学生信息安全竞赛创新实践能力赛初赛 CISCN2024 部分题目个人Writeup

以下为我个人在比赛中A出来的题目的题解。

解题过程

Power Trajectory Diagram

使用py中的numpy和pandas库读取npz文件并保存为csv文件,代码如下:

import numpy as np
import pandas as pd
np.set_printoptions(threshold=np.inf)
a1 = np.load('attachment.npz', allow_pickle=True)
print(a1.files)
print('read:', a1)
index = a1['index']
myin = a1['input']
myout = a1['output']
mytra = a1['trace']
# print(mytra.shape)
df = pd.DataFrame(mytra)
df.to_csv('data1.csv', index=False)
df1 = pd.DataFrame({'index':index, 'input': myin})
df1.to_csv('data2.csv', index=False)

得到data1.csv、data2.csv,合并得到data.csv。

打开data.csv,可以看到功耗数据,根据https://zhuanlan.zhihu.com/p/157585244,我认为该题的关键是在于找到与其它字符不同的字符,就是该index的正确密码。

基于此,利用Excel的折线图功能,例如第四个字符,如图所示:
在这里插入图片描述

可以看出,有一条绿色线与其它线都不同,为c,所以第四个字符就是c。

依次重复,得到整个密钥:_ciscn_2024_

即flag:flag{_ciscn_2024_}

androidso_re

使用GDA反编译题目所给的apk,可以看到判断flag的函数:
在这里插入图片描述
在这里插入图片描述

可以看到,程序是对输入的flag进行DES加密后与正确flag的密文进行比对,密文为:JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==

其中获取key和iv函数如下图:
在这里插入图片描述

可以看到,这两个函数为native函数,是在secret_entrace之中的,用压缩软件打开apk,可以从lib文件夹里找到该库。
在这里插入图片描述

解压下来,用IDA反编译,首先找到生成iv的函数:

在这里插入图片描述
在这里插入图片描述

根据代码可以判断此为ROT13加密,变换为65-49=16位,原文为 F2IjBOh1mRW=,加密得到iv:
在这里插入图片描述

接下来找到生成key的函数,根据代码可以判断,此为RC4加密,密钥为 YourRC4Key,原文为 TFSecret_Key,加密后经历了一次异或,key为 0x038933B8540C206,加密后,截取其前8位得到key:
在这里插入图片描述
在这里插入图片描述

最后,使用key和iv对密文进行解密得到flag:

在这里插入图片描述

通风机

使用binwalk可以分离出一个zlib文件,使用python解压,代码如下:

import zlib

def decompress_zlib_file(input_filename, output_filename):
    with open(input_filename, 'rb') as compressed_file:
        compressed_data = compressed_file.read()
        decompressed_data = zlib.decompress(compressed_data)

    with open(output_filename, 'wb') as output_file:
        output_file.write(decompressed_data)

# Example usage
input_file = '35.zlib'
output_file = 'decompressed_data.txt'
decompress_zlib_file(input_file, output_file)

用Winhex 打开 decompressed_data.txt,可以看到经过base64编码后的flag。

在这里插入图片描述

解码得到flag:

在这里插入图片描述

古典密码

根据题目名称,枚举各种古典密码,最后发现是Atbash密码,base64解密后得到接近flag的一串字符。

在这里插入图片描述

随后使用一把梭工具,发现其为栅栏密码并解密,得到flag。

在这里插入图片描述

whereThel1b

查看python代码,发现它使用了一个so,将输入的flag进行加密后与encry对比,判断flag。

在这里插入图片描述

首先对那个so文件进行逆向,发现根本看不懂。所以使用黑盒测试的方法,分别输入a、b、c、d、e、f、g、h,发现a、b、c,d、e、f,g、h加密后的第一个字符分别相等,第三、四个字符全部相等。同时输入1、2、3->4,4->8。通过这些规律发现该加密与base64有关,于是我输入56/4*3=42个a,观察得出的ret,与base64('a'*42)做对比,如图所示:

在这里插入图片描述

import base64
import whereThel1b

def main(flag):
    encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]
    ret = whereThel1b.trytry(flag)
    
    print(flag.decode(), ret[0], end='  ')
    if ret[0] == 108:
        print(flag)

main(b'a'*42)

print([i for i in base64.encodebytes(b'a'*42)])

观察发现并无明显规律,尝试是否为异或加密,解密代码如下:

encry = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]

a = [111, 79, 118, 80, 67, 85, 86, 72, 70, 78, 116, 93, 74, 73, 80, 77, 84, 119, 78, 122, 81, 103, 64, 79, 106, 71, 100, 69, 106, 113, 79, 123, 95, 121, 66, 94, 114, 66, 88, 75, 95, 65, 93, 124, 126, 127, 75, 75, 71, 75, 113, 73, 73, 84, 117, 75]
b = [89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 89, 87, 70, 104, 10]

ret = []

for i in range(0, len(encry)):
    ret += [a[i] ^ b[i] ^ encry[i]]

print(ret)
for i in ret:
    print(chr(i),end="")a

在这里插入图片描述

发现明显的Zmxh,为flag的base64编码,解密得到flag:

在这里插入图片描述

gdb_debug

用IDA反编译,定位main函数,可以发现程序逻辑为:

  1. 输入str,将str每一个字符异或一个随机数,得到str2

    在这里插入图片描述

  2. 定义str3,随机交换洗牌,得到一个0-38的随机不重复的序列

    在这里插入图片描述

  3. 根据str3,得到str4,使得str4[i]=str2[str[3]]

    在这里插入图片描述

  4. 将str4每一个字符异或一个随机数

    在这里插入图片描述

  5. 根据str4,得到s1,使得s1[i]=str4[i]^byte_5636B30010A0,其中byte_5636B30010A0固定且已给出

    在这里插入图片描述

  6. 将s1与s2作对比,若相同,则输入flag正确,其中s2为"congratulationstoyoucongratulationstoy"

    在这里插入图片描述

这个程序的特性在于,在置随机数种子时,使用的是当前时间按位与0xF0000000的结果为种子,使得种子在很长一段时间执行时都相同。
在这里插入图片描述

基于此,我们可以提前求出要用到的随机数(要在Linux系统上运行,与Win的rand()逻辑不同):

srand(((int)time(0))& 0xF0000000);
char rand1[38];
unsigned int rand2[38],rand3[38];
for(int i=0;i<len;i++)
{
    rand1[i] = rand();
    // cout << (unsigned int)(rand1[i]&0xff) << " ";
}
for(int i=len-1;i;--i)
{
    rand2[i] = rand()%(i+1);
    // cout << (unsigned int)(rand2[i]&0xff) << " ";
}
for(int i=0;i<len;i++)
{
    rand3[i] = rand();
}

然后根据上面所述步骤,反过来计算一遍,完整代码如下:

# Run in linux
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <vector>
#include <algorithm>
#include <stack>
#include <set>
#include <map>
#include <ctime>
#include <unistd.h>
#include "defs.h"
// #include <bits/stdc++.h>

using namespace std;
typedef long long LL;
typedef long double DD;

int main()
{
	srand(((int)time(0))& 0xF0000000);
	char s2[] = "congratulationstoyoucongratulationstoy";
	unsigned char byte_10A0[] = {
		0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 0xAC, 0xF1, 0x06, 0xBE, 0xAD, 0x88, 
		0x04, 0xD7, 0x12, 0xFE, 0xB5, 0xE2, 0x61, 0xB7, 0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 0x9D, 0x4D, 
		0xBC, 0x81, 0x8C, 0xE9, 0x88, 0x78, 0x00, 0x00
	};
	char rand1[38];
	unsigned int rand2[38],rand3[38];
	int len = strlen(s2);
	cout << "len:" << len << endl;
	for(int i=0;i<len;i++)
	{
		rand1[i] = rand();
		// cout << (unsigned int)(rand1[i]&0xff) << " ";
	}
	for(int i=len-1;i;--i)
	{
		rand2[i] = rand()%(i+1);
        // cout << (unsigned int)(rand2[i]&0xff) << " ";
	}
	for(int i=0;i<len;i++)
	{
		rand3[i] = rand();
	}
	
	for(int i=0;i<len;i++)
	{
		s2[i] ^= byte_10A0[i];
	}

	for(int i=0;i<len;i++)
	{
		s2[i] ^= rand3[i];
	}

	int str3[39];
	for(int i=0;i<len;i++)
	{
		str3[i] = i;
	}

	for(int i=len-1;i;--i)
	{
		int temp = str3[i];
		str3[i] = str3[rand2[i]];
		str3[rand2[i]] = temp;
	}

	//s2[i]=str2[str3[i]];
	char str2[39] = {0};
	for(int i=0;i<len;i++)
	{
		str2[str3[i]] = s2[i];
	}
    for(int i=0;i<len;i++)
	{
		str2[i] ^= rand1[i];
	}
	cout << str2;
	
	return 0; //-22 61 13 92
}

在Linux上运行,得到flag:
在这里插入图片描述

posted @ 2024-05-27 02:42  天翔RT  阅读(101)  评论(0编辑  收藏  举报