利用单兵渗透武器yakit实战encrypt-labs靶场
字数 5594 2025-11-05 23:45:18

利用Yakit实战encrypt-labs加密对抗靶场教学文档

1. 靶场与工具介绍

1.1 encrypt-labs靶场

  • 目标:一个专注于前端加密对抗的练习靶场,模拟了各种现代Web应用中常见的加密场景,用于提升渗透测试人员处理前端加密的能力。
  • 包含场景:非对称加密、对称加密、加签、禁止重放等。
  • 具体技术:AES、DES、RSA等算法的实战应用。

1.2 Yakit工具

  • 定位:一款功能强大的国产单兵渗透测试工具。
  • 核心优势
    • 高度集成:集成了多种安全测试功能。
    • 可扩展性:远超传统工具(如Burp Suite)的可玩性和可操作性。
    • Yak语言:内置基于Go的嵌入式脚本语言,支持热加载、并发,专为安全领域设计,简单高效。
    • 序列Fuzz:能够像流水线一样自动化处理复杂、连贯的请求,支持数据提取、继承和分析。

2. 实战前准备

  1. 部署靶场:按照SwagXz/encrypt-labs项目的说明,搭建好本地或远程测试环境。
  2. 创建数据库:根据靶场要求创建数据库并导入初始数据。
  3. 熟悉界面:访问靶场登录页面,前端提供了7种不同的登录模式,对应不同的加密方式。

3. 各加密场景分析与Yakit攻破方法

3.1 场景一:AES固定Key

  • 前端逻辑分析

    • 点击“AES固定Key”按钮触发sendDataAes函数。
    • 函数将用户名和密码组合成JSON字符串。
    • 使用AES-CBC模式进行加密,Key和IV均为固定值1234567890123456
    • 将加密后的密文通过encryptedData参数以POST请求发送到/encrypt/aes.php
  • Yakit攻破方法

    1. 使用Yak语言热加载:编写一个AES加密函数,复用前端的固定Key和IV。

    // 热加载函数定义
    aes = func(p) {
    key = "1234567890123456"
    iv = "1234567890123456"
    // 将输入的用户名密码(如"admin,password")分割并组成JSON
    results = str.Split(p, ",")
    m = {"username": results[0], "password": results[1]}
    jsonInput = json.dumps(m)
    // 使用AES-CBC-PKCS7Padding加密
    result = codec.AESCBCEncryptWithPKCS7Padding(key, jsonInput, iv)
    // 返回Base64编码结果
    base64Result = codec.EncodeBase64(result)
    return base64Result
    }
    2. **发起Fuzz攻击**:在Yakit的Web Fuzzer中,使用Payload和Yak函数结合进行密码爆破。
    POST /encrypt-labs/encrypt/aes.php
    ...
    Content-Type: application/x-www-form-urlencoded; charset=utf-8

    encryptedData={{urlesc({{yak(aes|admin,{{payload(pass_top25)}})}})}}
    ```
    - admin为固定用户名,{{payload(pass_top25)}}为密码字典。
    - {{yak(...)}}调用热加载的AES函数进行加密。
    - {{urlesc(...)}}确保加密后的数据符合URL编码格式。

3.2 场景二:AES服务端获取Key

  • 前端逻辑分析
    • 点击按钮触发fetchAndSendDataAes函数。
    • 首先向/encrypt/server_generate_key.php发起请求,服务端动态生成并返回本次会话的Key和IV(通常与Cookie关联)。
    • 然后用获取到的Key和IV对凭据进行AES加密,最后发送到/encrypt/aesserver.php验证。
  • Yakit攻破方法
    • 使用“序列Fuzz”功能:模拟浏览器的连续请求。
      1. Step 1:获取动态Key/IV
        • 发起一个GET请求到/encrypt/server_generate_key.php
        • 使用数据提取器(如正则表达式或JQ)从响应中提取出Key和IV,并设置为变量(如key_var, iv_var)。
        • 为确保每次Key不同,可在请求中设置随机的Cookie值。
      2. Step 2:加密并提交登录请求
        • 发起POST请求到/encrypt/aesserver.php
        • 使用热加载的Yak函数进行加密,但Key和IV不再固定,而是继承自Step 1中提取的变量:{{yak(aes_dynamic|admin,password,{{key_var}},{{iv_var}})}}
        • 同时,Cookie等信息也需要继承自Step 1的响应。

3.3 场景三:RSA加密

  • 前端逻辑分析
    • 使用jsencrypt.min.js库。
    • 用户名和密码被一个固定的RSA公钥直接加密。
    • 由于RSA是非对称加密,无法从公钥推算出私钥,故不能直接解密。
  • Yakit攻破方法
    • 热加载RSA加密函数:在Yak中实现相同的RSA公钥加密逻辑。
    rsa = func(p) {
    // 从前端代码中提取出的固定公钥
    pubKey = -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----
    // 使用公钥加密输入的数据
    encrypted = codec.PemPkcs1v15Encrypt(pubKey, p)
    return codec.EncodeBase64(encrypted)
    }
    ```
    • Fuzz攻击:在Web Fuzzer中,将用户名和密码组合后作为RSA加密的输入。
    encryptedData={{urlesc({{yak(rsa|admin,{{payload(pass_top25)}})}})}}
    ```

3.4 场景四:AES+RSA混合加密

  • 前端逻辑分析
    1. 随机生成一个AES Key和IV。
    2. 用这个AES Key和IV加密用户名和密码。
    3. 用一个固定的RSA公钥分别加密AES Key和IV。
    4. 将AES密文、加密后的Key和IV一同发送给服务端。
    5. 服务端用RSA私钥解密出AES Key和IV,再解密获得明文凭据。
  • Yakit攻破方法
    • 关键点:虽然AES Key是随机的,但RSA公钥是固定的。如果能获取到对应的RSA私钥,即可解密出任何会话的AES Key。
    • 私钥位置:文章提到私钥可能存放在前端源码或服务器的某个可访问文件中(如rsa_private_key.pem),需要仔细审计。
    • 热加载函数:编写一个复杂的Yak函数,模拟整个流程。如果无法获取私钥,则攻击难度极大,需要利用其他漏洞。

3.5 场景五:DES规律Key

  • 前端逻辑分析
    • 使用DES加密,Key和IV由用户名规律性生成
    • Key生成规则:取用户名,不足8位用6填充,超过8位取前8位。例如,用户admin生成Key为admin666
    • IV生成规则:取用户名的前4位,前面用9补满8位。例如,用户admin生成IV为9999admi
    • 用户名明文传输,密码被DES加密后传输。
  • Yakit攻破方法
    • 热加载DES函数:根据规则动态生成Key和IV。
    des = func(user, pass) {
    // 生成Key
    key = str.Substr(user, 0, 8) // 取前8位
    for i = 0; i < 8 - len(key); i++ {
    key = key + "6" // 不足补6
    }
    // 生成IV
    ivPrefix = str.Substr(user, 0, 4) // 取前4位
    iv = "9999" + ivPrefix // 前面补4个9
    // DES加密密码
    encrypted = codec.DESCBCEncrypt(key, pass, iv)
    return codec.EncodeBase64(encrypted)
    }
    ```
    • Fuzz攻击:假设用户名为admin,对密码进行爆破。
    username=admin&password={{urlesc({{yak(des|admin,{{payload(pass_top25)}})}})}
    ```

3.6 场景六:明文加签

  • 前端逻辑分析
    • 不再加密密码,而是发送明文。
    • 为了防止篡改,增加了签名机制。将用户名、密码、一个随机数(Nonce)和当前时间戳,用一个固定的Keybe56e057f20f883e)进行HmacSHA256计算,生成签名。
    • 将明文数据和签名一同发送。
  • Yakit攻破方法
    • 热加载签名函数:复现前端的签名逻辑。
    sign = func(user, pass) {
    key = "be56e057f20f883e"
    nonce = "123456" // 如果前端固定,则此处固定;如果动态,需提取
    timestamp = "1739195500" // 当前时间戳,需要动态生成
    // 拼接签名字符串
    signStr = sprintf("%s%s%s%s", user, pass, nonce, timestamp)
    // 计算HmacSHA256签名
    signature = codec.HmacSha256(key, signStr)
    return sprintf("username=%s&password=%s&nonce=%s×tamp=%s&signature=%s", user, pass, nonce, timestamp, signature)
    }
    ```
    • Fuzz攻击:在Web Fuzzer中直接调用该函数生成完整的POST Body。

3.7 场景七:加签Key在服务器端

  • 前端逻辑分析
    • 这是场景六的升级版。签名所需的Key不再硬编码在前端,而是存放在服务器。
    • 流程变为两次请求:
      1. 前端将用户名、密码、时间戳等数据发送到/encrypt/get-signature.php
      2. 服务端用其存储的Key计算签名,并将签名返回给前端。
      3. 前端再将数据和收到的签名一同提交到/encrypt/signdataserver.php进行验证。
  • Yakit攻破方法
    • 必须使用“序列Fuzz”
      1. Step 1:获取签名
        • /encrypt/get-signature.php发送POST请求,Body中包含用户名、密码(来自Payload)和当前时间戳(可设为变量保证一致)。
        • 从响应中提取出signature字段。
      2. Step 2:验证登录
        • /encrypt/signdataserver.php发送POST请求。
        • Body中的数据(用户名、密码、时间戳)继承自Step 1的请求。
        • 签名signature继承自Step 1的响应。

3.8 场景八:禁止重放

  • 前端逻辑分析
    • 主要防御重放攻击(拦截请求后重复发送)。
    • 前端使用一个固定的RSA公钥加密当前的时间戳(Date.now(),注意是毫秒级),生成一个random参数。
    • 将用户名、密码和这个random参数一起发送。服务端会解密random得到时间戳,并判断该请求是否在有效时间窗口内(如5分钟),过期则拒绝。
  • Yakit攻破方法
    • 热加载时间戳加密函数:在每次请求时,动态生成当前时间戳并进行RSA加密。
    timeenc = func() {
    pubKey = -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----
    // 注意!JS中Date.now()是毫秒,不需要除以1000
    timestamp = string(unixtime())
    encrypted = codec.PemPkcs1v15Encrypt(pubKey, timestamp)
    return codec.EncodeBase64(encrypted)
    }
    ```
    • Fuzz攻击:在Web Fuzzer中,每次请求都调用该函数生成新的random值。
    username=admin&password={{payload(pass_top25)}}&random={{urlesc({{yak(timeenc)}})}}
    ```

4. 总结与核心技巧

通过本靶场的实战,可以总结出应对前端加密的通用思路和Yakit的核心用法:

  1. 代码审计:首要任务是阅读和分析前端JavaScript代码,理解加密、签名、密钥生成的具体逻辑和流程。
  2. 识别关键:判断是静态密钥(固定/规律)还是动态密钥(服务端下发)。静态密钥可直接复现,动态密钥需处理会话。
  3. Yak语言热加载:将前端的加密/签名逻辑用Yak语言完美复现,是自动化攻击的基础。
  4. 序列Fuzz:对于多步骤的复杂场景(如服务端动态Key、服务端加签),序列Fuzz是唯一的自动化解决方案,它能优雅地处理请求间的依赖关系。
  5. 活用提取器:熟练使用数据提取器(正则、JQ等)从响应中获取Token、Key、Signature等动态值,并传递给后续请求。

利用Yakit实战encrypt-labs加密对抗靶场教学文档 1. 靶场与工具介绍 1.1 encrypt-labs靶场 目标 :一个专注于前端加密对抗的练习靶场,模拟了各种现代Web应用中常见的加密场景,用于提升渗透测试人员处理前端加密的能力。 包含场景 :非对称加密、对称加密、加签、禁止重放等。 具体技术 :AES、DES、RSA等算法的实战应用。 1.2 Yakit工具 定位 :一款功能强大的国产单兵渗透测试工具。 核心优势 : 高度集成 :集成了多种安全测试功能。 可扩展性 :远超传统工具(如Burp Suite)的可玩性和可操作性。 Yak语言 :内置基于Go的嵌入式脚本语言,支持热加载、并发,专为安全领域设计,简单高效。 序列Fuzz :能够像流水线一样自动化处理复杂、连贯的请求,支持数据提取、继承和分析。 2. 实战前准备 部署靶场 :按照 SwagXz/encrypt-labs 项目的说明,搭建好本地或远程测试环境。 创建数据库 :根据靶场要求创建数据库并导入初始数据。 熟悉界面 :访问靶场登录页面,前端提供了7种不同的登录模式,对应不同的加密方式。 3. 各加密场景分析与Yakit攻破方法 3.1 场景一:AES固定Key 前端逻辑分析 : 点击“AES固定Key”按钮触发 sendDataAes 函数。 函数将用户名和密码组合成JSON字符串。 使用AES-CBC模式进行加密, Key和IV均为固定值 : 1234567890123456 。 将加密后的密文通过 encryptedData 参数以POST请求发送到 /encrypt/aes.php 。 Yakit攻破方法 : 使用Yak语言热加载 :编写一个AES加密函数,复用前端的固定Key和IV。 // 热加载函数定义 aes = func(p) { key = "1234567890123456" iv = "1234567890123456" // 将输入的用户名密码(如"admin,password")分割并组成JSON results = str.Split(p, ",") m = {"username": results[ 0], "password": results[ 1 ]} jsonInput = json.dumps(m) // 使用AES-CBC-PKCS7Padding加密 result = codec.AESCBCEncryptWithPKCS7Padding(key, jsonInput, iv) // 返回Base64编码结果 base64Result = codec.EncodeBase64(result) return base64Result } 2. **发起Fuzz攻击**:在Yakit的Web Fuzzer中,使用Payload和Yak函数结合进行密码爆破。 POST /encrypt-labs/encrypt/aes.php ... Content-Type: application/x-www-form-urlencoded; charset=utf-8 encryptedData={{urlesc({{yak(aes|admin,{{payload(pass_ top25)}})}})}} ``` - admin 为固定用户名, {{payload(pass_top25)}} 为密码字典。 - {{yak(...)}} 调用热加载的AES函数进行加密。 - {{urlesc(...)}} 确保加密后的数据符合URL编码格式。 3.2 场景二:AES服务端获取Key 前端逻辑分析 : 点击按钮触发 fetchAndSendDataAes 函数。 首先向 /encrypt/server_generate_key.php 发起请求, 服务端动态生成并返回本次会话的Key和IV (通常与Cookie关联)。 然后用获取到的Key和IV对凭据进行AES加密,最后发送到 /encrypt/aesserver.php 验证。 Yakit攻破方法 : 使用“序列Fuzz”功能 :模拟浏览器的连续请求。 Step 1:获取动态Key/IV 发起一个GET请求到 /encrypt/server_generate_key.php 。 使用 数据提取器 (如正则表达式或JQ)从响应中提取出Key和IV,并设置为变量(如 key_var , iv_var )。 为确保每次Key不同,可在请求中设置随机的Cookie值。 Step 2:加密并提交登录请求 发起POST请求到 /encrypt/aesserver.php 。 使用热加载的Yak函数进行加密,但Key和IV不再固定,而是继承自Step 1中提取的变量: {{yak(aes_dynamic|admin,password,{{key_var}},{{iv_var}})}} 。 同时,Cookie等信息也需要继承自Step 1的响应。 3.3 场景三:RSA加密 前端逻辑分析 : 使用 jsencrypt.min.js 库。 用户名和密码被一个 固定的RSA公钥 直接加密。 由于RSA是非对称加密,无法从公钥推算出私钥,故不能直接解密。 Yakit攻破方法 : 热加载RSA加密函数 :在Yak中实现相同的RSA公钥加密逻辑。 rsa = func(p) { // 从前端代码中提取出的固定公钥 pubKey = -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY----- // 使用公钥加密输入的数据 encrypted = codec.PemPkcs1v15Encrypt(pubKey, p) return codec.EncodeBase64(encrypted) } ``` Fuzz攻击 :在Web Fuzzer中,将用户名和密码组合后作为RSA加密的输入。 encryptedData={{urlesc({{yak(rsa|admin,{{payload(pass_ top25)}})}})}} ``` 3.4 场景四:AES+RSA混合加密 前端逻辑分析 : 随机生成一个AES Key和IV。 用这个AES Key和IV加密用户名和密码。 用一个 固定的RSA公钥 分别加密AES Key和IV。 将AES密文、加密后的Key和IV一同发送给服务端。 服务端用RSA私钥解密出AES Key和IV,再解密获得明文凭据。 Yakit攻破方法 : 关键点 :虽然AES Key是随机的,但RSA公钥是固定的。如果 能获取到对应的RSA私钥 ,即可解密出任何会话的AES Key。 私钥位置 :文章提到私钥可能存放在前端源码或服务器的某个可访问文件中(如 rsa_private_key.pem ),需要仔细审计。 热加载函数 :编写一个复杂的Yak函数,模拟整个流程。如果无法获取私钥,则攻击难度极大,需要利用其他漏洞。 3.5 场景五:DES规律Key 前端逻辑分析 : 使用DES加密, Key和IV由用户名规律性生成 。 Key生成规则 :取用户名,不足8位用 6 填充,超过8位取前8位。例如,用户 admin 生成Key为 admin666 。 IV生成规则 :取用户名的前4位,前面用 9 补满8位。例如,用户 admin 生成IV为 9999admi 。 用户名明文传输,密码被DES加密后传输。 Yakit攻破方法 : 热加载DES函数 :根据规则动态生成Key和IV。 des = func(user, pass) { // 生成Key key = str.Substr(user, 0, 8) // 取前8位 for i = 0; i < 8 - len(key); i++ { key = key + "6" // 不足补6 } // 生成IV ivPrefix = str.Substr(user, 0, 4) // 取前4位 iv = "9999" + ivPrefix // 前面补4个9 // DES加密密码 encrypted = codec.DESCBCEncrypt(key, pass, iv) return codec.EncodeBase64(encrypted) } ``` Fuzz攻击 :假设用户名为 admin ,对密码进行爆破。 username=admin&password={{urlesc({{yak(des|admin,{{payload(pass_ top25)}})}})} ``` 3.6 场景六:明文加签 前端逻辑分析 : 不再加密密码,而是发送明文。 为了防止篡改,增加了签名机制。将用户名、密码、一个随机数(Nonce)和当前时间戳,用一个 固定的Key ( be56e057f20f883e )进行HmacSHA256计算,生成签名。 将明文数据和签名一同发送。 Yakit攻破方法 : 热加载签名函数 :复现前端的签名逻辑。 sign = func(user, pass) { key = "be56e057f20f883e" nonce = "123456" // 如果前端固定,则此处固定;如果动态,需提取 timestamp = "1739195500" // 当前时间戳,需要动态生成 // 拼接签名字符串 signStr = sprintf("%s%s%s%s", user, pass, nonce, timestamp) // 计算HmacSHA256签名 signature = codec.HmacSha256(key, signStr) return sprintf("username=%s&password=%s&nonce=%s×tamp=%s&signature=%s", user, pass, nonce, timestamp, signature) } ``` Fuzz攻击 :在Web Fuzzer中直接调用该函数生成完整的POST Body。 3.7 场景七:加签Key在服务器端 前端逻辑分析 : 这是场景六的升级版。签名所需的Key不再硬编码在前端,而是存放在服务器。 流程变为两次请求: 前端将用户名、密码、时间戳等数据发送到 /encrypt/get-signature.php 。 服务端用其存储的Key计算签名,并将签名返回给前端。 前端再将数据和收到的签名一同提交到 /encrypt/signdataserver.php 进行验证。 Yakit攻破方法 : 必须使用“序列Fuzz” : Step 1:获取签名 向 /encrypt/get-signature.php 发送POST请求,Body中包含用户名、密码(来自Payload)和当前时间戳(可设为变量保证一致)。 从响应中提取出 signature 字段。 Step 2:验证登录 向 /encrypt/signdataserver.php 发送POST请求。 Body中的数据(用户名、密码、时间戳)继承自Step 1的请求。 签名 signature 继承自Step 1的响应。 3.8 场景八:禁止重放 前端逻辑分析 : 主要防御重放攻击(拦截请求后重复发送)。 前端使用一个 固定的RSA公钥 加密当前的时间戳( Date.now() ,注意是毫秒级),生成一个 random 参数。 将用户名、密码和这个 random 参数一起发送。服务端会解密 random 得到时间戳,并判断该请求是否在有效时间窗口内(如5分钟),过期则拒绝。 Yakit攻破方法 : 热加载时间戳加密函数 :在每次请求时,动态生成当前时间戳并进行RSA加密。 timeenc = func() { pubKey = -----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY----- // 注意!JS中Date.now()是毫秒,不需要除以1000 timestamp = string(unixtime()) encrypted = codec.PemPkcs1v15Encrypt(pubKey, timestamp) return codec.EncodeBase64(encrypted) } ``` Fuzz攻击 :在Web Fuzzer中,每次请求都调用该函数生成新的 random 值。 username=admin&password={{payload(pass_ top25)}}&random={{urlesc({{yak(timeenc)}})}} ``` 4. 总结与核心技巧 通过本靶场的实战,可以总结出应对前端加密的通用思路和Yakit的核心用法: 代码审计 :首要任务是阅读和分析前端JavaScript代码,理解加密、签名、密钥生成的具体逻辑和流程。 识别关键 :判断是静态密钥(固定/规律)还是动态密钥(服务端下发)。静态密钥可直接复现,动态密钥需处理会话。 Yak语言热加载 :将前端的加密/签名逻辑用Yak语言完美复现,是自动化攻击的基础。 序列Fuzz :对于多步骤的复杂场景(如服务端动态Key、服务端加签),序列Fuzz是唯一的自动化解决方案,它能优雅地处理请求间的依赖关系。 活用提取器 :熟练使用数据提取器(正则、JQ等)从响应中获取Token、Key、Signature等动态值,并传递给后续请求。