The Challenge
You are led to a website called the “RITSEC Echo Simulator”, where it encourages you to test out some words in an input box. There’s a single button to test the word.
Fuzzing
I first entered some gibberish just to see how the application behaved, and a new page loaded with the following:
You entered: asdf
This word echoes (echoes) (echoes)...see?
asdf
asdf
asdf
Because it’s showing the data, this led me to think it’s either an XSS or command injection. There were no obvious signs that a bot or someone else is monitoring the site, so I leaned into command injection.
Echo…?
echo
is a command commonly used in linux. For example: echo something
will print something
as the ouput. You can use subshells (as is common in a lot of command injection vectors) to echo the result of another command. As an example, you could run: echo "My Username is $(whoami)"
:
Subshell
I tried adding just id
or whoami
to see if it was a direct injection, but that didn’t work out. It was just displaying the text. I moved on to using a subshell, as shown above with the username example. Let’s try $(id)
as an input:
hmmmmmmm, ok. There may be some filtering, or I’m not understanding exactly how this is called. This is a different response though, so it’s progress nonetheless!
Echo Subshell
I mean, the name of the challenge is “Echoes”, so let’s try to do the full echo command: echo $(id)
:
Boom! We got a remote code execution. Now we just need to find that pesky flag. Doing a directory listing, we leak the flag location (flag.txt
) by entering echo $(ls -la)
.
What was in the PHP Code?
Fortunately, we can read out arbitrary files using our RCE, and doing the ls -la
, we can see there’s check.php
in the current directory. Let’s take a look at that and figure out why our exploit worked this way. …but wait, echo $(cat check.php)
says that this word doesn’t echo. Is there something in place to prevent this? This is where I stopped looking because I had the flag. Future Leo, however, went back and checked the source code because I was missing something here. Let’s take a look at the relevant code:
<p class="php">This word
<?php
if (strlen($_POST["word"]) % 2 == 0) {
echo nl2br("echoes (echoes) (echoes)...see?\r\n");
$cmd = "echo ".$_POST["word"];
$outout = array();
exec($cmd, $outout);
echo $_POST["word"];
echo "<br />";
echo $_POST["word"];
echo "<br />";
foreach($outout as $line) {
echo $line;
echo "<br />";
}
}
else echo "does not echo... weird";
?>
So uhhhhh, it was an even/odd number of character thing? This is WAY more simple than I had initially thought, and I over-complicated things a good bit. My above assumptions only worked due to sheer dumb luck regarding the number of characters when running my attempted exploits.
Conclusion
I liked this challenge because of the “easy” remote code execution, however, I was really surprised to see how simple the logic actually was. I was assuming there was some filtering in place to prevent code exfiltration or something similar, but that wasn’t the case! This really brings to light the benefit of having source code available for gray-box testing. If this were for a pen-test, I would have written up steps to reproduce that were both inaccurate and overly complicated.