Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
wso2-rce-cve-2022-29464 | Kitploit
Strumenti/GitHubGitHub/tufanturhan/wso2-rce-cve-2022-29464
Generazione di PayloadAnalisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebPenetration Testing
GitHubtufanturhan/wso2-rce-cve-2022-29464

wso2-rce-cve-2022-29464

Vedi Repository
24 anni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2022-29464

Exploit per WSO2 RCE (CVE-2022-29464).

Dettagli

CVE-2022-29464 è una vulnerabilità critica su WSO2 scoperta da Orange Tsai. La vulnerabilità è un upload arbitrario di file non autenticato e senza restrizioni che consente ad attaccanti non autenticati di ottenere RCE sui server WSO2 caricando file JSP dannosi.

la route di upload vulnerabile è /fileupload, gestita da FileUploadServlet che è una route non protetta come si può vedere nel file di configurazione indentity.xml:```xml

root@kitploit:~
il `FileUploadServlet` e, al momento di [`init`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/FileUploadServlet.java#L71) e attraverso una serie di chiamate ai metodi, carica infine dal file di configurazione `carbon.xml` molteplici formati/azioni di upload dei file insieme all'oggetto che gestisce ogni formato.```java
    public void init(ServletConfig servletConfig) throws ServletException {
        this.servletConfig = servletConfig;
        try {
            fileUploadExecutorManager = new FileUploadExecutorManager(bundleContext, configContext, webContext);
            //Registering FileUploadExecutor Manager as an OSGi service
            bundleContext.registerService(FileUploadExecutorManager.class.getName(), fileUploadExecutorManager, null);
        } catch (CarbonException e) {
            log.error("Exception occurred while trying to initialize FileUploadServlet", e);
            throw new ServletException(e);
        }
    }

il costruttore della classe FileUploadExecutorManager è il seguente:```java public FileUploadExecutorManager(BundleContext bundleContext, ConfigurationContext configCtx, String webContext) throws CarbonException { this.bundleContext = bundleContext; this.configContext = configCtx; this.webContext = webContext; this.loadExecutorMap(); }

root@kitploit:~
il costruttore chiama il metodo privato [`loadExecutorMap()`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/FileUploadExecutorManager.java#L131) che è il punto in cui viene eseguito il caricamento della configurazione:```java
    private void loadExecutorMap() throws CarbonException {
        [snipped]
                try {
            documentElement = XMLUtils.toOM(serverConfiguration.getDocumentElement());
        } catch (Exception e) {
            String msg = "Unable to read Server Configuration.";
            log.error(msg);
            throw new CarbonException(msg, e);
        }
        [snipped]
        OMElement fileUploadConfigElement =
                documentElement.getFirstChildWithName(
                        new QName(ServerConstants.CARBON_SERVER_XML_NAMESPACE, "FileUploadConfig"));
        for (Iterator iterator = fileUploadConfigElement.getChildElements(); iterator.hasNext();) {
            OMElement mapppingElement = (OMElement) iterator.next();
            if (mapppingElement.getLocalName().equalsIgnoreCase("Mapping")) {
                OMElement actionsElement =
                        mapppingElement.getFirstChildWithName(
                                new QName(ServerConstants.CARBON_SERVER_XML_NAMESPACE, "Actions"));
                String confPath = System.getProperty(CarbonBaseConstants.CARBON_CONFIG_DIR_PATH);
        [snipped]

le configurazioni dei formati di upload dei file si trovano nel namespace FileUploadConfig nel file di configurazione XML, questa è la configurazione predefinita:```xml 100

root@kitploit:~
    <Mapping>
        <Actions>
            <Action>keystore</Action>
            <Action>certificate</Action>
            <Action>*</Action>
        </Actions>
        <Class>org.wso2.carbon.ui.transports.fileupload.AnyFileUploadExecutor</Class>
    </Mapping>

    <Mapping>
        <Actions>
            <Action>jarZip</Action>
        </Actions>
        <Class>org.wso2.carbon.ui.transports.fileupload.JarZipUploadExecutor</Class>
    </Mapping>
    <Mapping>
        <Actions>
            <Action>dbs</Action>
        </Actions>
        <Class>org.wso2.carbon.ui.transports.fileupload.DBSFileUploadExecutor</Class>
    </Mapping>
    <Mapping>
        <Actions>
            <Action>tools</Action>
        </Actions>
        <Class>org.wso2.carbon.ui.transports.fileupload.ToolsFileUploadExecutor</Class>
    </Mapping>
    <Mapping>
        <Actions>
            <Action>toolsAny</Action>
        </Actions>
        <Class>org.wso2.carbon.ui.transports.fileupload.ToolsAnyFileUploadExecutor</Class>
    </Mapping>
</FileUploadConfig>
root@kitploit:~
il metodo `loadExecutorMap()` crea e popola una `HashMap` di `<Action, Class>` con le Action e le Class estratte dal file di configurazione, che verrà poi utilizzata per scegliere quale classe usare per gestire correttamente un determinato formato/azione.

Successivamente, quando la rotta `/fileupload` riceve una richiesta POST, viene chiamato il metodo [`doPost()`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/FileUploadServlet.java#L53) del servlet. Il metodo si limita a inoltrare gli oggetti request e response al metodo `execute()` di `fileUploadExecutorManager`, che è stato inizializzato in `init()`.```java
    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);
        }
    }

il metodo execute(), divide l'URL della richiesta subito dopo la stringa fileupload/, il che significa che estrae tutto ciò che si trova dopo /fileupload/ nell'URL della richiesta e lo assegna a actionString.```java public boolean execute(HttpServletRequest request, HttpServletResponse response) throws IOException {

root@kitploit:~
    HttpSession session = request.getSession();
    String cookie = (String) session.getAttribute(ServerConstants.ADMIN_SERVICE_COOKIE);
    request.setAttribute(CarbonConstants.ADMIN_SERVICE_COOKIE, cookie);
    request.setAttribute(CarbonConstants.WEB_CONTEXT, webContext);
    request.setAttribute(CarbonConstants.SERVER_URL,
                         CarbonUIUtil.getServerURL(request.getSession().getServletContext(),
                                                   request.getSession()));


    String requestURI = request.getRequestURI();

    //TODO - fileupload is hardcoded
    int indexToSplit = requestURI.indexOf("fileupload/") + "fileupload/".length();
    String actionString = requestURI.substring(indexToSplit);

    // Register execution handlers
    FileUploadExecutionHandlerManager execHandlerManager =
            new FileUploadExecutionHandlerManager();
    CarbonXmlFileUploadExecHandler carbonXmlExecHandler =
            new CarbonXmlFileUploadExecHandler(request, response, actionString);
    execHandlerManager.addExecHandler(carbonXmlExecHandler);
    OSGiFileUploadExecHandler osgiExecHandler =
            new OSGiFileUploadExecHandler(request, response);
    execHandlerManager.addExecHandler(osgiExecHandler);
    AnyFileUploadExecHandler anyFileExecHandler =
            new AnyFileUploadExecHandler(request, response);
    execHandlerManager.addExecHandler(anyFileExecHandler);
    execHandlerManager.startExec();
    return true;
}
root@kitploit:~
l'`actionString` viene passato al costruttore della classe `CarbonXmlFileUploadExecHandler` insieme a `request` e `response`:```java
        private CarbonXmlFileUploadExecHandler(HttpServletRequest request,
                                               HttpServletResponse response,
                                               String actionString) {
            this.request = request;
            this.response = response;
            this.actionString = actionString;
        }

il costruttore li salverà nelle sue proprietà. dopo di che l'oggetto carbonXmlExecHandler insieme ad altri oggetti verrà aggiunto a execHandlerManager usando il metodo addExecHandler().```java public void addExecHandler(FileUploadExecutionHandler handler) { if (prevHandler != null) { prevHandler.setNext(handler); } else { firstHandler = handler; } prevHandler = handler; }

root@kitploit:~
quindi viene chiamato `execHandlerManager.startExec()`:```java
        public void startExec() throws IOException {
            firstHandler.execute();
        }

startExec() chiama execute() del primo oggetto aggiunto, che è CarbonXmlFileUploadExecHandler:```java public void execute() throws IOException { boolean foundExecutor = false; for (String key : executorMap.keySet()) { if (key.equals(actionString)) { AbstractFileUploadExecutor obj = executorMap.get(key); foundExecutor = true; obj.executeGeneric(request, response, configContext); break; } } if (!foundExecutor) { next(); } }

root@kitploit:~
[`execute()`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/FileUploadExecutorManager.java#L430) scorre la `HashMap` di `<Action, Class>` creata in precedenza e trova l'Action (chiave) uguale a `actionString`; se trovata, viene chiamato il metodo `executeGeneric()` dell'oggetto associato a quell'Action.
Per ricapitolare, la configurazione predefinita ha 7 azioni, che sono:
* `keystore`, `certificate`, `*` gestite da `org.wso2.carbon.ui.transports.fileupload.AnyFileUploadExecutor`
* `jarZip` gestita da `org.wso2.carbon.ui.transports.fileupload.JarZipUploadExecutor`
* `dbs` gestita da `org.wso2.carbon.ui.transports.fileupload.DBSFileUploadExecutor`
* `tools` gestita da `org.wso2.carbon.ui.transports.fileupload.ToolsFileUploadExecutor`
* `toolsAny` gestita da `org.wso2.carbon.ui.transports.fileupload.ToolsAnyFileUploadExecutor`
Ciascuno di questi oggetti gestisce l'upload in modo diverso; alcuni di essi accettano estensioni specifiche. 

Il primo che ho trovato vulnerabile alla scrittura arbitraria di file è stato `toolsAny` ([`ToolsAnyFileUploadExecutor`](https://github.com/wso2/carbon-kernel/blob/4.4.x/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/ToolsAnyFileUploadExecutor.java)).
`ToolsAnyFileUploadExecutor` non ha un metodo `executeGeneric()`, ma estende [`AbstractFileUploadExecutor`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/AbstractFileUploadExecutor.java#L61), che invece ha un metodo [`executeGeneric()`](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/AbstractFileUploadExecutor.java#L97):```java
    boolean executeGeneric(HttpServletRequest request,
                           HttpServletResponse response,
                           ConfigurationContext configurationContext) throws IOException {//,
        //    CarbonException {
        this.configurationContext = configurationContext;
        try {
            parseRequest(request);
            return execute(request, response);
        } catch (FileUploadFailedException e) {
            sendErrorRedirect(request, response, e);
        } catch (FileSizeLimitExceededException e) {
            sendErrorRedirect(request, response, e);
        } catch (CarbonException e) {
            sendErrorRedirect(request, response, e);
        }
        return false;
    }

executeGeneric() chiama prima parseRequest() con l'oggetto request come parametro:```java protected void parseRequest(HttpServletRequest request) throws FileUploadFailedException, FileSizeLimitExceededException { fileItemsMap.set(new HashMap<String, ArrayList>()); formFieldsMap.set(new HashMap<String, ArrayList>());

root@kitploit:~
    ServletRequestContext servletRequestContext = new ServletRequestContext(request);
    boolean isMultipart = ServletFileUpload.isMultipartContent(servletRequestContext);
    Long totalFileSize = 0L;

    if (isMultipart) {

        List items;
        try {
            items = parseRequest(servletRequestContext);
        } catch (FileUploadException e) {
            String msg = "File upload failed";
            log.error(msg, e);
            throw new FileUploadFailedException(msg, e);
        }
        boolean multiItems = false;
        if (items.size() > 1) {
            multiItems = true;
        }

        // Add the uploaded items to the corresponding maps.
        for (Iterator iter = items.iterator(); iter.hasNext();) {
            FileItem item = (FileItem) iter.next();
            String fieldName = item.getFieldName().trim();
            if (item.isFormField()) {
                if (formFieldsMap.get().get(fieldName) == null) {
                    formFieldsMap.get().put(fieldName, new ArrayList<String>());
                }
                try {
                    formFieldsMap.get().get(fieldName).add(new String(item.get(), "UTF-8"));
                } catch (UnsupportedEncodingException ignore) {
                }
            } else {
                String fileName = item.getName();
                if ((fileName == null || fileName.length() == 0) && multiItems) {
                    continue;
                }
                if (fileItemsMap.get().get(fieldName) == null) {
                    fileItemsMap.get().put(fieldName, new ArrayList<FileItemData>());
                }
                totalFileSize += item.getSize();
                if (totalFileSize < totalFileUploadSizeLimit) {
                    fileItemsMap.get().get(fieldName).add(new FileItemData(item));
                } else {
                    throw new FileSizeLimitExceededException(getFileSizeLimit() / 1024 / 1024);
                }
            }
        }
    }
}
root@kitploit:~
assicura innanzitutto che la richiesta POST sia una richiesta POST multipart, poi estrae i file caricati, verifica che la richiesta POST contenga almeno un file caricato e lo valida rispetto alla dimensione massima del file.
dopo il ritorno da `parseRequest()`, `executeGeneric()` chiamerà ora il metodo `execute()` che è [sovrascritto](https://github.com/wso2/carbon-kernel/blob/d47232dfb2b26c0ef18a74e2ef4aa503caa59697/core/org.wso2.carbon.ui/src/main/java/org/wso2/carbon/ui/transports/fileupload/ToolsAnyFileUploadExecutor.java#L36) da `ToolsAnyFileUploadExecutor`:```java
	@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;
	}

È qui che si trova il bug, il metodo execute() è vulnerabile a una path traversal poiché si fida del nome file fornito dall'utente nella richiesta POST. senza che la path traversal esca dalla directory tmp il file viene effettivamente salvato in:``` ./tmp/work/extra/$uuid/$filename

root@kitploit:~
con `uuid` restituito nella risposta:

![image](https://assets.kitploit.com/production/public/readmes/33730/46ab2e31428a23ca42c93423c5c2a7508cb72c7e508d0a7e5405a35c27a4f619.png)

il file può essere trovato in:

![image](https://assets.kitploit.com/production/public/readmes/33730/49f94872497ef3ce08545f18bf26a84e60729c3ad0faef81819d2af8adf44f1d.png)

Ora dobbiamo solo uscire dalla directory `tmp` e aggiungere la nostra shell JSP in una posizione servita da WSO2. una di queste posizioni è `./repository/deployment/server/webapps`:
![image](https://assets.kitploit.com/production/public/readmes/33730/0b60e9e33d9ed74a78436d46e069d59fa84c773cd381c729400d6fc811c8ce09.png)

questa directory contiene più applicazioni WAR distribuite e anche file WAR grezzi. una di quelle applicazioni WAR è `authenticationendpoint` che gestisce l'autenticazione a WSO2 e la sua posizione è `./repository/deployment/server/webapps/authenticationendpoint`:
![image](https://assets.kitploit.com/production/public/readmes/33730/ec6897e79bbb927cd87141ba9fd07d303ffe35f3c075c53982da6c3f3126bb52.png)

# PoC
![image](https://assets.kitploit.com/production/public/readmes/33730/f18951e9acbdfdbd282f6c83037d849069b2225774598bd70d1a135ff83bdc1c.png)

![image](https://assets.kitploit.com/production/public/readmes/33730/b513180803a0562bebfc66ea9dca8572ea6f9f8bc63a898c4e32cb811b0c2ebc.png)

![image](https://assets.kitploit.com/production/public/readmes/33730/0d02bf7c174a316d5acbdc73c245cefc1a9ee00d54887a3306f6a897708474f5.png)
Scarica lo strumento