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 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 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:
ctld)
cmd)
tmd)
pad)
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")
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.
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.
[KB1341].
The second way is similar, and relies on using a large number
of different oids. If a template produces an error, then no
cache file will be generated for that request. However, if
the template tries to be helpful by detecting invalid oids
and returning an apologetic message, then an attacker can
fill up your file system with apologetic messages. The other
common way for this problem to arise is when using a compound
oid; e.g. a number of parameters separated by dashes. The
easiest way to split up such a compound parameter is to use
Tcl's split command. Unless you explicitly check the
llength of the resulting list, an attacker can create a
large number of different oids by appending -n to the
end of the oid for many different values of n.
1 rather than 0. So the database can be flooded with
a great many heavy queries. If you've ever had this happen
by accident (and if you've worked with StoryServer or similar
products for long then I expect you have) you'll know how
messy it can be.
[KB1341] - Template extension validation
[SS] - StoryServer 4.2 Manuals
[SS1] - Restricting Access to the Servers by IP address (NT | Solaris)
[SS2]
Roadmap to Installation and Configuration
[SS3]
StoryServer Process Reference
(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)