I was reading Alex Smolen’s blog the other day and ran across the post “Command Injection Impossible in Java and .NET?” Interesting stuff! In an effort to avoid doing work I should actually be doing, I decided to look into it a bit more.
So I put together a tiny little program to try a bunch of different permutations to try and test this out. This is by no means an exhaustive fuzzing but I did run a number of command lines through Java that should have resulted in multiple commands being executed (cut and paste them from the Java System.out output). I zipped up the code and binaries and uploaded it here:
http://www.dancornell.com/files/JavaCommandInjection_v1_1.zip
If you go into the bin/ directory and run “java denimgroup.fuzzer.commandline.Main” it will try to run a bunch of commands. I have two scripts in the directory: intended and exploit. “intended” appends its command line arguments to intended_shell_results.txt and “exploit” appends its command line arguments to exploit_shell_results.txt. On Mac OS X 10.5.6 with Eclipse 3.4.0 using JDK 1.5.0 it runs the following commands through “Runtime.getRuntime().exec(command);”
./intended : ./exploit
./intended | ./exploit
./intended && ./exploit
./intended & ./exploit
./intended ! ./exploit
./intended >> ./exploit
./intended << ./exploit
./intended > ./exploit
./intended < ./exploit
./intended :: ./exploit
./intended ;; ./exploit
./intended ;: ./exploit
./intended :; ./exploit
./intended || ./exploit
Assuming that “exploit” was executed, you would expect to see something in the “exploit_shell_results.txt” For example, if you manually run “./intended ; ./exploit” from the shell (as Java tried and failed to do via exec()) it will put some info in the file. But – wait – there’s nothing there when Java tries to run it! Perhaps Alex and the OWASP site are right (!).
Clearly this merits further study. My list of payloads is, by no means, exhaustive. But this is certainly interesting. To the degree that the standard Java libraries seem to prevent at least the most boneheaded attempts at command injection – bravo! There is a long way to go before declaring victory, but this is at least encouraging. I’d want to spend a lot of compute cycles trying to fiddle with combinations of Unicode characters on different OSes and different JDKs, but these days I am kind of busy. The code is available under an Apache 2.0 license so anyone can feel free to make this happen.
And hey – maybe I’ll fire up VS.NET 2008 and make a C# version. Otherwise I might accidentally do some real work.
–Dan
dan _at_ denimgroup.com
One quick way to verify Java isn’t vulnerable is to see which native functions it’s using. On Linux, use strace -f java […]/Main on your test app and look for exec or system. Yup, we see execve — safe calls.
Whoops, I realized I should clarify/correct that. system() will still use the exec syscall, but it will pass the string to the shell to execute rather than execute directly.
hi!
the link to your demo code is dead. can you fix it please?
thanx sven