第十五届蓝桥杯网络安全个人赛部分赛题解析2(详细)

5、缺失的数据

赛题内容:

lose.py代码:

 

class WaterMarkDWT:
    def __init__(self, origin: str, watermark: str, key: int, weight: list):
        self.key = key
        self.img = cv2.imread(origin)
        self.mark = cv2.imread(watermark)
        self.coef = weight
 

    def arnold(self, img):
        r, c = img.shape
        p = np.zeros((r, c), np.uint8)
 
        a, b = 1, 1
        for k in range(self.key):
            for i in range(r):
                for j in range(c):  
                    x = (i + b * j) % r
                    y = (a * i + (a * b + 1) * j) % c
                    p[x, y] = img[i, j]
        return p
 
    def deArnold(self, img):
        r, c = img.shape
        p = np.zeros((r, c), np.uint8)
 
        a, b = 1, 1
        for k in range(self.key):
            for i in range(r):
                for j in range(c): 
                        x = ((a * b + 1) * i - b * j) % r
                        y = (-a * i + j) % c
                    p[x, y] = img[i, j]
        return p
 

 
    def get(self, size: tuple = (1200, 1200), flag: int = None):
        img = cv2.resize(self.img, size)
 
        img1 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
        img2 = cv2.cvtColor(self.mark, cv2.COLOR_RGB2GRAY)
 
        c = pywt.wavedec2(img2, 'db2', level=3)
        [cl, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = c
 
        d = pywt.wavedec2(img1, 'db2', level=3)
        [dl, (dH3, dV3, dD3), (dH2, dV2, dD2), (dH1, dV1, dD1)] = d
 
        a1, a2, a3, a4 = self.coef
 
        ca1 = (cl - dl) * a1
        ch1 = (cH3 - dH3) * a2
        cv1 = (cV3 - dV3) * a3
        cd1 = (cD3 - dD3) * a4
 
        waterImg = pywt.waverec2([ca1, (ch1, cv1, cd1)], 'db2')
        waterImg = np.array(waterImg, np.uint8)
 
        waterImg = self.deArnold(waterImg)
 
        kernel = np.ones((3, 3), np.uint8)
        if flag == 0:
            waterImg = cv2.erode(waterImg, kernel)
        elif flag == 1:
            waterImg = cv2.dilate(waterImg, kernel)
 
        cv2.imwrite('水印.png', waterImg)
        return waterImg


if __name__ == '__main__':
    img = 'a.png'
    k = 20
    xs = [0.2, 0.2, 0.5, 0.4]
    W1 = WaterMarkDWT(img, waterImg, k, xs)

解压orign.zip压缩包,发现图片进行了加密,但给出了字典,使用ARCHPR工具进行压缩包的密码爆破

----------

ARCHPR是一个爆破密码的小工具,可以自定义字典,也可以使用工具自带的字典,支持中文和英语,挺好用,感兴趣可以上网找找。

----------

结果如图:

得到密码,进行解密,得到彩色图片a.png,如图:

原newImg.png灰度图:

对lose.py代码进行检查,发现少了函数库的引用,以及不正确的缩进,和少了一部分代码语句,经过添加后如下:

import cv2
import numpy as np
import pywt
# 这三个库是添加的库

class WaterMarkDWT:
    def __init__(self, origin: str, watermark: str, key: int, weight: list):
        self.key = key
        self.img = cv2.imread(origin)  # 这里使用了cv2.imread()函数,则在程序前面加入cv2库的引用
        self.mark = cv2.imread(watermark)
        self.coef = weight


    def arnold(self, img):
        r, c = img.shape
        p = np.zeros((r, c), np.uint8)  # 这里使用了np.zeros()函数,则在程序前面加入numpy库的引用

        a, b = 1, 1
        for k in range(self.key):
            for i in range(r):
                for j in range(c):
                    x = (i + b * j) % r
                    y = (a * i + (a * b + 1) * j) % c
                    p[x, y] = img[i, j]
        return p

    def deArnold(self, img):
        r, c = img.shape
        p = np.zeros((r, c), np.uint8)

        a, b = 1, 1
        for k in range(self.key):
            for i in range(r):
                for j in range(c):
                        x = ((a * b + 1) * i - b * j) % r
                        y = (-a * i + j) % c
                        p[x, y] = img[i, j]  # 这里进行了缩进的修改,对比上面arnold方法
        return p



    def get(self, size: tuple = (1200, 1200), flag: int = None):
        img = cv2.resize(self.img, size)

        img1 = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
        img2 = cv2.cvtColor(self.mark, cv2.COLOR_RGB2GRAY)

        c = pywt.wavedec2(img2, 'db2', level=3)  # 这里使用了pywt.wavedec2()函数,则在程序前面加入pywt库的引用
        [cl, (cH3, cV3, cD3), (cH2, cV2, cD2), (cH1, cV1, cD1)] = c

        d = pywt.wavedec2(img1, 'db2', level=3)
        [dl, (dH3, dV3, dD3), (dH2, dV2, dD2), (dH1, dV1, dD1)] = d

        a1, a2, a3, a4 = self.coef

        ca1 = (cl - dl) * a1
        ch1 = (cH3 - dH3) * a2
        cv1 = (cV3 - dV3) * a3
        cd1 = (cD3 - dD3) * a4

        waterImg = pywt.waverec2([ca1, (ch1, cv1, cd1)], 'db2')
        waterImg = np.array(waterImg, np.uint8)

        waterImg = self.deArnold(waterImg)

        kernel = np.ones((3, 3), np.uint8)
        if flag == 0:
            waterImg = cv2.erode(waterImg, kernel)
        elif flag == 1:
            waterImg = cv2.dilate(waterImg, kernel)

        cv2.imwrite('水印.png', waterImg)
        return waterImg


if __name__ == '__main__':
    img = 'a.png'
    waterImg = 'newImg.png'  # 这里添加了一个参数waterImg,因为W1传递了四个参数,少一个
    k = 20
    xs = [0.2, 0.2, 0.5, 0.4]
    W1 = WaterMarkDWT(img, waterImg, k, xs)
    W1.get()  # 这里添加一行代码,获取程序运行的结果



这段程序的具体含义没太搞懂,大概就是对两张图像进行了小波分解和重构、arnold逆变换、以及最后的处理,变换成了一张含有flag的图像,其实具体的细节过程没必要搞的很清楚,因为我们的目标是找flag,不是图像变换的具体过程,利用好工具就行,程序运行后得到的图片结果如下:

6、RC4

赛题:

这里先拖入查壳工具,看看是多少位的程序:

可以看到红框中的信息,上面的红框显示是32位,下面的红框显示not packed,即无壳

拖入32位的IDA进行分析

----------

注:IDA是一款静态分析二进制代码的软件,支持32位与64位,功能很强大,感兴趣的伙伴可以上网查找相关资料学习,IDA的使用教程网上也有很多。

----------

点击左边_main_0函数(一般程序都是从main函数开始执行),点击Pseudocode-A界面,将鼠标点击空白部分,按下空格,出现下图界面:

分析代码:

看到上图调用了sub_401005()函数,传递了4个参数,并且下一行代码将Str进行了输出,如果在cmd命令行运行该程序的话,会输出gamelab@,显然没太多信息;双击该函数,进行跟踪,得到下图:

又是一个函数sub_401020(),同样传递了四个参数,双击该函数,进行跟踪,得到下图:

如果是经验丰富的大佬,可以看出是标准的rc4加密,但没有把加密结果进行输出,也没有返回。

解题思路:既然没有输出加密结果,也没有返回,那就得去内存里面找到这个结果。

分析sub_401020函数(代码为c语言),上面那个有解析的大图,分析出:传递了四个参数,密钥a1,密钥的长度a2,字符数组的首地址a3,字符数组的长度a4。

函数部分解释:加密字符数组使用s盒,即v13[]数组,生成s盒的密钥是参数a1,a1由最初的Str传递过来,也就是gamelab@,字符数组是以a3为起始地址的内存区域,有个问题,v5[]是char类型的数组,但对应的a3为什么是int类型?是因为最初传递的是(int)v5,传递(int)v5即为传递了整数形势的地址,也就是v5指针(数组的数组名也是一个指针)指向的地址本身被转换为了整数,简单说,就是传递了一个内存地址,而这个内存地址中的第一个值是v5数组的第一个值。然后使用s盒进行了加密。

加密过程如下:

for ( k = 0; k < a4; ++k )
  {
    v12 = (v12 + 1) % 0x100;
    v9 = (v9 + (unsigned __int8)v13[v12 + 256]) % 0x100;
    v7 = v13[v12 + 256];
    v13[v12 + 256] = v13[v9 + 256];
    v13[v9 + 256] = v7;
    result = (unsigned __int8)v13[v9 + 256];
    LOBYTE(result) = v13[(result + (unsigned __int8)v13[v12 + 256]) % 256 + 256] ^ *(_BYTE *)(k + a3);
    *(_BYTE *)(k + a3) = result;
  }

下面这行代码是将加密的字符(内存中这个地址*(_BYTE *)(k + a3)中的字符)赋值给了result的低八位字节

LOBYTE(result) = v13[(result + (unsigned __int8)v13[v12 + 256]) % 256 + 256] ^ *(_BYTE *)(k + a3);

下面这行代码又将result赋值给了*(_BYTE *)(k + a3)

*(_BYTE *)(k + a3) = result;

嗯?什么意思,也就是用加密的字符替换了原来位置的字符,那具体的内存地址是哪里呢?看到代码中是(k + a3),k是for循环的下标,a3是字符数组v5[]在内存中的起始地址,那么找到内存中a3的地址,是不是就找到了关于flag的信息,ok,开始!

1)、在返回result结果处打断点,如下图

2)、按下F9进入调试(我这里是本地调试,也就是local windwos debugger),出现图像如下,此时函数已经运行到断点处

此时程序已经运行到断点处,可以在IDA View-EIP界面按下F5,可以看到函数当前运行截至的位置,如下图:

4)、接下来去寻找a3的地址,点击功能栏Debugger->Debugger windows->Locals,如下:

5)、出现如下,找到红框中的窗口,这个窗口可以清晰的看到参数的变化以及参数的地址,可以看到a3是在寄存器esp的值加上偏移量为26c的位置处,具体的内存地址是0x19FEF8,下面去找地址

6)、进入IDA View-EIP模块,双击esp寄存器:

7)、双击后进入esp寄存器,如下图:

从红框中可以看出,地址是向下增长,我们要找的地址是0x19FEF8,所以向下找,最终找到如下图:

啊!直接找到了flag!!

7、欢乐时光happy time

flag被使用了算法分成若干个小块,每个块使用相同的加密解密方法,但是这个算法是对称加密,请将分析密文并还原。

赛题:

拖入IDA进行分析,点击main函数,F5反编译后,观察图中红框数据。如下图

4长的数组v5,11长的数组v6,通过read函数从终端或者键盘获取buf数组的内容,又调用cry函数对buf数组进行了神秘的操作,最后比较了buf数组前11位数据和v6数组的前十六位数据,不相同的话直接报错退出。那么推出,经过cry函数的操作后要使得buf前11位和v6的前11位相同,那么就看看cry函数的具体内容,双击cry函数,进入,出现如下图:

又到考验经验的时候了,有经验的大佬稍稍看看就可以得出这是XXTEA算法加密过程,而且是经过修改的。我没经验≡(▔﹏▔)≡,只能考完查查资料分析分析。

----------

XXTEA加密算法(eXtended eXtended TEA)是TEA算法的扩展版本,可以更加安全地加密数据。内容有点多,想了解的伙伴可以下方链接进行了解。

XXTEA加密算法-CSDN博客

TEA/XTEA/XXTEA系列算法 - zpchcbd - 博客园 (cnblogs.com)

----------

那么进行分析后发现,加密过程中修改了加密的轮数,也就是变量v9,以及要加密的数据长度,cry传入了buf数组的首地址,但只加密了前11个数据,对应要加密的数据长度a2。

结合main函数中buf与v6的比较,可以得出,v6即为加密后的数据,v5是加密过程中使用的密钥。

加密后的数据有显示为负数形式的,要转换为16进制,点击要转换的数据,右键选择Hexadecimal

下面使用脚本进行解密,当然要修改几处变量,代码如下:

#include <stdio.h>
#include <stdint.h>
#define DELTA 0x9e3779b9
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[(p&3)^e] ^ z)))
 
void btea(uint32_t *v, int n, uint32_t const key[4])
{
    uint32_t y, z, sum;
    unsigned p, rounds, e;
    if (n > 1)            /* 加密 */
    {
        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)      /* 解密 */
    {
        n = -n;
        rounds = 114 + 415/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()
{
    uint32_t v[11]= {1208664588,0xCE9037F2,0x8C212018,244490637,0xA4035274,611560113,0xA9EFDB58,0xA52CC5C8,0xE432CB51,0xD04E9223,1875931283};
    uint32_t const k[4]= {2036950869,1731489644,1763906097,1600602673};
    int n= 11; //n的绝对值表示v的长度,取正表示加密,取负表示解密
    // v为要加密的数据是11个32位无符号整数
    // k为加密解密密钥,为4个32位无符号整数,即密钥长度为128位
    //printf("加密前原始数据:%u %u\n",v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10]);
    //btea(v, n, k);
    printf("加密后的数据:%u %u %u %u %u %u %u %u %u %u %u\n",v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10]);
    btea(v, -n, k);//进行解密,v是加密后的数据,-n是加密后数据的长度,k是密钥 
    printf("解密后的数据:%u %u %u %u %u %u %u %u %u %u %u\n",v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9],v[10]);
    printf("%s",(char*)v);//转化为char *类型输出 
    return 0;
}

输出得到flag:

8、fd

这个题还是难的,目前还没理解,大家可以学习下面两篇文章中大佬的解题方法。

第十五届蓝桥杯大赛软件赛—网络安全选拔赛WP-CSDN博客

2024第十五届蓝桥杯网络安全赛项WriteUp-CSDN博客

基本到这结束了,经过这一趟还是收获多多的,一起加油!!

参考文章:第十五届蓝桥杯大赛软件赛—网络安全选拔赛WP-CSDN博客

2024第十五届蓝桥杯网络安全赛项WriteUp-CSDN博客

十五届蓝桥杯网络安全赛道部分题目wp-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值