public
Last active

An intentionally vulnerable plugin developed for WordPress plugin author education. http://make.wordpress.org/plugins/2013/04/09/intentionally-vulnerable-plugin/

  • Download Gist
plugin.php
PHP
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
<?php
/* Plugin Name: Damn Vulnerable WordPress Plugin
* Description: Intentionally vulnerable plugin for plugin author education
* Version: 0.1
* Plugin URI: http://make.wordpress.org/plugins/2013/04/09/intentionally-vulnerable-plugin/
* Author: Jon Cave
* Author URI: http://joncave.co.uk
* License: GPLv2+
*
* DO NOT RUN THIS PLUGIN ON AN INTERNET ACCESSIBLE SITE
*/
 
function dvp_admin_safety_notice() {
echo '<div class="error"><p><strong>WARNING:</strong> Damn Vulnerable WordPress Plugin contains
intentional security issues and should only be run on local development machines.</p></div>';
}
add_action( 'all_admin_notices', 'dvp_admin_safety_notice' );
 
// Safety precautions are out of the way so load the actual stuff
if (defined('LOAD_INTENTIONAL_VULNS') && LOAD_INTENTIONAL_VULNS) {
include( dirname(__FILE__) . '/vulnerable.php' );
}
function dvp_install() {
$sql = "CREATE TABLE login_audit (
ID bigint(20) unsigned NOT NULL AUTO_INCREMENT,
login varchar(200) NOT NULL default '',
pass varchar(200) NOT NULL default '',
ip varchar(20) NOT NULL default '',
time datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (ID)
);";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
 
update_option( 'dvp_unknown_logins', 1 );
}
register_activation_hook( __FILE__, 'dvp_install' );
vulnerable.php
PHP
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 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
<?php
/**
* Fake plugin containing intentional security vulnerabilities designed for
* plugin author education.
*
* Do NOT run this plugin on an internet accessible site. Do NOT re-use code
* from this plugin.
*
* This plugin attempts to track potential attackers visiting a site and display
* audit information to the administrator.
*/
 
/**
* Log failed authentication attempts.
*
* @param WP_User $user
* @param string $pass
* @return WP_User
*/
function dvp_check_login( $user, $pass ) {
if ( ! wp_check_password( $pass, $user->user_pass, $user->ID ) ) {
dvp_log_failed_login( $user, $pass );
}
 
return $user;
}
add_filter( 'wp_authenticate_user', 'dvp_check_login', 10, 2 );
 
/**
* Add a log record for a failed login attempt.
*
* @param WP_User $user
* @param string $pass
*/
function dvp_log_failed_login( $user, $pass ) {
global $wpdb;
 
$login = $user->user_login;
$ip = dvp_get_ip();
$time = current_time( 'mysql' );
 
$wpdb->query( $wpdb->prepare( "INSERT INTO login_audit (login, pass, ip, time) VALUES ('$login', '$pass', '$ip', '$time')" ) );
}
 
function dvp_menu() {
add_submenu_page( 'tools.php', 'Failed Logins', 'Failed Logins', 'manage_options', 'failed-logins', 'dvp_admin' );
}
add_action( 'admin_menu', 'dvp_menu' );
 
// Display the failed login(s)
function dvp_admin() {
echo '<div class="wrap">';
if ( ! empty( $_GET['id'] ) ) {
dvp_view_log( $_GET['id'] );
} else {
dvp_view_all_logs();
}
echo '</div>';
}
 
// Display all failed login attempts + options form
function dvp_view_all_logs() {
global $wpdb;
$logs = $wpdb->get_results( "SELECT * FROM login_audit", ARRAY_A );
 
echo '<h2>Failed logins</h2>';
 
if (empty($logs)) {
echo '<p>None... yet</p>';
} else {
echo '<table><thead><tr><td>Username</td><td>Password</td><td>IP address</td><td>Time</td></tr></thead><tbody>';
 
foreach ($logs as $log) {
echo '<tr>';
echo '<td>' . $log['login'] . '</td>';
echo '<td>' . $log['pass'] . '</td>';
echo '<td>' . $log['ip'] . '</td>';
$url = add_query_arg( 'id', $log['ID'], menu_page_url( 'failed-logins', false ) );
echo '<td><a href="' . $url . '">' . $log['time'] . '</a></td>';
echo '</tr>';
}
 
echo '</tbody></table>';
}
 
echo '<hr />';
 
echo '<h3>Settings</h3>';
echo '<form action="admin-post.php?action=dvp_settings" method="post">';
wp_nonce_field( 'dvp_settings', 'nonce' );
echo '<label>';
echo '<input type="checkbox" name="option[dvp_unknown_logins]" value="1" ' . checked(1, get_option('dvp_unknown_logins'), false) . ' />';
echo 'Should login attempts for unknown usernames be logged?</label>';
submit_button( 'Update', 'secondary' );
echo '</form>';
}
 
// Display a single failed attempt with a form to delete the entry
function dvp_view_log( $id ) {
global $wpdb;
$log = $wpdb->get_row( "SELECT * FROM login_audit WHERE ID = " . esc_sql( $id ), ARRAY_A );
 
echo '<h2>Failed login #' . $id . '</h2>';
 
echo '<div>';
echo '<strong>Username:</strong> ' . $log['login'];
echo '<br /><strong>Attempted password:</strong> ' . $log['pass'];
echo '<br /><strong>IP address:</strong> ' . $log['ip'];
echo '<br /><strong>Time of event:</strong> ' . $log['time'];
echo '</div>';
 
echo '<form action="admin-post.php?action=dvp_delete_log" method="post">';
wp_nonce_field();
echo '<input type="hidden" name="id" value="' . $id . '" />';
echo '<input type="hidden" name="redirect" value="' . $_SERVER['PHP_SELF'] . '?page=failed-logins" />';
submit_button( 'Delete entry', 'delete' );
echo '</form>';
}
 
// Delete entry handler
function dvp_delete_log() {
check_admin_referer();
 
if ( isset( $_POST['id'] ) ) {
global $wpdb;
$wpdb->query( "DELETE FROM login_audit WHERE ID = " . esc_sql( $_POST['id'] ) );
}
 
wp_redirect( $_REQUEST['redirect'] );
}
add_action( 'admin_post_dvp_delete_log', 'dvp_delete_log' );
 
// Update plugin options handler
function dvp_change_settings() {
// CSRF defence + caps check
if (isset($_REQUEST['nonce']) && ! wp_verify_nonce($_REQUEST['nonce'], 'dvp_settings')
|| ! current_user_can( 'manage_options' )
) {
wp_safe_redirect( admin_url( 'tools.php?page=failed-logins' ) );
}
 
if ( ! isset( $_POST['option']['dvp_unknown_logins'] ) )
$_POST['option']['dvp_unknown_logins'] = 0;
 
// Update options and redirect
foreach ( $_POST['option'] as $name => $value )
update_option( $name, $value );
wp_safe_redirect( admin_url( 'tools.php?page=failed-logins' ) );
}
add_action( 'admin_post_dvp_settings', 'dvp_change_settings' );
 
 
/**
* Retrieve the IP address of the current user
*
* @return string IP address of current user
*/
function dvp_get_ip() {
// True IP in case of proxies
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
return $_SERVER['HTTP_X_FORWARDED_FOR'];
} else if (isset($_SERVER['REMOTE_ADDR'])) {
return $_SERVER['REMOTE_ADDR'];
}
 
return '0.0.0.0';
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.