ÿØÿà JFIF    ÿÛ „ !.%+&8&+/1555$;@;4?.451 4,$,44444444444414444444444444444444444444444444444444ÿÀ  á á" ÿÄ     ÿÄ ?    !1AQaq"2‘¡±ÁðBRbrÑá#‚’¢²3S CñÿÄ   ÿÄ !    !1QAa‘2ÿÚ   ? 5˜Z¯V¦cø)›t/? z¨±>Õ5€¶‹Á¤·¼z¼Ü¬+ñ®v¤¨_ˆR­BFn©—˜ý®ç̝P8gýt·ÉSTŦˆìät?þé¼íìN/Þa)ì–í6ô… Ï¿øÃj´¿KÇü]ÿ ªô¹-eKànëÕHTx}ýSÜ›ÿ ”7Ø×&µ<¦  ¥ÑO¶[Ù¯ä¨ÞÃÿ PZ-¬;#õ|•oaÿ ©CìÞz3˜öː/¤­ñTûIØ}š^ mÓ%ªxˆ¥ÉŸu=Z+ISe¿45™¼u;ú&WØ÷€æßQ™®{|íx*TC“#ZŠìZ§²‹ 6pv…³¿¡äª*áZÐ%ÒOáˆo"x«OHk w±æ+¬V(kMúŸ5Vö«$ ÁrÏbàb57/luR ¸ÑÛj Òµì`Мq­û žICÀÊ•©4€Âcà¨Ï€O´<èÐ:›ù(Ë^L8þ‘ÍÌ#¸Ð_Ì©ÙK(Öz 4¬û+¸;ü’V’84‘¬ÃŽ:[â‡ÔÌáõp¢~§ªlæ£ö{®G>J¼"°‡7¯ÆÉèßû ‹É‹§ÁòÃýâßî ^ƾÙõ‹×óH#«LP½ïX=xÑÍ$|W?•~• îëÔ©ª‹ {ÝT…Kÿ ”hûâá)J*ö˜–ÔU;iÇ€/ ÆþjóZ\ýwØ=Ìm ºèËL9 ýèÆð/¨’¥öo=nË.%Îì ŽÕ¯È|{Oj²ƒE6e/ßdÄõ²Ìâ1O®ò×TsəԸhOMýíMˆ¿¼H˜l²,7Â¥#MF/Úf°Ö½± ¸–dr‹NýÊ íjqx{œÉ ä-È ¦ øÄër¨q°ð †nцýÑÄÆ’mä…n<0È™;ÁÝá¯ÁZƒ7FÀmì­ É&9ˆîéi¶ùN§Y• ÃZãAâ?•‡©‰ , ó¾IŸŠc1 4â&y­&pŠ­6;M À 0¹qç»p.á …ŸÅáK@%6·y6ƒ‰3?”úºŽ‰éX5ªPT §µ!=Mž«Ú½‹ÅgÂSâÉaþÓoö–¯ÁÔìR>5éÿ üs¶ÆUcÌ kÇR ]ÿ ù¬¼«VŽ;Â|‡~¢¦”ÏŰæ {L™Õ°Óv¹ò¸írޡעCÃ!íVÕ {¶»sŒNPg/ "uÕbkm²“$ďå¿é¹§°½æz¯6 †s¿!s–wÚÝ“™Œ °.ûj>·+™Òa…©Œ&rÝÎtÛë긪Ît’LAVp%c Úý[ÄzJ¾ÇàXXç@˜ó<êL]·T˜¾¥1Ó©V‡g´æ½¦Ý@¹óø!_@´ÞâSÁ —S3™•& ]@JHÚý©ZŽ €×æÔr»Áf!‡yÞ4Mv*èÓã_{‘åóUuљØ«Oïé*®EvÑ Œ÷‡U \"㪒ÍK+À 4“M¡ï:0¥5í!'<@î´”>Ç»&Z–ïCCV˜Ì5Šo&îhè.žû |ÓK©h$s6KìŒëã)¹hI¦GïOåóI;ììü#É$Š0…Ææ¥TØ.5­¾gn´ “ÂÖ\:hœ89G)J@„}œ:’Ò{/Š"¦_Æ×7Æ3VÇŠÊa]ÚŒÙ€Ä–=®uÁßâACZƒ§§£ Qnâ:«,×{tyø¬iÛcœÜÄ€H½ÄÍCk´÷šß .W'b¤Íåh]÷€=,Žv×cÚEÚHXJX¶îo¨FÒtèöŸ>ªª6[J®Fµ£sGÁeqõfe\íjÒÐïÄÐGˆe1Ø‹.Ø”‘Ëuø Y­ˆÜ ŽG|zùªüMpDnQWÄ”%JŠ™)â*p@Örš«ÕT2Ð%ˆG#ª„ ·¤!°ŸOTÂT¸aÚ%4&h™LµšØüÐ.F¿²ÐÞ_Ç‚¾ÅÃaÜ÷09Æ q€öy˜v‡85õN÷]¬äѼóS{°_MެúÔ#°Ç¸0åÞè2ëôPcvÆw9®ií1Ä8F™˜à‰´+‰Ik1òÝ7“Ñ×ÒsÝ\x‚h`ÞÑ`ó"|µEcý£n˜h`}GÞ !±ù²Ápü²ß6 0ïi󜵩SÈÇ7˜-ÕURO˜¦´f$ªž-Í6(œ}<„ éc øs]ŽŽ„*—¾ ìdŽ„)méª\¿êÎIg¾ØÞ~I#C/¼¼´EÁÈŽi8“©õådô·>euä ƒ'Ê×लR1ÉJE1ÐAát`t;ÇР%Ý<‡¥„ÍÆ`×Oyó)õiI€ñQaŸ4Ûù\áàaÃÔ¹HÃu¹*k€¦<„e S‡&õÏ B!ŽhüÞ`yj}mªf×\¿ Ç~æ­9‡û\՞Ǖg²1Žû5V7 !àöšm° c`ܬøÇìµÒ'P"?…´Ö,"§^•õލsÔ)6˜sæéÍR¼ ò|Sl”‹7 nPW Gòú÷½§O¯‡„l¡kSÞŒr½PÊ@æ¢pŽ-mÿ #Ÿ˜Àº¶Áä¦;ïÔæ$1££`“Õ>„—·ž)ßð³ñ#Ï Ô$¶œ‰ÊE‹À;÷º ¯«P:Ñ”8–IÊtpÞ3ª“>ê“þës4ò2OÏÕ­±zô†Õ§‰.÷ä¸;¿˜“'œ›žª}«Œ{ª±Ì 9ÔóÞÕ‡0 $íWV3Üì¬ —@kÝ4@¿r¼±½¬™›?øØæ´'Áé®CË3-g$˜ö‡×auÚi´Žp/êÛ æF›Ú2v‹ã¿¿,nB1̨ƃqÞa5͝@&Æû“él÷ \C²½UÍc ¯k×¢U ÖéQå™—-r wô ÞÏ<Ò=&=ÿ Ôê Òêˈt,i—;LîÜ á¸*ÚÃ1$êL•LÍ <É)ýÐà’ ;F™{ƒ™˜€&'}‚ãÄK`¡ÞT@I;®žZóè‚s’7®°›+§O­Åq©é»²9<Ô J ¼9O’HL»Ùïì¸rk¼Ž_ý‘TŸu[²ßÚŒ·ü÷B%¯E ŸÔX5êO´ Ç•€’I0 ÉJX` ñ¹õ%;µŸD‘«´€àwÒ™U ûئžÖö\×®×´8 ½‡ºÐÆÓ§?Àkmœ=;d5*@-ì0F Rªýš[Ü6âö̃ڸr*KA9· u*µæ£?U¸Âêí†8@¦X4 e-ò„0s{ HâUpU?¼mñRa°®a%Ð'tÉ×’\¾ÊÉ]t›h>·(Ë@R¼¡Ãt h}’O÷au<+nT…Ö…MӐ??Óe95 q>í/;&JSû °¯ÊéÞ øƒ*Ã2½Ài&:nôUl=¾¿5eˆ3”ñc|Ú2V”>„»&eE;«ÚäC p¢Û úy 9š[ŒÌx¼擼A&DåÒ¯ˆ¤ÀÌ;"˜ ÏQä¸åhÊ}Ûq«Û0WžÒ|»€ø®öCm5•\ÇÀ§Pe3£]0ÃàLDÉ‰1øªxjgwT‚÷¿LΨK‹›ùs—xˆÜ±µ kæ¸f‰‰ÜGk/LÛØ6d9ò¶ùA{ƒA3š/¬D¬khÓk‰`˜"㯒r¿±Óã jx‡°e}<Ñø\3y:'À•/h½Í€Ç4~g ?Û(¼]v‘ªlKÎâ~?O‚W%{Ì:“'©úNq¾›úo(X’¥¯ˆ nFê{Ç€ü?º'ë ø‹ì Þ09ŒÌç9Æ —ËC`j@ÓÄ(+a‹un¸#ÂꟋ{K`‘ÑÍÍ'à´»/Û,KW;Þ4²þð ï Nm|~fGÏ(…³Ã)«1ö­Õ ¥‡¨©ƒÃ™ü-s=à=U66Ï«Ýc蓦W¹íž®›nÔ%êÇìŒ<#Ü×84ån®Ð ÒåOC` ñânÑs‡¢ç 1õ%Îhì½Ã½® e:ݼUZo™`  ÅZŸŒÊ«ê1ÏÄo$q¹Þ€©ˆhÐÉä¯ñ[!…Ú˜àJ:x2$Íß&PåT£6ç— ‡Í*4Ýšçjÿ ‰É nófÐ ó(L5C•åÆ\rMÒ@ò }y-W}™üýVù—ú¢=Ù”c®‘< M ž ´Phr ¦©TD ‘ù.$´÷O‡‘V2Æò.=IUŒ=ž‡â¬i™aþÓåÙ?òUø'ØÖ•.~* šTŒ!•-×áºTâ®ä#õü'´ eýlYÅÓeÕKÂrT"CÚ@u!Óxƒ{š3€}1¿(r}%«nËamjÑ%ÑNEò v ˜à  σöK³,*º.àzù¨™Ó ÚçâU¦*¿ 9{%Ö¹ njûdaXöb) kÛÆ±ûÓ\°M7ˆÂ=û›ç¿Ã‚­V»Cg–8ÙêE- j)k$º`Ã-ùEýeBÆÇ]c¡°ñty&Òd0nõ'¡W+ƒ*|–øµFa\GQªEAÔp5\Ǽ·¼Ç8·õ -â§Ú[ ‡ uZeÖ 3}×d'+¹:ð+K†Û®s!Ï$úe€<Û”x)1»a­¡LC]¸µík…ÚàA»AYº{†ªS[¦5HÒ7ù --,ísòDØ€èk ÞÀîÜ ò@â( ËNˆë›4ô½•/¦o‡€Û7 ê•ÆêòðÜy'Án½µ á˜ݦ ndeo…[ì¶Ê,¥R³Ä=À±—–ß;£™´ñSâ*g§”ïaið‘Jå~™ÓÞ ß³Õ¢»8x埒²52>AÊb&-÷\7´éÄù€T˜,w;3{ï˜k…à¹ÄqÀ«œ{€\ ˆ¾[´¨јr &Úé„Ívˆ±8†¿]|¬ņ4I×pÞS1ÈÖz‰#Ìv‡G!YNògñ:màTz¢Ý1ô©^O=~ë|5Bã™ç•¼µõ•bÆ@úÕS¬ÈŒ#¬zünrŸ û” Z²•èðV"ÁHÚý©wÝ €7¼Ìu1hÑa3Éä û f$o¿É ™Ú›ÝçnpÒ3äÌ3†Í§,Äï]$‰/pê †«À¼¸e9­Æê_C]žƒ·ý·frÁN«, E=›Çq -‰öŒ:aÏ¿±í&£Í:-} 84‘ÿ eƒQÑeëSsuiA ³g㟥ú£?ÿ ʼn*”“÷aühe:ÊWa@ÒÞk±eØ] F Ô—r.åä˜ @ö¥ªZoÐýYL·¥S²G/‡ñ <~*ZÆ´è>JlòàÛÆ½ÿ 窘ìGN¢:I®KšJp/`íIÁÀõ#Ä-€ö­šµŒoF4|ÆQØÆ@Ì|£Ô…¢À{9˜è½Üó›€ôYÒÎYsið;ís¤€à²ˆ‚4qÉVŒI$ ‰"° æµ8cXGjœˏ¡Aâý•ËÜ¢ûï e·çLx']á"oÅÎê3¯Ç—¹”ó0nå‚âg{Œñ> S´˜îè°g238‚ãköÝfÚd´6Ò€;ò÷±¢™¼›º ¢Æ'¥Ðx'e¬ç ]bÈÆV¢ó‹kýBO ðÊâ$Ÿ!×T 3Mýמ žìٍàÌü‘8÷€àæØ8æ©6‰©L´«…oãpð„~Çk‰!ñ;‹”ÛžÍ àž±z Ÿôû øŸÝužÏ;ÿ #|u6™Þ¬ÚˆÐõA4¶â|ôl|Ê2ŽÇ¤ÝÅÇY.<#Aí.k§hóF‚”Y; M½Ö4hŸ4&›­¿tès´%FìL¥£Ãk‰ÇT¤haÁ¤ÚxfÉ`ÑìË›>i 3t‚:,–+^÷´–{Û–Nxi"x‘Ûg î¨>¥Õ܁ùZH,2Û“:8xÊ¢Çí9.É-Ìâã-=çjwµS˜dütžçwýGòú®®ûº_ˆýx$–¡ãøO EÚÛÏ÷R„×w+3£Á£öUMyR²¹âŒ°š›¸Ñãò9§Ó_Dl+Ùßc›úšGÅÌc†Ž!Ko=¶.‘Îÿ c²(2®V mª.ÿ ¹B›¹å ù„öŸSV>™ü¯$y:G¢Z×àøúdî¹û­·ýÇ´:•c LÍõi_‹ö+ÎæGÊè>OŠ•äž´§Þ{X}¨1ÚTc›»Qþ•êô°t¿OP?eæ~É{5]•ÙR£r5†nZ\ã@ &îJõ ¾àC°þV>fé¥/ü5ñÊIº_é5 ;e­h<@ Ä&æÃëE%;X,ÒãÆÞ`Oò¦kŸm#˜!ÀyÄ¢| óLšò¥Ä` ¶R=|ÈCâh5ò3DˆïF†ðÒ#ÅìÛœ?¸yhBãœí ZxßÎÄhºRK„`Þödvײ™ÀÈÑÒgŒuY w³%†ƒÓzõ ÖÏp‚dH®¦A´ù§»ÓÇMæ~)ˆð‡û:ù&Ä •vGD´À n ݇¼Ö8Fö óáà£~Ë¥x`oK|Ä?fxiØü%pìR>éò+Û±éÎ>núlFŤ'tq8LZÏvÃ?„¡ß±È⽆¯³íü@x|PöUäèØã¡ð‚ŒAìÏ"vÍwóŸÍ{ ý0.z È•Ö{,N¡£¡ŸKÕÙž>Ýœþ ÍÀ°<×EA!Å‚D™IúOÍ¡>ôG}Â` ÍßkÜL™Ž Þð™ {IøF²¹òQ3&!ÃÂÞz.d&Ï-sH¸,Ôõ˜ŽP€ 77ˆÝ¼ÊëÜw =cÕ Ú,ØÐ5ÎYÐ)ì´öœgŒ[¤ßv㙑8心>h]§µháYš£²ºÑ.{Ï7Sð•?´~×SÃKýJÛ˜ ™Íäiúu<µX¶1õ^kâçIÑ£sZ4h>j*ÔšD:4­¿_ ÷¸ Õxæÿ ¸?Mù _•­ÊÐ ä ÷ý ÑwL œ­ïnTkÛUÍN©ë:¦fV ¶ÜÔÜMªÅâA½–¿R×TXš-%iTÊT•‡Ù‚JôϐZxWÑè‰f‰òG º ×Õû2aZ7OU3[“×AT–ÞŒ…-‘¤”Ì ì&(ˆ¿­•ƒkï’:ðY¦W‘ Å)“†‘˜³Åtcø˜ñTÂwÚÇ4|üLÇªí–v- qˆèU qPE.†â‘˜µ Æ,ÐÅs]8¾„oúÑ i>ÜxxÈó)ƒ ´æÁâØ$À‰vžŸf$Ž |ãw;ÀÁIJ»b` {¦Ó¤Ú$©YÀ‘n@Óïž«9J¼êG m¤ ܯ¹ÌW4€ÐÒÅÛ‡#褕Ÿn-?í|с¥÷Ú¹¬'´ÞÜ9ÓK `hê£SÄSà?7—Wí_´…óB›»:=Ãïq`<8ñÓŒÑlú2d¬ê³£hÖ[l|$vÝro~'R®‰§°ñmY ͧäP |PUª¹·:3Œ[Û{Xÿ ºâ@‚W–Äé u‚ ¯´*=íή.pûÒdt @G‰¬ s¸ ëÉücr ÞæÑ¨Ê@>¤¢Ö±. Þ'¯°ÌME[YéïĵÂCå½ Ué©Áû'Ê9%eÔðNU”ë‘ÌsD3/®+UI˜9h.WC”빓$#:pz:YÓ ¿xž* ³$Í +$kñAŠ‹†¢ Uê>¸)_š¬÷©ßAÂÔb9ÇU ¯¾á•9¯ÏÏ÷O÷¼¼Fähal1‰3Ì[Ïr•´UCksNÐ] R‘¸¥H+§Šé†c©vÖÞ0iÓ76s†î!§=ß ¼~Ô'°Ãmäoäš³ªøi1úÉ)³yV8 CLÄØÁ‘WYïi€H6ÖÑiámø^ÈY´°Ñ7¥Û*—Ñ©L«Qƒï—Ùrÿ ›£Ð*š¸ˆL©ˆ$ˆ ÷¾D§9È®«qbqC)–ˆïv´çñsÑVT­Ø, <àïºÀO«Jý·õ àfPìð .wFšir´þ’2_Y *Æ€x\« ì€9š@ Ž|F⇥ˆkZ@hÖÄ0t¿-<“‹qµ¾*ZL¤Ú)&BJpÓF5=$„at*Zš$’ÑtdûÝRI1 2މ$€$I$#‰SÞ’Hë¬ï;Á$¡t$’`<(ñÇt)$‡Ð.Êf¢X’Kt=Éé$‚ˆªè¢oÝëòI%Rgcª÷ŠyI%¡‰ÿ !ñ)´õ $¤ Ô’IIGÿÙ--- -- The VNC library provides some basic functionality needed in order to -- communicate with VNC servers, and derivatives such as Tight- or Ultra- -- VNC. -- -- Summary -- ------- -- The library currently supports the VNC Authentication security type only. -- This security type is supported by default in VNC, TightVNC and -- "Remote Desktop Sharing" in eg. Ubuntu. For servers that do not support -- this authentication security type the login method will fail. -- -- Overview -- -------- -- The library contains the following classes: -- -- o VNC -- - This class contains the core functions needed to communicate with VNC -- -- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html -- @author Patrik Karlsson -- Version 0.1 -- Created 07/07/2010 - v0.1 - created by Patrik Karlsson local bits = require "bits" local match = require "match" local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" local table = require "table" local tableaux = require "tableaux" _ENV = stdnse.module("vnc", stdnse.seeall) local HAVE_SSL, openssl = pcall(require,'openssl') VENCRYPT_SUBTYPES = { PLAIN = 256, TLSNONE = 257, TLSVNC = 258, TLSPLAIN = 259, X509NONE = 260, X509VNC = 261, X509PLAIN = 262, X509SASL = 263, TLSSASL = 264, } VENCRYPT_SUBTYPES_STR = { [256] = "Plain", [257] = "None, Anonymous TLS", [258] = "VNC auth, Anonymous TLS", [259] = "Plain, Anonymous TLS", [260] = "None, Server-authenticated TLS", [261] = "VNC auth, Server-authenticated TLS", [262] = "Plain, Server-authenticated TLS", [263] = "SASL, Server-authenticated TLS", [264] = "SASL, Anonymous TLS", } local function process_error(socket) local status, tmp = socket:receive_buf(match.numbytes(4), true) if( not(status) ) then return false, "VNC:handshake failed to retrieve error message" end local len = string.unpack(">I4", tmp) local status, err = socket:receive_buf(match.numbytes(len), true) if( not(status) ) then return false, "VNC:handshake failed to retrieve error message" end return false, err end local function first_of (list, lookup) for i=1, #list do if tableaux.contains(lookup, list[i]) then return list[i] end end end -- generalized output formatter for security types and subtypes local function get_types_as_table (types, lookup) local tmp = {} local typemt = { __tostring = function(me) return ("%s (%s)"):format(me.name, me.type) end } for i=1, types.count do local t = {name = lookup[types.types[i]] or "Unknown security type", type=types.types[i]} setmetatable(t, typemt) table.insert( tmp, t ) end return tmp end VNC = { versions = { ["RFB 003.003"] = "3.3", ["RFB 003.007"] = "3.7", ["RFB 003.008"] = "3.8", -- Mac Screen Sharing, could probably be used to fingerprint OS ["RFB 003.889"] = "3.889", }, sectypes = { INVALID = 0, NONE = 1, VNCAUTH = 2, RA2 = 5, RA2NE = 6, TIGHT = 16, ULTRA = 17, TLS = 18, VENCRYPT = 19, GTK_VNC_SASL = 20, MD5 = 21, COLIN_DEAN_XVP = 22, MAC_OSX_SECTYPE_30 = 30, MAC_OSX_SECTYPE_35 = 35, MSLOGON = 0xfffffffa, }, -- Security types are fetched from the rfbproto.pdf sectypes_str = { [0] = "Invalid security type", [1] = "None", [2] = "VNC Authentication", [5] = "RA2", [6] = "RA2ne", [16]= "Tight", [17]= "Ultra", [18]= "TLS", [19]= "VeNCrypt", [20]= "GTK-VNC SASL", [21]= "MD5 hash authentication", [22]= "Colin Dean xvp", -- Mac OS X screen sharing uses 30 and 35 [30]= "Apple Remote Desktop", [35]= "Mac OS X security type", [0xfffffffa] = "UltraVNC MS Logon", }, new = function(self, host, port, socket) local o = { host = host, port = port, socket = socket or nmap.new_socket(), } o.socket:set_timeout(5000) setmetatable(o, self) self.__index = self return o end, --- Connects the VNC socket connect = function(self) return self.socket:connect(self.host, self.port, "tcp") end, --- Disconnects the VNC socket disconnect = function(self) return self.socket:close() end, --- Performs the VNC handshake and determines -- * The RFB Protocol to use -- * The supported authentication security types -- -- @return status, true on success, false on failure -- @return error string containing error message if status is false handshake = function(self) local status, data = self.socket:receive_buf(match.pattern_limit("[\r\n]+", 16), true) if not status or not string.match(data, "^RFB %d%d%d%.%d%d%d[\r\n]") then stdnse.debug1("ERROR: Not a VNC port. Banner: %s", data) return false, "Not a VNC port." end data = data:sub(1,11) local vncsec = { count = 1, types = {} } if ( not(status) ) then return status, "ERROR: VNC:handshake failed to receive protocol version" end self.protover = VNC.versions[data] local cli_version = data if ( not(self.protover) ) then stdnse.debug1("ERROR: VNC:handshake unsupported version (%s)", data) self.protover = string.match(data, "^RFB (%d+%.%d+)") --return false, ("Unsupported version (%s)"):format(data:sub(1,11)) local versions = { "RFB 003.003", "RFB 003.007", "RFB 003.008", "RFB 003.889", } for i=1, #versions do if versions[i] >= data then break end cli_version = versions[i] end end self.client_version = VNC.versions[cli_version or "RFB 003.889"] status = self.socket:send( (cli_version or "RFB 003.889") .. "\n" ) if ( not(status) ) then stdnse.debug1("ERROR: VNC:handshake failed to send client version") return false, "ERROR: VNC:handshake failed" end if ( self.client_version == "3.3" ) then local status, tmp = self.socket:receive_buf(match.numbytes(4), true) if( not(status) ) then return false, "VNC:handshake failed to receive security data" end vncsec.types[1] = string.unpack(">I4", tmp) self.vncsec = vncsec -- do we have an invalid security type, if so we need to handle an -- error condition if ( vncsec.types[1] == 0 ) then return process_error(self.socket) end else local status, tmp = self.socket:receive_buf(match.numbytes(1), true) if ( not(status) ) then stdnse.debug1("ERROR: VNC:handshake failed to receive security data") return false, "ERROR: VNC:handshake failed to receive security data" end vncsec.count = string.unpack("B", tmp) if ( vncsec.count == 0 ) then return process_error(self.socket) end status, tmp = self.socket:receive_buf(match.numbytes(vncsec.count), true) if ( not(status) ) then stdnse.debug1("ERROR: VNC:handshake failed to receive security data") return false, "ERROR: VNC:handshake failed to receive security data" end for i=1, vncsec.count do table.insert( vncsec.types, (string.unpack("B", tmp, i)) ) end self.vncsec = vncsec end return true end, --- Creates the password bit-flip needed before DES encryption -- -- @param password string containing the password to process -- @return password string containing the processed password createVNCDESKey = function( self, password ) -- exactly 8 chars needed if #password > 8 then password = password:sub(1,8) elseif #password < 8 then password = password .. string.rep('\0', 8 - #password) end return password:gsub(".", function(c) return string.char(bits.reverse(c:byte())) end) end, --- Encrypts a password with the server's challenge to create the challenge response -- -- @param password string containing the password to process -- @param challenge string containing the server challenge -- @return the challenge response string encryptVNCDES = function (self, password, challenge) local key = self:createVNCDESKey(password) return openssl.encrypt("des-ecb", key, nil, challenge, false) end, sendSecType = function (self, sectype) return self.socket:send( string.pack("B", sectype)) end, --- Attempts to login to the VNC service using any supported method -- -- @param username string, could be anything when VNCAuth is used -- @param password string containing the password to use for authentication -- @param authtype The VNC auth type from the VNC.sectypes table (default: best available method) -- @return status true on success, false on failure -- @return err string containing error message when status is false login = function( self, username, password, authtype ) if ( not(password) ) then return false, "No password was supplied" end if not authtype then if self:supportsSecType( VNC.sectypes.NONE ) then self:sendSecType(VNC.sectypes.NONE) return self:login_none() elseif self:supportsSecType( VNC.sectypes.VNCAUTH ) then self:sendSecType(VNC.sectypes.VNCAUTH) return self:login_vncauth(username, password) elseif self:supportsSecType( VNC.sectypes.TLS ) then self:sendSecType(VNC.sectypes.TLS) return self:login_tls(username, password) elseif self:supportsSecType( VNC.sectypes.VENCRYPT ) then self:sendSecType(VNC.sectypes.VENCRYPT) return self:login_vencrypt(username, password) elseif self:supportsSecType( VNC.sectypes.TIGHT ) then self:sendSecType(VNC.sectypes.TIGHT) return self:login_tight(username, password) elseif self:supportsSecType( VNC.sectypes.MAC_OSX_SECTYPE_30 ) then self:sendSecType(VNC.sectypes.MAC_OSX_SECTYPE_30) return self:login_ard(username, password) else return false, "The server does not support any matching security type" end elseif ( not( self:supportsSecType( authtype ) ) ) then return false, string.format( 'The server does not support the "%s" security type.', VNC.sectypes_str[authtype]) end end, login_none = function (self) if self.client_version == "3.8" then return self:check_auth_result() end -- nothing to do here! return true end, --- Attempts to login to the VNC service using VNC Authentication -- -- @param username string, could be anything when VNCAuth is used -- @param password string containing the password to use for authentication -- @return status true on success, false on failure -- @return err string containing error message when status is false login_vncauth = function( self, username, password ) local status, chall = self.socket:receive_buf(match.numbytes(16), true) if ( not(status) ) then return false, "Failed to receive authentication challenge" end local resp = self:encryptVNCDES(password, chall) status = self.socket:send( resp ) if ( not(status) ) then return false, "Failed to send authentication response to server" end return self:check_auth_result() end, check_auth_result = function(self) local status, result = self.socket:receive_buf(match.numbytes(4), true) if ( not(status) ) then return false, "Failed to retrieve authentication status from server" end if string.unpack(">I4", result) ~= 0 then return false, "Authentication failed" end return true end, handshake_aten = function(self, buffer) -- buffer is 24 bytes, currently unused, no idea what it's for. if #buffer ~= 24 then return false end self.aten = buffer return true end, login_aten = function(self, username, password) username = username or "" self.socket:send(username .. ("\0"):rep(24 - #username) .. password .. ("\0"):rep(24 - #password)) return self:check_auth_result() end, handshake_tight = function(self) -- TightVNC security type -- https://vncdotool.readthedocs.org/en/0.8.0/rfbproto.html#tight-security-type -- Sometimes also ATEN KVM VNC: -- https://github.com/thefloweringash/chicken-aten-ikvm local status, buf = self.socket:receive_bytes(4) if not status then return false, "Failed to get number of tunnels" end -- If it's ATEN, it sends 24 bytes right away. Need to try parsing these -- in case it's TightVNC instead, though. local aten = #buf == 24 and buf local ntunnels, pos = string.unpack(">I4", buf) -- reasonable limits: ATEN might send a huge number here if ntunnels > 0x10000 then return self:handshake_aten(aten) end local tight = { tunnels = {}, types = {} } if ntunnels > 0 then local have = #buf - pos + 1 if have < 16 * ntunnels then local newbuf status, newbuf = self.socket:receive_bytes(16 * ntunnels - have) if not status then if aten then return self:handshake_aten(aten) end return false, "Failed to get list of tunnels" end buf = buf .. newbuf aten = false -- we must have read something beyond 24 bytes end local have_none_tunnel = false for i=1, ntunnels do local tunnel = {} tunnel.code, tunnel.vendor, tunnel.signature, pos = string.unpack(">I4 c4 c8", buf, pos) if tunnel.code == 0 then have_none_tunnel = true end tight.tunnels[#tight.tunnels+1] = tunnel end -- at this point, might still be ATEN with a first byte of 1, but chances are it's Tight if have_none_tunnel then -- Try the "NOTUNNEL" tunnel, for simplicity, if it's available. self.socket:send("\0\0\0\0") else -- for now, just return the first one. TODO: choose a supported tunnel type self.socket:send(string.pack(">I4", tight.tunnels[1].code)) end end local have = #buf - pos + 1 if have < 4 then local newbuf status, newbuf = self.socket:receive_bytes(4 - have) if not status then if aten then return self:handshake_aten(aten) end return false, "Failed to get number of Tight auth types" end buf = buf .. newbuf if #buf > 24 then aten = false end end local nauth nauth, pos = string.unpack(">I4", buf, pos) -- reasonable limits: ATEN might send a huge number here if nauth > 0x10000 then return self:handshake_aten(aten) end if nauth > 0 then have = #buf - pos + 1 if have < 16 * nauth then local newbuf status, newbuf = self.socket:receive_bytes(16 * nauth - have) if not status then if aten then return self:handshake_aten(aten) end return false, "Failed to get list of Tight auth types" end buf = buf .. newbuf if #buf > 24 then aten = false end end for i=1, nauth do local auth = {} auth.code, auth.vendor, auth.signature, pos = string.unpack(">I4 c4 c8", buf, pos) tight.types[#tight.types+1] = auth end end if aten and pos < 24 then -- server sent 24 bytes but we could only parse some of them. Probably ATEN KVM return self:handshake_aten(aten) end self.tight = tight return true end, login_tight = function(self, username, password) local status, err = self:handshake_tight() if not status then return status, err end if self.aten then return self:login_aten(username, password) end if #self.tight.types == 0 then -- nothing further, no auth return true end -- choose a supported auth type for _, auth in ipairs({ {1, "login_none"}, {2, "login_vncauth"}, {19, "login_vencrypt"}, }) do for _, t in ipairs(self.tight.types) do if t.code == auth[1] then self.socket:send(string.pack(">I4", t.code)) return self[auth[2]](self, username, password) end end end return false, "The server does not support any supported Tight security type" end, handshake_tls = function(self) local status, err = self.socket:reconnect_ssl() if not status then return false, "Failed to reconnect SSL" end local status, tmp = self.socket:receive_buf(match.numbytes(1), true) if ( not(status) ) then stdnse.debug1("ERROR: VNC:handshake failed to receive security data") return false, "ERROR: VNC:handshake failed to receive security data" end local vncsec = { count = 1, types = {} } vncsec.count = string.unpack("B", tmp) if ( vncsec.count == 0 ) then return process_error(self.socket) end status, tmp = self.socket:receive_buf(match.numbytes(vncsec.count), true) if ( not(status) ) then stdnse.debug1("ERROR: VNC:handshake failed to receive security data") return false, "ERROR: VNC:handshake failed to receive security data" end for i=1, vncsec.count do table.insert( vncsec.types, (string.unpack("B", tmp, i)) ) end self.vncsec = vncsec return true end, login_tls = function( self, username, password ) local status, err = self:handshake_tls() if not status then return status, err end return self:login(username, password) end, handshake_vencrypt = function(self) local status, buf = self.socket:receive_buf(match.numbytes(2), true) local maj, min, pos = string.unpack("BB", buf) if maj ~= 0 or min ~= 2 then return false, string.format("Unknown VeNCrypt version: %d.%d", maj, min) end self.socket:send(string.pack("BB", maj, min)) status, buf = self.socket:receive_buf(match.numbytes(1), true) status, pos = string.unpack("B", buf) if status ~= 0 then return false, string.format("Server refused VeNCrypt version %d.%d", maj, min) end status, buf = self.socket:receive_buf(match.numbytes(1), true) local nauth, pos = string.unpack("B", buf) if nauth == 0 then return false, "No VeNCrypt auth subtypes received" end -- vencrypt auth types are u32 status, buf = self.socket:receive_buf(match.numbytes(nauth * 4), true) pos = 1 local vencrypt = { count = nauth, types = {} } for i=1, nauth do local auth auth, pos = string.unpack(">I4", buf, pos) table.insert(vencrypt.types, auth) end self.vencrypt = vencrypt return true end, login_vencrypt = function(self, username, password) local status, err = self:handshake_vencrypt() if not status then return status, err end local subauth = first_of({ VENCRYPT_SUBTYPES.TLSNONE, VENCRYPT_SUBTYPES.X509NONE, VENCRYPT_SUBTYPES.PLAIN, VENCRYPT_SUBTYPES.TLSPLAIN, VENCRYPT_SUBTYPES.X509PLAIN, VENCRYPT_SUBTYPES.TLSVNC, VENCRYPT_SUBTYPES.X509VNC, -- These not supported yet --VENCRYPT_SUBTYPES.TLSSASL, --VENCRYPT_SUBTYPES.X509SASL, }, self.vencrypt.types) if not subauth then return false, "The server does not support any supported security type" end self.socket:send(string.pack(">I4", subauth)) local status, buf = self.socket:receive_buf(match.numbytes(1), true) if not status or string.byte(buf, 1) ~= 1 then return false, "VeNCrypt auth subtype refused" end if subauth == VENCRYPT_SUBTYPES.PLAIN then return self:login_plain(username, password) end status, err = self.socket:reconnect_ssl() if not status then return false, "Failed to reconnect SSL to VNC server" end if subauth == VENCRYPT_SUBTYPES.TLSNONE or subauth == VENCRYPT_SUBTYPES.X509NONE then return self:check_auth_result() elseif subauth == VENCRYPT_SUBTYPES.TLSVNC or subauth == VENCRYPT_SUBTYPES.X509VNC then return self:login_vncauth(username, password) elseif subauth == VENCRYPT_SUBTYPES.TLSPLAIN or subauth == VENCRYPT_SUBTYPES.X509PLAIN then return self:login_plain(username, password) elseif subauth == VENCRYPT_SUBTYPES.TLSSASL or subauth == VENCRYPT_SUBTYPES.X509SASL then return self:login_sasl(username, password) end end, login_plain = function(self, username, password) username = username or "" local status = self.socket:send(string.pack(">I4 I4", #username, #password) .. username .. password) if not status then return false, "Failed to send plain auth" end return self:check_auth_result() end, login_sasl = function(self, username, password) -- TODO: support this! return false, "Unsupported" end, login_ard = function(self, username, password) -- Thanks to David Simmons for describing this protocol: -- https://cafbit.com/post/apple_remote_desktop_quirks/ local status, buf = self.socket:receive_bytes(4) if not status then return false, "Failed to get auth material lengths" end local gen, keylen, pos = string.unpack(">I2I2", buf) if #buf - (pos - 1) < 2*keylen then local status, buf2 = self.socket:receive_bytes(2*keylen - #buf) if not status then return false, "Failed to get auth material" end buf = buf .. buf2 end local modulus, pos = string.unpack("c"..keylen, buf, pos) local pubkey, pos = string.unpack("c"..keylen, buf, pos) -- DH key exchange pubkey = openssl.bignum_bin2bn(pubkey) modulus = openssl.bignum_bin2bn(modulus) gen = openssl.bignum_dec2bn(gen) local secret = openssl.bignum_pseudo_rand(512) -- 512 bit DH? yeah, ok. local ourkey = openssl.bignum_mod_exp(gen, secret, modulus) local shared = openssl.bignum_mod_exp(pubkey, secret, modulus) -- Pad shared secret with nulls shared = openssl.bignum_bn2bin(shared) shared = ('\0'):rep(keylen - #shared) .. shared -- Generate AES key as MD5 of shared DH secret local aeskey = openssl.md5(shared) -- Encrypt username and password with AES in ECB mode local blob = username .. ('\0'):rep(64 - #username) .. password .. ('\0'):rep(64 - #password) local hash = openssl.encrypt('aes-128-ecb', aeskey, '', blob, false) -- Send encrypted blob and DH public key local tmpkey = openssl.bignum_bn2bin(ourkey) -- pad public key on the left with nulls self.socket:send(hash .. ('\0'):rep(keylen - #tmpkey) .. tmpkey) return self:check_auth_result() end, --- Returns all supported security types as a table -- -- @return table containing a entry for each security type getSecTypesAsTable = function( self ) return get_types_as_table(self.vncsec, VNC.sectypes_str) end, getVencryptTypesAsTable = function (self) return get_types_as_table(self.vencrypt, VENCRYPT_SUBTYPES_STR) end, --- Checks if the supplied security type is supported or not -- -- @param sectype number containing the security type to check for -- @return status true if supported, false if not supported supportsSecType = function( self, sectype ) for i=1, self.vncsec.count do if ( self.vncsec.types[i] == sectype ) then return true end end return false end, --- Returns the protocol version reported by the server -- -- @param version string containing the version number getProtocolVersion = function( self ) return self.protover end, --- Send a ClientInit message. --@param shared boolean determining whether the screen should be shared, or whether other logged-on users should be booted. --@return status true if message was successful, false otherwise --@return table containing contents of ServerInit message, or error message. client_init = function (self, shared) self.socket:send(shared and "\x01" or "\x00") local status, buf = self.socket:receive_buf(match.numbytes(24), true) if not status then return false, "Did not receive ServerInit message" end local width, height, bpp, depth, bigendian, truecolor, rmax, gmax, bmax, rshift, gshift, bshift, pad1, pad2, namelen, pos = string.unpack(">I2I2 BBBB I2I2 I2BB BI2B I4", buf) local status, buf = self.socket:receive_buf(match.numbytes(namelen), true) if not status then return false, "Did not receive ServerInit desktop name" end local name = buf:sub(1,namelen) return true, { width = width, height = height, bpp = bpp, depth = depth, bigendian = bigendian, truecolor = truecolor, rmax = rmax, gmax = gmax, bmax = bmax, rshift = rshift, gshift = gshift, bshift = bshift, name = name } end } if not HAVE_SSL then local login_unsupported = function() return false, "Login type unsupported without OpenSSL" end VNC.login_vncauth = login_unsupported VNC.login_tls = login_unsupported VNC.login_ard = login_unsupported end local unittest = require "unittest" if not unittest.testing() then return _ENV end test_suite = unittest.TestSuite:new() -- Crypto tests require OpenSSL if HAVE_SSL then local test_vectors = { -- from John the Ripper's vnc_fmt_plug.c -- pass, challenge, response { "1234567890", "\x2f\x75\x32\xb3\xef\xd1\x7e\xea\x5d\xd3\xa0\x94\x9f\xfd\xf1\xd8", "\x0e\xb4\x2d\x4d\x9a\xc1\xef\x1b\x6e\xf6\x64\x7b\x95\x94\xa6\x21" }, { "123", "\x79\x63\xf9\xbb\x7b\xa6\xa4\x2a\x08\x57\x63\x80\x81\x56\xf5\x70", "\x47\x5b\x10\xd0\x56\x48\xe4\x11\x0d\x77\xf0\x39\x16\x10\x6f\x98" }, { "Password", "\x08\x05\xb7\x90\xb5\x8e\x96\x7f\x2a\x35\x0a\x0c\x99\xde\x38\x81", "\xae\xcb\x26\xfa\xea\xaa\x62\xd7\x96\x36\xa5\x93\x4b\xac\x10\x78" }, { "pass\xc2\xA3", "\x84\x07\x6f\x04\x05\x50\xee\xa9\x34\x19\x67\x63\x3b\x5f\x38\x55", "\x80\x75\x75\x68\x95\x82\x37\x9f\x7d\x80\x7f\x73\x6d\xe9\xe4\x34" }, } for _, v in ipairs(test_vectors) do test_suite:add_test(unittest.equal( VNC:encryptVNCDES(v[1], v[2]), v[3]), v[1]) end end return _ENV