Practical Jni4Net
Practical Jni4Net
Dinis Cruz
Buy on Leanpub

Leanpub book, originally based on Blog posts

This book started with the Jni4net related blog posts published on my blog and eventually evolved into the book you have in your hands (or eReader).

The idea to use my blog posts was to:

  • kickstart the creation of this book (and provide a number of chapters that could be further improved)
  • capture the multiple experiments and learning curves that I experienced (while learning how to use Jni4net)
  • provide a ‘real world’ point of view on how to learn and use Jni4net

The theme of this book is ‘Practical’ (hence the name ‘Practical Jni4net’), and what I am trying to do here is to show how to use these technologies in practical situations, specially how to apply them to solve real problems. This means that sometimes the end result is a bit messy, with lots of rabbit-holes/tangents followed (and un-followed). But that is how it works. When learning a new technology, what is really important is to experiment a lot, and see how it works for the problem we have at hand.

An open book, freely available at GitHub

My objective with this book is to share knowledge and to help others (as I have been helped by numerous other online resources)

If you are reading this on your eReader, please visit https://github.com/DinisCruz/Book_Practical_Jni4net for a full hyperlinked copy of the content AND (more importantly) the code samples used in the book.

This repository contains the full source materials that are used to create the version available at Leanpub which can be downloaded for free, or paid for using the dynamic ‘how much do you want to pay’ slider. These fees help to cover the costs of creating this book, so if you bought the book, THANK YOU, if you haven’t, then it would be great if you could help a bit (assuming you liked and learned from this book).

I’m also using the GitHub’s Issues (see here) to manage the work items, ideas and bugs/problems with the content/code-samples.

Please use it if you want to provide any ideas, fixes or contributions to this book.

Finally, note that this book is still in a ‘draft release status’ with lots of content and fixes to be added.

I can be contacted directly at dinis.cruz@owasp.org (note that sometimes I’m not very good with my email, so don’t be shy to resend your email/question multiple times :) )

Notes about current structure

The current version groups the posts by published month.

I’m still thinking about the best way to structure this content, and how to present it in a easy to read/consume format.

It would be great if you (the reader) could provide some feedback on the book’s structure, for example:

  • if you think the book’s order should be different (or chapters renamed)
  • a particular chapter is not very clear, easy-to-understand or relevant
  • etc…

About the Author

Dinis Cruz is a Developer and Application Security Engineer focused on how to develop secure applications. A key drive is on ‘Automating Application Security Knowledge and Workflows’ which is the main concept behind the OWASP O2 Platform and the FluentSharp APIs.

After many years (and multiple roles) Dinis is still very active at OWASP, currently leading the OWASP O2 Platform project and helping out other projects and initiatives.

After failing to scale his own security knowledge, learned Git, created security vulnerabilities in code published to production servers, delivered training to developers, and building multiple CI (Continuous Integration) environments; Dinis had the epiphany that the key to application security is “Secure Continuous Delivery: Developer’s Immediate Connection to What They’re Creating”. This ‘Immediate Connection/Feedback’ concept is deep rooted in the development of the O2 Platform, and is something that will keep Dinis busy for many years.

Change log:

Here are the changes made (per version):

  • v0.22 (Jan 2016)
    • Major improvements on editor-ui where it now renders a local site using express and markdown
    • Changed intro, removed ‘Making Java, .NET and C++ apps work together’ post (which is now part of the intro)
    • Major refactor and clean up of content files:
      • Each month has it own folder which contains the respective images
      • Checked/fixed all images, and updated links to referenced Pdfs
      • All files were renamed to allow easy editing and maintenance
      • Significant content fixes and refactoring
    • Reached 95% book completion (waiting for feedback before marking it as complete)
  • v0.21 (Dec 2015)
    • Started text refactoring in order to get better structure for book generation and book editing
  • v0.20 (April 2015)
    • Setup leanpub to use Github instead of Dropbox
    • updated content: Introduction
  • v0.16 (Mar 2014)
    • First release of book with raw import from blogger posts (no formatting or editing done)
    • Created Git repo on local dropbox sync folder
    • created github repository for this book: https://github.com/DinisCruz/Book_Practical_Jni4Net
    • Added this change log

Introduction

In November 2012 I found a way to make Java and .Net applications work together.

That is something that I’ve always wanted to be able to do, since it would allow the use of O2’s REPL in Java application.

The the key technology innovations that were required to make this happen were:

  • 1) Side-by-site JVM/CLR execution and programming (in same process) - This is the ability provided by the amazing http://jni4net.sourceforge.net/ FOSS project which creates bridges between Java and .Net (see this research paper for the main concept between .Net/Java bridges http://views.cs.up.ac.za/vdata/Views-CCPE.pdf )
  • 2) Injection of Managed/Unmanaged controls into another process’s controls/windows - This the capability of the O2 Platform that allows the easy injection of .NET dlls into other non managed process.

Note that this is still a massive hack, but it works :)

It would be great if there was a more official way to make this happen.

This book contains my Jni4Net experiments and research.

1. November 2012

  • C# REPL a java process (ZAP Proxy)
  • Controlling OWASP ZAP remotely (via Java BeanShell REPL in .Net)
  • Writing and Invoking O2 Methods from Java and Eclipse

C# REPL a java process (ZAP Proxy)

After I discovered the Jni4Net FOSS project which provides the foundation blocks to create a Java bridge to .Net (and vice-versa).

To try Jni4Net, and see if it was really possible to have .Net and Java code running on the same process (with the CLR and JVM being able to invoke each other’s methods), I decided to see if I could connect the O2 Platform with the OWASP ZAP project (with both running on the same process)

My first step was to use the Injecting C# DLLs into Managed (C#) and Unmanaged (C++) processes O2 capabilities to inject an C# REPL into the ZAP process.

And here they are in action:

  • the foreground window is the (CLR based) C# REPL
  • the background window is the (JVM based) ZAP process.

After some experiments, I was able to use Jni4Net to create an mini .Net tool (based on the the Util - Java Decompiler (JAD based) v1.0.exe ) that used Jni4Net’s direct access to the JVM to show (and browse) the the currently loaded *.jar files (based on data retrieved from the JVMs ClassLoader).

For example here are some ZAP classes, and the decompiled main method:

For more details on how these PoCs were created, take a look at https://bintray.com/artifact/download/dinis-cruz/Books/Using-Jni4Net-Part-1.pdf

Controlling OWASP ZAP remotely (via Java BeanShell REPL in .Net)

Once I was able to use C# REPL in java process I was able to use the ZAP BeanShell support to start controlling and manipulating ZAP’s GUI from the .Net C# REPL.

Here is an example of adding a new ‘Site’ (i.e. a TreeNode) to the main ZAP ‘Site’s window (i.e. TreeView)

For more details on how this PoC was created, take a look at https://bintray.com/artifact/download/dinis-cruz/Books/Using-Jni4Net-Part-2.pdf

Writing and Invoking O2 Methods from Java and Eclipse

After using C# REPL in java process and controlling OWASP ZAP remotely, the next step was to see if we could consume (and code) the .NET APIs from Java.

And again Jni4Net really worked!

Here is a .NET WinForms control, coded and executed from the (Eclipse written) Java code:

Once we could create *.jar files, it was a small step to create an Eclipse plugin that would load up a CLR and popup a C# based Form.

Or more interestingly an C# REPL editor (running in the same process as Eclipse):

For more details on how these PoCs were created, take a look at https://bintray.com/artifact/download/dinis-cruz/Books/Using-Jni4Net-Part-3.pdf

2. March 2013

  • Invoking an OWASP AppSensor Java method from .NET C# REPL
  • Invoking Java BeanShell from .Net CLR
  • Loading OWASP ESAPI jar and its dependencies
  • Getting list of Jars loaded in SystemClassLoader
  • Java BeanShell REPL v1.0.exe

Invoking an OWASP AppSensor Java method from .NET C# REPL (using Jni4Net)

On the topic of AppSensor, you might find the code snippet below interesting.

Inside an O2 Platform C# REPL editor (which is running in .Net’s CLR), I was able to:

  • load the AppSensor jar in a new class loader,
  • access/view its classes in a GUI
  • create an instance of org.owasp.appsensor.trendmonitoring.TrendEvent
  • execute the getTime method

Note that the AppSensor code is running on the Java’s JVM (loaded in the same process as the .Net’s CLR)

The code is still in very rough status, but it works :)

Here (screenshot below) is what it looks like: * note the Date value in the output window (bottom right) which is the result (shown as a .NET String) of the Java getTime method * on top you have a view into the AppSensor’s classes, methods, parameters, return type * on the bottom left you can see the written C# REPL script

CropperCapture[34]
CropperCapture[34]

Here is the code:

  1 //var topPanel = "{name}".popupWindow(700,400);  
  2 var topPanel = panel.clear().add_Panel();  
  3 //"".open_ConsoleOut();
  4 
  5 var jarToLoad = @"E:/_Code_Tests/_AppSensor/AppSensor-0.1.3.jar";
  6 
  7 
  8 var bridgeSetup = new BridgeSetup(){Verbose=true};
  9 
 10 var jniAction = new API_Jni4Net_Active();
 11 
 12 //bridgeSetup.AddClassPath(jarToLoad);  
 13 //return "here";  
 14 try  
 15 {  
 16     Bridge.CreateJVM(bridgeSetup);  
 17 }  
 18 catch(System.Exception ex)  
 19 {  
 20     ex.log();  
 21     return "error";  
 22 }
 23 
 24 var jniEnv = JNIEnv.ThreadEnv;
 25 
 26 //calculate list of classes in Jar file  
 27 var jarFile = Class.forName("java.util.jar.JarFile")  
 28                    .getConstructor(new java.lang.Class[] { java.lang.String._class })  
 29                    .newInstance (new java.lang.Object[] { jniEnv.NewString(jarToLoad) });
 30 
 31 var entries = jarFile.getClass().getMethod("entries",null)  
 32                                 .invoke(jarFile, null);  
 33 var hasMoreElements = entries.getClass().getMethod("hasMoreElements",null);  
 34 var nextElement = entries.getClass().getMethod("nextElement",null);  
 35 var classesInJar = new List<string>();  
 36 while((bool)(java.lang.Boolean)hasMoreElements.invoke(entries, null))  
 37 {  
 38     var path = nextElement.invoke(entries, null).str();  
 39     if (path.ends(".class"))  
 40     classesInJar.add(path.remove(".class").replace("/","."));  
 41 }
 42 
 43 //Get class loader for Jar
 44 
 45 
 46 var jarToLoad_asUrl = new java.io.File(jarToLoad).toURL();  
 47 var servletApi_asUrl = new java.io.File(@"E:\_Code_Tests\_AppSensor\servlet-api.jar").toURL();
 48 
 49 //var url = new java.net.URL(jarToLoad);
 50 
 51 var urlArray = jniEnv.NewObjectArray(2, java.net.URL._class, null);  
 52 jniEnv.SetObjectArrayElement(urlArray, 0, jarToLoad_asUrl);  
 53 jniEnv.SetObjectArrayElement(urlArray, 1, servletApi_asUrl);
 54 
 55 var urlClassLoaderClass = java.lang.Class.forName("java.net.URLClassLoader");
 56 
 57 var ctor = urlClassLoaderClass.getConstructors()[2];   
 58 var systemClassLoader = ClassLoader.getSystemClassLoader();  
 59 var urlClassLoader = (ClassLoader)ctor.newInstance(new java.lang.Object[] { urlArray, systemC\
 60 lassLoader });
 61 
 62 
 63 //var appSensorClass = urlClassLoader.loadClass("org.owasp.appsensor.APPSENSOR");  
 64 //var appSensorClass = urlClassLoader.loadClass("org.owasp.appsensor.trendmonitoring.referenc\
 65 e.InMemoryTrendDataStore$1");
 66 
 67 foreach(var classInJar in classesInJar)  
 68 {   
 69     try  
 70     {  
 71         urlClassLoader.loadClass(classInJar);  
 72         "Loaded class: {0}".info(classInJar);  
 73     }  
 74     catch(System.Exception ex)  
 75     {  
 76         "Failed to load {0} due to {1}".error(classInJar, ex.Message);  
 77     }  
 78 }
 79 
 80 var treeView = topPanel.add_TreeView().java_SetTreeView_To_Show_Jni4Net_Reflection_Data();  
 81 var loadedClasses = jniAction.java_From_ClassLoader_get_Loaded_Classes(urlClassLoader);  
 82 treeView.add_Nodes(loadedClasses, (@class)=>@class.getName(), true);
 83 
 84 //invoke a method from AppSensor  
 85 var trendEvent = urlClassLoader.loadClass("org.owasp.appsensor.trendmonitoring.TrendEvent").g\
 86 etConstructors().first()  
 87                                .newInstance(new java.lang.Object[] { new Date(),  
 88 jniEnv.NewString("1"),  
 89 jniEnv.NewString("aaa"),  
 90 jniEnv.NewString("ccc") }) ;  
 91 return trendEvent.getClass()  
 92                  .getMethod("getTime",null).invoke(trendEvent,null)  
 93                  .str();
 94 
 95 
 96 //return loadedClasses;   
 97 /*  
 98 //Get JavaProperties from the loaded JVM  
 99 Properties javaSystemProperties = java.lang.System.getProperties();  
100 foreach (java.lang.String key in Adapt.Enumeration(javaSystemProperties.keys()))  
101     "key: {0}".info(key);   
102 return javaSystemProperties;  
103 */  
104 return "ok";  
105 //using java.io;  
106 //using java.lang;  
107 //using java.util;  
108 //using net.sf.jni4net;  
109 //using net.sf.jni4net.jni  
110 //using net.sf.jni4net.adaptors;  
111 //O2Ref:Jni4Net/lib/jni4net.n-0.8.6.0.dll
112 
113 //O2File:API_Jni4Net_Active.cs  

note: this code sample was running on the x64 version of the O2 Platform (because the default JavaHome in my dev VM points to a x64 Java version)

Invoking Java BeanShell from .Net CLR

Here is a very rough PoC of how I was able to execute a JavaBean shell script from inside the O2 Platform (with the java code executed under a JVM)

Executing “return 2+2;” as a java beanshell comand (see result on the bottom right Output pane)

image
image
 1 var jni4Net = new API_Jni4Net();  
 2 jni4Net.setUpBride();
 3 
 4 var beanShellJar = "http://www.beanshell.org/bsh-2.0b4.jar".uri().download(false);  
 5 var _string = JNIEnv.ThreadEnv.NewString("return 2+2; ");  
 6 var interpreter_Class = beanShellJar.java_Jar_Class("bsh.Interpreter");
 7 
 8 var interpreter = interpreter_Class.newInstance();  
 9 var result = interpreter.java_Invoke_UsingSignature("eval","(Ljava/lang/String;)Ljava/lang/Ob\
10 ject;",_string);  
11 return result.toString();
12 
13 return beanShellJar.java_Jar_Classes();
14 
15 //using net.sf.jni4net.jni;  
16 //using java.lang;  
17 //using java.net;  
18 //O2File:API_Jni4Net.cs  
19 //O2Ref:jni4net.n-0.8.6.0.dll  

Loading OWASP ESAPI jar and its dependencies

Here is a pretty cool PoC where I was able to load an jar file and its dependencies into an ‘Jni4Net created’ JVM

Using the system class loader

This is the ESAPI class we want to load (the code below returns null)

1 new API_Jni4Net().setUpBride();
2 return "org.owasp.esapi.util.ObjFactory".java_Class();  

Using the technique shown in Adding files to java classpath at runtime - Stack Overflow , we can add the esapi jar into the sysLoader class path

 1 new API_Jni4Net().setUpBride();
 2 
 3 var esapiJar = @"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar";  
 4 var classLoader = ClassLoader.getSystemClassLoader();  
 5 var addUrl = classLoader.getClass().getSuperclass().getDeclaredMethod("addURL", new Class[]{U\
 6 RL._class});  
 7 addUrl.setAccessible(true);  
 8 addUrl.invoke(classLoader, new java.lang.Object[]{ esapiJar.java_File().toURL() });
 9 
10 return "org.owasp.esapi.util.ObjFactory".java_Class();
11 
12 //using net.sf.jni4net.jni;  
13 //using java.lang;  
14 //using java.net;  
15 //O2File:API_Jni4Net.cs  
16 //O2Ref:jni4net.n-0.8.6.0.dll  

which will now work:

image
image

If we now try to load all classes in the ESAPI jar, we will get 172 classes and a number of class load errors (due to missing jars references)

image
image

Let’s refactor the code and create the addJarToSystemClassLoader method

image
image

And load one of the dependencies (note the increased number of classes loaded (183)):

image
image

And now if we load all jars in the libs folder (all 30 of them), we will get 197 classes and no load errors

image
image

Here are the jars added to the classpath:

image
image

Here is the code (shown above) that loaded all esapi classes into the system class path:

 1 new API_Jni4Net().setUpBride();
 2 
 3 var classLoader = ClassLoader.getSystemClassLoader();
 4 
 5 Action<string> addJarToSystemClassLoader =   
 6     (pathToJar)=>{   
 7                     var addUrl = classLoader.getClass()  
 8                                             .getSuperclass()  
 9                                             .getDeclaredMethod("addURL", new Class[]{URL._cla\
10 ss});  
11                     addUrl.setAccessible(true);  
12                     addUrl.invoke(classLoader, new java.lang.Object[]{ pathToJar.java_File().\
13 toURL() });   
14                  };
15 
16 var esapiJar = @"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar";  
17 var esapiLibs = @"E:\_Code_Tests\ESAPI\libs";
18 
19 addJarToSystemClassLoader(esapiJar);  
20 foreach(var jarFile in esapiLibs.files("*.jar"))  
21     addJarToSystemClassLoader(jarFile);
22 
23 var classesInJar = esapiJar.java_Jar_Classes_Names();  
24 return classLoader.loadClasses(classesInJar).size();
25 
26 //using net.sf.jni4net.jni;  
27 //using java.lang;  
28 //using java.net;  
29 //O2File:API_Jni4Net.cs  
30 //O2Ref:jni4net.n-0.8.6.0.dll  

Once these classes are loaded we can use the tool shown in C# REPL a java process (ZAP Proxy) to browse them and view its source code:

image
image

We can now create instances of ESAPI using reflection.

One problem to solve is the need to define where the ESAPI.properties file is:

 1 new API_Jni4Net().setUpBride();
 2 var classLoader = ClassLoader.getSystemClassLoader();
 3 
 4 var arrayList = "java.util.ArrayList".java_Class().newInstance();
 5 
 6 return "org.owasp.esapi.reference.DefaultSecurityConfiguration".java_Class().newInstance();
 7 
 8 var easpi = "org.owasp.esapi.ESAPI".java_Class();  
 9 return easpi.getMethod("encoder",null).invoke(null,null);  
10 return easpi.newInstance().typeFullName();  

The code above will throw an error on line 439 of the DefaultSecurityConfiguration file

image
image

which is:

image
image

Using a separate class loader

Here is a script that loads 172 classes from the ESAPI jar

 1 var jni4Net = new API_Jni4Net();  
 2 jni4Net.setUpBride();
 3 
 4 var esapiJar = @"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar";   
 5 var classLoader = (new URL[] {esapiJar.java_File().toURL() }).java_ClassLoader_forJars();
 6 
 7 return classLoader.loadClasses(esapiJar.java_Jar_Classes_Names()).size();
 8 
 9 //using net.sf.jni4net.jni;  
10 //using java.lang;  
11 //using java.net;  
12 //O2File:API_Jni4Net.cs  
13 //O2Ref:jni4net.n-0.8.6.0.dll  

This version will load 183 classes since we are also loading the servlet-api

 1 var jni4Net = new API_Jni4Net();  
 2 jni4Net.setUpBride();  
 3 var servletApi = @"E:\_Code_Tests\ESAPI\libs\servlet-api-2.4.jar";  
 4 var esapiJar  =  @"E:\_Code_Tests\ESAPI\esapi-2.0.1.jar";   
 5 var classLoader = (new URL[] {esapiJar.java_File().toURL() , servletApi.java_File().toURL() }\
 6 ).java_ClassLoader_forJars();
 7 
 8 return classLoader.loadClasses(esapiJar.java_Jar_Classes_Names()).size();  
 9 //using net.sf.jni4net.jni;  
10 //using java.lang;  
11 //using java.net;  
12 //O2File:API_Jni4Net.cs  
13 //O2Ref:jni4net.n-0.8.6.0.dll  

Getting list of Jars loaded in SystemClassLoader

I just created a couple extension methods for Jni4Net that allow (amongst other things) the listing of the jars currently loaded in the SystemClassLoader (see API_Jni4Net.cs for the code of these .NET Extension Methods)

The objective is to simplify the use of Jni4Net, and to hide the complexity in consuming Java code from .NET.

Here are a couple examples of these Extension Methods in action:

When you create a simple Jni4Net bridge there is only one jar loader:

image
image

Next lets load a jar dynamically and see it appear in the list of loaded jars

image
image

Note that once the jar is loaded we can access its classes:

image
image

Create instances and invoke methods:

image
image

Here is the script show above:

 1 var jni4Net = new API_Jni4Net().setUpBride();  
 2 var env = jni4Net.jniEnv;
 3 
 4 var classLoader = ClassLoader.getSystemClassLoader();  
 5 var beanShellJar = "http://www.beanshell.org/bsh-2.0b4.jar".uri().download(false);
 6 
 7 classLoader.loadJar(beanShellJar);  
 8 var interpreter_Class = beanShellJar.java_Jar_Class("bsh.Interpreter");
 9 
10 return interpreter_Class.newInstance()
11 		    .java_Invoke_UsingSignature("eval",  
12                                                     "(Ljava/lang/String;)Ljava/lang/Object;",\
13   
14                                                     "return \"hello from java: \" + (2 + 2); "
15                                                        .java_String()
16                                                    ).str();
17 
18 return classLoader.jarsInClassPath();  
19 //using java.lang;  
20 //O2File:API_Jni4Net.cs  
21 //O2Ref:jni4net.n-0.8.6.0.dll  

Finally we can also load/add to the system class path, entire folders with jars. For example all ESAPI dependencies:

image
image

Java BeanShell REPL v1.0.exe

Using the technique shown in Invoking Java BeanShell from .Net CLR, here is REPL that allows the quick execution of Java BeanShell command in a C# GUI

You can download this stand-alone O2 tool from: Util - Jni4Net - Java BeanShell REPL v1.0.exe

This is what the default GUI looks like:

image
image

If you expand the Console Out panel, you can see the Jni4Net initialization messages:

image
image

There are a number of code samples included:

image
image

Which will be auto executed on selection:

image
image

This one for example:

image
image

will create a Java button:

image
image

which of course can be modified and executed:

image
image

Also included is a REPL menu

image
image

That allows the scripting of the current Form:

image
image

like for example: changing its title and making all controls pink

image
image

or inject a WebBrowser (on the left) with the Jni4Net website:

image
image

The other REPL menu item:

image
image

Allows the scripting and visualization of the Jni4Net object:

image
image

For reference here is the script (also available at O2.Platform.Scripts\3rdPartyJni4NetUtil - Jni4Net - Java BeanShell REPL.h2) that created this GUI (a bit messy and in need for a good dose of refactoring)):

  1 O2Setup.extractEmbededConfigZips();
  2 
  3 //Set value of Bridge.homeDir  
  4 var jni4NetDir = PublicDI.config.ToolsOrApis.pathCombine(@"Jni4Net\lib");  
  5 var fieldInfo = (FieldInfo)typeof(Bridge).field("homeDir");  
  6 PublicDI.reflection.setField(fieldInfo, jni4NetDir);  
  7 //return typeof(Bridge).fieldValue("homeDir");
  8 
  9 "jni4net.j-0.8.6.0.jar location: {0}".info(Bridge.FindJar());
 10 
 11 //stand-alone tool not working (not finding the "jni4net.j-0.8.6.0.jar");
 12 
 13 //"jni4net.n-0.8.6.0.dll is at: {0}".info("jni4net.n-0.8.6.0.dll".assembly_Location());  
 14 var topPanel = "Util - JavaBean REPL - {0}".format(clr.details()).popupWindow(800,400)   
 15                                                                  .insert_LogViewer();   
 16 //var topPanel = panel.clear().add_Panel();
 17 
 18 Action execute =null;
 19 
 20 var replGui = topPanel.add_REPL_Gui();   
 21 replGui.On_ExecuteCode = ()=> execute();
 22 
 23 replGui.Output_Panel.insert_Below("Console Out").add_ConsoleOut();
 24 
 25 "test console out".console_WriteLine();
 26 
 27 var codeText = replGui.Code_Panel.add_SourceCodeViewer();  
 28 var toolStrip = topPanel.insert_Above_ToolStrip()  
 29                         .add_Button("Run", "btExecuteSelectedMethod_Image".formImage(),()=> e\
 30 xecute())  
 31                         .toolStrip();  
 32 var samplesMenu = toolStrip.add_DropDown("Java BeanShell Code Samples", "help_browser".formIm\
 33 age());   
 34 var beanShellJar = "http://www.beanshell.org/bsh-2.0b4.jar".uri().download(false);   
 35 //configure Jni4Net bridge and BeanShell  
 36 "Configuring Jnu4Net".info();  
 37 var jni4Net = new API_Jni4Net();  
 38 jni4Net.setUpBride();  
 39 "Default Jni4Net bridge setup ".info();
 40 
 41 var interpreterClass = beanShellJar.java_Jar_Class("bsh.Interpreter");  
 42 if(interpreterClass.isNull() && clr.x86()) // most likely means it couldn't find a compatible\
 43    
 44 {  
 45     var javaHomeLocation = @"C:\Program Files (x86)\Java\jre7";  
 46     "interpretreClass was null, and this is a 32bit process, so to set-up bridge with JavaHom\
 47 e: {0}".error(javaHomeLocation);  
 48     var bridgeSetup = new BridgeSetup() { JavaHome = javaHomeLocation};  
 49     jni4Net.setUpBride(bridgeSetup);  
 50     interpreterClass = beanShellJar.java_Jar_Class("bsh.Interpreter");  
 51 }  
 52 var interpreter = interpreterClass.ctor();
 53 
 54 if (interpreter.isNull())  
 55 {  
 56     "Failed to create interpreter instance".error();  
 57 }
 58 
 59 java.lang.System.@out.println("Hello Java world!");
 60 
 61 //set execute method  
 62 execute =   
 63 ()=>{   
 64         var code = codeText.get_Text().java_String();  
 65         try  
 66         {  
 67             var result = interpreter.java_Invoke_UsingSignature("eval","(Ljava/lang/String;)L\
 68 java/lang/Object;",code);   
 69             replGui.showOutput(result.str());   
 70         }  
 71         catch(System.Exception ex)  
 72         {  
 73             ex.log("Execution error");  
 74             replGui.showErrorMessage(ex.Message);  
 75         }   
 76     };   
 77     Action<string,string> addCodeSample =   
 78         (title, codeSample)=> samplesMenu.add_Button(title,   
 79                                                ()=>{  
 80                                                         codeText.set_Text(codeSample);  
 81                                                         execute();  
 82                                                    });  
 83     Func<string> getJni4NetReplCode =  
 84         ()=>{  
 85                 return "return jni4Net.bridgeSetup;".line().line() +   
 86                        "//O2Ref:jni4net.n-0.8.6.0.dll".line() +   
 87                        "//O2Ref:{0}".format(jni4Net.type().Assembly.ManifestModule.str());  
 88              };
 89 
 90 
 91 toolStrip.add_DropDown("REPL", "text_x_script".formImage())  
 92          .add_Button("REPL Form" , ()=>topPanel.parentForm().script_Me("form"))  
 93          .add_Button("REPL Jni4Net" , ()=>jni4Net.script_Me("jni4Net").set_Code(getJni4NetRep\
 94 lCode()))  
 95          .add_Button("REPL Jni4Net Assembly" , ()=>jni4Net.type().Assembly.script_Me("assembl\
 96 y"));
 97 
 98 toolStrip.add_Button("Open BeanSheel website", "internet_web_browser".formImage(),
 99                             ()=>"http://www.beanshell.org/".startProcess())  
100          .add_Button("View Jni4Net O2 Blog posts", "internet_web_browser".formImage(),
101                             ()=>"http://blog.diniscruz.com/search/label/Jni4Net".startProcess\
102 ());
103 
104 //Code samples
105 
106 addCodeSample("Hello World", "return \"Hello World (from java bean)\";");  
107 addCodeSample("Java Properties", "return java.lang.System.getProperties();");
108 
109 addCodeSample("Int sums",   
110              @"int a = 12;  
111                return a + 30;");
112 
113 addCodeSample("Hashtable and date",   
114              @"Hashtable hashtable = new Hashtable();  
115                Date date = new Date();  
116                hashtable.put( ""today"", date );  
117                return hashtable.get(""today"");");
118 
119 
120 addCodeSample("Create java button",  
121              @"button = new JButton( ""My Button"" );  
122                frame = new JFrame( ""My Frame"" );  
123                frame.getContentPane().add( button, ""Center"" );  
124                frame.pack();  
125                frame.setVisible(true);
126 
127                return ""You should have a Java button"" +   
128                ""somewhere on your screen"";");
129 
130 
131 addCodeSample("System.out.println (not working)",  
132             @"java.lang.System.out.println(""Hello Java world!"");  
133               return ""done"";");
134 
135 samplesMenu.items().first()  
136             .PerformClick();
137 
138 replGui.Execute_Button.click();  
139 replGui.Output_Panel.splitterDistance(50);
140 
141 return "done";
142 
143 
144 //using System.Reflection  
145 //using net.sf.jni4net  
146 //using net.sf.jni4net.jni;  
147 //using java.lang;  
148 //using java.net;  
149 //O2File:API_Jni4Net.cs  
150 //O2Ref:Jni4Net\lib\jni4net.n-0.8.6.0.dll  
151 //O2Embed:java.ico  
152 //O2EmbedTool:Jni4Net  

3. May 2013

  • First execution of ESAPI.jar Encoder methods from O2’s C# REPL

First execution of ESAPI.jar Encoder methods from O2’s C# REPL

In April 2013 (when preparing to do the OWASP AppSensor and O2 Platform at Security B-Sides London workshop with colin), I achieved something that I have been trying to do for a while:

  • Use the O2 Platform’s C# REPL environment to programatically access (in real time) the ESAPI jar apis and methods.
  • Consume AppSensor’s jar directly from a .NET app (in that case TeamMentor)

When I was integrating AppSensor (java) with TeamMentor (.NET) I needed to solve the the problem described in Loading OWASP ESAPI jar and its dependencies from C# since AppSensor has an hard dependency on ESAPI (i.e. without ESAPI, AppSensor doesn’t work)

After a bit of research and coding, here is the first code sample that shows ESAPI being consumed from O2 (via Jni4Net)

image
image

Note how the ESAPI Encoder’s encodeForHTML method is being executed:

image
image

And displayed in the Output window:

image
image

To to clarify, although this code is being triggered and executed from a .Net GUI and CLR, the actual code that is doing the encoding is the one from http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/org/owasp/esapi/Encoder.html which is running running on a JVM inside the same process as the CLR (the magic sauce is provided by the amazing Jni4Net)

For example here is the execution result of the ESAPI Encoder’s encodeForJavascript:

image
image

Which is exactly what I wanted :)

I wonder if we can also execute the current ESAPI unit test the same way? For example, now that we have the capability to see what the encodings output of the Java version of ESAPI looks like, we can try to compare it with the ESAPI .NET methods (since they should match right?)

Here is code sample shown in above:

 1 var jni4Net = new API_Jni4Net();
 2 jni4Net.setUpBride();
 3 var jarPath = @"E:\_Code_Tests\OWASP_AppSensor\_O2_Test";
 4 var jars = jarPath.files("*.jar");
 5 
 6 
 7 var classLoader = jni4Net.systemClassLoader().loadJars(jars);
 8 var esapi = classLoader.loadClass("org.owasp.esapi.ESAPI");
 9 var encoder =  esapi.getMethod("encoder",null).invoke(null,null);
10 
11 
12 return encoder.getClass().getMethod("encodeForJavaScript",new Class[] {java.lang.String._clas\
13 s} )
14     	  .invoke(encoder, new java.lang.Object[] { "aaa<h1>bbb<h1>".java_String()});
15 
16 //using net.sf.jni4net.jni;
17 //using java.lang;
18 //using java.net;
19 //O2File:API_Jni4Net.cs
20 //O2Ref:jni4net.n-0.8.6.0.dll

Here is the current folder set-up and jars loaded:

image
image

A key to make it work is the fact that the ESAPI.properties file is in the same path as the ESAPI.jar

4. June 2013

  • Another step in the use of ESAPI and AppSensor Jars from .Net/C#

Another step in the use of ESAPI and AppSensor Jars from .Net/C

At the OWASP EU Tour London Chapter event meeting I presented the next step of my research on using ESAPI and AppSensor inside a .NET application like TeamMentor (using Jni4Net to allow the JVM to work side by side with the CLR).

The source code of the demo I presented is posted to the github.com:DinisCruz/TeamMentor_3_3_AppSensor repo, and this post shows a number of screenshots of what is in there.

I used TeamMentor’s TBot C# and AngularJS pages to create the prototypes (since it is very easy and fast to code in that enviroment)

The pages were added to the main TBot ** control panel, in 3 new sections: **AppSensor, AppSensor/ESAPI and AppSensor/JVM:

image
image

Let’s look at all of them and see what they do.

Java Properties

Shows the Properties of the current JVM, and is a good first script to run (since it shows that the Jni4Net CLR to JVM bridge is correctly set up)

image
image

Jars In Class Path

This one shows the Jar’s currently loaded and some details about the loaded classes

image
image

The image above shows that there is only one jar loaded at start (jni4net.j-0.8.6.0.jar) and below is what it looks after the Setup AppSensor Tbot page is executed

image
image

Setup AppSensor

This will load up the AppSensor Jars and perform a simple test to see if one of the expected classes can be loaded

image
image

View ESAPI Encodings

Once we have the ESAPI loaded we can open up this page that shows what all the ESAPI encodings looks like

image
image
image
image

Note how many they are: encodeForHTML , encodeForHTMLAttribute, encodeForCSS, encodeForJavascript, encodeForVBScript, encodeForLDAP, encodeForDN, encodeForXPath, encodeForXML, encodeForXmlAttribute, encodeForURL you can use this GUI to try out what a specific encoding looks like.

For example change the text on the left and click on of the ‘encodeFor…‘ buttons

image
image

AppSensor Logs

Shows the currently registered logs

image
image

To help to create a new log entry, this page provides a link to:

Create AppSensor Exception

which looks like this:

image
image

This page (for testing) allows the use of the ex querystring parameter to create a new AppSensor log message

image
image

and clicking on View AppSensor Logs, which show details of the log:

image
image

5. August 2013

  • Consuming a forked version of Jni4Net
  • Compiling Jni4Net from Source
  • Fixing the ‘Attempted to read or write protected memory’ issue

Consuming a forked version of Jni4Net

An O2 user was having some issues with my Jni4Net scripts, and after some research, I realized that the problem existed inside the current published jni4net.n-0.8.6.0.dll:

image
image

The problem is that with the 0.8.6 version we get an ‘Attempted to read or write protected memory’ error when trying to connect to an existing Java process we previously injected O2 into.

The solution is to use the latest version of Jni4Net, which is not available for direct download, but its code it at: http://jni4net.googlecode.com/svn jni4Net

After getting the compilation and generation process right (see Dealing with ‘Attempted to read or write protected memory), I had this folder:

image
image

I was then able to write these scripts (which worked):

1) start ZAP and inject O2 into the new process:

image
image
 1 var apiZap = new API_Zap();
 2 apiZap.Launch();
 3 var process = apiZap.ZapProcess;
 4 process.waitFor_MainWindowHandle();
 5 var o2Injector =  new API_O2_Injector();  			
 6 o2Injector.injectIntoProcess(process, false,true);    
 7 
 8 //using OWASP
 9 //O2File:API_Zap.cs
10 //O2File:API_O2_Injector.cs
11 //using O2.XRules.Database.APIs

2) hook VisualStudio to that process (assumes there is only one java.exe process)

image
image
 1 var visualStudio = new VisualStudio_2010();
 2 var processes = visualStudio.dte().Debugger.LocalProcesses;
 3 Func<string, EnvDTE.Process> findProcess =
 4   (name)=>{
 5 				foreach(EnvDTE.Process process in processes) //linq doesn't work here
 6 					if (process.Name.contains(name))
 7 						return process;
 8 				return null;
 9 			};
10 EnvDTE.Process targetProcess = findProcess("java.exe");
11 targetProcess.Attach();
12 return targetProcess;

3) create bridge and output java properties (inside the ZAP REPL)

image
image
 1 Environment.SetEnvironmentVariable("JAVA_HOME", @"C:\Program Files (x86)\Java\jre7");
 2 Bridge.CreateJVM( new BridgeSetup(){Verbose=true});
 3 
 4 Properties javaSystemProperties = java.lang.System.getProperties();
 5 
 6 foreach (java.lang.String key in Adapt.Enumeration(javaSystemProperties.keys()))
 7 
 8 "key: {0}".info(key);
 9 
10 //using java.io;
11 //using java.lang;
12 //using java.util;
13 //using net.sf.jni4net;
14 //using net.sf.jni4net.adaptors;
15 //O2Ref:E:\O2\_Source_Code\test\jni4net\jni4net\target\jni4net-0.8.7.0-bin\lib\jni4net.n-0.8.\
16 7.0.dll

4) Executed PoC - Jni4Net - Classes, Methods, Fields in target.h2 script (inside ZAP process)

image
image

which listed all loaded java classes (and its decompiled code):

image
image

To make this work (and deal with the ‘Attempted to read or write protected memory’ prob) I had to copy the jni4net.j-0.8.7.0.jar to the ZAP default class path and manually skip a bit of code when connected to VisualStudio

image
image

Compiling Jni4Net from Source

After using the git svn clone -s http://jni4net.googlecode.com/svn jni4Net command, to create a local clone of the SVN repo:

image
image

I started by opening the jni4net.sln file in VS 2010.

But on first compile I had this error:

image
image

which was created by the missing selvin.exportdllattribute-0.2.6.0.dll

image
image

which looks like should be here:

image
image

let’s take a look at the v0-8-generics branch

image
image

Since it is also not there, I just downloaded it from:

image
image

… and saved it to:

image
image

… and updated the references

image
image

Now the code compiles, but we get this error:

image
image

… which is caused by this post build command:

image
image

… and is resolved by downloading this file:

image
image

… into this folder:

image
image

I was able to get it to compile by changing the selvin.exportdll-0.2.6.0.exe to selvin.exportdll-0.2.5.0.exe (couldn’t find the 0.2.6.0 version)

image
image

Next there was a bunch of NUnit errors, which were resolved using

image
image

Now we have a clean compilation (with only a bunch of warnings)

image
image

But, they all fail to execute:

image
image

This was a good sign that I should look for a readme.txt, which I found in the repo root (ie. RTFM when everything else fails :) )

image
image

From that file I got the clue to run the loadTools.cmd script:

image
image

… which downloads the missing files into the lib folder:

image
image

Since we now have the 0.2.6.0 versions, I updated back the VS solution (and removed the nUnit package from Nuget)

Then I executed

image
image

… and

image
image

… this took a while, and although most looked ok:

image
image

… the last one failed:

image
image

That said, it looked like the required files seemed to have been created:

image
image

And the Unit tests now pass:

image
image

I didn’t like the fact that we had that build error, so I tracked the problem to a missing NUnit installation:

image
image

Since I’m on a x64 VM and the path is hard-coded in the Maven script, I had to copy the installed nunit files into the expected folder:

image
image

… which didn’t work

image
image

The problem was caused by the fact that I’m currently using an x64 JDK:

image
image

Forcing a x86 (32bit) version of the JDK will do the trick

image
image

Since the tests expect to find Nunit in the (x86) folder:

image
image

We need to rename the NUnit-2.5.8 folder to the expected value:

image
image

Finally we have a successful complete build:

image
image

… with all created files placed inside the target folder:

image
image

Fixing the ‘Attempted to read or write protected memory’ issue

This error happened when running a java process (like ZAP):

image
image

…with the O2 Platform REPL injected into:

image
image

… and executing PoC - Jni4Net - List JavaProperties.h2 scrit, resulted in an unmanaged error (which is always a worse case scenario in the .NET Interop world)

image
image

As the (simpler script shows), the error happens on the CreateJVM invocation

image
image

My next step was to create a local build of Jni4Net (see Compiling Jni4Net from Source) and to use it to attach into an existing running ZAP with an O2 REPL injected.

Here is the moment when I have VisualStudio hooked, the script compiled (in the ZAP REPL), the jni4net dll loaded (with Symbols) in VisualStudio and a breakpoint on the CreateJVM method:

image
image

Here is where I think the problem exists:

image
image

The args object (created via JNI) seems to be empty.

It is then assigned to the value of the Jni4Net class path string

image
image

The args object is used here:

image
image

And inside that method, if I let args to be used, we will get the ‘Attempted to read or write protected memory’ error

image
image

But, if I change the execution path (manually) and set it to the line below (where no args is passed)

image
image

Then the execution will be ok (note that the path with the &initArgs would had thrown an ‘Attempted to read or write protected memory’ by now):

image
image

The only problem with this approach (which is basically not adding the classpath clue to the current JVM) is that unless we manually add the jni4net jar to the target app, we will get an exception here:

image
image

i.e. br.handle would be 0 (meaning that the net.sf.jnin4net.Bridge class could not be found)

To fix it, I added the Patch_IgnoreArgsInAttach property

image
image

… which is then used here (to allow the selection of the path that works)

image
image

I also changed the assembly name (so it is easy to track its use):

image
image

After the compilation I copied it to the main target folder:

image
image

To test it , I used the script

image
image

… to start ZAP with a REPL, where I could execute OK:

image
image

Final step is to create a zip of the bin folder

image
image

Put it on a public available location like DropBox

Update the installer API to use that version:

image
image

Update the API_Jni4Net.cs to use the jni4net.n-0.8.7.0_Patched.dll assembly (as seen below on first compile the referenced will be downloaded)

image
image

… once the compilation works:

image
image

I was able to to run Jni4Net in the main O2 Platform process

image
image

…and on the ‘injected into’ java processes:

image
image

Pushing changes to GitHub

Once the fix was working ok I added a remote to the local repo:

image
image

… push it

image
image

… and confirm that the commits I did locally (with the patch)

image
image

… where pushed successfully:

image
image