Fortify issue - Command Injection - java

I am trying to do hp fortify security scan for my java application. I have few issues and i have fixed it. But i am unable to find the fix for the below issue.
Command Injection
String hostname = execReadToString("hostname").split("\\.")[0];
public static String execReadToString(String execCommand) throws IOException {
try (Scanner s = new Scanner(Runtime.getRuntime().exec(execCommand).getInputStream()).useDelimiter("\\A")) {
return s.hasNext() ? s.next() : "";
}
The method execReadToString() calls exec() to execute a command. This call might allow an attacker to inject malicious commands.
So i have tried with process builder also.
private static void gethostname(String cmd1) throws IOException {
if(Pattern.matches("[A-Za-z]+", cmd1)) {
ProcessBuilder pb = new ProcessBuilder(cmd1);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String readline;
while ((readline = reader.readLine()) != null) {
System.out.println(readline);
}
}
}
Even this is giving me an security issue This start() call might allow an attacker to inject malicious commands.
What will be the ideal fix for this issue?
Thanks in advance

Usually this is because you're using user input to frame the command string, wherein user can inject malicious code to manipulate what command is being run ultimately (even if you add validation there will be ways to circumvent that).
In your case you seem to be hardcoding the command so this shouldn't be a problem, however, see the OWASP page on hardcoded command invocation (emphasis mine):
Unlike the previous examples, the command in this example is
hardcoded, so an attacker cannot control the argument passed to
system(). However, since the program does not specify an absolute path
for make, and does not scrub any environment variables prior to
invoking the command, the attacker can modify their $PATH variable to
point to a malicious binary named make and execute the CGI script from
a shell prompt. And since the program has been installed setuid root,
the attacker's version of make now runs with root privileges.
The environment plays a powerful role in the execution of system
commands within programs. Functions like system() and exec() use the
environment of the program that calls them, and therefore attackers
have a potential opportunity to influence the behavior of these calls.
Resolution:
Use native Java APIs / libraries to achieve what you want, instead of running a command - this is probably the best option. Use commands only when unavoidable, eg: 3rd party tools which do not have a Java client library. This approach has the added advantage of being more portable and in most cases, more efficient too. This library might help your scenario.
If you have to run a command, ensure you do not use user-supplied or external data even indirectly to construct it.
Or if you're hardcoding the command to run from the code, use absolute path to the command and do not use environment variables as part of it. For hostname (assuming you use the built-in command) this is usually /usr/bin/hostname but you can find the command path for your environment using which hostname.

Related

ProcessBuilder's inputstream empty depending of OS

I made this simple piece of code to test ProcessBuilder:
#SpringBootApplication
public class TerminalDemoApplication {
public static void main(String[] args) {
SpringApplication.run(TerminalDemoApplication.class, args);
try {
System.out.println("hello");
Process process = new ProcessBuilder("python", "--version").start();
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
int exitCode = process.waitFor();
System.out.println("\nExited with error code : " + exitCode);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
}
It works in Windows (returns python version of my system) but the same code in my macbook returns end of line, so basically empty. ¿This needs further configuration according to the OS? ¿why is this happening?
What error code are you getting?
There are (at least) two explanations; that error code would indicate which one it is.
You're not running python, or running 'the wrong' python
This would mean you are getting an error code of some sort, or an exception.
The likely reason for this is a path issue.
Running python, just like that - as in, no path information at all, is nominally neccessarily broken: That's just not how your OS works, it has no idea what to do with this path.
It's a bashism (as in, the shell does it, not the OS) to interpret such a command as 'oh, actually, go through each listed entry in the $PATH environment variable, and stick that path in front of this name, see if you find an executable there. If you do, run that and stop).
Java mostly doesn't engage in any bashisms. But, in a few bizarre places, it does - it tries to do basic space splitting when you use the single-string version of new ProcessBuilder), which is a shellism, and it does attempt to do basic PATH lookup, but that's about where it ends. It won't do * unpacking, which on windows is an OS-level thing but on posix systems is a shellism.
I strongly, strongly advise you to avoid java's basic shellisms. It's unreliable and highly OS-specific.
So: Always pass arguments explicitly (good, you're doing that), always use ProcessBuilder (good, you're doing that), never use relative paths (that's where you're going wrong).
It's going to the error stream instead
processes on OSes are generally hooked up to 3 pipes, not 2. There's the 'standard in', the 'standard out' and the 'standard err'. Your own java process exposes these as System.out, in, and err.
In linux in particular, it is common to redirect standard out of some process to a file or another process.
This means that standard err naturally has the property that it tends to emit to the console, even if you are redirecting things. In other words, the terms 'standard out' and 'standard err' are really stupid names on posix. The much better naming would be 'standard process output' and 'standard process messages'.
Asking python to print its version is in a bit of a limbo scenario. The string "Python v3.0.1" or whatnot is certainly not an error, but it's a bit dubious if one should consider this as 'the output of the process'. It's likely that the authors of the python tool consider it more 'some information I should print to you, even if you are redirecting things.
Thus, my guess is that this version is heading out to standard err instead.
You can solve this in two ways: Either read from standard err as well, or, use process builder's features: You can ask it to bundle up standard out and standard err into a single stream (.redirectErrorStream(true)).
I would expect the exit code to be 0 if this explanation is the correct one.

Py4j launch_gateway not connecting properly

I am trying to use py4j to open up a gateway that I can use to pass objects from java into python. When I try to open a gateway with the py4j function launch_gateway it does not seem to properly connect to my Java class. However, when I launch my java class in the command line and then connect to it in python using JavaGateway everything works as expected. I would like to be able to use the built in method as I am sure that I am not accounting for things that have already been considered in the design of py4j, but I'm just not sure what I'm doing wrong.
Let's say I wanted to create a gateway to the class sandbox.demo.solver.UtilityReporterEntryPoint.class. In the command line I can do this by executing the following:
java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer
This launches as expected and I can use the methods in my class from within python after connecting to the gateway. So far so good.
My understanding of the py4j documentation would lead me to believe I should do the following to launch the gateway in python:
port = launch_gateway(classpath='sandbox.demo.solver.UtilityReporterEntryPoint')
params = GatewayParameters(port=port)
gateway= JavaGateway(gateway_parameters=params)
I get no errors when executing these three lines, but when I try to access my java class methods with gateway.entry_point.someMethod() it fails with the following error:
Py4JError: An error occurred while calling t.getReport. Trace:
py4j.Py4JException: Target Object ID does not exist for this gateway :t
at py4j.Gateway.invoke(Gateway.java:277)
at py4j.commands.AbstractCommand.invokeMethod(AbstractCommand.java:132)
at py4j.commands.CallCommand.execute(CallCommand.java:79)
at py4j.GatewayConnection.run(GatewayConnection.java:214)
at java.lang.Thread.run(Thread.java:745)
Obviously something is not getting called correctly within launch_gateway or I am feeding it the wrong information.
In the py4j source code for launch_gateway you can see that given the inputs you provide and those constructed by the function, a command is constructed that eventually gets called by subprocess.Popen. So given the input passed to launch_gateway above the command passed into Popen would be:
command = ['java', '-classpath', '/Users/grr/anaconda/share/py4j/py4j0.10.4.jar:sandbox.demo.solver.UtilityReporterEntryPoint', 'py4j.GatewayServer', '0']
Passing this command to Popen returns the listening port as expected. However, connecting to this listening port still does not allow access to my class methods.
Finally, passing the command as a single string to Popen without the final argument ('0'), properly launches a gateway which again operates as expected. Having taken a glance at the Java source code for py4j.GatewayServer.class this makes no sense as the main method seems to indicate that the class should exit with status 1 if the length of arguments is 0.
At this point I'm kind of at a loss. I can hack my way into a workable solution, but as I said I'm sure that ignores important aspects of the gateway behavior and I don't like hacky solutions. I'd love to tag #Barthelemy in this one, but hopefully he reads this. Thanks in advance for any help.
EDIT
For now I have been able to work around this issue with the following steps.
Package entire project including all external dependencies into a single jar file magABM-all.jar, with 'Main-Class' set to UtilityReporterEntryPoint.
Include if...else block regarding presence of --die-on-exit exactly like it is in GatewayServer.java
Use subprocess.Popen to call the command to run the project jar.
UtilityReporterEntryPoint.java
public static void main(String[] args) throws IOException {
GatewayServer server = new GatewayServer(new UtilityReporterEntryPoint());
System.out.println("Gateway Server Started");
server.start();
if (args[0].equals("--die-on-exit")) {
try {
BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in, Charset.forName("UTF-8")));
stdin.readLine();
System.exit(0);
} catch (java.io.IOException e) {
System.exit(1);
}
}
}
app.py
def setup_gateway()
"""Launch a py4j gateway using UtilityReporterEntryPoint."""
process = subprocess.Popen('java -jar magABM-all.jar --die-on-exit', shell=True)
time.sleep(0.5)
gateway = JavaGateway()
return gateway
In this way I can still use gateway.shutdown if necessary and if the python process that starts the py4j gateway dies or is closed the gateway will be closed.
N.B I would by no means consider this a final solution as py4j was written by much smarter individuals with a clear purpose in mind and I am sure that there is a way to manage this exact workflow within the confines of py4j. This is just a stopgap solution.
There are a few issues:
The classpath parameter in launch_gateway should be a directory or a jar file, not a class name. For example, if you want to include additional Java libraries, you would add them to the classpath parameter.
The error you receive when you call gateway.entry_point.someMethod() means that you have no entry point. When you call launch_gateway, the JVM is started with GatewayServer.main, which launches a GatewayServer with no entry point: GatewayServer server = new GatewayServer(null, port). It is not possible currently to use launch_gateway and specify an entry point.
When you start the JVM with java -cp /Users/grr/anaconda/share/py4j/py4j0.10.4.jar: sandbox.demo.solver.UtilityReporterEntryPoint py4j.GatewayServer I believe the JVM uses UtilityReporterEntryPoint as the main class. Although you did not provide the code, I assume that this class has a main method and that it launches a GatewayServer with an instance of UtilityReporterEntryPoint as the entry point. Note that there is a whitespace between the colon and the class name so UtilityReporterEntryPoint is seen as the main class and not as being part of the classpath.

How to execute a linux terminal command from LUAJ?

I want to simply execute a linux terminal command like ls from LuaJ and the result that it will return or anything that returns i want to receive it and will show the names in the Java Gui. I searched but found this but not one with LuaJ.
Is there any function to execute the terminal command from LuaJ ??
There are multiple ways to do this, for one, you can implement it yourself in Java then link it to LuaJ.
LuaFunction command = new OneArgFunction()
{
public LuaValue call(LuaValue cmd)
{
Process p = Runtime.getRuntime().exec("/bin/sh", "-c", cmd.checkstring());
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
int returnCode = p.waitFor();
return LuaValue.valueOf(returnCode);
}
}
globals.set("command", command);
Then in Lua:
local code = command("ls");
The problem with actually getting the output of a command is that you can't just have a fixall solution. For all the system knows you could be calling a program which runs for 2 hours generating constant output, which could be an issue, not to mention if the program requires input. If you know you're only going to use certain functions you can make a dirty version of above function to capture the output from the stream and return it all instead of the exit code, just don't use it on other processes that don't return quickly. The other alternative is to create a class that wraps the input and output streams from the process and return a coerced version of that class, and manage the input and output from lua.
Lua does have a function that's part of the OsLib called execute(), if execute doesn't exist in your current environment then in Java call:
globals.load(new OsLib());
Before loading the lua code. the os.execute() function returns the status code, and doesn't return the streams, so no way to get the output there. To get around this you can modify the command to pipe the output to a temp file and open it with the io library (new IoLib() if doesn't exist in current environment).
The other option is to use io.openProcess, which also executes the command and returns a file to read the output from.
Resources:
http://luaj.org/luaj/3.0/api/org/luaj/vm2/lib/OsLib.html
http://luaj.org/luaj/3.0/api/org/luaj/vm2/lib/IoLib.html

How to call a bash script from GWT-RPC server (Java)

I want to call a bash script from GWT server
I coded up my first application with GWT/RPC, and I need to call a bash script on the server side (from MyOwnServiceImpl extends RemoteServiceServlet implements MyOwnService).
ProcessBuilder doesn't work
To do that, I confess that I am using java.lang.ProcessBuilder, which is apparently "not supported by GAE" (I just ignored the warning). As it is running on the server side, it seemed to me that it should work anyways. I feel that I am missing something.
Something seems to be preventing the call from being executed, even though the required packages are correctly imported, the binaries are found, the execution doesn't crash. But the call is just not successful (for example even mkdir is not executed on the server).
Related posts weren't much help...
How to execute a Unix shell script via GWT? (does not give a complete answer, and I could not simply comment on the answer)
GWT + ProcessBuilder (mentions precisely the solution I implemented which is not working for me, see above)
Any thoughts on this would be much appreciated, thanks!
In a GWT application without GAE you can use Runtime.getRuntime().exec("some command");
If you want to read out the result of the command, you can use:
Process p = Runtime.getRuntime().exec("A command");
BufferedReader in = new BufferedReader(new InputStreamReader(p.getErrorStream()));
StringBuilder builder = new StringBuilder();
String line = null;
while ((line = in.readLine()) != null) {
builder.append(line + "\n");
}
String result = builder.toString();
If the command above should not work, i guess you have to remove GAE from your project to run a bash script.
you can call bash script with GWT,if your servet side on your computer.
the limit is GAE for secury. no way to cross this limit.

using cmd with in responsive mode in c++ or java

I am using OpenSSL in my c++ app, The problem is if I use exec("Open ssl command")
Then it will execute that particular command , but actually this command is repsonsive,I mean it further asks you "Are you sure you want to do this Y/N?"
I don't know how to cater this scenario.How can I use java or C++ to run a command line which is responsive,Any help would be appreciated.
Thanks
Easy enough in Java. Just:
Get the Process handle.
Read the Process' input stream for prompts written to stdout.
Respond to prompts by writing to the Process' output stream.
Here's a quick Groovy sample because it's even easier than Java:
def cmd = ... // the command you want to run
def process = cmd.execute()
def processStdout = new Scanner(process.inputStream)
def processStdin = process.outputStream
def outputLine = processStdout.nextLine()
if (outputLine == 'some prompt written to stdout') {
processStdin << 'your response\n'
}
If you can't follow the Groovy, I can expand it to Java.
Note that this sample doesn't handle the potentially important tasks of ensuring the stdout and stderr of the nested process are fully consumed to prevent blocking, nor does it handle ensuring the process exits cleanly.
Update: Here's that same thing in Java:
import java.io.OutputStream;
import java.util.Scanner;
public class SubprocessIO {
public static void main(String[] args) throws Exception {
String[] cmd = { ... your command as a series of strings ... };
Process process = Runtime.getRuntime().exec(cmd);
Scanner processStdout = new Scanner(process.getInputStream());
OutputStream processStdin = process.getOutputStream();
String outputLine = processStdout.nextLine();
if (outputLine.equals("some prompt written to stdout")) {
processStdin.write("your response\n".getBytes());
processStdin.flush();
}
}
}
I forgot to make a note on the first go-round that the \n in the response is crucial, assuming the app is expecting you to enter something and then press Enter. Also, you're probably better off using the line.separator system property
Basically you just need to make sure you enter all required information on the commandline, and use -batch to avoid further questions, for example:
openssl ca -days 3650 -out client.crt -in client.csr -config \path\to\configs -batch -passin pass:PASSWORD -key password
If this does not work for any specific openssl command, please specify it in your question which command you need to execute.
For openssl the answer by Wimmel is the right approach. Depending on your exact use case, you may want to prepare or construct a configuration file that contains recurring parameters and specify the varying parameters (and a pointer to the config file) on the command line. The -batch option, that is available at least with the common openssl commands for managing certificates will ensure that no interactivity occurs - if you have specified insufficient parameters the commands will fail.
For running the command and evaluating its results, you still need the corresponding functionality. In Java you use the ProcessBuilder and Process classes. In C++ there is no standard way to do this (the system() function is too limited for most uses), so you need to use platform-specific C functions (e.g. CreateProcess, posix_spawn or fork/exec) or find a suitable C++ library.
But for directly answering interactive questions programmatically these interfaces may be insufficient. Interactive dialog may be quite complicated. Typically this is not as simple as treating all input and output as a simple character stream. Details depend on the platform and program, but you may need something like expect (see http://en.wikipedia.org/wiki/Expect) to deal with this.
Update: of course the approach to invoke an external CLI for all of this is not necessarily the best and introduces a whole new set of extraneous side-issues. You may be better off using a suitable cryptographic API (for example BouncyCastle http://www.bouncycastle.org/)

Categories