Enforcing Java Security Manager in Restricted Windows Environments
Good morning
Currently I am working on a Terminal-Server-Project which provides applications to users. Through Software Restriction Policys the users are restricted to a certain set of executables (Whitelisting). One of these permitted executables is java.exe. So if Java is enabled any Java Application can be executed on the system. This allows a malicious user to execute arbitrary Java code, like replacement shells (JSH), RDP clients (Propero Java RDP), network port scanners etc. I could block java.exe but the business requirement are that the company's Java application must still work. This lead me into this research on how to whitelist Java applications in a restricted Windows environment.
First of all Java has a mechanism called Java2 Security which allows to implement policies based on code location on disk or digital signatures. These policies are configured through the files java.policy and java.security. When java.exe gets executed these policies are not enforced. To enforce the Java system property java.security.manager must included on startup: java.exe -Djava.security.manager MyCode
This poperty causes Java's Security Manager to be installed and the policy to be enforced. So fare so good. But how can I pass this parameter without having it to be specified on the command line?
Well Java offers the environment variable _JAVA_OPTIONS. So I thought I place the parameter into a Windows System Environment Variable: _JAVA_OPTIONS=-Djava.security.manager=
Testing showed that java.exe can be executed with Security Manager without passing the parameter on the command line directly. Further testing revealed that when I start a cmd.exe as a low-privileged user I can overwrite this System Environment Variable and I can bypass the Java Security Manager: set _JAVA_OPTIONS=
I try the same from within a Microsoft Word. Effect is the same. According to my research and feedback from Microsoft the System Environment Variables can be overwritten within the process for the local process. For details see: http://www.virusbtn.com/files/johnlambert_vb2002.pdf. On page 13 in Chapter "Analysis of Path Rule" there it is written: "Environment variables are not secure, and any user who can load a command prompt can temporarily redefine them."
So this melts down to my question: Is there a way to tell java.exe to always use the Java Security Manager without the possiblity of manipulation by the user?
Kind regards
Jan P. Monsch
Malware.java:
import java.io.*;
public class Malware {
public static void main(String[] inArguments) {
try {
FileOutputStream fos = new FileOutputStream("touch.txt");
fos.close();
}
catch (IOException e) {
e.printStackTrace();
}
finally {
System.out.flush();
try {
Thread.sleep(5000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
java.policy:
grant {
//Empty -> no privileges
};
java.security:
security.provider.1=sun.security.provider.Sun
security.provider.2=com.sun.net.ssl.internal.ssl.Provider
security.provider.3=com.sun.rsajca.Provider
security.provider.4=com.sun.crypto.provider.SunJCE
security.provider.5=sun.security.jgss.SunProvider
securerandom.source=file:/dev/random
login.configuration.provider=com.sun.security.auth.login.ConfigFile
policy.provider=sun.security.provider.PolicyFile
policy.url.1=file:${java.home}/lib/security/java.policy
policy.expandProperties=true
policy.allowSystemProperty=false
policy.ignoreIdentityScope=false
keystore.type=jks
system.scope=sun.security.provider.IdentityDatabase
package.access=sun.
security.overridePropertiesFile=false
ssl.KeyManagerFactory.algorithm=SunX509
ssl.TrustManagerFactory.algorithm=SunX509
networkaddress.cache.negative.ttl=10
Word Makro:
Private Declare Function SetEnvironmentVariable Lib "kernel32.dll" Alias
"SetEnvironmentVariableA" (ByVal lpName As String, ByVal lpValue As
String) As Long
Sub StartCmdExe()
SetEnvironmentVariable "_JAVA_OPTIONS", "-Dasdf"
StartProgram "C:\PROGRA~1\JAVA\J2RE14~1.2_1\BIN\java.exe Malware"
End Sub
Sub StartProgram(Path)
Dim shellObj As WshShell
Set shellObj = New WshShell
shellObj.CurrentDirectory = "C:\PROGRA~1\JAVA\J2RE14~1.2_1\BIN\"
shellObj.Run Path
End Sub

