Security Research
Showing results for 
Search instead for 
Do you mean 

Why does Windows rearrange the arguments when executing external process?

SamN on ‎07-02-2014 08:12 AM

Most people, including myself, would expect java.lang.Runtime.exec(String[]) to pass the arguments array to the command without any modification. This is indeed true, but only on UNIX, not on Windows.

 

Take a look at the following code snippets, where a Java program calls a C++ program via Runtime.exec(String[]). Keep in mind that the call is made with a string array and not a single string. Then ask yourself why does it look like the command line arguments have been rearranged?

 

 

Expected Output

Actual Output

[1] apple

[2] banana “orange

[3] pear “watermelon

[1] apple

[2] banana orange pear

[3] watermelon

 

It turns out this is because Windows does not support multiple command line arguments -- it only supports one. If you look at the Windows CreateProcess() API, you can see the function accepts only one single string as the command line argument. The illusion that both Java and C++ can call and receive multiple command line arguments is created because both libraries perform some extra work to achieve the trick. In our example, the Java library concatenates the string array into a single string before calling CreateProcess(). On the C++ side, the C++ library splits the single string back into an array before executing the main() entry point. However, when Java concatenates strings, it quotes them if they contain one or more spaces, without escaping any existing quote characters ("). The Java API is not the only API that does it this way: if you use C/C++ execl() to create a new process, it concatenates command line arguments in the same way.

 

 

Since it is the responsibility of the newly started application to parse a single string into an array, different programs (or languages/libraries/etc…) can behave differently. Luckily, most programs are either compiled with Visual Studio or follow Visual Studio’s parsing rules. Unfortunately, Visual Studio changed its implementation in 2008, so there are at least two sets of popular parsing rules.

 

Post-2008

Command Line Input

Argv[1]

Argv[2]

Argv[3]

Argv[4]

Argv[5]

"""Call Me Ishmael""" 

"Call Me Ishmael" 

 

 

 

 

""""Call Me Ishmael"" b c 

"Call 

Me

Ishmael

b

C

 

Pre-2008

Command Line Input

Argv[1]

Argv[2]

Argv[3]

Argv[4]

Argv[5]

"""Call Me Ishmael""" 

"Call 

Me

Ishmael"

 

 

""""Call Me Ishmael"" b c 

"Call Me Ishmael" 

b

c

 

 

(From How Command Line Parameters Are Parsed by David Deley)

 

Even though I agree with Alex Smolen (and OWASP’s footnote) that it is unlikely that one would be able to inject an extra command unless executing with “cmd.exe /c xxx”, if we take a broader definition of command injection, we still need to guard against command “argument” injection – and the problem we discussed above is obviously one of the possible risks.

 

References:
1. How Command Line Parameters Are Parsed by David Deley
2. Everyone quotes command line arguments the wrong way 

 

 

 

0 Kudos
About the Author

SamN

Labels
Events
Aug 29 - Sep 1
Boston, MA
HPE Big Data Conference 2016
Attend HPE’s Big Data Conference on August 29 - September 1, 2016 to learn from peers in every industry and hear from Big Data experts and thought lea...
Read more
Sep 13-16
National Harbor, MD
HPE Protect 2016
Protect 2016 is our annual conference on September 13 - 16, 2016, and is the place to meet the world’s top information security talent, discuss new pr...
Read more
View all