2023第七届河南省高等学校信息安全对抗大赛-御网杯-ISCC2023线下赛-(misc+cryoto)(详解-思路-脚本)

芜湖~

是真累呀  原本一天的时间 硬打了一天半 还是那句话 不评价 各位道友心中自有公论

我misc手又发现一个小小的非预期 哎 没想到线下也有这种情况

欧克 以下是我自己的一些思路和解析 有什么问题或者建议随时都可以联系我

2023第七届河南省高等学校信息安全对抗大赛-御网杯-ISCC2023线下赛

下文我是misc和cryoto的见解和思路

附件下载

链接:https://pan.baidu.com/s/1qaIl_ZJVaBY4Kpnkl3NFMw?pwd=lulu 
提取码:lulu 
--来自百度网盘超级会员V3的分享

目录

Misc

Color

代码解释

Sarilang

看到音频第一步是干啥

补充

Badimages

Cryoto

xor4

脚本解析

上脚本

不安全的公钥

一个字符而已

代码解释

加油各位( •̀ ω •́ )y 期待与君再相逢


Misc

Color

 只有一个txt文件

 当文件打开 里面的文件暴露在我们眼前时 哇哦

我相信很多老手立马就明白怎么做

这就是一道很简单的RGB转图片的题目 更不用说文件名还是个提示

(当然新手就一定要多积累)

这里我们上脚本(带解析)

我们需要写一个脚本 创建一个空白的RGB图像,然后从指定的文件"color.txt"中读取颜色信息,并将这些颜色信息逐个应用于图像的每个像素点。最后,通过im.show()方法显示图像。

from PIL import Image

# 定义图像的宽度和高度

x = 500

y = 500

# 创建一个新的RGB图像

im = Image.new("RGB", (x, y))

# 打开并读取颜色文件

file = open("./color.txt", "r")

# 遍历图像的每个像素for i in range(x):

    for j in range(y):

        # 从文件中读取一行颜色信息,并去除换行符

        line = file.readline().strip("\n")

        

        # 去除括号并分割RGB值

        line = line.replace("(", "").replace(")", "")

        rgb = list(line.split(","))

        

        # 将颜色值转换为整数,并将RGB值应用到当前像素

        im.putpixel((i, j), (int(rgb[0]), int(rgb[1].strip(" ")), int(rgb[2].strip(" "))))

        # 显示图像

im.show()

代码解释

上述代码中,我们使用了PIL(Python Imaging Library)库来进行图像处理。具体步骤如下:

  • 引入Image类:我们从PIL库中导入Image模块,这样我们就可以使用其中的函数和方法。
  • 定义图像尺寸:我们使用变量x和y分别指定图像的宽度和高度,这里设置为500。
  • 创建空白图像:通过Image.new()函数创建一个新的RGB图像对象,使用参数"RGB"指定图像的颜色模式为红绿蓝(RGB),并将宽度和高度作为参数传递进去。
  • 打开颜色文件:通过open()函数打开名为"color.txt"的文件,并指定为只读模式。该文件应该包含一系列RGB颜色值,每行一个颜色值。
  • 遍历图像像素:使用嵌套的for循环遍历图像的每个像素点,外层循环控制行数,内层循环控制列数。
  • 读取颜色信息:使用file.readline()函数逐行读取文件中的颜色信息,并通过.strip("\n")方法去除每行末尾的换行符。
  • 解析颜色信息:通过字符串操作去除括号,并使用.split(",")方法将RGB值分割成字符串列表。
  • 转换颜色值:使用int()函数将RGB字符串转换为整数,并分别赋值给red、green和blue变量。
  • 应用颜色信息:通过im.putpixel()方法将RGB值应用到当前遍历到的像素点上,传递参数为当前像素的坐标(i, j)和颜色值(red, green, blue)。
  • 显示图像:通过im.show()方法显示生成的图像。
  • 请确保在运行代码之前,已经准备好了名为"color.txt"的文件,并按照每行一个颜色值的格式进行存储,例如:(255, 0, 0)表示红色。

直接运行得到flag

flag{fb8c67f9-712b-4f3d-9cb2-9219685421a9}

Sarilang

还是只有一个文件 不过这次是一个音频

歌挺好听的 

看到音频第一步是干啥

甲:那它是音频第一步肯定看波形图呀

乙:咦 misc不关什么类型,第一步一定是看文件源码

我:什么 拿到音频第一步不应该是享受歌曲吗? 草原最美的花 火红的撒日朗

欧克欧克 回到正题

其实最开始我也看过波形图 但没有什么用

那我们就从源码看起 010走起

 我们在文件尾发现了很明显的提示

AES加密 密码是12345678

可这是离线状态 断网

我们想想有什么隐写软件 是用AES加密

静默之眼(silenteye) 别问我怎么知道(都是电脑上有的工具试错的) 不过这个工具挺冷门的

 我们选择文件 选择解密

运行得到一个txt的文件(解压过的)

里面是密密麻麻由012组成的编码

我的天 最烦这种了

欧克欧克 现在让我们仔细思考一下

什么编码是用三个字符组成的

这一下子 我还真没想起来几个

不过我们在仔细观察 如果非要转一个字符

0最常变的不就是.

1长的想!

这个2那就是?

那我们直接一手替换

卧槽 不转不知道一转吓一跳 这不是brainfuck编码的变种码

断网 这种要么使用脚本 要么使用离线的工具箱 还好我都有 不愧是一个misc手

python2 ook.py -o 2.txt

 保存到记事板里

再运行一次

python2 ook.py -b 3.txt

得到flag 哎 这个题主打的就是冷门

补充

这里补充一下知识点

Ook! Ook! 是一种通过模仿猩猩语言来表达的编码。它是在Brainfuck基础上衍生出来的一种变体编码。Ook! Ook! 使用三个字符组成,即 "Ook."、"Ook?" 和 "Ook!"。

每个 "Ook!" 表示一个指令。以下是对应关系:

  • "Ook. Ook?":相当于 Brainfuck 中的 "<"
  • "Ook? Ook.":相当于 Brainfuck 中的 ">"
  • "Ook. Ook.":相当于 Brainfuck 中的 "+"
  • "Ook! Ook!":相当于 Brainfuck 中的 "-"
  • "Ook! Ook.":相当于 Brainfuck 中的 "."
  • "Ook. Ook!":相当于 Brainfuck 中的 ","
  • "Ook! Ook?":相当于 Brainfuck 中的 "["
  • "Ook? Ook!":相当于 Brainfuck 中的 "]"

Ook! Ook! 编码的使用方式和含义与 Brainfuck 类似,只是使用了不同的语言描述

Brainfuck是一种由八个字符组成的编码。这种编码是一种极简主义的编程语言,由八个指令符号组成,包括">"、"<"、"+"、"-"、"."、","、"["和"]"。

Badimages

 看看名字 大概意思是坏掉的镜像

盲猜这个题的思路是要恢复里面的一个文件或者数据

但是但是这个题有非预期解  这要是线上又是给我加分

 我直接cat他 哈哈

 在最后 我们发现了flag 直接结束

正常解 也就是我最开始说的思路

感兴趣的可以去试试

后期我要时间 也会上传

Cryoto

xor4

 

只有一个原文件和脚本

这一看 应该就猜到了思路

Flag运行task.py得到cipher

我们需要做的就是把解析脚本 把cipher逆过来 得到flag

下面是task.py 我们先分析一下

脚本解析

 当然,我将详细解析这个脚本的每个部分:

from secret import flag

这行代码从名为 "secret" 的模块中导入了一个变量 flag。根据代码片段提供的信息,我们可以假设 flag 是包含秘密标志的字符串。

import random

这行代码导入了 Python 的内置模块 random,它提供了生成随机数的功能。

k = random.randint(0, 255)

这行代码使用 random.randint() 函数生成一个在区间 [0, 255] 之间(包括边界)的随机整数,并将其赋值给变量 k。这个随机整数将作为 XOR 运算的密钥。

cipher = “”

for c in flag:

    cipher += chr(ord(c) ^ k)

这部分代码使用循环遍历 flag 字符串中的每个字符,并进行以下操作:

  • ord(c) 获取字符 c 的 ASCII 值。
  • 将 ASCII 值与密钥 k 进行异或运算:ord(c) ^ k
  • chr() 函数将结果转换回相应的字符。
  • 最后,将得到的字符追加到 cipher 字符串中。

这样循环执行直到遍历完整个 flag 字符串,生成了经过 XOR 运算后的密文字符串 cipher

with open("cipher", "w") as f:

    f.write(cipher)

这部分代码使用 open() 函数创建一个名为 "cipher" 的文件,并以写入模式打开它。然后,通过 write() 方法将密文字符串 cipher 写入到文件中。最后,使用 with 语句来确保文件操作的正确关闭。

脚本的目标是使用 XOR 运算和随机生成的密钥对秘密标志进行加密,并将生成的密文保存到名为 "cipher" 的文件中。

对flag中的每一个字符都异或上了同一个数字k,进行加密。

明文中的所有字符,都和同一个密钥k进行了异或。

因此,只需要穷举出256钟可能的k,然后尝试去异或解密,如果解密出来的字符串中含有“flag”,则说明解密成功。

上脚本

with open("cipher", "r") as f:

    cipher = f.read()

    #打开名为 "cipher" 的文件,并以只读模式打开它





for k in range(0, 256):

    msg = ""

    #外层循环使用 range(0, 256) 遍历从 0 到 255 的所有可能的密钥

    for c in cipher:

    #内层循环遍历 cipher 字符串中的每个字符

        msg += chr(ord(c) ^ k)

        #chr() 函数将结果转换回相应的字符。

-       #最后,将得到的字符追加到 msg 字符串中,以构建解密后的消息

    if "flag" in msg:

        print(msg)

        break

        #解密后的消息中包含字符串 "flag",则输出该消息并跳出循环

运行得到flag

flag{c30dd6b0-38a3-5f88-830c-52ed3b67c81f}

不安全的公钥

 一个公钥一个密文

很明显是RSA解密

pem公钥文件可以提取出n和e

而有n,我们就需要费马分解得到p和q,进行rsa解密

当然风儿西的工具应该是我目前了解到离线解rsa最方便的工具了

但脚本还是要有的

# -*- coding: utf-8 -*-



from Crypto.PublicKey import RSA

from gmpy2 import *



def Pollard_rho_func_2(a,n):

    return (pow(a,n-1,n)+3)%n

with open('pub.pem', 'r') as f:

    key = RSA.importKey(f)

    print('n:'+str(key.n))

    print('e:'+str(key.e))

    n = key.n

    e = key.e



# 费get p,q



ori=2

a=Pollard_rho_func_2(ori,n)

b=Pollard_rho_func_2(a,n)

p=1

i=1

while (a!=b):

    if (gcd(abs(a-b),n)>1):

        p=gcd(abs(a-b),n)

        break

    else:

        a = Pollard_rho_func_2(a,n)

        b = Pollard_rho_func_2(b,n)

        b = Pollard_rho_func_2(b,n)

    i+=1

    if (i%100==0):

        print(i)

if (p!=1):

    print('p:'+str(p))

    q = n/p

    print('q:'+str(q))

# p= 189749484366449861630736482622030204229600074936733397229668738586605895979811823994029500725448581332746860468289540041125768726148614579255062994177531727784605194094836998282676712435286273497842956368997116036170165393912022560935791934662695453870846024312915604049805219410140420469163797779129644454583

# q= 177993461816075408240866752227210319316825574291000376727523991315086097605063837563342286560819823849610146713383370383386260295565108973920944593141677024612114517119831676665456754235233172344362610684938542774386956894066675103840244633202469661725050948177995671009070311486253646420435061175078660441183



d = invert(e,(p-1)*(q-1))

print('d:'+str(d))

#c = 0xc1bb8cbb9581abf710cab1908a04772f6cc972756e161a5a0615eaf1505d6928e545e626a508abd8c008d43c4eab5ee751c2b5e297891784dc851d8ba887907278142bc70649b503fdec092b143f3afc4508e1671f503c8e38d624befdeeea2bfd3e947289000568a2e409d0f955e19ebb9dccb798543c6435247a8d6b05facddb7f270fce1cecf92994beb7f3119d7f09caa4cff46c9e8db119e41726d0a0ce02ab2b5ae42c3e64c17746a29a32bd642a6045d73078ae8bd1f54a869760474b395c493ffc69cd8020647dcb0610779296a7c18aa984c5b74414e45bdf5d44000888765e457fb84e1ba3b6f60f7ab4f3b9047614f36adf49eac5d662c5916fb8

c = 0x2093fdefa37b3b4ef0d45f42e32f98aa3f1495f06ef6a24250



origin = pow(c,d,n)

print('*'*20)

print(hex(origin)[2:].decode('hex'))

得到gkce~ow]dDyYsg|]{<}jtcsq

这一看 不是凯撒就是栅栏 因为两个括号都有

有工具可以上工具 但脚本的编写还是要会的

a = "gkce~ow]dDyYsg|]{<}jtcsq"

b = ''

# 遍历字符串 'a' 中的每个字符for i in range(len(a)):

    j = i / 2 + 1



    # 如果索引 'i' 是偶数,则从字符的 ASCII 值中减去 'j'

    if i % 2 == 0:

        b += chr(ord(a[i]) - j)

    else:

        # 如果索引 'i' 是奇数,则将 'j' 添加到字符的 ASCII 值中

        b += chr(ord(a[i]) + j)

# 打印转换后的字符串 'b'print(b)

在这段代码中,你使用了一个循环来遍历字符串a的每个字符,并通过一些算术运算来对字符进行加密或解密。

具体来说,在加密过程中,你通过将字符的ASCII码减去索引除以2再加1来获得加密后的字符。而在解密过程中,你将字符的ASCII码加上索引除以2来获得原始字符。

根据你提供的字符串"a",

flag{we_l0v3_encrYpti0n}

一个字符而已

 当文件打开的那一刻

这是一个字符吗 这是一堆字符

好烦 好烦

但看到这里 我忽然想到今年iscc线上的一道misc题 AL的那个大题

那个题最后也得到了一个类似上面的文本 他是只有其中一行是真的编码 解码后才是flag

其他的行全是干扰信息

感慨完了 我们继续看这道题

文本全部是16进制表示

可以将所有字符转换成ascii看下内容

但发现转换完后输出都是乱码

 题目的名称是一个字符而已 

结合以往经验和线上的相似题 猜测是异或加密 且正确答案是其中一行使用某个字符异或后的结果 

思路不出意外应该是这,但如果真的一个一个去手解 怕整个线下的时间都不够

由于不知道秘钥是否是可见字符 所以可以使用0,255循环解密所有内容

 因为文件一共有500行,每一行使用255此解密,最终输出的结果为500*255=127500行,就算正确的结果在其中,我们也很难用眼睛逐行查看。

因为最终的flag肯定可读ascii码,所以我们筛选出所有结果中的数字、字母、空格组合的结果

这是一个大致的思路

后面会给脚本的具体解释

#coding:utf-8

import binascii



# 将16进制转换为ASCII

def hex2char(data):

    output = binascii.unhexlify(data)

    return output



# 异或解密函数,tips为加密字符串,key为秘钥,长度可变

def xor_encrypt(tips, key):

    lkey = len(key)

    secret = []

    num = 0



    for each in tips:

        if num >= lkey:

            num = num % lkey



        # 将每个字符与秘钥进行异或运算,并将结果转换为ASCII字符

        secret.append(chr(ord(each) ^ ord(key[num])))

        num += 1



    # 将解密后的字符列表连接成字符串并返回

    return "".join(secret)



# 打开文件并读取所有行的内容

txt = open('enc.txt', 'r').readlines()



# 遍历文件中的每一行

for line in txt:

    # 尝试使用0到255之间的不同整数作为秘钥进行解密操作

    for i in range(0, 255):

        a = 1

        result = xor_encrypt(hex2char(line.strip('\n')), chr(i))



        # 筛选出只包含数字、字母和空格的解密结果

        for j in result.strip('\n'):

            k = ord(j)



            # 如果字符不是数字、字母或空格,则将标志a设置为0

            if k < ord('z') + 1 and k > ord('0') - 1:

                pass

            elif k == 32:

                pass

            else:

                a = 0

                break



        # 如果解密结果只包含数字、字母和空格,则打印该结果

        if a == 1:

            print(result)

        # python2

代码解释

当你运行这段代码时,它会尝试解密一个名为'enc.txt'的输入文件中的每一行内容。

首先,代码定义了两个函数:

1.hex2char(data)函数使用binascii模块将十六进制数据转换为ASCII字符串。

  • 它接受一个参数data,表示要转换的十六进制数据。
  • 函数内部调用binascii.unhexlify()函数来执行转换操作。
  • 最后,将转换后的ASCII字符串作为结果返回。2.

2.xor_encrypt(tips, key)函数执行异或加密和解密操作。

  • 它接受两个参数:tips表示要加密或解密的字符串,key表示密钥。
  • 函数内部定义了一些变量:lkey表示密钥的长度,secret用于存储加密或解密的结果,num用于跟踪密钥中的字符位置。
  • 函数通过逐个字符地对密钥和输入字符串执行异或运算来进行加密或解密。如果密钥长度不足,则循环使用密钥中的字符。
  • 异或运算通过将字符转换为ASCII码,执行异或操作,然后将结果转换回字符形式来实现。
  • 最后,函数将所有结果字符拼接为一个字符串并返回。

接下来,我们来分析主要的代码逻辑:

  1. txt = open('enc.txt', 'r').readlines():打开名为'enc.txt'的文件并读取所有行,将每一行作为一个字符串存储在txt列表中。
  2. for line in txt::遍历txt列表中的每一行(即文件中的每一行内容)。
  3. for i in range(0, 255)::对于整数值从0到254(ASCII码范围)进行循环,这些值代表可能的密钥字符。
  4. a = 1:初始化变量a为1,用于标记解密结果是否符合筛选条件。
  5. result = xor_encrypt(hex2char(line.strip('\n')), chr(i)):将当前行内容去除换行符,并将其转换为ASCII字符串。然后,使用当前循环中的密钥字符调用xor_encrypt()函数来解密当前行内容,并将解密结果存储在result变量中。
  6. 接下来,通过以下步骤对解密结果进行筛选:
  • for j in result.strip('\n')::对解密结果中的每个字符进行循环处理。
  • k = ord(j):获取字符j的ASCII码,并将其存储在k变量中。
  • 检查字符的ASCII码是否满足以下条件:
  • if k < ord('z') + 1 and k > ord('0') - 1: pass:字符是数字或字母之间的ASCII码范围,继续循环。
  • elif k==32: pass:字符是空格的ASCII码,继续循环。
  • else: a = 0; break:如果字符既不是数字和字母,也不是空格,则将变量a设置为0,并跳出内部循环。

7.if a == 1: print(result):在完成内部循环后,检查变量a的值是否为1。如果是,则表示解密结果符合筛选条件,将其打印输出。\ 

运行得到flag 最好是python2的环境

flag{leKwFMfjcEitrqoTmdkIZSPRVLYxWsQU}

加油各位( •̀ ω •́ )y 期待与君再相逢

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

路baby

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

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

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

打赏作者

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

抵扣说明:

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

余额充值