Exploiting Timed Based RCE

Checking the timeIn a recent penetration testing project we encountered a situation where in order to prove exploitability and possible damage we had to exfiltrate data from an isolated server using an OS command injection time based attack.

The scope of the project was an API. During the testing process we identified an interesting GET request that received 2 parameters: the first  a string and the other one ID number.

By fuzzing the string parameter, at first, it looked like we had a potential SQL injection, based on the way it handled single quotes. Trying this attack vector didn’t seem successful, but when we sent the ` sleep  10` command and the HTTP response returned 10 seconds later, we knew we had something.  Our first thought was that this was game over for the application, we managed to get a Remote Code Execution on the API server.

But something was not quite OK. We assumed from the response headers that  the API was hosted on a Windows platform, but the tried payload should only work on Bash or PowerShell in some cases.

These where the possibilities at hand. We now had to test and find out if the injection was in PowerShell or Bash.

We managed to clarify this by running a simple “if” statement, containing a sleep command if the condition was evaluated to true.

IF.PNG

With that out of our way, we tried to set up a way to interact with our servers, but this was unsuccessful. We tried establishing TCP connections using a number of tools like: ncat, wget, curl, but none seemed to work. We then tried other exfiltration techniques like: FTP connection, DNS queries and even ICMP packets but none seemed to work.  We later found out that the server we were accessing was in a private network isolated by firewall from or to the outside world.

We could execute commands but we could not see the output of the command.

One colleague suggested that we could use the sleep command to guess char by char the outputted value and also we could automate this task. This would work just like getting the output from a time based SQL Injection.

Our first approach, in order to test if this could work and considering network delay, was to make a script that uses a command to determine if the letter in position X is equal to Y.

whoami.PNG

After running a simple script we got the whoami command output.

You can imagine that getting the output of command in this time based manner proved to be a Sisyphean task. But this wasn’t the most annoying limitation. We soon found out that our GET parameter was limited to only 48 characters, and the payload exceeded the limit. Our method of bypassing this restriction was to split and output the command that we wanted to execute in a temporary file on the server, execute it and write the execution output to another file that we will read the data from.

fromfile.PNG

Using the payload above we are at exactly 48 characters in length but the limitation hit again. If we want to extract more than 9 characters we can’t, because we would exceed the limit.

After realizing that we can write files to the remote host piece by piece and then execute that script to do a certain task, we started writing an intermediary script that would help us, so by that we can execute shorter commands.

Combining all these ideas we came up with a tool that does all those things. Instead of using Bash we switched to Python. We also replaced the process of guessing each character with guessing the ASCII value of the character, so in this way we can save a lot of pointless requests.

Why use this tool rather than all the existing ones?

We know you would recommend using commix in situations like these. Commix has a lot of exfiltration techniques available, one of them even being Time Based. It can also identify possible OS command injection vulnerabilities. But, although it is a great tool, we could not use commix for 2 main reasons:

  • The payloads used by commix are very long and did not work in our case.
  • It is really very slow because of the approach used and it would have taken a lot of time to extract a whoami command output.

How does the tool work?

The script has 3 parts:

  1. One script that allows guessing the length of the command output from the file (length.py or length.bat).
  2. One script that allows guessing the ASCII value of the character from the X position (ascii.py or ascii.bat).
  3. The main script that sends commands and analyses the responses times in order to determine true of false conditions.

The extraction process looks like this:

  1. Write the command output into a file
  2. Guess the command output length using the length.py script:

To guess the command output length, a few steps are followed:

python ascii.py {NUMBER} {IS_GREATER} {WHERE_THE_OUTPUT_IS_AT} {TIME_DELAY}

  1. Is the output greater than 0? : python l.py 0 0 0 4 => no delay detected, which means that it is true
  2. Is the output greater than 10?: python l.py 10 0 0 4=> 4 seconds delay detected, which means this is false
  3. Is the output equal to 10?: python l.py 10 1 0 4 => no delay detected, which means that is false

  4. Is the output equal to 9?: python l.py 9 1 0 4=> 4 seconds delay detected, which means we found the output length

After we know the output length we can now proceed to guess the ASCII characters codes. This task is done by ascii.py: python ascii.py {CHAR_POS} {ASCII_VALUE} {IS_GREATER} {WHERE_THE_OUTPUT_IS_AT} {TIME_DELAY}.

The guessing process is the same as guessing the length of command output. Instead of guessing the length value, we guess the ASCII value of a specific character.

Here are some print screens of the tool in action:
tool.PNG

Extracting uname -a:

uname-a3.PNG

uname-a4.PNG

We further tried to extract /etc/password which had ~2863 in length and it worked fine:etc_passwd.PNG

To give it a try, you can use the following simple PHP script:

setup.PNG

The tool is available for download here:

https://github.com/dancezarp/TBDEx

Any suggestions are welcome.

19 comments

    1. There is a mention in the article where it is specified that the server was “isolated” from external communication, including DNS traffic.

      Like

  1. Did you try to write in a file located somewhere in the root path of the web app? (I mean the output of the OS commands)
    Or to locate the username and database and try to change your account name with information from the OS?

    Like

      1. That’s a brilliant idea but unfortunately only the API server can access the isolated machine from the local network, we are not executing code directly to the vulnerable server, the API server sends the request to the vulnerable machine, so we can not have any direct output.

        Like

    1. It is really efficient but I already mentioned in the article that the scenario is a vulnerable server that doesn’t have any access from inside to outside, that was the whole idea of the tool and the article.

      Like

  2. For the ‘guessing ascii codes’ part you may save sometime by exfilling (a new word?) via a base64(gzip(data)) approach.

    For /etc/password it worked out as twice as quick for me.

    You could do a binary search (greater than/less than) at each character. So if the first char was 6 it might do 8, 4, 6.

    Like

    1. That’s a very good idea, maybe you can create a pull request and i will merge it to the main branch. I think this can be used for big outputs, for smaller outputs i think it’s enough the ASCII method.
      Thank you very much!

      Like

Leave a Reply