01563: Security Vulnerability in EditTemplate
Description: I've found another bug in "pmwiki.php" involving an unfiltered variable. It's difficult to assess the severity of the bug because, although it is possible to output the contents of any file, the chain of conditions required to do so is very long.
This concerns the "EditTemplate()" function. In line 3190, the value from $_REQUEST['template'] is passed in unfiltered.
This value is passed on to "PageExists()" until we finally end up in "PageStore->pagefile".
In line 2039, the slash "/" is converted to a dot "."
This prevents the process from escaping the directory under Linux.
In Windows, however, directories are separated by a backslash "\". In other words, it is possible to deviate from the specified directories. Back to the "EditTemplate()" function. On line 3193, the system searches for the keyword "text" and, if found, adopts it. Therefore, content can only be displayed on Windows if the line begins with "text=".
Example using Windows: (The version doesn't matter.)
The web server is PHP itself and can be found at "C:\php\php.exe." PmWiki is located in the "C:\php\www\pmwiki" directory.
On my desktop, there is a file named "test.txt" with the content "text=Anyone who reads this is stupid."
I start the web server with "php -S 0.0.0.0:8080 -t www router.php" and open PmWiki in the Edge browser with a blank page:
http://localhost:8080/pmwiki/pmwiki.php?n=Main.NewPage.
Now I add the attack code:
http://localhost:8080/pmwiki/pmwiki.php?n=Main.NewPage&template=..\..\..\..\users\user\desktop\test.txt?action=edit.
And I see my text appear.
What happened? With "..\", I moved out of the "wiki.d" directory and into the parent directory. I repeat this four times until I end up in the root directory. From there, I can navigate further. But I can't exit the drive letter.
In summary: You need to know the path where PmWiki is installed on Windows and the location of a text file containing the content you're interested in, which starts with "text="—I'd classify that as difficult.
I would fix the bug in three different places:
- First, on line 3190: There, the variable
$rqtshould be filtered using a regular expression. - On lines 1523, 1843, and 2039, I would replace str_replace('/', '.', ...) with preg_replace('![/\\\\]!', '.', ...).
- In the "PageStore->read()" function (line 2061), I would also ensure that only PmWiki code can be loaded.
Wiki pages have a key name with content in every line.
For example, "version=...", "text=...", "time=..." .
I would now add an optional security variable that specifies how to handle unexpected content:
- 0 -> Everything is loaded, regardless of what it is (current behavior).
- 1 -> If the line does not begin with "key=", it is ignored. (I would recommend it)
- 2 -> As soon as a line does not begin with "key=", the process is aborted. (Maximum Security Level)
That would kill the problem three ways.
This is an interesting catch, thanks! The request template value should be converted to a page name, then it should be safe, now added to the prerelease. I cannot test it on Windows, please report if it is fixed.
I've also updated PageStore->pagefile() like you suggested, just in case something else calls it with unsafe $pagename. About cb_expandscripturl() and MatchNames(), they are unrelated. About read(), a line's key may also contain timestamps and other properties before "=", and if it doesn't have "=", the whole line becomes the key in the $page['whole line'] entry with an empty value, and it does nothing, is ignored by PmWiki (but can be saved back to disk after the page is saved). I have to think about whether this is something wikis or recipes may actually use. --Petko
Yes, I can confirm that the bug has been fixed.
Regarding "cb_expandscripturl()" and "MatchNames()": I simply searched for "str_replace('/'," and listed all the matches.
And as for the "pageStore->read()" function, my basic idea was to prevent the function from reading data that clearly doesn’t belong to PmWiki. – I mean, with that vulnerability, I could have read any file into PmWiki—even binary files. (Unfortunately, they weren’t displayed.)
Michael Engelke