Browsing to the site, we are greeted by a page asking for an IP to check and a[link to the backend source code](http://2018shell3.picoctf.com:56517/index.txt) :
```php<html><head>	<title>Monitoring Tool</title>	<script>	function check(){		ip = document.getElementById("ip").value;		chk = ip.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);		if (!chk) {			alert("Wrong IP format.");			return false;		} else {			document.getElementById("monitor").submit();		}	}	</script></head><body>	<h1>Monitoring Tool ver 0.1</h1>	<form id="monitor" action="index.php" method="post" onsubmit="return false;">  Input IP address of the target host	<input id="ip" name="ip" type="text"> 	<input type="button" value="Go!" onclick="check()">	</form>	<hr>
 Input IP address of the target host	<input id="ip" name="ip" type="text"> 
Target is NOT alive.</h3>");				break;			} else if (strpos($str, ', 0% packet loss') !== false){				printf("<h3>Target is alive.</h3>");				break;			}		}	} else {		echo "Wrong IP Format.";	}}?><hr>index.php source code</body></html>```
Since the input is passed to php's `exec`, it seems like we have a commandinjection to exploit. Two things stand in our way :
1. The input is validated2. The command output is not returned
Let's figure this out
### Broken input validation = command injection
As the hint indicates, the IP addresses are not validated the same way on thefront-end and on the backend :
Front-end validation regex :
`/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/`
Back-end validation regex
`/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])/`
The important difference here is that both regex start with `^` (which matchesthe beginning of the string), but only the front-end regex ends with `$` (whichmatches the end of the string). What that means is that the front-end willreject the input if it contains anything after the IP, but the back-end won't.
Front-end validation is completely useless, since we can send requests directlyto the server.
The command executed is shown in that line of the source :
```phpexec('ping -c 1 '.$ip, $cmd_result);```
Where `$ip` is our input (`$cmd_result` is used to store the output).
now our input needs to start with an ip address and provide a command to run.so if we provide `127.0.0.1 ; command`, `command` will be executed after`ping`.
Now what should our payload be ?
### Choosing a payload
The backend code doesn't return the input of what it `exec`s, it only returnsa message indicating whether the `ping`ed ip replied :
```phpforeach($cmd_result as $str){    if (strpos($str, '100% packet loss') !== false){        printf("<h3>Target is NOT alive.</h3>");        break;    } else if (strpos($str, ', 0% packet loss') !== false){        printf("<h3>Target is alive.</h3>");        break;    }}```
That means we can't simply run `ls` to look for the flag file and then `cat` it.
There are many ways of getting around that, the most obvious approach herebeing a [reverse shell](http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet).
I decided to use a different payload for fun, based on two assumptions :
1. Python 2 is installed on the server2. There is a flag file in the task's directory
My payload was `python -m SimpleHTTPServer 9999` (`127.0.0.1; python -m SimpleHTTPServer 9999`).
The [SimpleHTTPServer module](https://docs.python.org/2/library/simplehttpserver.html)is part of the Python 2 standard library (it has been renamed to `http.server`in Python 3), which means it's available if python is. When executed (usingpython's `-m` option), it creates an HTTP server listening on the port passedas an argument (`9999` here) and serving the current working directory.
When sending that payload, the client hangs : that means the code hasn'treturned, since it's running the http server.
Now if port `9999` is not firewalled, we should be able to browse to`http://2018shell3.picoctf.com:56517` and get a file listing of the task'sdirectory.
And indeed, the flag is at `http://2018shell3.picoctf.com:9999/flag.txt` :`picoCTF{n3v3r_trust_a_b0x_36d4a875}`.