freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

实战 JS逆向思路
2024-02-02 15:36:52

前言

话说在一次的授权测试中,发现了一个有意思的站点,通篇密文,然后我便开始研究其中的解码方法,并附上一些知识点,正文如下。

十六进制解码条件

如果要解密一大串的十六进制编码的数据,第一步肯定要知道需要哪些必要条件才能进行解码啊,那么我们就需要知道以下信息:1. 加密算法:首先,你需要知道所使用的加密算法。常见的加密算法包括AES、DES、RSA等。在你的情况下,你提到是AES加密,这是非常常见且安全的一种对称加密算法。

2. 密钥:对于对称加密算法(如AES),你需要知道用于加密和解密的密钥。密钥的长度可以是128位、192位或256位,这取决于你选择的AES变体(AES-128、AES-192、AES-256)。

3. 初始化向量 (IV):对于某些模式(如CBC模式),你需要一个初始化向量(IV)。IV不需要是保密的,但必须与密文匹配。也就是说,如果你用相同的密钥和不同的IV加密两次,那么两次加密的结果将是不同的,但都可以被相同的密钥和IV解密。

4. 模式:AES可以与多种模式一起使用,如ECB、CBC、CFB、OFB等。不同的模式有不同的用途和安全性考虑。在ECB模式中,对于相同的明文内容,每次加密都会生成相同的密文。这意味着,如果使用相同的密钥对多个块进行加密,每个块都将生成相同的密文。而在CBC模式中,每个块的加密都取决于前一个块的密文。这意味着,对于相同的明文内容,每次加密都会生成不同的密文

5. 填充方案:某些模式需要特定的填充方案。例如,在CBC模式中,通常使用PKCS#7填充。

综上,我们需要知道它使用的加密算法、密钥、模式以及初始化向量IV值(只针对于某些模式),接下来我们进入实战分析。

JS算法逆向【AES算法】

1. 访问页面:

第一反应,直接扔到https://gchq.github.io/CyberChef/里解码,失败。

2. 回到原本的站点找寻解码方式,回到初始门户网站点击F12,开始全局搜索decrypt函数,尝试寻找其加密解密方式:

发现加解密算法为AES,模式有cbc模式,还有ecb模式。(这里下文会进行分点分析)

3. 继续基于AES的加密算法,检索AES,发现new AES的函数,这里传入的参数就是密钥,并把断点就打在key被赋值后,也就是下图中的this.prepare(),然后就发现密钥被打印在控制台了:

在控制台中输入this.key         【访问当前对象(this)有一个名为 key 的属性】

再输入this.key.toString();         【获取 key 属性的值,并调用它的 toString() 方法。toString() 是一个内置方法,用于将一个对象转换为字符串表示形式。如果 key 是一个数字或其他非字符串类型,这将很有用,因为你可以得到一个字符串形式的表示。】4. 显示的密钥为:116, 104, 101, 45, 116, 101, 114, 114, 111, 114, 105, 115, 116, 115, 46, 46
看起来是一串字符的ASCII码值,用逗号分隔,故尝试将这些值转换回对应的字符。可以写个脚本进行解码,脚本如下:

# 定义密钥的ASCII码值列表  
key_list = [116, 104, 101, 45, 116, 101, 114, 114, 111, 114, 105, 115, 116, 115, 46, 46]  
  
# 使用chr()函数将ASCII码值转换为字符,并使用join()函数连接成字符串  
key_string = ''.join(chr(value) for value in key_list)  
  
print(key_string)  # 输出: "th!te!tr!to!ti!ts!tu.u"

运行脚本输出结果为:the-terrorists..

也可以放到https://gchq.github.io/CyberChef/解一下,成功,结果为:the-terrorists..
5. 现在已知条件都差不多了,开始编写一个解密脚本,输出解密成功后的内容,但是从步骤2得知有ecb和cbc两个模式,怎么办呢,那就都尝试一下。

EBC模式

已知:密文(访问页面中的就是)、加密方式aes、密钥the-terrorists..

但是ECB模式不需要初始化向量。(所以ECB模式进行加密和解密可能会导致安全问题,因为它不提供真正的块加密的安全性,但是由此以来提高了加密速度)

解密脚本编写如下:

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes  
from cryptography.hazmat.backends import default_backend  
from cryptography.hazmat.primitives import padding  
import binascii  
  
# 密钥和初始向量  
key = b"the-terrorists.."  
iv = b""  # ECB模式不需要初始向量  
  
# 十六进制密文  
hex_ciphertext = "your-hex-ciphertext"  
  
# 将十六进制密文转换为二进制数据  
ciphertext = binascii.unhexlify(hex_ciphertext)  
  
# 创建一个AES解密器对象  
cipher = Cipher(algorithms.AES(key), modes.ECB(), backend=default_backend())  
  
# 创建一个PKCS#7填充器对象  
padder = padding.PKCS7(128).padder()  
  
# 解密数据(需要一个与加密时匹配的填充方案)  
decryptor = cipher.decryptor()  
decrypted_data = decryptor.update(ciphertext) + decryptor.finalize()  
  
# 去除填充字节(如果存在)  
unpadder = padding.PKCS7(128).unpadder()  
decrypted_data = unpadder.update(decrypted_data) + unpadder.finalize()  
  
# 将二进制数据转换为字符串  
decrypted_text = decrypted_data.decode("utf-8")  
  
print("Decrypted Text:", decrypted_text)

cmd运行一下,发现报错:错误可能的原因包括:

问题出在解密过程中的去填充(unpadding)步骤。具体来说,cryptography库在尝试去除PKCS#7填充时遇到了无效的填充字节,导致了ValueError异常。

这个问题通常发生在解密的数据被篡改或损坏的情况下。如果加密和解密使用的是相同的密钥和算法,并且输入的数据是有效的密文,那么解密过程应该能够成功完成,不会出现这样的错误。

解决这个问题的方法是:

(1)检查密文:确保你使用的密文是有效的,并且没有被篡改。

(2)检查密钥和算法:确保你使用的密钥和加密算法与用于加密的密钥和算法匹配。

(3)检查填充方案:确保你在解密时使用的填充方案与加密时使用的填充方案一致。

(4)使用正确的库版本:确保你使用的cryptography库版本与加密时使用的版本兼容。

对于第一点,还有待商榷,那就先不管第一点,去尝试第二种模式CBC模式进行解密

CBC模式

已知:密文(访问页面中的就是)、加密方式aes、密钥the-terrorists..

CBC模式使用一个随机生成的初始化向量,使得相同的明文块加密为不同的密文块。(所以CBC模式相比ECB模式提高了安全性,但同时由于串行处理数据,使得加密速度很慢)

在前文“十六进制解码条件”中提到CBC模式需要一个初始化向量IV,在这里IV代码里没写,故CBC模式的IV被硬编码为全0的字节串。

初始化向量(IV)是一个用于加密算法的随机或伪随机的数值,通常与密钥一起使用来初始化密码算法的状态。在加密过程中,IV起着随机化的作用,以确保相同的明文在经过相同密钥的加密下产生不同的密文,增加密码强度。

综上,解密脚本编写如下:

#!/usr/bin/python  
from cryptography.hazmat.backends import default_backend  
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes  
from cryptography.hazmat.primitives import padding  
  
def decrypt_aes(key_str, ciphertext_hex):  
    backend = default_backend()  
      
    # 将密钥字符串转换为字节串  
    key = bytes(key_str, 'utf-8')  
      
    # 将十六进制字符串转换为字节串  
    ciphertext = bytes.fromhex(ciphertext_hex)  
      
    # 使用AES算法和CBC模式  
    cipher = Cipher(algorithms.AES(key), modes.CBC(bytes([0]*16)), backend=backend)  
      
    decryptor = cipher.decryptor()  
      
    # 解密密文  
    decrypted_data = decryptor.update(ciphertext) + decryptor.finalize()  
      
    # 使用PKCS7填充,可以根据具体情况选择其他填充方式  
    unpadder = padding.PKCS7(128).unpadder()  
      
    # 移除填充并返回解密后的数据  
    return unpadder.update(decrypted_data) + unpadder.finalize()  
  
def main():  
    # 提示用户输入密钥和密文  
    key_str = input("请输入密钥(字符串格式):")  
    ciphertext_hex = input("请输入十六进制密文: ")  
      
    try:  
        decrypted_data = decrypt_aes(key_str, ciphertext_hex)  
        print("Decrypted Data:", decrypted_data[16:].decode('utf-8'))  
        #print(bytes.fromhex(decrypted_data.hex()))  
    except Exception as e:  
        print("Decryption error:", e)  
  
if __name__ == "__main__":  
    main()

运行一下,成功解码:还可以使用在线解密工具https://www.toolhelper.cn/:    都可以成功解密,完结撒花!

最后

如果我即时去复现的话那么这个手机号中间4位是不会有****的,但是由于工作繁忙+期间站点停过,所以现在才有时间把这篇文章给梳理完,导致管理员已经把泄露的手机号打码了。

# 渗透测试 # 网络安全 # 数据安全 # 漏洞分析 # 网络安全技术
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录