From 49895b081660404c2add8ec85c8483610bc0f91a Mon Sep 17 00:00:00 2001 From: Jens Maus Date: Wed, 4 Nov 2020 20:06:33 +0100 Subject: [PATCH] added a sessionID check to all our .cgi scripts so that they can only be executed within an valid WebUI login. This fixes #11, thus CVE-2019-18938. --- www/backup.cgi | 37 ++++++++++++++++++++-------------- www/config_js.cgi | 26 +++++++++++++----------- www/email.js | 48 ++++++++++++++++++++++++++++++++------------- www/index.html | 2 -- www/querystring.tcl | 9 +++++++++ www/save.cgi | 32 ++++++++++++++++++++---------- www/session.tcl | 13 ++++++++++++ www/testmail.cgi | 40 +++++++++++++++++++++---------------- www/testtcl.cgi | 31 +++++++++++++++++------------ 9 files changed, 156 insertions(+), 82 deletions(-) create mode 100644 www/querystring.tcl create mode 100644 www/session.tcl diff --git a/www/backup.cgi b/www/backup.cgi index bba4c1c..e10536a 100644 --- a/www/backup.cgi +++ b/www/backup.cgi @@ -7,21 +7,28 @@ # ### -#set datum [clock seconds] -#set datum [clock format $datum -format {%d-%m-%Y}] +load tclrega.so +source querystring.tcl +source session.tcl -# Backup ausführen -set backup "/etc/config/addons/email/backup.sh" -exec $backup +puts "Content-Type: text/plain; charset=iso-8859-1" +puts "" -# Ausgabe des Backups -after 2000 - if { [file exists "/etc/config/addons/email/email-backup.tar.gz"] } { - puts "Content-Type: text/plain" - puts "" +if {[info exists sid] && [check_session $sid]} { + #set datum [clock seconds] + #set datum [clock format $datum -format {%d-%m-%Y}] + + # Backup ausführen + set backup "/etc/config/addons/email/backup.sh" + exec $backup + + # Ausgabe des Backups + after 2000 + if { [file exists "/etc/config/addons/email/email-backup.tar.gz"] } { puts -nonewline "BACKUPOK" - } else { - puts "Content-Type: text/plain" - puts "" - puts "ERROR" - } \ No newline at end of file + } else { + puts -nonewline "ERROR: could not find backup" + } +} else { + puts -nonewline "Error: no valid session" +} diff --git a/www/config_js.cgi b/www/config_js.cgi index b02c9c7..0a63198 100644 --- a/www/config_js.cgi +++ b/www/config_js.cgi @@ -8,6 +8,9 @@ # @license Public Domain ## +load tclrega.so +source querystring.tcl +source session.tcl source /etc/config/addons/email/config.tcl ################################################################################ @@ -67,8 +70,7 @@ proc putMails {} { global MAIL_DIR MAIL_IDS set first 1 - puts " Mails:" - puts " \[" + puts " \"Mails\": \[" foreach id $MAIL_IDS { if { 1 != $first } then { puts " ," } else { set first 0 } @@ -125,8 +127,7 @@ proc putAccount {} { catch { array set account [loadFromFile $ACCOUNT_FILE] } - puts " Account:" - puts " \{" + puts " \"Account\": \{" puts " \"server\": \"[jsstring $account(Server)]\"," puts " \"from\": \"[jsstring $account(From)]\"," puts " \"auth\": \"[jsstring $account(Auth)]\"," @@ -154,11 +155,14 @@ proc putUserScript {} { puts "Content-Type: text/javascript; charset=utf-8" puts "" -puts "Configuration =" puts "\{" -putMails -puts " ," -putAccount -puts " ," -putUserScript -puts "\};" +if {[info exists sid] && [check_session $sid]} { + putMails + puts " ," + putAccount + puts " ," + putUserScript +} else { + puts "ERROR: no valid session" +} +puts "\}" diff --git a/www/email.js b/www/email.js index 3b9f3cf..a71f070 100644 --- a/www/email.js +++ b/www/email.js @@ -6,6 +6,9 @@ * @license Public Domain **/ +var SessionId = ""; +var Configuration; + /*############################################################################*/ /*# DOM-Funktionen #*/ /*############################################################################*/ @@ -210,7 +213,7 @@ Mail = function(mailData) * @const Mail.URL * @brief URL zum Speichern von E-Mails. **/ -Mail.URL = "/addons/email/save.cgi?mail" +Mail.URL = "/addons/email/save.cgi"; Mail.prototype = { @@ -306,7 +309,7 @@ Mail.prototype = data += this.m_content; var result = "AJAX error"; - try { result = http.post(Mail.URL, data); } + try { result = http.post(Mail.URL + '?sid=' + SessionId + '&mail', data); } catch (ex) { } if ("OK" == result) { alert("E-Mail wurde erfolgreich gespeichert!"); } else { alert("Fehler beim Speichern der E-Mail (" + result + ")!"); } @@ -380,7 +383,7 @@ MailCollection = Account = { - URL: "/addons/email/save.cgi?account", + URL: "/addons/email/save.cgi", init: function() { @@ -411,7 +414,7 @@ Account = data += "\n"; var result = "AJAX error"; - try { result = http.post(Account.URL, data); } + try { result = http.post(Account.URL + '?sid='+SessionId+'&account', data); } catch (ex) { } if ("OK" == result) { alert("Kontodaten wurden erfolgreich gespeichert!"); } else { alert("Fehler beim Speichern der Kontodaten (" + result + ")!"); } @@ -434,7 +437,7 @@ Account = **/ Tcl = { - URL: "/addons/email/save.cgi?userScript", + URL: "/addons/email/save.cgi", /** * @fn init @@ -456,7 +459,7 @@ Tcl = data += $("userScriptTextArea").value; var result = "AJAX error"; - try { result = http.post(Tcl.URL, data); } + try { result = http.post(Tcl.URL + '?sid='+SessionId+'&userScript', data); } catch (ex) { } if ("OK" == result) { alert("Tcl Script wurde erfolgreich gespeichert!"); } else { alert("Fehler beim Speichern des Tcl Scripts (" + result + ")!"); } @@ -482,7 +485,7 @@ TestTCL = data += $("userScriptTextArea").value; var result = "AJAX error"; - try { result = http.m_request("GET", TestTCL.URL, null); } + try { result = http.m_request("GET", TestTCL.URL + '?sid='+SessionId, null); } catch (ex) { } if ("TCLOK" == result) { alert("Das Tcl-Skript ist okay!"); } else { alert("Das Tcl-Skript ist fehlerhaft: (" + result + ")"); } @@ -496,7 +499,7 @@ TestTCL = Test = { - URL: "/addons/email/testmail.cgi?ID=1", + URL: "/addons/email/testmail.cgi", /** * @fn apply @@ -509,7 +512,7 @@ Test = data += $("userScriptTextArea").value; var result = "AJAX error"; - try { result = http.m_request("GET", Test.URL, null); } + try { result = http.m_request("GET", Test.URL + '?sid='+SessionId+'&ID=1', null); } catch (ex) { } if ("OK" == result) { alert("Testmail wurde gesendet!"); } else { alert("Fehler beim Senden der Email (" + result + ")!"); } @@ -527,7 +530,7 @@ Backup = apply: function() { var result = "AJAX error"; - try { result = http.m_request("GET", Backup.URL, null); } + try { result = http.m_request("GET", Backup.URL + '?sid='+SessionId, null); } catch (ex) { } if ("BACKUPOK" == result) { window.open('/addons/email/addon/email-backup.tar.gz'); } @@ -545,8 +548,25 @@ Backup = **/ startup = function() { - MailCollection.init(); - Account.init(); - Tcl.init(); - MainMenu.select("mailMenuButton"); + if (location.search) + { + if (location.search.indexOf("sid=") > -1) + { + var teil = location.search.substring(location.search.indexOf("sid=") + 4); + if (teil.indexOf("&") > -1) + SessionId = teil.substring(0, teil.indexOf("&")); + else + SessionId = teil; + } + } + + Configuration = JSON.parse(http.m_request("GET", "/addons/email/config_js.cgi?sid="+SessionId, null)); + if (typeof(Configuration.Mails) !== 'undefined') { + MailCollection.init(); + Account.init(); + Tcl.init(); + MainMenu.select("mailMenuButton"); + } else { + alert("ERROR: no valid session"); + } }; diff --git a/www/index.html b/www/index.html index 3daa9de..b27e805 100644 --- a/www/index.html +++ b/www/index.html @@ -6,8 +6,6 @@ - -
diff --git a/www/querystring.tcl b/www/querystring.tcl new file mode 100644 index 0000000..bd1f01f --- /dev/null +++ b/www/querystring.tcl @@ -0,0 +1,9 @@ +catch { + set input $env(QUERY_STRING) + set pairs [split $input &] + foreach pair $pairs { + if {0 != [regexp "^(\[^=]*)=(.*)$" $pair dummy varname val]} { + set $varname $val + } + } +} diff --git a/www/save.cgi b/www/save.cgi index 091fbad..4e34b5a 100644 --- a/www/save.cgi +++ b/www/save.cgi @@ -34,7 +34,15 @@ # @license Public Domain ## -if { [catch { +load tclrega.so +source session.tcl +source querystring.tcl + +puts "Content-Type: text/plain; charset=iso-8859-1" +puts "" + +if { [info exists sid] && [check_session $sid] } { + if { [catch { source /etc/config/addons/email/config.tcl @@ -90,7 +98,14 @@ if { [catch { # 3. CGI-Query übernehmen if { [info exists env(QUERY_STRING)] } then { - set __args(Query) $env(QUERY_STRING) + set input $env(QUERY_STRING) + set pairs [split $input &] + foreach pair $pairs { + if {0 == [regexp "^(\[^=]*)=(.*)$" $pair dummy varname val]} { + set __args(Query) $pair + break + } + } } } @@ -249,14 +264,11 @@ if { [catch { default { error "Unknown Command [__args_get Query]" } } - puts "Content-Type: text/plain" - puts "" puts -nonewline "OK" -} errorMessage] } then { - puts "Content-Type: text/plain" - puts "" - puts "ERROR $errorMessage" + } errorMessage] } then { + puts -nonewline "ERROR $errorMessage" + } +} else { + puts -nonewline "ERROR: no valid session" } - - diff --git a/www/session.tcl b/www/session.tcl new file mode 100644 index 0000000..cbd4e8d --- /dev/null +++ b/www/session.tcl @@ -0,0 +1,13 @@ +#!/bin/tclsh + +load tclrega.so + +proc check_session sid { + if {[regexp {@([0-9a-zA-Z]{10})@} $sid all sidnr]} { + set res [lindex [rega_script "Write(system.GetSessionVarStr('$sidnr'));"] 1] + if {$res != ""} { + return 1 + } + } + return 0 +} diff --git a/www/testmail.cgi b/www/testmail.cgi index 6d69bc8..8df303e 100755 --- a/www/testmail.cgi +++ b/www/testmail.cgi @@ -7,24 +7,30 @@ # @license Public Domain ## +load tclrega.so +source querystring.tcl +source session.tcl + +puts "Content-Type: text/plain; charset=iso-8859-1" +puts "" + set email "/etc/config/addons/email/email" -if { [info exists env(QUERY_STRING)] } { - regsub -all {[&=]} $env(QUERY_STRING) { } query_str - regsub -all { } $query_str { {} } query_str - foreach {key val} $query_str { - set query($key) $val - } - if { [info exists query(ID)] } { - set ID [ format "%02d" $query(ID) ] - exec $email $ID - puts "Content-Type: text/plain" - puts "" - puts -nonewline "OK" - } else { - puts "Content-Type: text/plain" - puts "" - puts "ERROR ID missing" +if {[info exists sid] && [check_session $sid]} { + if { [info exists env(QUERY_STRING)] } { + regsub -all {[&=]} $env(QUERY_STRING) { } query_str + regsub -all { } $query_str { {} } query_str + foreach {key val} $query_str { + set query($key) $val + } + if { [info exists query(ID)] } { + set ID [ format "%02d" $query(ID) ] + exec $email $ID + puts -nonewline "OK" + } else { + puts -nonewline "ERROR: ID missing" + } } +} else { + puts -nonewline "Error: no valid session" } - diff --git a/www/testtcl.cgi b/www/testtcl.cgi index 39a39f7..577720e 100755 --- a/www/testtcl.cgi +++ b/www/testtcl.cgi @@ -7,26 +7,31 @@ # ### -# tcl.log File löschen -set killlog "/var/log/tcl.log" -catch { file delete -force -- $killlog } +load tclrega.so +source querystring.tcl +source session.tcl -# TCL Check ausführen -set tcl "/etc/config/addons/email/tclcheck.tcl" -exec $tcl - -# tcl.log öffnen und Inhalt in tcllog übergeben +puts "Content-Type: text/plain; charset=iso-8859-1" +puts "" +if {[info exists sid] && [check_session $sid]} { + # tcl.log File löschen + set killlog "/var/log/tcl.log" + catch { file delete -force -- $killlog } + + # TCL Check ausführen + set tcl "/etc/config/addons/email/tclcheck.tcl" + exec $tcl + + # tcl.log öffnen und Inhalt in tcllog übergeben if { [file exists "/var/log/tcl.log"] } { set tcllog [open "/var/log/tcl.log" r] set tclerror [read $tcllog] close $tcllog - puts "Content-Type: text/plain" - puts "" puts "$tclerror" } else { - puts "Content-Type: text/plain" - puts "" puts -nonewline "TCLOK" } - +} else { + puts -nonewline "Error: no valid session" +}