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

PHP Hurts Programmers (and other tales)

PHP Hurts Programmers (and other tales)

Find out some of the sneaky ways the web’s favourite language-to-hate can give unsuspecting users just enough rope to hang themselves with. Take a slightly deeper dive into a few real-world bugs, and see how to (hopefully) avoid them in your own code.

Links from the end:

PHP The Right Way - http://www.phptherightway.com/
PHP: A fractal of bad design

https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
WordPress vulnerability discussed:
https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html
Simple Machine Forums vulnerability discussed:
https://www.alertlogic.com/blog/writing-exploits-for-exotic-bug-classes-php-type-juggling/
ExpressionEngine vulnerability
https://foxglovesecurity.com/2017/02/07/type-juggling-and-php-object-injection-and-sqli-oh-my/
OWASP Resources
Both of these are “work in progress” / drafts
https://www.owasp.org/index.php/PHP_Security_Cheat_Sheet
https://www.owasp.org/index.php/PHP_Configuration_Cheat_Sheet
https://www.owasp.org/index.php/PHP_Object_Injection
PHP Configuration Checker (php.ini)
https://github.com/sektioneins/pcc
All about shell escaping & php
https://gist.github.com/Zenexer/40d02da5e07f151adeaeeaa11af9ab36
List of static analysis tools for PHP
https://github.com/exakat/php-static-analysis-tools
Gary Bernhardt’s “WAT” talk
https://www.destroyallsoftware.com/talks/wat

Keith Humm

March 29, 2017
Tweet

Other Decks in Programming

Transcript

  1. PHP Hurts Programmers
    And other tales

    View Slide

  2. $ whoami
    Keith Humm
    Button Actuator

    Solvam Corporation Ltd

    @spronkey

    View Slide

  3. “you pull out the hammer, but to your
    dismay, it has the claw part on both sides”

    View Slide

  4. • The language itself
    • Dangerous stdlib & extensions
    • PHP deployment & php.ini

    View Slide

  5. • The language itself
    • Dangerous stdlib & extensions
    • PHP deployment & php.ini

    View Slide

  6. Type Juggling
    “a variable's type is
    determined by the context in
    which the variable is used”

    View Slide

  7. Type Juggling
    when PHP screws with your
    variables


    View Slide

  8. > $x = “2 plus 3”; string(8)“2 plus 3”
    > $x += 1; int(3)
    > $x *= 0.333; double(0.999)
    > $x = $x && true; bool(true)

    View Slide

  9. > “foo” == TRUE true
    > “foo” == 0 true
    > TRUE == 0 false
    > “55” == “055” true
    > 55 != 055 true
    *https://www.destroyallsoftware.com/talks/wat
    WAT.

    View Slide

  10. C. A. R. Hoare
    Invented quicksort
    … and the null pointer
    “The most important property of a program is
    whether it accomplishes the intention of its
    user.”

    View Slide

  11. Real World Example #1
    Type Juggling → WordPress Rest API content injection
    https://blog.sucuri.net/2017/02/content-injection-
    vulnerability-wordpress-rest-api.html

    View Slide

  12. • Posts have an integer id property that’s
    populated by URL router
    • WordPress sometimes prioritises HTTP GET and
    POST vars instead
    • WordPress inconsistent in usage of router id vs
    request id
    /wp-json/wp/v2/posts/123
    /wp-json/wp/v2/posts/123?id=456haxxed

    View Slide

  13. > update_item_permissions_check() {

    $post = get_post( $request_id );


    if($post && ) {

    return WP_Error 

    }


    return true;

    }
    • Our request_id, 456haxxed is nonsense
    • So no $post is found
    • Skip right through to return true;

    View Slide

  14. > update_item() {

    $id = (int) $request_id;

    $post = get_post( $id );

    if($post) do_update_stuff();

    }

    View Slide

  15. View Slide

  16. > update_item() {

    $id = (int) $request_id;

    $post = get_post( $id );

    if($post) do_update_stuff();

    }
    /wp-json/wp/v2/posts/123?id=456haxxed
    hax0red j00r bl0g

    View Slide

  17. Rule #1
    Rules are hard to
    remember

    View Slide

  18. How to protect
    yourself

    View Slide

  19. ✓ Avoid type juggling wherever possible

    Use strict comparison operators e.g. ===
    ✓ Use the right tools for the job

    i.e. hash_equals for timing-safe string comparison
    ✓ … don’t forget to use them for things like CSRF tokens
    ✓ Consider promoting primitives to objects

    i.e. function verify(ResetToken $t) : boolean
    ✓ Consider phpdoc annotations & static analysis

    /** @returns boolean **/

    https://github.com/exakat/php-static-analysis-tools
    ✓ Read www.phptherightway.com

    View Slide

  20. • The language itself
    • Dangerous stdlib & extensions
    • PHP deployment & php.ini

    View Slide

  21. > array_filter($input, $callback)

    array_map($callback, $input)

    mostly just annoying
    ✓ Use the newer OO APIs where available
    ✓ Consider third party libs e.g. underscore-php for
    fnprog

    View Slide

  22. > strip_tags()
    > strip_tags($str, $allowable_tags)

    welcome to the land of XSS
    ✓ Use HTMLPurifier or OWASP AntiSammy
    ✓ Check that your template engine does too

    View Slide

  23. > addslashes()

    when all you have is a hammer, 

    everything looks like a nail.
    ✓ Use an escaping technique fit for purpose -
    whether you are escaping for the shell, or SQL

    View Slide

  24. > (pre 7.0) mysql_escape_string()

    totally insecure. deprecated in 2002 (!)

    still works in PHP 5.6 (!?!)
    > (mysql/mysqli)_real_escape_string()

    be very careful—don’t trust this with your life
    ✓ Use PDO, and PDO::quote
    ✓ Use prepared statements / parameterised queries
    ✓ Try not to build SQL with _printf()

    View Slide

  25. > escapeshellarg()

    Sometimes OK in controlled env

    But it’s impossible to use safely in all envs
    > escapeshellcmd()

    Completely insecure

    Actually undermines previous sanitisation
    ✓ Never use escapeshellcmd
    ✓ Avoid functions that use it internally - mail(), system() etc.
    ✓ Avoid shelling out if you can
    ✓ Use pcntl extension with pcntl_fork and pcntl_exec

    View Slide

  26. > unserialize()

    Not for user input, ever

    Potentially lets users control code execution
    ✓ Never unserialise() user input
    ✓ Use an interchange format instead
    ✓ JSON, Protobufs, Msgpack, Thrift are all good choices

    View Slide

  27. > include() / require()

    A bit of a relic. There’s a better way™
    ✓ Use PHP’s autoloader
    ✓ Use PSR-1 or PSR-4 and Composer

    View Slide

  28. > mcrypt

    Most popular* crypto extension.
    Unmaintained since 2007.
    ✓ Use libsodium (+Halite), or OpenSSL instead
    ✓ Use random_bytes or ircmaxell\RandomLib for csprng
    ✓ Don’t roll your own crypto!

    View Slide

  29. Real World Example #2
    Type Juggling → Bypass authentication in “Simple
    Machine Forums”
    https://www.alertlogic.com/blog/writing-exploits-for-
    exotic-bug-classes-php-type-juggling/

    View Slide

  30. • Code verifying a password recovery token
    • Tokens generated randomly and emailed to user
    • User input hashed, then first 10 chars are
    compared
    if ( 

    substr(md5($input), 0, 10)

    == 

    substr($storedHash, 0, 10)

    )

    View Slide

  31. > substr($storedHash,0,10) string “0e12345678”
    > $input = “190539”;
    > substr(md5($input),0,10) string “0e25261622”
    > (“0e12345678” == “0e25261622”) → bool(?)

    View Slide

  32. > substr($storedHash,0,10) string “0e12345678”
    > $input = “190539”;
    > substr(md5($input),0,10) string “0e25261622”
    > (“0e12345678” == “0e25261622”) → bool(true)
    gained admin access

    View Slide

  33. • Hashes can look like scientific notation
    “0e12345678”
    • == operator may coerce either/both sides to ints
    • …if they “look like numbers”
    if ( 

    substr(md5($input), 0, 10)

    == 

    substr($storedHash, 0, 10)

    )

    View Slide

  34. View Slide

  35. Real World Example #3
    Type Juggling → Object Injection → SQLi

    in Expression Engine
    https://foxglovesecurity.com/2017/02/07/type-juggling-
    and-php-object-injection-and-sqli-oh-my/

    View Slide

  36. • Cookie $payload storing serialised PHP objects
    • Cookie signed with $signature, supplied in cookie itself
    • Valid signature in theory shows cookie untampered
    • sess_crypt_key is private
    • But $payload is entirely user controlled
    if (
    md5( $payload . $this->sess_crypt_key )
    ==
    $signature
    )

    View Slide

  37. • unserialize() sets username to an actual
    instance of EE’s Token\Variable class,
    instead of a plain string
    • System passes username from the new object
    to EE’s SQL engine where()
    a:1:{s:13:”:new:username”;O:67:"EllisLab\\\
    \\ExpressionEngine\\\\\Library\\\\\Parser\\
    \\\Conditional\\\\\Token\\\\Variable":1:{s:
    6:"lexeme";s:1:"'; DROP TABLE `users`;”;}}

    View Slide

  38. • EE’s SQL escape routine allows __toString()
    of this object to be included in query verbatim
    • Instance’s state can be crafted as needed by
    adjusting serialised data
    a:1:{s:13:”:new:username”;O:67:"EllisLab\\\
    \\ExpressionEngine\\\\\Library\\\\\Parser\\
    \\\Conditional\\\\\Token\\\\Variable":1:{s:
    6:"lexeme";s:1:"'; DROP TABLE `users`;”;}}

    View Slide

  39. Don’t roll your own
    cryptography

    View Slide

  40. • The language itself
    • Dangerous stdlib & extensions
    • PHP deployment & php.ini

    View Slide

  41. > @fopen(‘http://non-existant.file', ‘r’);
    • allow_url_fopen controls whether this works at all
    • … unless it’s in disable_functions
    • @ operator suppresses the does-not-exist warning
    • … unless scream.enabled is set in php.ini
    • … or it was set with ini_set()
    • error_reporting setting can also alter this

    View Slide

  42. • display_errors

    Whether errors are output to the browser
    • allow_url_include

    Whether you can include() code from a remote URL
    • allow_url_fopen

    Whether fopen() can load remote files (use cURL!)
    • session.use_cookies

    Whether sessions use cookies or URL parameters
    • zend.multibyte

    Allows encodings like SJIS/BIG5 to be used for source files

    View Slide

  43. ✓ You must control your environment
    ✓ …or trust whoever does
    ✓ Make environment config part of your deployment
    ✓ Consider Suhosin if running third party apps
    ✓ Be careful with Apache mod_php

    What if a user uploads dodgy_script.php7 ?
    ✓ Use php.ini security analysis tools

    e.g. https://github.com/sektioneins/pcc 


    View Slide

  44. –Porky Pig
    “That’s all folks!”

    View Slide

  45. Link-fu
    • PHP The Right Way - http://www.phptherightway.com/
    • PHP: A fractal of bad design

    https://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/
    • WordPress vulnerability discussed:

    https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html
    • Simple Machine Forums vulnerability discussed:

    https://www.alertlogic.com/blog/writing-exploits-for-exotic-bug-classes-php-type-juggling/
    • ExpressionEngine vulnerability

    https://foxglovesecurity.com/2017/02/07/type-juggling-and-php-object-injection-and-sqli-oh-my/
    • OWASP Resources

    Both of these are “work in progress” / drafts

    https://www.owasp.org/index.php/PHP_Security_Cheat_Sheet 

    https://www.owasp.org/index.php/PHP_Configuration_Cheat_Sheet 

    https://www.owasp.org/index.php/PHP_Object_Injection
    • PHP Configuration Checker (php.ini)

    https://github.com/sektioneins/pcc
    • All about shell escaping & php

    https://gist.github.com/Zenexer/40d02da5e07f151adeaeeaa11af9ab36
    • List of static analysis tools for PHP

    https://github.com/exakat/php-static-analysis-tools
    • Gary Bernhardt’s “WAT” talk

    https://www.destroyallsoftware.com/talks/wat

    View Slide