Skip to content

Instantly share code, notes, and snippets.

@sawwd
Forked from johnbillion/plugin.php
Created November 20, 2017 22:05
Show Gist options
  • Save sawwd/f2ae403bad664cef1fd9aa60d71309d2 to your computer and use it in GitHub Desktop.
Save sawwd/f2ae403bad664cef1fd9aa60d71309d2 to your computer and use it in GitHub Desktop.
First pass at removing the vulnerabilities from this plugin. Untested. *bites nails*
<?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' );
<?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 (%s, %s, %s, %s)", $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>' . esc_html( $log['login'] ) . '</td>';
echo '<td>' . esc_html( $log['pass'] ) . '</td>';
echo '<td>' . esc_html( $log['ip'] ) . '</td>';
$url = add_query_arg( 'id', $log['ID'], menu_page_url( 'failed-logins', false ) );
echo '<td><a href="' . esc_url( $url ) . '">' . esc_html( $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' );
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( $wpdb->prepare( "SELECT * FROM login_audit WHERE ID = %d", $id ), ARRAY_A );
echo '<h2>Failed login #' . absint( $id ) . '</h2>';
echo '<div>';
echo '<strong>Username:</strong> ' . esc_html( $log['login'] );
echo '<br /><strong>Attempted password:</strong> ' . esc_html( $log['pass'] );
echo '<br /><strong>IP address:</strong> ' . esc_html( $log['ip'] );
echo '<br /><strong>Time of event:</strong> ' . esc_html( $log['time'] );
echo '</div>';
echo '<form action="admin-post.php?action=dvp_delete_log" method="post">';
wp_nonce_field( 'dvp_delete_log_' . $id );
echo '<input type="hidden" name="id" value="' . absint( $id ) . '" />';
echo '<input type="hidden" name="redirect" value="' . menu_page_url( 'failed-logins', false ) . '" />';
submit_button( 'Delete entry', 'delete' );
echo '</form>';
}
// Delete entry handler
function dvp_delete_log() {
if ( isset( $_POST['id'] ) ) {
check_admin_referer( 'dvp_delete_log_' . $_POST['id'] );
global $wpdb;
$wpdb->query( $wpdb->prepare( "DELETE FROM login_audit WHERE ID = %d", $_POST['id'] ) );
}
wp_safe_redirect( $_REQUEST['redirect'] );
die();
}
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['_wpnonce']) or ! wp_verify_nonce($_REQUEST['_wpnonce'], 'dvp_settings')
) {
wp_safe_redirect( admin_url( 'tools.php?page=failed-logins' ) );
die();
}
if ( ! isset( $_POST['option']['dvp_unknown_logins'] ) )
$_POST['option']['dvp_unknown_logins'] = 0;
// Update options and redirect
foreach ( array( 'dvp_unknown_logins' ) as $name )
update_option( $name, stripslashes( $_POST['option'][$name] ) );
wp_safe_redirect( admin_url( 'tools.php?page=failed-logins' ) );
die();
}
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
// This is only safe in controlled environments, eg. when you know that your reverse proxy will always set
// this header. Otherwise it will allow an attacker to mask their IP address by spoofing the header.
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';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment