Re: Key-passing from PHP to TCL CGI script - how is it done (web security issue)?



TCL v.8.3
OS: FreeBSD UNIX

[TCL]
#!/usr/local/bin/tclsh

puts "Content-type: text/html; charset=\"UTF-8\"\n\n"

source xml_procs.tcl
source vignette_procs.tcl
source tcl_string_tools.tcl
source tcl_http_email_tools.tcl
source cgi.tcl
source menubar_procs.tcl

source cgi_globals.tcl

# MY STUFF
source tcl_http_email_tools.tcl
set cannotPzn [catch {
set style [HTTP_GET $env(SERVER_NAME) 80
/cgi-bin/cgiwrap/ppowell/php4.cgi/~ppowell/my/style.php {}
$env(HTTP_COOKIE)]
} cannotPznErrMsg]
if {$cannotPzn} {set style {}}

cgi_input

lappend integerVars triviaID answerID hasSubmittedTrivia
lappend textVars firstname lastname valIdentifier unique_key

set allVars [concat $integerVars $textVars]

foreach var $allVars {
if {[catch {cgi_import $var} trash] && [lsearch -exact $integerVars
$var] >= 0} {
set $var 0
} elseif {[catch {cgi_import $var} trash]} {
set $var {null}
}
}


set html {
<html>
<head>
<title>Tack!</title>
}

append html "\n<link rel=\"style***\" type=\"text/css\"
href=\"http://$env(SERVER_NAME)/val.css\">"

append html {
<script src=/js/val_header.js></script>
<script src=/js/leftnavbanner.js></script>
</head>
<body bgcolor=eeeedd link=cc0000 vlink=cc0000 alink=000099>
}

append html "[PRODUCE_MENUBAR]<p>$style"

# NEW 8/7/2004 USE PHP (AS CGI) TO CHECK IF TRIVIA EXISTS OR NOT
INSTEAD OF SLOWER TCL PROCESSING
set stuff [HTTP_GET $serverName 80
"$cgi/php4.cgi/~ppowell/trivia/check_trivia.php?triviaID=$triviaID" {}
{}]
regsub -nocase {^.*<body[^>]*>([a-zA-Z0-9 ]*)</body>.*$} $stuff "\\1"
hasFoundTrivia
set hasFoundTrivia [string trim $hasFoundTrivia]
if {$hasFoundTrivia != 1} {set hasFoundTrivia 0}

if {!$hasFoundTrivia} {
append html {
<script type="text/javascript">location.href="/index.shtml";</script>
<noscript><meta http-equiv="Refresh"
content="0;URL=/index.shtml"></noscript>
}
}

set isValidTrivia 1; # NEW 9/10/2005: SERVER-SIDE VALIDATION
set hasEnteredTrivia 0
set hasEnteredDup 0
set msg {}; # SET IT UP TO DEFAULT NULL

# NEW 9/10/2005 SERVER-SIDE VALIDATION
if {$hasFoundTrivia && !$hasEnteredTrivia && !$hasEnteredDup &&
$isValidTrivia} {
if {[string length $firstname] == 0 || [string length $lastname] == 0}
{
set isValidTrivia 0
set msg {Please enter a first and last name}
} elseif {![IS_WORD $firstname] || ![IS_WORD $lastname]} {
set isValidTrivia 0
set msg {Please enter a legitimate first and last name}
}
}

# NEW 8/7/2004 USE PHP (AS CGI) TO CHECK IF USER IS ATTEMPTING TO ENTER
ANOTHER TRIVIA RESPONSE TO THE SAME QUESTION THEY ALREADY ENTERED
if {$hasFoundTrivia && !$hasEnteredTrivia && !$hasEnteredDup &&
$isValidTrivia} {
# USE REMOTE PHP (AS CGI) SCRIPT TO CHECK FOR REPOSTING
set stuff [HTTP_GET $serverName 80
"$cgi/php4.cgi/~ppowell/trivia/check_unique_entry.php?triviaID=$triviaID&valIdentifier=$valIdentifier"
{} {}]
regsub -nocase {^.*<body[^>]*>([a-zA-Z0-9 ]*)</body>.*$} $stuff "\\1"
hasEnteredTrivia
set hasEnteredTrivia [string trim $hasEnteredTrivia]
if {$hasEnteredTrivia != 1} {set hasEnteredTrivia 0}
}


# NEW 8/7/2004 USE PHP (AS CGI) TO CHECK IF REPOSTING HAS OCCURRED
if {$hasFoundTrivia && !$hasEnteredTrivia && !$hasEnteredDup &&
$isValidTrivia} {
# USE REMOTE PHP (AS CGI) SCRIPT TO CHECK FOR REPOSTING
set stuff [HTTP_GET $serverName 80
"$cgi/php4.cgi/~ppowell/trivia/check_unique_key.php?unique_key=$unique_key"
{} {}]
regsub -nocase {^.*<body[^>]*>([a-zA-Z0-9 ]*)</body>.*$} $stuff "\\1"
hasEnteredDup
set hasEnteredDup [string trim $hasEnteredDup]
if {$hasEnteredDup != 1} {set hasEnteredDup 0}
}


if {$hasFoundTrivia && !$hasEnteredTrivia && !$hasEnteredDup &&
$isValidTrivia} {
# GET THE CORRECT ANSWER ID AND QUESTION
set stuff [HTTP_GET $serverName 80
"$cgi/php4.cgi/~ppowell/trivia/get_attribute.php?triviaID=$triviaID&attribute=correctanswerid"
{} {}]
regsub -nocase {^.*<body[^>]*>([a-zA-Z0-9 ]*)</body>.*$} $stuff "\\1"
thisCorrectAnswerID
set stuff [HTTP_GET $serverName 80
"$cgi/php4.cgi/~ppowell/trivia/get_attribute.php?triviaID=$triviaID&attribute=question"
{} {}]
regsub -nocase {^.*<body[^>]*>([a-zA-Z0-9 ]*)</body>.*$} $stuff "\\1"
thisQuestion
set stuff [HTTP_GET $serverName 80
"$cgi/php4.cgi/~ppowell/trivia/get_attribute.php?triviaID=$triviaID&attribute=expdate"
{} {}]
regsub -nocase {^.*<body[^>]*>([a-zA-Z0-9 ]*)</body>.*$} $stuff "\\1"
thisExpDate
}

if {![info exists thisCorrectAnswerID]} {set thisCorrectAnswerID 0}
if {![info exists thisQuestion]} {set thisQuestion {}}
if {![info exists thisExpDate]} {set thisExpDate [clock scan now]}

if {!$isValidTrivia} {
append html "
${font}Please re-enter your trivia with valid responses: $msg</font>
"
} elseif {$hasEnteredTrivia} {
append html "
${font}We're sorry but we already have your response. Try another
trivia another time</font>
"
} else {

if {!$hasEnteredDup} {
set trivResultsFile [file join $env(DOCUMENT_ROOT) xml triviaresults]
set trivResultsList [XML_GET_ALL_ELEMENT_ATTRS $trivResultsFile
entry]
set trivResultsCount [XML_GET_ELEMENT_ATTR_COUNT $trivResultsList]
if {[string length $trivResultsList] == 0} {
set maxID 1
} else {
set maxID [expr {[XML_MAXID $trivResultsList] + 1}]
}

foreach var "firstname lastname" {
set $var [XML_CLEANUP_ATTRIBUTE [set $var]]
}

lappend trivResultsAttrs id $maxID triviaID $triviaID answerID
$answerID correctAnswerID
lappend trivResultsAttrs $thisCorrectAnswerID firstname "$firstname"
lastname "$lastname"
lappend trivResultsAttrs valIdentifier "$valIdentifier" unique_key
"$unique_key"

set results [XML_WRITE_BY_PARSE $trivResultsFile entry trivia
$trivResultsAttrs]
} else {
set results 1; # DUMMY VALUE TO ALLOW FOR REPOSTING
}

if {!$results} {
append html "
${font}We're sorry but we couldn't process your response. Please try
again later</font>
"
} else {
append html "
<div align=\"center\"><script
type=\"text/javascript\">leftNavBannerMaker('tack!');</script><noscript>Tack!</noscript></div><p>
${font}Thanx for your entry! We will reveal the answer to <font
color=\"#cc0000\">$thisQuestion</font> on <font
color=\"#cc0000\">[clock format $thisExpDate -format "%b %d,
%Y"]</font><p>
Meanwhile, have you filled out a <a
href=\"/profile/login.php\">Profile</a> yet or signed our <a
href=\"/guestbook.shtml\">Guestbook</a>, or even
entered <a href=\"/event/calendar.php\">an event</a>?</font>
"
}
}

puts $html
[/TCL]


gwl wrote:
> Phil,
>
> If you could post the problem script to the comp.lang.tcl newsgroup and what
> OS you are using, it is more than likely we can tell you how to plug the
> security hole. Partictularly from the description you include -- sounds
> like it may be a well known coding problem (i.e. not handling user data in a
> safe way).
>
> To answer your question, you can pass data either as an argument to the
> script on its command line (i.e. when you kick it off) or via an enviornment
> variable. In general, if you are having security problems with handling
> user supplied data, I'd recommend passing via an enviornment variable (it is
> harder to introduce a security hole).
>
> BTW, a properly written CGI script is no less safe than a properly written
> PHP script -- you just have to know what you are doing.
>
> comp.lang.php wrote:
> > On one of my sites, I have a TCL CGI script that has a security hole
> > in spite of it having effective server-side validation (the fact that
> > it's CGI IS its security hole). The front end is a PHP script, and I
> > am writing server-side validation onto it, however, it is required to
> > redirect to the TCL CGI script because only a CGI script has the
> > ability to access a group-accessible XML script on the back end.
> >
> > I had to take the whole thing down because a hacker found a way to
> > exploit the TCL CGI script and send in viral DoS-generating data
> > packets via simple form text field submissions, somehow even bypassing
> > the TCL CGI script's server-side validation.
> >
> > Hence, that is why I am writing server-side validation on the front-end
> > PHP script, which is not CGI, of course.
> >
> > The only way I could figure out how to make this secure was the concept
> > of "key passing", that is, passing a key from the PHP script into a
> > $_SESSION variable, then the TCL CGI script must have the same key on
> > its end, somehow, in order to expedite further.
> >
> > Bottom line: I have no clue how to do this. Is there anyone out there
> > that knows this stuff and can either give me a quick tutorial or point
> > me in the right direction? I have absolutely no idea where to begin,
> > nor do I know any other means of ensuring web security.
> >
> > *NOTE* I cannot destroy the TCL CGI script, because only a CGI script
> > can access the group-accessible XML on the back end, so that's not an
> > option by any means.
> >
> > Thanx
> > Phil
> >

.