最近开始起有关ctf的学习,简单记录一下侥幸搞出来的两道crypto题
一.classical
首先拿到题目附件
由命名可知,应该是有关古典密码方面的题目,打开后可以看到一串密文
观察密文特点可以发现其内容只包含大小写字母和数字,在查询有关加密密文特点后,发现该特点与base58编码形式最相近,于是进行base58解码
最后得到一串音符,感觉是音符加密,于是在网上找到有关解码网站,最后得到flag(附音符解码网站:https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=yinyue)
二.ezrsa
由题目可知是有关rsa算法的题目,打开附件后看到四个文本,其中一个为public(刚开始后缀名不是txt)
于是将其后缀改为txt文本打开,看到以下信息:
因为是第一次做ctf,查找有关资料后懂得了这得拿去公钥解码,于是得到如下信息:
再将得到的n拿去分解得到p和q
最后在python上编写脚本,利用所得的e,p,q参数去解码三个附件
代码如下:
import rsa
import base64
import gmpy2
e = 65537
n = 98432079271513130981267919056149161631892822707167177858831841699521774310891
p = 302825536744096741518546212761194311477
q = 325045504186436346209877301320131277983
phi = (p - 1) * (q - 1)
d = gmpy2.invert(e, phi)
key = rsa.PrivateKey(n, e, d, q, p)
# 需要解密的文件列表
file_list = [
"C:\\Users\\Desktop\\ctf\\crypto\\file2\\encrypted.message1",
"C:\\Users\\Desktop\\ctf\\crypto\\file2\\encrypted.message2",
"C:\\Users\\Desktop\\ctf\\crypto\\file2\\encrypted.message3"
]
# 存储解密结果的字符串
decrypted_data_combined = ""
# 循环解密文件
for file_path in file_list:
with open(file_path, "rb") as f:
encrypted_data = f.read()
decrypted_data = rsa.decrypt(encrypted_data, key) # 解密数据
decrypted_data_combined += decrypted_data.decode().replace("\n", "") # 移除换行符
# 打印连接后的解密结果
print(decrypted_data_combined)
最后成功得到flag
三.总结及拓展
1.加密密文的一些特征
在解第一题时查阅了不少相关资料,在此作为笔记,以便将来参考,以下内容来源于这篇文章:
https://baijiahao.baidu.com/s?id=1721920305612879489&wfr=spider&for=pc
1.1 Base 系列编码
-
Base16:结尾没有等号,数字要多于字母;
-
Base32:字母要多于数字,明文数量超过10个,结尾可能会有很多等号;
-
Base58:结尾没有等号,字母要多于数字;
-
Base64:一般情况下结尾都会有1个或者2个等号,明文很少的时候可能没有;
-
Base85:等号一般出现在字符串中间,含有一些奇怪的字符;
-
Base100:密文由 Emoji 表情组成。
1.2 Unicode 编码
Unicode 又称为统一码、万国码、单一码,是一种在计算机上使用的字符编码。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。其主要特征如下:
-
以
\u
、&#
或&#x
开头,后面是数字加字母组合
PS:\u
开头和 &#x
开头是一样的,都是16进制 Unicode 字符的不同写法,&#
则是 Unicode 字符10进制的写法,此外,&#
和 &#x
开头的,也称为 HTML 字符实体转换,字符实体是用一个编号写入 HTML 代码中来代替一个字符,在 HTML 中,某些字符是预留的,如果希望正确地显示预留字符,就必须在 HTML 源代码中使用字符实体。
1.3 Escape 编码
Escape 编码又叫 %u 编码,Escape 编码就是字符对应 UTF-16BE 表示方式前面加 %u,Escape 不会对 ASCII 字母和数字进行编码,也不会对下面这些 ASCII 标点符号进行编码: * @ - _ + . /
,其他所有的字符都会被转义序列替换。其主要特征如下:
-
以
%u
开头,后面是数字加字母组合
1.4 URL / Hex 编码
URL 和 Hex 编码的结果是一样的,不同的是当你用 URL 编码网址时是不会把 http
、https
关键字和 /
、?
、&
、=
等连接符进行编码的,而 Hex 编码则全部转化了,其主要特征如下:
-
以
%
开头,后面是数字加字母组合
1.5 MD5
MD5 实质是一种消息摘要算法,一个数据的 MD5 值是唯一的,同一个数据不可能计算出多个不同的 MD5 值,但是,不同数据计算出来的 MD5 值是有可能一样的,知道一个 MD5 值,理论上是无法还原出它的原始数据的,MD5 是最容易辨别的,主要特征如下:
-
密文一般为 16 位或者 32 位,其中 16 位是取的 32 位第 9~25 位的值;
-
组成方式为字母(a-f)和数字(0-9)混合,字母可以全部是大写或者小写。
除了通过密文特征来判断以外,我们还可以搜索源代码,标准 MD5 的源码里是包含了一些特定的值的,没有这些特定值,就无法实现 MD5:
-
0123456789ABCDEF
、0123456789abcdef
-
1732584193
、-271733879
、-1732584194
、271733878
PS:某些特殊情况下,密文的长度也有可能不止 16 位或者 32 位,有可能是在官方算法上有一些魔改,通常也是在 16 位的基础上,左右填充了一些随机字符串。
示例:
1.6 SHA 系列
SHA 是比 MD5 更安全一点的摘要算法,SHA 通常指 SHA 家族算法,分别是 SHA-1、SHA-2、SHA-3,其中 SHA-2 是 SHA-224、SHA-256、SHA-384、SHA-512 的并称,SHA-3 是 SHA3-224、SHA3-256、SHA3-384、SHA3-512、SHAKE128、SHAKE256 的并称,其名字的后缀的数字就代表了结果的大小(bit),注意,SHAKE 算法结果的大小并不是固定的,其他算法特征如下:
-
SHA-1:字母(a-f)和数字(0-9)混合,固定位数 40 位;
-
SHA-224/SHA3-224:字母(a-f)和数字(0-9)混合,固定位数 56 位;
-
SHA-256/SHA3-256:字母(a-f)和数字(0-9)混合,固定位数 64 位;
-
SHA-384/SHA3-384:字母(a-f)和数字(0-9)混合,固定位数 96 位;
-
SHA-512/SHA3-512:字母(a-f)和数字(0-9)混合,固定位数 128 位。
示例:
1.7 HMAC 系列
HMAC 这种算法就是在 MD5、SHA 两种加密的基础上引入了秘钥,其密文也和 MD5、SHA 类似,密文的长度和使用的 MD5、SHA 算法对应密文的长度是一样的。特征如下:
-
HMAC-MD5:字母(a-f)和数字(0-9)混合,位数一般为 32 位;
-
HMAC-SHA-1:字母(a-f)和数字(0-9)混合,固定位数 40 位;
-
HMAC-SHA-224 / HMAC-SHA3-224:字母(a-f)和数字(0-9)混合,固定位数 56 位;
-
HMAC-SHA-256 / HMAC-SHA3-256:字母(a-f)和数字(0-9)混合,固定位数 64 位;
-
HMAC-SHA-384 / HMAC-SHA3-384:字母(a-f)和数字(0-9)混合,固定位数 96 位;
-
HMAC-SHA-512 / HMAC-SHA3-512:字母(a-f)和数字(0-9)混合,固定位数 128 位。
HMAC 和 SHA、MD5 的密文都很像,当无法确定是否为 HMAC 时,可以通过其名称搜索到加密方法,如果传入了密钥 key,说明就是 HMAC,当然你也可以直接当做是 SHA 或 MD5 来解,解密失败时就得考虑是否有密钥,是否为 HMAC 了,在 JS 中,通常一个 HMAC 加密方法是这样写的:
function HmacSHA1Encrypt(word, key) { return CryptoJS.HmacSHA1(word, key).toString(); }
示例(密钥 123456abcde):
1.8 RSA
RSA 加密算法是一种非对称加密算法,通过公钥加密结果,必须私钥解密。 同样私钥加密结果,公钥可以解密,应用非常广泛,在网站中通常使用 JSEncrypt 库来实现,其最大的特征就是有一个设置公钥的过程,我们可以通过以下方法来快速初步判断是否为 RSA 算法:
-
搜索关键词
new JSEncrypt()
,JSEncrypt
等,一般会使用 JSEncrypt 库,会有 new 一个实例对象的操作; -
搜索关键词
setPublicKey
、setKey
、setPrivateKey
、getPublicKey
等,一般实现的代码里都含有设置密钥的过程;
RSA 的私钥、公钥、明文、密文长度也有一定对应关系,也可以从这方面初步判断:
2.RSA算法解题过程
一般这种题目涉及,m,c,e,d,n,p,q等参数
m为明文,c为密文,e为公钥,d为私钥,p和q为两个素数,n=p*q
如上题所示,公钥的信息未直接给出,在解析后还是得出了e和n的信息,再分解n得到p和q,然后解出d(d满足e*d mod (p-1)(q-1)=1),然后用所得的所有数据解出加密文本
当然RSA还有拓展,因为还是初学,暂且先记录第一种解法,日后碰到不同的再加以记录