I had an older version of YetiShare laying around, and decided to see if I could find anything fun to play with. Since I made quite a few findings, I decided to write about most of them here instead of making separate articles about each of them. It was hard at first to figure out a way to confirm the findings in the newer versions since I didn’t have a license. But with the help of others; including YetiShare themselves, I was able to fully confirm everything. I will probably be writing a separate article later about other findings that were made, since I made new findings in the patched release they made. They gave me a license to the latest version for me to review, and then more was found and reported. I would like to thank the support at MFScripts (The makers of YetiShare) for being so patient with me and my continuous rambling and spamming about new discoveries; but when I get into the flow … there’s just no stopping it. I will try to keep this article light and just describe shortly about each finding, then you can find the technical details in the respective Github repository. I also want to mention that I did not have access to any versions below v3.5.2, but older versions are likely to be vulnerable as well.
SQL injection in multiple places v3.5.2–v4.5.3
Many of the functions in the administrator interface sends a request in the background to fetch some data. This background request has several parameters for sorting and filtering out the data it retrieves. Most if not all of the functions that does this in said interface, uses the same format; and so the same vulnerability was present in all of them. The parameter sSortDir_0 was put straight into the SQL query, unfiltered, and then the query was executed. It was argued that this was not very serious since it’s in the admin interface, but it could be used together with other attacks to “trick” an administrator into running malicious queries (a so called Cross-site request forgery).
[00:19:10] [INFO] testing connection to the target URL
sqlmap resumed the following injection point(s) from stored session:
Parameter: sSortDir_0 (GET)
Type: boolean-based blind
Title: MySQL >= 5.0 boolean-based blind - ORDER BY, GROUP BY clause
Type: stacked queries
Title: MySQL >= 5.0.12 stacked queries (comment)
Type: time-based blind
Title: MySQL >= 5.1 time-based blind (heavy query - comment) - PROCEDURE ANALYSE (EXTRACTVALUE)
[00:19:10] [INFO] testing MySQL
[00:19:10] [INFO] confirming MySQL
[00:19:10] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Apache 2.4.7, PHP 5.5.9
back-end DBMS: MySQL >= 5.0.0
[00:19:10] [INFO] fetching current user
[00:19:10] [INFO] retrieved: root@localhost
SQL injection in fileIds parameter v3.5.2
This one is similar to above but only affected the version I had and possibly older versions. It’s different however, in the way that it does not require an administrators account to execute it. Still I found it suitable to report it in case anyone is running 3.5.2 or below and might want to be alerted about it.
Password reset hash brute-force v3.5.2–v4.5.3
So, in this case the string that is created and then sent in a link to the users email when a password reset is requested, used a weak method of creating said string. It was possible to trigger the password reset for a user, and then guess the string within a few hours. The proof-of-concept on Github can be optimized to make it go even faster, but it proves my point. The function that does the actual reset of the password, requires the string (hash) and the user id. The user id of the administrator account is always 1, and to get the email to trigger the actual reset function in the first place one could either just figure that out in some other way, or just assume that the administrator account used the default one, since one is set automatically during install.
user@ayu:~/Desktop$ php guess.php
[+] Creating range and starting attack, this can take an hour or so
[+] Got 1575725248. Testing 0.57667000 - 0.93107200
[+] New password set: password2
Special thanks to Andreas Gustafsson for pointing out that the microtime() function in PHP always has two zeros at the end of the microseconds part of the string (0.57667000), and to Robin Gustafsson for helping in further explaining why that mattered (I’m slow so I didn’t get it at first. What I thought they meant at first was that they wanted me to remove the zeros, which would make the resulting string not match the needed result set). Thanks to this, the estimated time for guessing the hash went down from about 48 hours to just under 1 hour (It can be optimized to be faster).
Missing cookie flags v3.5.2–v4.5.3
Basically the session cookie was missing needed flags to keep the session safe from certain attacks. The HttpOnly flag makes sure that the browser wont allow scripts to access the cookie, thus protection it from cross-site scripting attacks (XSS). The Secure flag tells the browser to only send the cookie over a secure (HTTPS) channel; meaning without it, if there are resources loaded within the same domain that go over a clear text protocol like HTTP (maybe the site loads images like this), the cookie would be sent in clear text. Anyone listening on said clear text protocol, could then fetch the cookie and munch it. The SameSite flag tells the browser to not send the cookie in cross-site requests. All of the flags were missing, however.
User enumeration via forgot password v3.5.2–v4.5.3
While discussing the above findings with the support, I found these two. They are simple attacks but can be used by a persistent attacker to get information about what users are in the system. The first one is that the forgot password page simply displays a message telling you if a user exists in the database or not based on the email.
The second issue was actually a timing one. The process of creating the reset hash and sending the email takes longer than it does when the email does not exist. So if a user exists, it would take longer time. The difference is small, but large enough for an attacker to get a hunch (even if above mentioned issue was to be fixed).
Cross-site scripting v3.5.2–v4.5.3
Two different cross-site scripting points were found that could be used (for instance) in combination with the missing cookie flags, to steal user sessions. In this first case, there was one in the log viewer in the administration interface. The examples are simple and just runs the most simplest of scripts that shows a popup with a 1 in it.
The second one was in get_all_file_server_paths.ajax.php, although the file name and path differs between versions. More details on that plus the full example can be found in the Github repositories above.
Timeline (90 days by default)
- 2019–12–09 — Reported to vendor
- 2019–12–11 — Vendor releases update
- 2019–12–17 — Vendor agrees on disclosure on the 23rd for some findings
- 2020–03–09 — Deadline
But wait, there’s more!
During the review of YetiShare, there were more findings. Some were made when I reviewed the fixes to the above issues, and some were just made later or will take longer time to fix; thus the need for a longer disclosure date. All of this is being released with the vendor’s permission within the 90-day disclosure window. As soon as they allow it, or the time runs out (they can extend the time as well as I follow Googles guidelines on this); I will release the rest of the findings. Their latest fixed release as of me writing this, is 4.5.4 and can be downloaded at https://yetishare.com/.
So until the next batch of little bugs is to be released, I wish you a Merry Christmas ❤.