freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

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

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客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录