---[  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%\<bogus name>.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
/_vti_bin/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.

- WHAT'S THE PROBLEM?  MS SQL server allows batch commands.

- WHAT'S THAT MEAN?  I can do something like:

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

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

- WHAT'S THAT REALLY MEAN?  People can possibly piggyback SQL commands into
your statements.  Let's say you have:

	SELECT * FROM table WHERE x=%%criteria from webpage user%%

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.

- WHAT FILES OF MINE ARE AFFECTED?  Well, ASP and IDC files are problematic.
At least you can fix ASP files, but you're kinda stuck when it comes to
IDCs.

- EXACTLY HOW ARE IDCs AFFECTED?  Say we wanted to query a database of 
names=phone #s, where the user gives us a name, and we supply all the 
matching phone numbers.  A Sql call like 

	SELECT * FROM phonetable WHERE NAME='namewewant'

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

- ARE THERE ANY .IDCs SOMEONE COULD USE AGAINST ME?  Glad you asked.  There's
a file included with IIS 3.0 in the /scripts/tools directory, called ctss.idc,
which has a SQL statement like:

	CREATE TABLE %table% (...table defs...)

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)

- EXACTLY HOW ARE ASPs AFFECTED?  Typical ADODB code looks something
like:

	<% SQLquery="SELECT * FROM phonetable"
	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 %>

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:

- BUT I DON'T KNOW THE DSN NAME, LOGIN NAME, OR PASSWORD!  You don't need
them.  The developer of the page that contains the SQL will already take care
of that.  We're piggy-backing SQL commands onto a command that will work
(otherwise, the page/application wouldn't work normally anyway!).  If the
normal page can get to the SQL server through a firewall, VPN, etc, then so
can this command.  It can, and will, go wherever the normal pages/SQL can
go.

- BUT I CAN'T VIEW THE SECOND RETURNED RECORDSET!  Yes, this is a problem
most of the time.  Not too many applications are built assuming multiple
recordset returns, so usually don't cooperate.  But, let me just say
there's a stored procedure in SQL that lets you email results of a command
to anywhere....you don't need to see the results in your web browser.

- BUT WHAT GOOD IS RUNNING MORE SQL COMMANDS?  My friend, my friend.  Think
bigger.  Think better.  Think stored procedures.  I'm not going to include
exploit examples, because that's not what this is about.  This is simply to
show that the problem exists.

- BUT WHAT IF THEY HAVE COMPLEX SQL COMMANDS?  Yes, this can be tricky, but
it's still possible.  Think of it like writing a buffer overflow.  ;-)  If
we have:

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

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.

- HOW CAN I PROTECT MYSELF?  Put quotes around every string taken from the
web user that's used in your SQL statement, and also change any single
quotes (') into double single quotes ('')--this protects everything.  In case
of numeric criteria, check to see that the numeric string given back is,
in fact, all numbers. And since you can't do any of the above in IDCs,
switch to ASP.  Don't allow access to any of the SQL servers extended
procedures.  Best of all, don't use raw SQL in your web applications;
called custom stored  procedures on the SQL server, and pass the web
user's dynamic criteria as parameters.

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?

- Don't use sample files/applications on public/production servers.
- Don't use 'local-host only' security, especially on proxys.
- Watch what exactly is changed when you upgrade.
- Don't assume user's input is ok for SQL queries.

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

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

----[  EOF
