ÿØÿà 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ÿÙ--- -- DRDA Library supporting a very limited subset of operations. -- -- Summary -- * The library currently provides functionality to: (1) Query the server for -- basic settings using the getServerInfo function of the helper -- class. (2) Authenticate to a DB2 server using a plain-text username and -- password. -- -- The library contains the following classes: -- * DRDA -- ** Implements the Distributed Relational Database Architecture class . -- * DRDAParameter -- ** Implements a number of functions to handle DRDA parameters. -- * DDM -- ** Implements the DDM portion of the DRDA structure -- * Command -- ** Provides functions for easy creation of the most common DRDAs. -- ** Implemented as a static class that returns an instance of the DRDA. -- * Helper -- ** A helper class that provides easy access to the rest of the library -- * DB2Socket -- ** A smallish socket wrapper that provides fundamental buffering -- * StringUtil -- ** Provides EBCDIC/ASCII conversion functions -- * Comm -- ** Provides fundamental communication support (send/receive DRDAPacket) -- * DRDAPacket -- ** A class holding one or more DRDA's and provides some basic access methods -- -- The following sample code illustrates how scripts can use the Helper class -- to interface with the library: -- -- -- db2helper = drda.Helper:new() -- status, err = db2helper:connect(host, port) -- status, res = db2helper:getServerInfo() -- status, err = db2helper:close() -- -- -- The implementation is based on packet dumps and the excellent decoding -- provided by Wireshark. -- -- There is some documentation at -- http://publib.boulder.ibm.com/infocenter/dzichelp/v2r2/topic/com.ibm.db29.doc.drda/db2z_drda.htm. -- -- @copyright Same as Nmap--See https://nmap.org/book/man-legal.html -- @author Patrik Karlsson -- -- -- Version 0.2 -- Created 05/08/2010 - v0.1 - created by Patrik Karlsson -- Revised 07/27/2010 - v0.2 - Added the comm class and made a few improvements -- to sending and receiving packets. Changed the -- helper login method to support: -- x IBM DB2 -- x Apache Derby -- x IBM Informix Dynamic Server local match = require "match" local nmap = require "nmap" local stdnse = require "stdnse" local string = require "string" local table = require "table" _ENV = stdnse.module("drda", stdnse.seeall) -- CodePoint constants CodePoint = { CODEPNT = 0x000c, TYPDEFNAM = 0x002f, TYPDEFOVR = 0x0035, ACCSEC = 0x106d, SECCHK = 0x106e, EXCSAT = 0x1041, PRDID = 0x112e, SRVCLSNM = 0x1147, SVRCOD = 0x1149, SYNERRCD = 0x114a, SRVRLSLV = 0x115a, EXTNAM = 0x115e, SRVNAM = 0x116d, USRID = 0x11a0, PASSWORD = 0x11a1, SECMEC = 0x11a2, SECCHKCD = 0x11a4, SECCHKRM = 0x1219, SYNTAXRM = 0x124c, MGRLVLLS = 0x1404, EXCSATRD = 0x1443, ACCSECRD = 0x14ac, ACCRDB = 0x2001, PRDDATA = 0x2104, RDBACCL = 0x210f, RDBNAM = 0x2110, CRRTKN = 0x2135, ACCRDBRM = 0x2201, RDBNFNRM = 0x2211, RDBAFLRM = 0x221a, RDBATHRM = 0x22cb, } -- Security Mechanism SecMec = { USER_PASSWORD = 0x0003, USER_ONLY = 0x0004, CHANGE_PASSWORD = 0x0005, USER_PASS_SUBST = 0x0006, USER_ENC_PASS = 0x0007, ENC_USER_ENC_PASS = 0x0009, ENC_CHANGE_PASS = 0x000A, KERBEROS = 0x000B, ENC_USER_DATA = 0x000C, ENC_USER_ENC_PASS_ENC_DATA = 0x000D, ENC_USER_ENC_PASS_ENC_NEWPASS_ENC_DATA = 0x000E, } DRDAPacket = { new = function(self, drda_array) local o = { drda_array = drda_array, count = #drda_array } setmetatable(o, self) self.__index = self return o end, getDRDAByCodePoint = function( self, codepoint ) for i=1, #self.drda_array do if ( self.drda_array[i].DDM.CodePoint == codepoint ) then return self.drda_array[i] end end end, getDRDA = function( self, n ) return ( #self.drda_array >= n ) and self.drda_array[n] or nil end, __tostring = function( self ) local data = "" -- do some DDM fixup in here for i=1, #self.drda_array do if ( i == 1 and #self.drda_array > 1 ) then self.drda_array[1].DDM.Format = 0x41 else self.drda_array[i].DDM.Format = 0x01 end self.drda_array[i].DDM.CorelId = i data = data .. tostring(self.drda_array[i]) end return data end } -- Distributed Relational Database Architecture (DRDA) Class DRDA = { new = function(self, ddm) local o = { Parameters = {}, DDM = ddm } setmetatable(o, self) self.__index = self return o end, --- Sets the DDM -- -- @param ddm DDM to assign to the DRDA -- @return status boolean true on success, false on failure setDDM = function( self, ddm ) if ( not(ddm) ) then return false, "DDM cannot be nil" end self.DDM = ddm return true end, --- Adds a DRDA parameter to the table -- -- @param param DRDAParam containing the parameter to add to the table -- @return status bool true on success, false on failure -- @return err string containing the error message if status is false addParameter = function( self, param ) if ( not(self.DDM) ) then stdnse.debug1("drda.DRDA.addParameter: DDM must be set prior to adding parameters") return false, "DDM must be set prior to adding parameters" end if ( not(param) ) then stdnse.debug1("drda.DRDA.addParameter: Param cannot be nil") return false, "Param cannot be nil" end table.insert(self.Parameters, param) -- update the DDM length fields self.DDM.Length = self.DDM.Length + param.Length self.DDM.Length2 = self.DDM.Length2 + param.Length return true end, --- Gets a parameter from the DRDA parameter table -- -- @param codepoint number containing the parameter type ro retrieve -- @return param DRDAParameter containing the requested parameter getParameter = function( self, codepoint ) for _, v in ipairs( self.Parameters ) do if ( v.CodePoint == codepoint ) then return v end end return end, --- Converts the DRDA class to a string -- -- @return data containing the object instance __tostring = function(self) if ( not(self.DDM) ) then stdnse.debug1("drda.DRDA.toString: DDM cannot be nil") return nil end local data = { string.pack(">I2BBI2I2I2", self.DDM.Length, self.DDM.Magic, self.DDM.Format, self.DDM.CorelId, self.DDM.Length2, self.DDM.CodePoint ) } for k,v in ipairs(self.Parameters) do data[#data+1] = tostring(v) end return table.concat(data) end, --- Sends the DRDA over the db2socket -- -- @param db2socket DB2Socket over which to send the data -- @return Status (true or false). -- @return Error code (if status is false). send = function( self, db2socket ) return db2socket:send( tostring(self) ) end, --- Receives data from the db2socket and builds a DRDA object -- -- @param db2socket from which to read data -- @return Status (true or false). -- @return Data (if status is true) or error string (if status is false). receive = function( self, db2socket ) local DDM_SIZE = 10 local pos = 1 -- first read atleast enough so that we can populate the DDM local status, data = db2socket:receive_buf( match.numbytes(DDM_SIZE), true ) if ( not(status) ) then stdnse.debug1("drda.DRDA.receive: %s", data) return false, ("Failed to read at least %d bytes from socket"):format(DDM_SIZE) end local ddm = DDM:new() ddm:fromString( data ) self:setDDM( ddm ) status, data = db2socket:receive_buf( match.numbytes(ddm.Length - 10), true ) if ( not(status) ) then return false, ("Failed to read the remaining %d bytes of the DRDA message") end -- add parameters until pos reaches the "end" repeat local param = DRDAParameter:new() pos = param:fromString( data, pos ) self:addParameter( param ) until ( #data <= pos ) return true end, } -- The DRDAParameter class implements the DRDA parameters DRDAParameter = { --- DRDA Parameter constructor -- -- @param codepoint number containing the codepoint value -- @param data string containing the data portion of the DRDA parameter -- @return o DRDAParameter object new = function(self, codepoint, data) local o = { CodePoint = codepoint, Data = data, Length = ( data and #data + 4 or 4 ) } setmetatable(o, self) self.__index = self return o end, --- Converts the DRDA Parameter object to a string -- -- @return data string containing the DRDA Parameter __tostring = function( self ) return string.pack(">I2I2", self.Length, self.CodePoint) .. (self.Data or "") end, --- Builds a DRDA Parameter from a string -- -- @param data string from which to build the DRDA Parameter -- @param pos number containing the offset into data -- @return pos the new position after processing, -1 on error fromString = function( self, data, pos ) if( #data < 4 ) then return -1 end self.Length, self.CodePoint, pos = string.unpack( ">I2I2", data, pos ) if ( self.Length > 0 ) then self.Data, pos = string.unpack("c" .. self.Length - 4, data, pos ) end return pos end, --- Returns the data portion of the parameter as an ASCII string -- -- @return str containing the data portion of the DRDA parameter as ASCII getDataAsASCII = function( self ) return StringUtil.toASCII( self.Data ) end, --- Returns the data in EBCDIC format -- -- @return str containing the data portion of the DRDA parameter in EBCDIC getData = function( self ) return self.Data end, } -- Distributed data management (DDM) DDM = { Formats = { RESERVED = 0x80, CHAINED = 0x40, CONTINUE = 0x20, SAME_CORRELATION = 0x10, }, Length = 10, Magic = 0xD0, Format = 0x41, CorelId = 1, Length2 = 4, CodePoint = 0, --- Creates a new DDM packet -- -- @param codepoint -- @param format -- @param corelid -- @return DDM object new = function(self, codepoint, format, corelid) local o = { CodePoint = codepoint, Format = format, CorelId = corelid } setmetatable(o, self) self.__index = self return o end, --- Converts the DDM object to a string __tostring = function( self ) return string.pack(">I2BBI2I2I2", self.Length, self.Magic, self.Format, self.CorelId, self.Length2, self.CodePoint) end, --- Constructs a DDM object from a string -- -- @param str containing the data from which to construct the object fromString = function( self, str ) local DDM_SIZE = 10 local pos = 1 if ( #str < DDM_SIZE ) then return -1, ("drda.DDM.fromString: str was less than DDM_SIZE (%d)"):format( DDM_SIZE ) end self.Length, self.Magic, self.Format, self.CorelId, self.Length2, self.CodePoint, pos = string.unpack( ">I2BBI2I2I2", str ) return pos end, --- Verifiers if there are additional DRDA's following -- -- @return true if the DRDA is to be chained, false if it's the last one isChained = function( self ) if ( (self.Format & DDM.Formats.CHAINED) == DDM.Formats.CHAINED ) then return true end return false end, --- Set the DRDA as chained (more following) -- -- @param chained boolean true if more DRDA's are following setChained = function( self, chained ) if ( self:isChained() ) then self.Format = ( self.Format ~ self.Formats.CHAINED ) else self.Format = ( self.Format | self.Formats.CHAINED ) end end, } -- static DRDA packet construction class Command = { --- Builds an EXCSAT DRDA packet -- -- @param extname string containing the external name -- @param srvname string containing the server name -- @param rellev string containing the server product release level -- @param mgrlvlls string containing the manager level list -- @param srvclass string containing the server class name -- @return drda DRDA instance EXCSAT = function( extname, srvname, rellev, mgrlvlls, srvclass ) local drda = DRDA:new( DDM:new( CodePoint.EXCSAT ) ) drda:addParameter( DRDAParameter:new( CodePoint.EXTNAM, StringUtil.toEBCDIC( extname ) ) ) drda:addParameter( DRDAParameter:new( CodePoint.SRVNAM, StringUtil.toEBCDIC( srvname ) ) ) drda:addParameter( DRDAParameter:new( CodePoint.SRVRLSLV, StringUtil.toEBCDIC( rellev ) ) ) drda:addParameter( DRDAParameter:new( CodePoint.MGRLVLLS, mgrlvlls ) ) drda:addParameter( DRDAParameter:new( CodePoint.SRVCLSNM, StringUtil.toEBCDIC( srvclass ) ) ) return drda end, --- Builds an ACCSEC DRDA packet -- -- @param secmec number containing the security mechanism ID -- @param database string containing the database name -- @return drda DRDA instance ACCSEC = function( secmec, database ) local drda = DRDA:new( DDM:new( CodePoint.ACCSEC ) ) drda:addParameter( DRDAParameter:new( CodePoint.SECMEC, secmec )) drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) )) return drda end, --- Builds a SECCHK DRDA packet -- -- @param secmec number containing the security mechanism ID -- @param database string containing the database name -- @param username string -- @param password string -- @return drda DRDA instance SECCHK = function( secmec, database, username, password ) local drda = DRDA:new( DDM:new( CodePoint.SECCHK ) ) drda:addParameter( DRDAParameter:new( CodePoint.SECMEC, secmec )) drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) )) drda:addParameter( DRDAParameter:new( CodePoint.USRID, StringUtil.toEBCDIC(username) ) ) drda:addParameter( DRDAParameter:new( CodePoint.PASSWORD, StringUtil.toEBCDIC(password) ) ) return drda end, --- Builds an ACCRDB DRDA packet -- -- @param database string containing the database name -- @param rdbaccl string containing the RDB access manager class -- @param prdid string containing the product id -- @param typdefnam string containing the data type definition name -- @param typdefovr string containing the data type definition override -- @return drda DRDA instance ACCRDB = function( database, rdbaccl, prdid, prddata, typdefnam, crrtkn, typdefovr ) local drda = DRDA:new( DDM:new( CodePoint.ACCRDB ) ) drda:addParameter( DRDAParameter:new( CodePoint.RDBNAM, StringUtil.toEBCDIC(StringUtil.padWithChar(database,' ', 18)) ) ) if ( rdbaccl ) then drda:addParameter( DRDAParameter:new( CodePoint.RDBACCL, rdbaccl ) ) end if ( prdid ) then drda:addParameter( DRDAParameter:new( CodePoint.PRDID, StringUtil.toEBCDIC( prdid ) ) ) end if ( prddata ) then drda:addParameter( DRDAParameter:new( CodePoint.PRDDATA, StringUtil.toEBCDIC( prddata ) ) ) end if( typdefnam ) then drda:addParameter( DRDAParameter:new( CodePoint.TYPDEFNAM, StringUtil.toEBCDIC( typdefnam ) ) ) end if( crrtkn ) then drda:addParameter( DRDAParameter:new( CodePoint.CRRTKN, crrtkn ) ) end if( typdefovr ) then drda:addParameter( DRDAParameter:new( CodePoint.TYPDEFOVR, typdefovr ) ) end return drda end } -- Helper Class Helper = { new = function(self) local o = {} setmetatable(o, self) self.__index = self return o end, --- Connect to the DB2 host -- -- @param host table -- @param port table -- @return Status (true or false). -- @return Error code (if status is false). connect = function( self, host, port ) self.comm = Comm:new( host, port ) return self.comm:connect() end, --- Closes an open connection. -- -- @return Status (true or false). -- @return Error code (if status is false). close = function( self ) self.comm:close() end, --- Returns Server Information (name, platform, version) -- -- @return table containing extname, srvclass, -- srvname and prodrel getServerInfo = function( self ) local mgrlvlls = stdnse.fromhex("1403000724070008240f00081440000814740008") local drda_excsat = Command.EXCSAT( "", "", "", mgrlvlls, "" ) local response, param, err local status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_excsat } ) ) if ( not(status) ) then return false, err end local drda = packet:getDRDAByCodePoint( CodePoint.EXCSATRD ) if ( drda ) then response = {} param = drda:getParameter( CodePoint.EXTNAM ) if ( param ) then response.extname = param:getDataAsASCII() end param = drda:getParameter( CodePoint.SRVCLSNM ) if ( param ) then response.srvclass = param:getDataAsASCII() end param = drda:getParameter( CodePoint.SRVNAM ) if ( param ) then response.srvname = param:getDataAsASCII() end param = drda:getParameter( CodePoint.SRVRLSLV ) if ( param ) then response.prodrel = param:getDataAsASCII() end else return false, "The response contained no EXCSATRD" end return true, response end, --- Login to DB2 database server -- -- @param database containing the name of the database -- @param username containing the authentication username -- @param password containing the authentication password -- @return Status (true or false) -- @return err message (if status if false) login = function( self, database, username, password ) local mgrlvlls = stdnse.fromhex("1403000724070008240f00081440000814740008") local secmec, prdid = "\00\03", "JCC03010" local tdovr = stdnse.fromhex("0006119c04b80006119d04b00006119e04b8") local crrtkn= stdnse.fromhex("d5c6f0f0f0f0f0f14bc3c6f4c4012a11168414") local drda_excsat = Command.EXCSAT( "", "", "", mgrlvlls, "" ) local drda_accsec = Command.ACCSEC( secmec, database ) local drda_secchk = Command.SECCHK( secmec, database, username, password ) local drda_accrdb = Command.ACCRDB( database, "\x24\x07", "DNC10060", nil, "QTDSQLASC", crrtkn, tdovr) local status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_excsat, drda_accsec } ) ) if( not(status) ) then return false, packet end if ( packet:getDRDAByCodePoint( CodePoint.RDBNFNRM ) or packet:getDRDAByCodePoint( CodePoint.RDBAFLRM ) ) then stdnse.debug1("drda.Helper.login: ERROR: RDB not found") return false, "ERROR: Database not found" end local drda = packet:getDRDAByCodePoint( CodePoint.ACCSECRD ) if ( not(drda) ) then return false, "ERROR: Response did not contain any valid security mechanisms" end local param = drda:getParameter( CodePoint.SECMEC ) if ( not(param) ) then stdnse.debug1("drda.Helper.login: ERROR: Response did not contain any valid security mechanisms") return false, "ERROR: Response did not contain any valid security mechanisms" end if ( string.unpack(">I2", param:getData()) ~= SecMec.USER_PASSWORD ) then stdnse.debug1("drda.Helper.login: ERROR: Securite Mechanism not supported") return false, "ERROR: Security mechanism not supported" end status, packet = self.comm:exchDRDAPacket( DRDAPacket:new( { drda_secchk, drda_accrdb } ) ) if( not(status) ) then return false, "ERROR: Login failed" end -- -- At this point we have a few differences in behaviour -- * DB2 has told us earlier if the DB does not exist -- * Apache Derby will do so here, regardless of the login was -- successful or not -- * Informix will tell us that the DB does not exist IF the -- login was successful -- -- Therefore the order of these checks are important!! if ( packet:getDRDAByCodePoint( CodePoint.ACCRDBRM ) ) then return true -- Apache Derby responds differently with usernames containing spaces elseif ( packet:getDRDAByCodePoint( CodePoint.RDBATHRM ) ) then return false, "ERROR: Login failed" -- Informix responds with a SECCHKRM DDM response elseif ( packet:getDRDAByCodePoint( CodePoint.SECCHKRM ) ) then drda = packet:getDRDAByCodePoint( CodePoint.SECCHKRM ) param= drda:getParameter( CodePoint.SECCHKCD ) if ( param and param:getData() == "\0" ) then return true end elseif ( packet:getDRDAByCodePoint( CodePoint.RDBNFNRM ) or packet:getDRDAByCodePoint( CodePoint.RDBAFLRM ) ) then return false, "ERROR: Database not found" end return false, "ERROR: Login failed" end, } -- The communication class Comm = { new = function(self, host, port) local o = { host = host, port = port, socket = nmap.new_socket() } setmetatable(o, self) self.__index = self return o end, connect = function(self) return self.socket:connect(self.host, self.port) end, close = function(self) return self.socket:close() end, recvDRDA = function( self ) local drda_tbl = {} repeat local drda = DRDA:new() local status, err = drda:receive( self.socket ) if ( not(status) ) then return false, err end table.insert(drda_tbl, drda) until ( not(drda.DDM:isChained()) ) return true, drda_tbl end, --- Sends a packet to the server and receives the response -- -- @param DRDAPacket -- @return status true on success, false on failure -- @return packet an instance of DRDAPacket exchDRDAPacket = function( self, packet ) local drda, err local status, err = self.socket:send( tostring(packet) ) if ( not(status) ) then stdnse.debug1("drda.Helper.login: ERROR: DB2Socket error: %s", err ) return false, ("ERROR: DB2Socket error: %s"):format( err ) end status, drda = self:recvDRDA() if( not(status) ) then stdnse.debug1("drda.Helper.login: ERROR: DB2Socket error: %s", drda ) return false, ("ERROR: DB2Socket error: %s"):format( drda ) end return true, DRDAPacket:new( drda ) end } -- EBCDIC/ASCII Conversion tables a2e_hex = "00010203372D2E2F1605250B0C0D0E0F101112133C3D322618193F271C1D1E1F\z 405A7F7B5B6C507D4D5D5C4E6B604B61F0F1F2F3F4F5F6F7F8F97A5E4C7E6E6F\z 7CC1C2C3C4C5C6C7C8C9D1D2D3D4D5D6D7D8D9E2E3E4E5E6E7E8E9ADE0BD5F6D\z 79818283848586878889919293949596979899A2A3A4A5A6A7A8A9C04FD0A107\z 202122232415061728292A2B2C090A1B30311A333435360838393A3B04143EE1\z 4142434445464748495152535455565758596263646566676869707172737475\z 767778808A8B8C8D8E8F909A9B9C9D9E9FA0AAABAC4AAEAFB0B1B2B3B4B5B6B7\z B8B9BABBBC6ABEBFCACBCCCDCECFDADBDCDDDEDFEAEBECEDEEEFFAFBFCFDFEFF" e2a_hex = "000102039C09867F978D8E0B0C0D0E0F101112139D8508871819928F1C1D1E1F\z 80818283840A171B88898A8B8C050607909116939495960498999A9B14159E1A\z 20A0A1A2A3A4A5A6A7A8D52E3C282B7C26A9AAABACADAEAFB0B121242A293B5E\z 2D2FB2B3B4B5B6B7B8B9E52C255F3E3FBABBBCBDBEBFC0C1C2603A2340273D22\z C3616263646566676869C4C5C6C7C8C9CA6A6B6C6D6E6F707172CBCCCDCECFD0\z D17E737475767778797AD2D3D45BD6D7D8D9DADBDCDDDEDFE0E1E2E3E45DE6E7\z 7B414243444546474849E8E9EAEBECED7D4A4B4C4D4E4F505152EEEFF0F1F2F3\z 5C9F535455565758595AF4F5F6F7F8F930313233343536373839FAFBFCFDFEFF" -- Creates the lookup tables needed for conversion a2e_tbl = stdnse.fromhex(a2e_hex) e2a_tbl = stdnse.fromhex(e2a_hex) -- Handle EBCDIC/ASCII conversion StringUtil = { --- Converts an ASCII string to EBCDIC -- -- @param ascii string containing the ASCII value -- @return string containing the EBCDIC value toEBCDIC = function( ascii ) return string.gsub(ascii, ".", function(a) local val = a:byte() + 1 return a2e_tbl:sub(val, val) end) end, --- Converts an EBCDIC string to ASCII -- -- @param ebcdic string containing EBCDIC value -- @return string containing ASCII value toASCII = function( ebcdic ) return string.gsub(ebcdic, ".", function(e) local val = e:byte() + 1 return e2a_tbl:sub(val, val) end) end, --- Pads a string with a character -- -- @param str string to pad -- @param chr char to pad with -- @param len the total length of the finished string -- @return str string containing the padded string padWithChar = function( str, chr, len ) return str .. string.rep(chr, len - #str) end, } return _ENV;