Web
Nmap discovered a Web server on the target port 80
The running service is Apache httpd 2.4.54
Webroot at
/index.php
It appears to be an online retailer for watch
Wappalyzer identified technologies involved
It’s written in PHP
The Client section reveals 3 potential users
The Contact section doesn’t appear to be responsive
There are 2 additional files hard-coded in to the web root;
/shop
and /upload.php
/shop
301 to
/shop/index.php
It lists recently added products
These products are set with a parameter of
id
within the page=product
parameter
/shop/index.php?page=cart
Adding an item to the cart sends a POST request to the
/shop/index.php?page=cart
page with the POST data
Then it loads the
/shop/index.php?page=cart
page with a GET request
The Update button also sends a POST request to the
/shop/index.php?page=cart
page with the shown POST data
This seems to refresh the session, which refreshes the cart
Same goes for the Place Order button, but it leads to the
/shop/index.php?page=placeorder
page afterwards
The Clear button however empties the cart
I will check for other potential values to the page
parameter
Parameter Mining
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ ffuf -c -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-words-lowercase.txt -u http://$IP/shop/index.php?page=FUZZ -ic -fw 811
________________________________________________
:: Method : GET
:: URL : http://10.10.11.229/shop/index.php?page=FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-words-lowercase.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
:: Filter : Response words: 811
________________________________________________
[Status: 500, Size: 0, Words: 1, Lines: 1, Duration: 42ms]
* FUZZ: index
[Status: 200, Size: 2033, Words: 670, Lines: 64, Duration: 31ms]
* FUZZ: cart
[Status: 200, Size: 15, Words: 3, Lines: 1, Duration: 31ms]
* FUZZ: product
[Status: 200, Size: 2584, Words: 825, Lines: 68, Duration: 31ms]
* FUZZ: products
[Status: 500, Size: 0, Words: 1, Lines: 1, Duration: 27ms]
* FUZZ: functions
[Status: 200, Size: 1192, Words: 312, Lines: 38, Duration: 28ms]
* FUZZ: placeorder
:: Progress: [107982/107982] :: Job [1/1] :: 621 req/sec :: Duration: [0:02:46] :: Errors: 0 ::
ffuf found 4 additional values to the page
parameter
/shop/index.php?page=product
It seems that the
page=product
parameter is used to display a single item with the id
parameter as it’s required
Like so
/shop/index.php?page=products
Whereas the
page=products
displays all the product
index
and functions
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ curl http://$IP/shop/index.php?page=index -I
HTTP/1.0 500 Internal Server Error
date: Wed, 30 Aug 2023 11:08:27 GMT
server: Apache/2.4.54 (Ubuntu)
set-cookie: PHPSESSID=jlb15v1ndtvo6b0lqfitveoha7; path=/
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
connection: close
content-type: text/html; charset=UTF-8
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ curl http://$IP/shop/index.php?page=functions -I
HTTP/1.0 500 Internal Server Error
date: Wed, 30 Aug 2023 11:08:19 GMT
server: Apache/2.4.54 (Ubuntu)
set-cookie: PHPSESSID=9hu9d1h7akk0braaddvl3kbn08; path=/
expires: Thu, 19 Nov 1981 08:52:00 GMT
cache-control: no-store, no-cache, must-revalidate
pragma: no-cache
connection: close
content-type: text/html; charset=UTF-8
index
and functions
to the page
parameter returns code 500
/upload.php
The
/upload.php
file supports file upload
A PDF file archived with .zip
extension is expected
This seems to suggest that there is someone on the other end that actively checks for uploaded files by opening them, which provides an opportunity for an attacker to upload a malicious PDF file that could potentially open up a door for other attack vectors including SSRF or RCE
I tested the file upload feature by uploading a ZIP archive with a testing PDF file in it
It shows that the file was successfully uploaded and UNZIPPED and is waiting for review by a staff member
The UNZIPPED content appears to be saved to uploads/8cf3bbfea34209ac4333ee48a0c09d7e/test.pdf
It is indeed available at `uploads/8cf3bbfea34209ac4333ee48a0c09d7e/test.pdf
Interesting thing here is that the web application generated a directory whose name appears be a MD5 hash string
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ hashid 8cf3bbfea34209ac4333ee48a0c09d7e
Analyzing '8cf3bbfea34209ac4333ee48a0c09d7e'
[+] MD2
[+] MD5
[+] MD4
[+] Double MD5
[+] LM
[+] RIPEMD-128
[+] Haval-128
[+] Tiger-128
[+] Skein-256(128)
[+] Skein-512(128)
[+] Lotus Notes/Domino 5
[+] Skype
[+] Snefru-128
[+] NTLM
[+] Domain Cached Credentials
[+] Domain Cached Credentials 2
[+] DNSSEC(NSEC3)
[+] RAdmin v2.x
It definitely looks to be a hash string
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ md5sum test.zip
8cf3bbfea34209ac4333ee48a0c09d7e test.zip
It turns out to be the calculated hash string of the ZIP file itself
Extension
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ touch a.php ; zip a.zip a.php
adding: a.php (stored 0%)
Content with PHP extension seems to fail to upload due to the extension filter in the server side
I can make it work by modifying the POST data, but the uploaded file will be saved with the
.pdf
extension
However, I cannot load the content let alone invoking code execution due to the .pdf
extension
It would work only if I could control the extension One method would be the Nullbyte Injection
Nullbyte Injection
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ echo "hello there 123" > b.txtA.pdf ; zip b.zip b.txtA.pdf
adding: b.txtA.pdf (stored 0%)
I will first create an arbitrary txt file with the
.txtA.pdf
extension and archive it to b.zip
Then I will inject a null byte to the location of the A
character.
This will terminate the remaining, but the web app will still see the content as a valid PDF file
It worked. Notice the whitespace;
b.txt .pdf
Moving on to the Exploitation phase
Fuzzing
┌──(kali㉿kali)-[~/archive/htb/labs/zipping]
└─$ ffuf -c -w /usr/share/wordlists/seclists/discovery/web-content/directory-list-2.3-medium.txt -u http://$IP/FUZZ -ic -e .php, .txt
________________________________________________
:: Method : GET
:: URL : http://10.10.11.229/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Extensions : .php
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405,500
________________________________________________
[status: 301, Size: 314, Words: 20, Lines: 10, Duration: 25ms]
* fuzz: uploads
[status: 301, Size: 311, Words: 20, Lines: 10, Duration: 26ms]
* fuzz: shop
[status: 301, Size: 313, Words: 20, Lines: 10, Duration: 27ms]
* fuzz: assets
[status: 200, Size: 5321, Words: 1882, Lines: 113, Duration: 27ms]
* fuzz: upload.php
[status: 200, Size: 16738, Words: 5717, Lines: 318, Duration: 4483ms]
* fuzz: index.php
[status: 403, Size: 277, Words: 20, Lines: 10, Duration: 29ms]
* fuzz: server-status
:: Progress: [661641/661641] :: Job [1/1] :: 1503 req/sec :: Duration: [0:07:49] :: Errors: 0 ::
No additional endpoint found