Around March 14th 2019 I found Local File Inclusion, Path Traversal and File Write on the Gucci subdomain glft.gucci.com on port 3443 (https://glft.gucci.com:3443/). When attempting to go to the subdomain on the regular port 80/433 you would be met with a message that the subdomain was an intranet interface. So all of the findings combined, a malicious actor could have read local files, uploaded a phishing page, upload a shell which could have led to a reverse shell, opening up a potential of traversing the internal network.
The “GLFT” stands for “Gucci Large File Transfer”. What this seemed to be was a page for Gucci employees to upload and send files, either to other employees, company partners, retailers, advertising companies, etc. As far as I can remember, there was no limitation to what could be uploaded. Whatever you uploaded would be sent via email. Regardless of what you uploaded, even web pages or anything else you could interact with your only option was to save the file.
I feel as if I’ve gone a bit too in depth and made this write-up longer than it needs to be, so any feedbacks I’d very much appreciate. These can be sent to my Twitter. Also feel free to ask any questions, my DMs are open.
When I first came across the GLFT subdomain it was because it was sent in a group chat I was in. Around the time of typing this I found out that it was being shared around a lot but fortunately it was only for bragging rights for knowing about it’s existence and not because of the vulnerabilities that existed. I had no intentions of looking for vulnerabilities on Gucci’s domain prior to being sent this, however it was cool to have been sent it for me to have found the issues.
As you can see from the image there’s three out of six interactive sections that need to be completed. However here’s a rundown of each one.
- From – This is the sender email. This can be anything but needs to have ‘@gucci.com’, i.e. ‘[email protected]’. This isn’t the real sender, but rather the displayed email only.
- To – This is the receiving email. Unlike the ‘From’ field there’s no limitations on what domain this email could be sent to. This could be a fake email. The domain doesn’t need to exist and the TLD could be invalid, i.e. ‘[email protected]’.
- Recipients list – This is purely here to show all the emails the file will be sent to. Here you will be able to remove an email.
- Message – This will be the body of the email. This is mostly used for a comment to the recipients.
- File – Here you will have to select what file you want to upload and send. You’re given a remove button if you need to change the file or selected the wrong one.
- Expires – There’s three options for how long you can have the file available for. The chosen file will expire in either ‘24 hours’, ‘3 days’ or ‘1 week’.
As far as I remember you are limited to 300GB for uploading. You’re also offered a program, however I hadn’t looked into the application.
So for this section I’ll be trying to explain the whole process I went through as best as I can remember. For the test file I used for uploading, I named it test.txt and spammed my keyboard for less than a second to get some quick random characters. The size of the file was 7 bytes, keep that in mind. I then opened up Burpsuite, opened up Firefox incognito and switched my proxy settings on. I turned on intercept in Burp and clicked send on the upload page.
The first thing I was greeted with was a POST request to
With this request it sent data such as
The parameter ‘smb64’ was the text you’re sending as the message. Despite the name smb64 it wasn’t base64 encoded. After forwarding that request, the next was another POST to
In this was the UID of the uploaded file, we will take note of that
17472BB. Again, I forward the request and this POST request was to
/upload.ajax.php. This is where we get to have fun.
There were 11 form-data segments, however for bugs we only need three of them. They were
The first two were just the filename, however one oversight I made was not checking if both fields were needed. The final field was the contents of the file. Now, normally what this is meant to do is write the contents in the
file field to both or either
From now on we’ll refer as
F3 in the same order as they are at the start of this paragraph. We’ll get to this bit after, however if the location of F1/F2 exists then F3 is ignored and instead your UID is assigned to that file. So, if you set F1/F2 to
you will download the passwd file. So, after altering F1 & F2 to the LFI payload we forward the request a few times then turn intercept off. At the bottom the PIN will be displayed, in this case
8936. To start the download, we’ll use the UID and PIN together in the following URL
After this I wondered if I could try find any other pages that might be on the subdomain. I went ahead and started ‘dirsearch’ and one of the pages that came back as 200 OK was
test.php. After going to the page assuming it could be phpinfo, it was a phpdotenv page which fortunately displayed useful information to perform file write, which could include RFI. For this case, the web root was
So now we go through the whole process until we get to our
/upload,ajax.php request, but this time we edit all F1, F2 and F3. So, to confirm the file doesn’t exist so we can write, I went to
POC.txt which resulted in a 404.
F3 doesn’t need to be edit if the file you’re uploading contains what you want to be written. So after setting F1 and F2 to
../../../../../../../var/www/html/script/ggsend/POC.txt sent the rest of the requests and turned intercept off. I went to POC.txt and I still got a 404.
At first I was confused, thinking maybe I can’t upload outside of the web root. I tried going to the download file with the UID and PIN for the upload, which resulted in downloading the same file with the same contents. I went through the whole process again just incase I done something wrong, and the file was there.
This is when it came to me that the file isn’t placed outside of the web root until you attempt to download it. You don’t need to download it either, you can cancel it. As long as it’s prompted it’ll move the file to the web root. It tries to write to the current directory so the path traversal is required, but going all the way back to the file system first is to be on the safe side.
So, after Gucci took down their GLFT page they eventually reuploaded it, however it seemed as if they had fixed a few things. In this section I’ll be correcting anything in the previous section as well as add additions that I didn’t have evidence of, such as the RCE paragraph below.
Of course, if we can write files to the web root it’s time to see if we can get Remote Code Execution. So after we go through the whole process we can upload a phpinfo page so we’re able to see what PHP functions are allowed. We can then go straight through to uploading a simple PHP shell. For this, I used the nice and short code from PentestPartners which is
For me to do this without making the shell potentially available to others, I decided to make the filename a random 16 char string as well as the cmd parameter another random 16 char string. For the case of POC, the filename was “6BFj05qv0Kyi25r0.php” and the paremeter is “UIhh8sft6QxpSM2j”. Going to
Resulted in the following:
The fixes that seemed to have happened is issues with the message body that were included in the Twitter thread that prompted the downtime of GLFT. As for what I could remember about the “From” email being restricted to “@gucci.com” or potentially other Gucci domains, you are able to now send emails from any email, although as I mentioned before this isn’t the real sender.
The first line of the email will contain the information of the file you selected, however all the edited fields in the request are previewed in the second part, as well as the upload progress bar.
I also mentioned that I made an oversight and didn’t check whether either or both
resumableRelativePath were actually needed for LFI or path traversal. Still sticking to the F1 and F2 names respectively, it seems that F2 is redundant.
Only F1 is needed even if both fields have the same filename. I’m unsure as to what can be the actual reason to this, as F2 doesn’t seem to be printed in the email either.
For new things that I learnt was the receiving email does have a invalid email trigger. The TLD can still be invalid, but if it is over 6 characters long it’s classed as invalid, such as: [email protected] is valid, but [email protected] is not.
Along with this, any files uploaded to the web root is still in the upload system and has the expiry applied to it. If you wanted a permanent upload you could edit the expiry in the
calcolaUID.ajax.php request to be a large number, i.e. ‘999999’. This is characterised as days, so this would be just under 2738 years.
Alternatively, you could wget the file using a shell. If you don’t edit the expiry, only the shell would expire but nothing you wget via the shell.
- March 13th 2019 - Found GLFT
- March 14th 2019 - Found the vulnerabilities
- March 15th 2019 - Used Gucci’s contact page
- March 19th 2019 - Requested Disclosure Assistance through HackerOne
- April 29th 2020 - Subdomain was tweeted about
- April 30th 2020 - Gucci removed the upload page
- May 4th 2020 - Gucci reuploaded the upload page
- May 8th 2020 - Completely taken down
- May 9th 2020 - Writeup Release
I should note over the year I have made multiple attempts to contact Gucci regarding this issue. Via their contact form on gucci.com, Disclosure Assistance via HackerOne and tweeting them. Since it’s been over a year it’s way past the recommended responsible disclosure timeframe of 90 days. They’ve had plenty of time to get it fixed but ignored the attempts of contact. Although I suspect legal action may be taken, I have tried and tried again to help them, but they made this the last resort.
Another update is Gucci has blocked my home IP from GLFT. I get a connection time out whilst connecting perfectly on a VPN. Instead of going through the process professionally like the vallued $10.2+ billion company they are. I understand fully that I most likely won’t be getting a reward nor do I want to urge them to.
So, what do we take away from all of this? Well, one thing for sure is if you find an upload tool on a company subdomain it’s possible it’s coded by them and not a public application that’s been tested for the purpose of wide public use. It’s worth checking to see what permissions the HTTPD user has and to fully test what your limitations are when trying to upload and download a file. Also never feel as if you don’t have the ability to find vulnerabilities with web applications, no matter how big the company is. Even if you aren’t going to be paid for the bugs you find, you still get valuable experience out of it.