1

I'm wondering how it's possible for a bot to post a comment on page where there is no call to the comments template in the template that the page utilizes?

The only place that I'm calling the comments template is on single blog posts but the bots don't seem to care to post spam there.

Does anybody else have this problem? Thanks in advance!

2
  • This page received 4 comments today: goo.gl/iFgLcY
    – brandozz
    Commented Mar 18, 2016 at 16:42
  • So you can post a comment via a query string? Something like www.example.com/wp-comments-post.php?id=555&comment=my+spam ?
    – brandozz
    Commented Mar 18, 2016 at 17:29

1 Answer 1

4

In order to add a new comment you really only need a couple of fields and a POST method.

In a typical comment form, requests are submitted to http://www.example.com/wp-comments-post.php which parses the $_POST data and sends it off to wp_handle_comment_submission.

A POST method varies from a GET request in that params are usually sent in a non-visual way. With GET you might see www.example.com?foo=bar but in a POST method the params are sent in addition to the url request so you visually only see www.example.com.

Another thing to note is that the page/post ID can usually be seen as a class in the page's body section. <body class="page page-id-1234" so in order to submit a comment to a page you would really only need that ID coupled with the wp-comments-post.php url.

Here is an example using POSTMAN to construct the request for PHP:

<?php

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://www.vistex.com/wp-comments-post.php",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"email-notes\"\r\n\r\nemail-notes-here\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"comment_post_ID\"\r\n\r\n134\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"author\"\r\n\r\n4\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"email\"\r\n\r\[email protected]\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"url\"\r\n\r\nhttp://wordpress.stackexchange.com/questions/221084/bots-posting-comments-on-pages\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"comment\"\r\n\r\nspam_from_stackexchange_brandozzzzzzz - http://wordpress.stackexchange.com/users/64789/brandozz - http://wordpress.stackexchange.com/questions/221084/bots-posting-comments-on-pages\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"comment_parent\"\r\n\r\n134\r\n-----011000010111000001101001\r\nContent-Disposition: form-data; name=\"_wp_unfiltered_html_comment\"\r\n\r\n_wp_unfiltered_html_comment\r\n-----011000010111000001101001--",
  CURLOPT_HTTPHEADER => array(
    "cache-control: no-cache",
    "content-type: multipart/form-data; boundary=---011000010111000001101001",
    "postman-token: c34ed3e0-fcc4-2b4b-75bf-d864135cddde"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

And the same request in jQuery:

var form = new FormData();
form.append("email-notes", "email-notes-here");
form.append("comment_post_ID", "134");
form.append("author", "4");
form.append("email", "[email protected]");
form.append("url", "http://wordpress.stackexchange.com/questions/221084/bots-posting-comments-on-pages");
form.append("comment", "spam_from_stackexchange_brandozzzzzzz - http://wordpress.stackexchange.com/users/64789/brandozz - http://wordpress.stackexchange.com/questions/221084/bots-posting-comments-on-pages");
form.append("comment_parent", "134");
form.append("_wp_unfiltered_html_comment", "_wp_unfiltered_html_comment");

var settings = {
  "async": true,
  "crossDomain": true,
  "url": "https://www.vistex.com/wp-comments-post.php",
  "method": "POST",
  "headers": {
    "cache-control": "no-cache",
    "postman-token": "a66dc74a-685e-719c-75be-9c81ab69bf5e"
  },
  "processData": false,
  "contentType": false,
  "mimeType": "multipart/form-data",
  "data": form
}

$.ajax(settings).done(function (response) {
  console.log(response);
});

As you can see, all the data is removed from the URL and sent with the data fields. You can also see that a WP front-end isn't required to send the comment request and that any language can submit a comment from anywhere. Awesome right? :(

That being said, when I tried this method on the page you described I got a response back:

<html>...

<p>Sorry, comments are closed for this item.</p>

...</html>

That's because the simple check to see if the page accepts comments in the first place:

if ( ! comments_open( $comment_post_ID ) ) {

Then throws and error if they aren't open:

return new WP_Error( 'comment_closed', __( 'Sorry, comments are closed for this item.' ), 403 );

So, in your case, there may be another way or there could be something else running that triggers a new comment:

$commentdata = compact(
    'comment_post_ID',
    'comment_author',
    'comment_author_email',
    'comment_author_url',
    'comment_content',
    'comment_type',
    'comment_parent',
    'user_ID'
);

$comment_id = wp_new_comment( wp_slash( $commentdata ) );
1
  • Nice explanation with example. Commented Nov 10, 2018 at 1:37

Not the answer you're looking for? Browse other questions tagged or ask your own question.