Secure Coding with WordPress Mark Jaquith markjaquith.com coveredwebservices.com
Jan 12, 2015
Secure Coding with WordPress
Mark Jaquithmarkjaquith.com
coveredwebservices.com
XSSCSRFSQL injection
privilege escalation
shell execution
Plugin security is hit-or-miss
Mostly miss
SQL Injection
<?php$wpdb->query( "UPDATE $wpdb->posts SET post_title = '$newtitle' WHERE ID = $my_id" );?>
<?php$newtitle = $wpdb->escape( $newtitle );$my_id = absint( $my_id );
$wpdb->query( "UPDATE $wpdb->posts SET post_title = '$newtitle' WHERE ID = $my_id" );?>
$wpdb->update()
<?php$wpdb->update( $wpdb->posts, array( 'post_title' => $newtitle ), array( 'ID' => $my_id ) );?>
$wpdb->insert()
<?php$wpdb->insert( $wpdb->posts, array( 'post_title' => $newtitle ) );?>
<?php$wpdb->update( $wpdb->posts, array( 'post_title' => $newtitle, 'post_content' => $newcontent ), array( 'ID' => $my_id, 'post_title' => $old_title ) );?>
<?php$post_title = 'New Title';$wheres['ID'] = 123;$wheres['post_title'] = 'Old Title';$wpdb->update( $wpdb->posts, compact( 'post_title' ), $wheres );?>
$wpdb->prepare()
<?php$title = 'Post Title';$ID = 123;$content = $wpdb->get_var( $wpdb->prepare( "SELECT post_content FROM $wpdb->posts WHERE post_title = %s AND ID = %d", $title, $ID ) );?>
•Uses sprintf() formatting
•%s for strings
•%d for integers
•You should not quote or escape
Escapelate
XSS
<h1><?php echo $title;?></h1>
<?php $title = '<script> pwnage(); </script>'?><h1><?php echo $title;?></h1>
Anything that isn’t hardcoded
is suspect
Better:Everything is suspect
wp_specialchars()
<?php $title = '<script> pwnage(); </script>'?><h1><?php echo wp_specialchars( $title );?></h1>
<?php$title = '" onmouseover="pwnd();';?><a href="#wordcamp" title="<?php echo wp_specialchars( $title );?>">Link Text</a>
attribute_escape()
<?php$title = '" onmouseover="pwnd();';?><a href="#wordcamp" title="<?php echo attribute_escape( $title );?>">Link Text</a>
<?php $url = 'javascript:pwnage();';?><a href="<?php echo attribute_escape( $url );?>">Link Text</a>
clean_url()
<?php $url = 'javascript:pwnage();';?><a href="<?php echo clean_url( $url );?>">Link Text</a>
sanitize_url(), sister of clean_url()
js_escape()
CSRF
Authorizationvs.
Intention
Noncesaction-, object-,
user-specific time limited secret keys
Specific to •WordPress user
•Action attempted
•Object of attempted action
•Time window
wp_nonce_field()
<form action="process.php" method="post"><?php wp_nonce_field('plugin-action_object');?>
...</form>
check_admin_referer( )
<?php// before output goes to browsercheck_admin_referer('plugin- action_object');?>
Still need to use current_user_can()
AJAXCSRF
• wp_create_nonce( 'your_action' );
• &_ajax_nonce=YOUR_NONCE
• check_ajax_referer( 'your_action' );
Privilege Escalation
current_user_can()
Set your salts!http://api.wordpress.org/secret-key/1.1/
Stupid shit I see all the time
exec()
<form action="<?php echo $_SERVER['REQUEST_URI']; ?>">
Thank you!