StoryServer - a note on security

Introduction:

Vignette StoryServer is used increasingly widely for creating large database backed web sites. So far I have heard of no case in which an organisation's security has been compromised because of it. This is good because a great many StoryServer sites are vulnerable, usually because of simple misconfiguration. It is ironic that the worst example is www.vignette.com which last time I checked could be arbitrarily modified by any internet user with appropriate knowledge in at least two different ways.

Computer security is notoriously difficult to ensure. The usual problems in my experience are lack of awareness and apathy: either the administrator doesn't know there's anything wrong, or she doesn't care. This document is an attempt to address the first of these problems. It is aimed at the technical reader with a good working knowledge of StoryServer. I shall use without definition terms which are defined in Vignette's documentation.

Information about the security of web servers, database systems and standard network services is comprehensively documented elsewhere. As far as I know, this is the first attempt to collect the particular problems which arise from StoryServer and to offer solutions where possible.

I've divided potential problems into four categories: (The first two are the most fun)

The CMS:

The problem with the CMS can be summarised simply: its access control is illusory. The username/password dialog box which pops up when you connect to the CMS using the Production center is just for show. The underlying protocol contains no authentication mechanisms which can't be easily circumvented. The "encryption" used for passwords is a kind of scrambling which can easily be unscrambled.

To illustrate the problem I've included a couple of Perl modules, StoryServer::CMS and StoryServer::Crypt. The former implements a subset of the CMS protocol (which is used for communication between the Production Center and the CMS) and the latter implements scrambling and unscrambling routines dealing with the format used by StoryServer to store passwords, registration keys etc. They total fewer than 200 lines of code. No rocket science.

The script getpasswd.pl takes the hostname and port number of a CMS as command line parameters, and prints the StoryServer 'admin' password and the database password for that installation.

[~/scratch/pl]$ ./getpasswd.pl www.vignette.com 30210
Database password = v1gnett3
Admin password = change+it

The lessons from this are clear. Restrict who can connect to your CMS. The CMS ought probably to be inside a firewall. Furthermore, you can set the PE_ALLOW_IPS variable in your StoryServer.cfg file [SS1] to control which IP addresses are allowed to connect to your CMS. Set it. Remember, anyone who connects to your CMS can have administrative privileges over your site. Be afraid.

The CAS:

The content application server (formerly known as delivery engine) also behaves in a rather less secure way than the naive system administrator might expect.

As outlined in Vignette's docs [SS3] a CAS consists of four processes:

The page generator (ctld)
Interprets your templates
The cache manager (cmd)
Clears bits of the page cache, on request
The template manager (tmd)
Updates the template cache, on request
The placement manager (pad)
Updates static files (the kind which you get by doing "new file" from the Production center) on request.

I haven't done any detailed investigation of pad, so I don't know how it works. But both cmd and tmd work in a similar fashion: they listen on their respective ports (5705 and 5727 by default, on Solaris) and accept HTTP-style requests. The really worrying one is tmd. Although the canonical versions of your templates are stored in the database, the CAS doesn't read them from there in order to process requests. It maintains a "template cache" on disk, which it uses instead. That's why tmd takes so long to start up: it's reading all the templates in from the database and putting them in the template cache.

Now, when you edit a template (in the case of Development CASs) or when you launch a template (in the case of a Live CAS) the CMS sends a request to the appropriate template manager(s), asking that they update their cache and including the body of the new or updated template. Do you see the problem yet? That's right! The default configuration allows anyone to send messages to your template manager. So anyone can 1) Add a template to the site, which amounts to being able to run arbitrary code on your server and arbitrary queries or updates on your database, or 2) Replace any of your existing templates with something completely different.

The easiest way to check whether you're vulnerable is to try and connect to your template manager with a web browser. See http://www.shell.com:9002/ for example. Anyone who can see the status page could also update any of your templates just by writing a short HTML form. (Or as Microsoft would put it, "utilising advanced web development technologies")

The database:

A common outline for a StoryServer template is that it will query the database for some text, which it will then use in the returned page. And because StoryServer doesn't support the use of bind variables in database queries, it's common to see constructs like this:

	 SEARCH TABLE foo INTO foo_results SQL "
		SELECT thingy
		FROM foo
		WHERE ID = $foo_id
	 "

If (as is often the case) foo_id has been initialised from the oid (ie. the third component of the comma-separated CURL) and its form hasn't been suitably validated, then you are effectively allowing anyone to see the results of arbitrary queries of your database. Long and complex strings can be put into the oid, which StoryServer helpfully URL-unescapes before giving to your template. (Actually it's unescaped twice. I have no idea why.)

Suppose that I could arrange for the value of foo_id to be

"NULL
 UNION
SELECT BOBDB__OBJVAL thingy
FROM vgn_cf"
(using Oracle syntax)

then I've just extracted a lot of sensitive configuration information including your database password. (But of course you've had the sense and foresight to store the password in encrypted form. See the decrypt() function from StoryServer::Crypt) I could also, for example, query the data dictionary to see what tables you have and then inspect their contents. I could inspect all your template source.

I would guess that you don't want any of those things.

Notice that the intruder needs to know the names and approximate datatypes of the result columns. But never underestimate the power of trial-and-error guesswork. Most people give their database columns sensible names.

In a real system the templates which perform queries like this are often components, and you might be confident that only "good" data is being passed to your components. That doesn't protect you though, because a component can still be directly accessed through the web.

You can usually find out the component paths used on a page simply by changing the .html extension to .txt, and reading the #include directives. It is possible to prevent this - see [KB1341] for details. However it's very unwise to rely on the fact that nobody knows your component paths: if you've given them sensible names they'll probably be easy to guess, and inside information has a tendency to leak out over time. Microsoft's recent hotmail blunder was a mistake of this kind.

Denial of service:

Finally, there are a number of ways in which a StoryServer site could be made to run very slowly, or even to stop serving pages altogether. Here I'll only mention attacks which are specific to StoryServer: the operating system and webserver can usually be attacked too.


References:

(me:
I've been using StoryServer for more than a year in the course of
my work with Guardian Unlimited. I've never used the CAS or CMS
on Windows NT, only Solaris 2.6)