How does java Runtime.getRuntime().exec(...) search for executables on windows? - java

I'm trying to do a proof of concept exploit to show how changing the path variable can replace standard programs for malicious ends. I put a dummy program called "cmd.exe" in a directory "C:\path\to\fake_exe\" and changed the path to have that at the front.
Below is the function I'm using to demonstrate, but it runs normally (i.e., it passes the arguments to the correct cmd.exe instead of my fake one). I even passed "cmd" to the function, and it opened my dummy program! So the path variable is definitely set to find my fake cmd.exe correctly, but the exec(..) function is finding the proper cmd.exe regardless.
How does the exec(...) function find executables? Where is this documented?
static void unsafeExec(String cmd) throws IOException, InterruptedException {
String[] run = new String[3];
run[0] = "cmd.exe";
run[1] = "/C";
run[2] = cmd;
Process p = Runtime.getRuntime().exec(run);
BufferedReader stdIN = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdER = new BufferedReader(new InputStreamReader(p.getErrorStream()));
p.waitFor();
String s;
while ((s = stdIN.readLine()) != null) {
System.out.println(s);
}
while ((s = stdER.readLine()) != null) {
System.out.print(s);
}
}

Related

java process builder add path to environment not working

I have a problem with adding a path to the environment of a process using processbuider. I have no clue why the process is ignoring the environment. Here is my example:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;
public class main {
public static void main(String [ ] args) {
try {
String s = null;
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "fsl");
Map<String, String> env;
env = pb.environment();
env.put("FSLDIR", "/usr/local/fsl/bin/");
Process p = pb.start();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
System.out.println("Process p:");
// read the output from the command
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
//////////*********\\\\\\\\\\\
ProcessBuilder pb2 = new ProcessBuilder("/usr/local/fsl/bin/fsl");
s = null;
Process p2 = pb2.start();
stdInput = new BufferedReader(new
InputStreamReader(p2.getInputStream()));
stdError = new BufferedReader(new
InputStreamReader(p2.getErrorStream()));
System.out.println("Process p2:");
// read the output from the command
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Output:
Process p:
/bin/bash: fsl: command not found
Process p2:
DISPLAY is not set. Please set your DISPLAY environment variable!
And you see FSL wants some more variables to be set. That is why p2 is not an option.
As Jdamian said, Bash searches the directories in the PATH environment variable to find binaries - Bash does not look for your FSLDIR variable, nor will it treat the values of arbitrary variables as executables.
The first thing you should always do when running into issues with a process library (e.g. ProcessBuilder in Java, subprocess in Python), is try to replicate the issue directly in the shell. If you run fsl or /bin/bash -c fsl in your shell you'll likely see the same error (if you don't you're not running your Java binary the same way as your shell) which confirms the issue is not related to Java.
Once you've confirmed that it's just a question of how to fix it. If you intend for fsl to be always available add its containing directory to your PATH in your ~/.bashrc file:
export PATH="$PATH:/usr/local/fsl/bin"
If you just want it available in your Java binary, modify the PATH in-process:
// notice there's no need for `bash -c`
ProcessBuilder pb = new ProcessBuilder("fsl");
pb.environment().put("PATH",
"/usr/local/fsl/bin" + File.pathSeparator + System.getenv("PATH"));
In practice however, your code will often be much more maintainable and easier to work with if you don't modify the PATH and instead simply always invoke external processes by their absolute path, like your second example:
ProcessBuilder pb = new ProcessBuilder("/usr/local/fsl/bin/fsl");
These two commands are (roughly) equivalent, but the latter is far more clear, and less likely to introduce confusing bugs.

Java can't run cmd-command's properly

I am attempting to generate a list of all installed Programs on my Windows machine.
This is the command I am using:
WMIC /output:D:\miep product get name && type D:\miep > D:\miep_
You might have realized that I'm also trying to make a type-Command as I need the output in UTF-8.
I made a Whitelist for this with a simple loop where I will look later where in my file certain Names will appear and keep them while I remove everything else.
The command works in the command prompt, but when I try to do the same inside my Java Program it keeps telling me I've got an Invalid GET-Expression ...
Here is my function:
void createLists() throws IOException {
//String cmd = "WMIC /output:D:\\miep.csv product get name /format:\"%WINDIR%\\System32\\wbem\\de-DE\\csv.xsl\"";
String cmd = "WMIC /output:D:\\miep product get name && type D:\\miep > D:\\miep_";
System.out.println(cmd);
Process p;
p = Runtime.getRuntime().exec(cmd);
p.getOutputStream().close();
String line;
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = stdout.readLine()) != null) {
System.out.println(line);
}
stdout.close();
BufferedReader stderr = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = stderr.readLine()) != null) {
System.out.println(line);
}
stderr.close();
System.out.println("Done");
}
I also tried the converting stuff with the .csv files as you might have seen in the second line of my code and the same:
Works in CMD, but not in my Java-Program..!
Here it keeps telling me that it's an Invalid XSL-Format
Can someone help?

Java function to toggle socket state via raspberry pi

I have a function in java which is being executet on my raspberry pi and should send a signal to toggle the targeted sockets state to on / off.
Thats my current function:
public static void rcswitch(int housecode,int unitcode, int onoff) throws InterruptedException, IOException {
String housestring = Integer.toString(housecode);
String unitstring = Integer.toString(unitcode);
String onoffstring = Integer.toString(onoff);
ProcessBuilder builder = new ProcessBuilder("/bin/bash", "-c", "sudo /home/pi/rcswitch-pi/send", housestring, unitstring, onoffstring);
Process proc = builder.start();
BufferedReader reader =
new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}
}
However, it doesn't seem like the terminal is receiving the command as it does not output anything. It should show something like "command received" and execute it then. When I normally execute the /send command in the terminal it works just fine. In eclipse it just works fine and throws the expected error.
Thanks for your answers :)
It is most likely that an error has occured while executing the command. Keep in mind that Process#getInputStream() does not include standard error stream of the process. You should use Process#getErrorStream(). Something like:
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line = null;
while((line = reader.readLine()) != null) {
System.out.print(line + "\n");
}

Java: is there a way to run a system command and print the output during execution?

I have a python script and it takes a long time to finish. I would like to run it from Java, but also output the script's output while it is executing, so that I can tell if it is properly running.
I've searched and only found examples where we output the output after the system command has finished, rather than during its execution.
Any way to do it while the script is running?
Here's what I have
public void doSomething() throws IOException {
String[] callAndArgs = {"python", "/hi.py"};
Process p = Runtime.getRuntime().exec(callAndArgs);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
i managed to get it working like this (Note it requires java7):
package test;
import java.lang.ProcessBuilder.Redirect;
public class Test {
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("python","/home/foobar/Programming/test/src/test/test.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
p.waitFor();
}
}
python (note i flush on python to make it work using sys.stdout.flush())
import time,sys
c =0
while c<=50:
time.sleep(1)
print("----")
c = c +1
sys.stdout.flush()
Note if you don't want to flush in a loop you can use this:
ProcessBuilder pb = new ProcessBuilder("python","-u","/home/foobar/Programming/NetBeansProjects/test/src/test/test.py");
Redirect.INHERIT
Indicates that subprocess I/O source or destination will be the same as those of the current process. This is the normal behavior of most operating system command interpreters (shells).
I've searched and only found examples where we output the output after
the system command has finished, rather than during its execution.
That's weird, because your example should be dumping the output as the command is executing.
Instead of using BufferedReader, you could try reading directly from the InputStream instead as the required conditions for readLine might not be being met until after the process exits.
I'd also recommend that you use a ProcessBuilder over Process directly, as, apart from anything else, it allows you to redirect the output from the error stream into the input stream, allowing you to read just one stream instead of two...
This might also be an issue with Python and how it flushes it output buffers...
For example, rather then waiting for the BufferedReader to decide when to return, try printing each character from the stream as it occurs/is reported
ProcessBuilder pb = new ProcessBuilder("test.py");
pb.redirectError();
Process p = pb.start();
InputStream is = null;
try {
is = p.getInputStream();
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char)in);
}
} finally {
try {
is.close();
} catch (Exception e) {
}
}
Update
Doing a little reading, Python seems to be buffering its out out before sending it to the stdout. I don't think you can fix this on the a Java side, but need to alter either the way Python is run or the script works.
See How to flush output of Python print? for more details
I'm suspecting that you are writing to stderr, which you can't see because you are blocking on stdin. Use a ProcessBuilder instead of doing exec. This way, you can redirect stderr and stdin into a single stream.
Here is an example:
import java.io.*;
public class Test {
public static void main(String... args) throws IOException {
ProcessBuilder pb =
new ProcessBuilder("test.py");
pb.redirectErrorStream(true);
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader bf = new BufferedReader(reader);
String s;
while ((s = bf.readLine()) != null) {
System.out.println(s);
}
}
}
Alternatively you can spawn threads to read from stdin/stderr respectively.
Another thing to look for is output buffering by python. You can see if this is the cause by doing:
import sys
sys.stdout.flush()
after you write to stdout
Don't use #readLine as the conditional in your while loop. Instead wrap your inputStream in a scanner and use #hasNextLine()
Scanner in = new Scanner(p.getInputStream());
while (in.hasNextLine()) {
System.out.println(in.nextLine());
}

Running Python scripts in Java

I'm trying to run a python script during the execution of my java code, because it will depend on the output received from the python script. So far I've tried using jythonc, unfortunately to no success, and now im trying to use the java Runtime and java Process to execute the python script.
Now I've run into a problem when trying to call the python script. I feel as though it doesn't even call the script because it takes less than a couple seconds to get to the next page....
Could the problem be how I am calling the python script?? I am trying to run this through a web application...
Here is some of my code:
String run = "cmd /c python duplicatetestingoriginal.py" ;
boolean isCreated = fwr.writeFile(BugFile, GD, 500, true, 5, "LET");
if(isCreated){
try{
r = Runtime.getRuntime();
p = r.exec(run);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line = "";
while ((line = stdInput.readLine()) != null) {
System.out.println(line);
}
while ((line = stdError.readLine()) != null) {
errorW.write(line);
}
int exitVal = p.waitFor();
arrayList = fwr.readResults();
}catch(Exception e){
}
}
else{
// troubleshoot....
}
Instead of String for the command, split it to chunks and make a String[]. No need to state cmd /c, I think.
This is a sample code from my application:
//Running on windows
command = new String[4];
command[0]=directory.getCanonicalPath()+"/data/ExtenalApp.exe"; //extenal commandline app, not placed in path, but in subfolder
command[1]=directory.getCanonicalPath()+"/data/SomeFile.txt"; //file needed for the external app, sent as an argument
command[2]=arg1; //argument for the app
command[3]=arg2; //argument for the app
//Running on Mac
command = new String[6];
command[0]="python";
command[1]=directory.getCanonicalPath()+"/data/wp.py"; //path to the script
command[2]="-F"; //argument/Flag/option
command[3]="--dir="+path; //argument/option
command[4]="--filename="+filename; //argument/option
command[5]=argument; //argument/option
Process process = Runtime.getRuntime().exec(command);
process.waitFor();
process.destroy();
I don't handle the Input/Output streams because the script/app doesn't require input, and outputs only when finished, nothing important. Which might not be the case for you.

Categories

Resources