Présentation du plugin
Le plugin Wordpress Comments Link Optimization (slug: comments-link-optimization
) se présente de cette façon :
Comments Link Optimization what prevent all search engine crawl your comments link.
Comments Link Optimization will modify link below.
Comments author link. Comments content link. Comment Optimize URL will not modify link below.
Visitors reply link. (@user)
La version testée est la 1.10.5 qui date d’il y a 7 ans.
La vulnérabilité
Dans le script comments-link-optimization.php
on trouve une classe du même nom dont le constructeur déclare une fonction d’initialisation :
1
2
3
4
5
6
7
8
9
10
11
12
13
class CommentsLinkOptimization
{
function __construct() {
add_action('init', array($this, 'init'));
add_filter('comment_text', array($this, 'modifyCommentText'), 99);
add_filter('get_comment_author_url', array($this, 'modifyCommentAuthorUrl'), 99);
}
function init() {
load_plugin_textdomain( 'comments-link-optimization' );
$this->checkRedirect();
}
On voit qu’à l’intérieur, la méthode checkRedirect
de la classe est appelée. Cette dernière récupère le paramètre r
qui est normalement une URL et le passe à printHTML
:
1
2
3
4
5
6
7
function checkRedirect() {
$redirect = isset($_GET['r']) ? $_GET['r'] : FALSE;
if( $redirect ){
$this->printHTML(urldecode($redirect));
die();
}
}
Le code de printHTML
est assez long, mais c’est surtout le gros bloc echo
qui nous intéresse :
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
function printHTML($url)
{
$title = __('Redirecting', 'comments-link-optimization');
$jumpContent = sprintf(
/* translators: %s: Html tag <a> */
__('The page will jump to %s after 3 seconds.', 'comments-link-optimization'),
"<a href=\"$url\">$url</a>"
);
$backContent = sprintf(
/* translators: 1: The begin of html tag <a> 2: The end of html tag <a> */
__('If you do not want to visit the page, you can %1$s return to the previous page %2$s .',
'comments-link-optimization'),
'<a href="#" onclick="return goback();">',
'</a>'
);
echo <<<EOT
<html>
<head>
<meta name="robots" content="noindex, nofollow">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>$title</title>
<style type="text/css">
body,td,div,.p,a{font-family:arial,sans-serif}
div,td{color:#000}
.f{color:#6f6f6f}
a:link{color:#00c}
a:visited{color:#551a8b}
a:active{color:red}
div.a{border-top:1px solid #bbb;border-bottom:1px solid #bbb;background:#f2f2f2;margin-top:1em;width:100%}
div.b{padding:0.5em 0;margin-left:10px}
div.c{margin-top:35px;margin-left:35px}
</style>
<script type="text/javascript">
function goback() {window.history.go(-1);return false;}
setTimeout(function(){window.location.href="$url";},3000);
</script>
</head>
<body topmargin=3 bgcolor=#ffffff marginheight=3>
<div class=a><div class=b><font size=+1><b>$title</b></font></div></div><div class=c> $jumpContent
<br><br> $backContent<br><br><br></div>
</body>
</html>
EOT;
}
On voit dans l’appel à echo
que l’URL est affichée telle quelle dans la page sans échappement préalable d’éventuels caractères HTML.
Il s’agit donc d’une vulnérabilité XSS de type reflected.
PoC:
1
http://localhost:8000/?r=%3C%2Fscript%3E%3CScRiPt%3Ealert%28%2Fwms9bnq9ff%2F%29%3C%2FsCrIpT%3E