From 2b03fa316d46f537ae620faa4a10d8c0bc613b51 Mon Sep 17 00:00:00 2001 From: D9ping Date: Sat, 4 Aug 2018 01:58:34 +0200 Subject: [PATCH 1/4] Escape client input, console output etc. before doing any echo. Signed-off-by: D9ping --- ajax/networking/get_int_config.php | 2 +- includes/admin.php | 8 +- includes/authenticate.php | 1 - includes/config.php | 1 - includes/configure_client.php | 15 ++-- includes/dashboard.php | 33 ++++--- includes/dhcp.php | 71 ++++++++------- includes/functions.php | 135 ++++++++++++++--------------- includes/hostapd.php | 77 +++++++++------- includes/networking.php | 46 +++++----- includes/system.php | 22 ++--- includes/themes.php | 11 ++- 12 files changed, 221 insertions(+), 201 deletions(-) diff --git a/ajax/networking/get_int_config.php b/ajax/networking/get_int_config.php index 59b3a762..5e1c9b86 100644 --- a/ajax/networking/get_int_config.php +++ b/ajax/networking/get_int_config.php @@ -6,6 +6,7 @@ include_once('../../includes/functions.php'); if(isset($_POST['interface']) && isset($_POST['csrf_token']) && CSRFValidate()) { $int = $_POST['interface']; + // FIXME slashes and other forbidden filename characters not stripped. [security] if(!file_exists(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini')) { touch(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini'); } @@ -21,4 +22,3 @@ if(isset($_POST['interface']) && isset($_POST['csrf_token']) && CSRFValidate()) echo json_encode($jsonData); } -?> diff --git a/includes/admin.php b/includes/admin.php index 46f388e0..e649ea27 100755 --- a/includes/admin.php +++ b/includes/admin.php @@ -8,7 +8,7 @@ function DisplayAuthConfig($username, $password){ if (CSRFValidate()) { if (password_verify($_POST['oldpass'], $password)) { $new_username=trim($_POST['username']); - if ($_POST['newpass'] != $_POST['newpassagain']) { + if ($_POST['newpass'] !== $_POST['newpassagain']) { $status->addMessage('New passwords do not match', 'danger'); } else if ($new_username == '') { $status->addMessage('Username must not be empty', 'danger'); @@ -16,7 +16,8 @@ function DisplayAuthConfig($username, $password){ if (!file_exists(RASPI_ADMIN_DETAILS)) { $tmpauth = fopen(RASPI_ADMIN_DETAILS, 'w'); fclose($tmpauth); - } + } + if ($auth_file = fopen(RASPI_ADMIN_DETAILS, 'w')) { fwrite($auth_file, $new_username.PHP_EOL); fwrite($auth_file, password_hash($_POST['newpass'], PASSWORD_BCRYPT).PHP_EOL); @@ -46,7 +47,7 @@ function DisplayAuthConfig($username, $password){
- +
@@ -76,4 +77,3 @@ function DisplayAuthConfig($username, $password){ diff --git a/includes/authenticate.php b/includes/authenticate.php index 8a729679..79151a24 100755 --- a/includes/authenticate.php +++ b/includes/authenticate.php @@ -10,4 +10,3 @@ if (!$validated) { die ("Not authorized"); } -?> diff --git a/includes/config.php b/includes/config.php index 366b52e9..46536280 100755 --- a/includes/config.php +++ b/includes/config.php @@ -31,4 +31,3 @@ define('RASPI_CHANGETHEME_ENABLED', true ); define('LOCALE_ROOT', 'locale'); define('LOCALE_DOMAIN', 'messages'); -?> diff --git a/includes/configure_client.php b/includes/configure_client.php index b6dda6fc..7121ad75 100755 --- a/includes/configure_client.php +++ b/includes/configure_client.php @@ -158,14 +158,14 @@ function DisplayWPAConfig(){
-
+

showMessages(); ?>

- +
@@ -191,19 +191,19 @@ function DisplayWPAConfig(){ - - + + - + X - + - + --- @@ -233,4 +233,3 @@ function DisplayWPAConfig(){ diff --git a/includes/dashboard.php b/includes/dashboard.php index 5e4c9561..e39c246c 100755 --- a/includes/dashboard.php +++ b/includes/dashboard.php @@ -85,16 +85,16 @@ function DisplayDashboard(){

-

-

-

-


+

+

+

+


-

-


-

-

+

+


+

+

@@ -102,18 +102,18 @@ function DisplayDashboard(){

-

-

-

-

-

-


+

+

+

+

+

+


% + aria-valuenow="" aria-valuemin="0" aria-valuemax="100" + style="width: %;">%
@@ -143,4 +143,3 @@ function DisplayDashboard(){ diff --git a/includes/dhcp.php b/includes/dhcp.php index f65059f6..281da43d 100755 --- a/includes/dhcp.php +++ b/includes/dhcp.php @@ -14,7 +14,7 @@ function DisplayDHCPConfig() { if (CSRFValidate()) { $config = 'interface='.$_POST['interface'].PHP_EOL .'dhcp-range='.$_POST['RangeStart'].','.$_POST['RangeEnd'].',255.255.255.0,'.$_POST['RangeLeaseTime'].''.$_POST['RangeLeaseTimeUnits']; - exec( 'echo "'.$config.'" > /tmp/dhcpddata',$temp ); + exec( 'echo "'.$config.'" > /tmp/dhcpddata',$temp); system( 'sudo cp /tmp/dhcpddata '. RASPI_DNSMASQ_CONFIG, $return ); if( $return == 0 ) { @@ -83,14 +83,14 @@ function DisplayDHCPConfig() { $dselected = ''; switch( $arrRangeLeaseTime[2] ) { - case "h": - $hselected = " selected"; + case 'h': + $hselected = ' selected="selected"'; break; - case "m": - $mselected = " selected"; + case 'm': + $mselected = ' selected="selected"'; break; - case "d": - $dselected = " selected"; + case 'd': + $dselected = ' selected="selected"'; break; } @@ -119,42 +119,49 @@ function DisplayDHCPConfig() {
- +
- +
- +
- +
@@ -166,7 +173,7 @@ function DisplayDHCPConfig() { } else { echo''; } - ?> +?>
@@ -190,16 +197,18 @@ function DisplayDHCPConfig() { - ' . $lease_item . ''; - } - echo ''; - }; - ?> +'.htmlspecialchars($lease_item, ENT_QUOTES).''.PHP_EOL; + } + + echo ' '.PHP_EOL; +}; + +?> @@ -210,12 +219,10 @@ function DisplayDHCPConfig() {
- +
- diff --git a/includes/functions.php b/includes/functions.php index 8d05d415..ba97f147 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -55,7 +55,7 @@ function safefilerewrite($fileName, $dataToSave) { */ function CSRFToken() { ?> - + "; + echo '"; + + echo '' , PHP_EOL; } /** @@ -220,96 +223,93 @@ function DisplayOpenVPNConfig() { ?>
-
-
Configure OpenVPN -
- -
- - - -
-

-
- -

Client settings

+
+
Configure OpenVPN
+ +
+ + + +
+

+
+ +

Client settings

- - -
+ + +
- +
-

Server settings

-
+

Server settings

+
- - + +
- +
- +
- +
- +
- +
- +
-
+
'; + echo '' , PHP_EOL; } else { - echo ''; + echo '' , PHP_EOL; } - ?> +?>
-
- +
+
+?>
-
-
Configure TOR proxy -
+
+
Configure TOR proxy
@@ -365,37 +364,37 @@ function DisplayTorProxyConfig(){
- +
- +
- +
- +
- +
- +
@@ -404,47 +403,47 @@ function DisplayTorProxyConfig(){
- +
- +
- +
- +
- +
- +
-
- +
+ '; + echo '' , PHP_EOL; } else { - echo ''; + echo '' , PHP_EOL; }; ?> @@ -470,26 +469,26 @@ function SaveTORAndVPNConfig(){ echo "Attempting to start openvpn"; exec( 'sudo /etc/init.d/openvpn start', $return ); foreach( $return as $line ) { - echo $line."
"; + echo htmlspecialchars($line, ENT_QUOTES).'
' , PHP_EOL; } } elseif( isset($_POST['StopOpenVPN']) ) { echo "Attempting to stop openvpn"; exec( 'sudo /etc/init.d/openvpn stop', $return ); foreach( $return as $line ) { - echo $line."
"; + echo htmlspecialchars($line, ENT_QUOTES).'
' , PHP_EOL; } } elseif( isset($_POST['StartTOR']) ) { echo "Attempting to start TOR"; exec( 'sudo /etc/init.d/tor start', $return ); foreach( $return as $line ) { - echo $line."
"; + echo htmlspecialchars($line, ENT_QUOTES).'
' , PHP_EOL; } } elseif( isset($_POST['StopTOR']) ) { echo "Attempting to stop TOR"; exec( 'sudo /etc/init.d/tor stop', $return ); foreach( $return as $line ) { - echo $line."
"; + echo htmlspecialchars($line, ENT_QUOTES).'
' , PHP_EOL; } } } -?> + diff --git a/includes/hostapd.php b/includes/hostapd.php index 5aecec39..c5a41bd3 100755 --- a/includes/hostapd.php +++ b/includes/hostapd.php @@ -62,7 +62,8 @@ function DisplayHostAPDConfig(){ $arrConfig[$arrLine[0]]=$arrLine[1]; } }; - ?> + +?>
@@ -96,7 +97,7 @@ function DisplayHostAPDConfig(){
- +
@@ -129,7 +130,7 @@ function DisplayHostAPDConfig(){
- +
@@ -140,7 +141,7 @@ function DisplayHostAPDConfig(){ '; + echo '
'; } else { echo "
Logfile output not enabled"; } @@ -154,8 +155,14 @@ function DisplayHostAPDConfig(){
@@ -163,7 +170,7 @@ function DisplayHostAPDConfig(){
- + - + +
" /> '; + echo '' , PHP_EOL; } else { - echo ''; + echo '' , PHP_EOL; }; - ?> +?>
@@ -448,12 +456,17 @@ function DisplayHostAPDConfig(){ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status) { // It should not be possible to send bad data for these fields so clearly // someone is up to something if they fail. Fail silently. - if (!(array_key_exists($_POST['wpa'], $wpa_array) && array_key_exists($_POST['wpa_pairwise'], $enc_types) && in_array($_POST['hw_mode'], $modes))) { - error_log("Attempting to set hostapd config with wpa='".$_POST['wpa']."', wpa_pairwise='".$_POST['wpa_pairwise']."' and hw_mode='".$_POST['hw_mode']."'"); + if (!(array_key_exists($_POST['wpa'], $wpa_array) && + array_key_exists($_POST['wpa_pairwise'], $enc_types) && + in_array($_POST['hw_mode'], $modes))) { + error_log("Attempting to set hostapd config with wpa='".$_POST['wpa']."', wpa_pairwise='".$_POST['wpa_pairwise']."' and hw_mode='".$_POST['hw_mode']."'"); // FIXME: log injection return false; } - if ((!filter_var($_POST['channel'], FILTER_VALIDATE_INT)) || intval($_POST['channel']) < 1 || intval($_POST['channel']) > 14) { - error_log("Attempting to set channel to '".$_POST['channel']."'"); + + if ((!filter_var($_POST['channel'], FILTER_VALIDATE_INT)) || + intval($_POST['channel']) < 1 || + intval($_POST['channel']) > 14) { + error_log("Attempting to set channel to '".$_POST['channel']."'"); // FIXME: log injection return false; } @@ -477,25 +490,29 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status) exec('sudo /etc/raspap/hostapd/disablelog.sh'); } } + write_php_ini(["LogEnable" => $logEnable],'/etc/raspap/hostapd.ini'); // Verify input - if (strlen($_POST['ssid']) == 0 || strlen($_POST['ssid']) > 32) { + if (empty($_POST['ssid']) || strlen($_POST['ssid']) > 32) { // Not sure of all the restrictions of SSID $status->addMessage('SSID must be between 1 and 32 characters', 'danger'); $good_input = false; } + if (strlen($_POST['wpa_passphrase']) < 8 || strlen($_POST['wpa_passphrase']) > 63) { $status->addMessage('WPA passphrase must be between 8 and 63 characters', 'danger'); $good_input = false; } + if (! in_array($_POST['interface'], $interfaces)) { // The user is probably up to something here but it may also be a // genuine error. $status->addMessage('Unknown interface '.$_POST['interface'], 'danger'); $good_input = false; } - if (strlen($_POST['country_code']) != 0 && strlen($_POST['country_code']) != 2) { + + if (strlen($_POST['country_code']) !== 0 && strlen($_POST['country_code']) != 2) { $status->addMessage('Country code must be blank or two characters', 'danger'); $good_input = false; } @@ -510,6 +527,7 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status) fwrite($tmp_file, 'auth_algs=1'.PHP_EOL); fwrite($tmp_file, 'wpa_key_mgmt=WPA-PSK'.PHP_EOL); + // TODO: deal with ini file value escaping. E.g. ssid=E=mc2 becomes ssid=E\=mc2 fwrite($tmp_file, 'ssid='.$_POST['ssid'].PHP_EOL); fwrite($tmp_file, 'channel='.$_POST['channel'].PHP_EOL); fwrite($tmp_file, 'hw_mode='.$_POST['hw_mode'].PHP_EOL); @@ -531,6 +549,7 @@ function SaveHostAPDConfig($wpa_array, $enc_types, $modes, $interfaces, $status) return false; } } + return true; } -?> + diff --git a/includes/networking.php b/includes/networking.php index d0b01f3e..25a40542 100755 --- a/includes/networking.php +++ b/includes/networking.php @@ -30,7 +30,7 @@ function DisplayNetworkingConfig(){ '.$interface.''; + echo '
  • '.htmlspecialchars($interface, ENT_QUOTES).'
  • '; } ?> @@ -42,8 +42,8 @@ function DisplayNetworkingConfig(){ foreach($interfaces as $interface) { echo '
    -
    '.$interface.'
    -
    +
    '.htmlspecialchars($interface, ENT_QUOTES).'
    +
    '; } @@ -55,63 +55,63 @@ function DisplayNetworkingConfig(){
    - +
    -
    +

    ' . _("Adapter IP Address Settings") . '

    ' . _("Enable Fallback to Static Option") . '


    ' . _("Static IP Options") . '

    - - + +
    - - + +
    - - + +
    - - + +
    - - + +
    - ' . _("Save settings") . ' - ' . _("Apply settings") . ' + ' . _("Save settings") . ' + ' . _("Apply settings") . '
    '; } - ?> +?>
    diff --git a/includes/system.php b/includes/system.php index 6a07b3da..308b3121 100755 --- a/includes/system.php +++ b/includes/system.php @@ -141,23 +141,23 @@ function DisplaySystem(){

    -

    -

    -


    +

    +

    +


    -
    % + aria-valuenow="" aria-valuemin="0" aria-valuemax="100" + style="width: %;">%
    -
    % + aria-valuenow="" aria-valuemin="0" aria-valuemax="100" + style="width: %;">%
    @@ -200,9 +200,9 @@ function DisplaySystem(){
    +
    - + diff --git a/includes/themes.php b/includes/themes.php index fb3850c0..fded5bd3 100755 --- a/includes/themes.php +++ b/includes/themes.php @@ -11,13 +11,13 @@ function DisplayThemeConfig(){ switch( $_COOKIE['theme'] ) { case "custom.css": - $cselected = "selected"; + $cselected = ' selected="selected"'; break; case "hackernews.css": - $hselected = "selected"; + $hselected = ' selected="selected"'; break; case "terminal.css": - $tselected = "selected"; + $tselected = ' selected="selected"'; break; } @@ -37,9 +37,9 @@ function DisplayThemeConfig(){
    @@ -59,5 +59,4 @@ function DisplayThemeConfig(){ From bbea02cc542a39766a7b15d3d860409efe36c348 Mon Sep 17 00:00:00 2001 From: D9ping Date: Sat, 4 Aug 2018 14:03:14 +0200 Subject: [PATCH 2/4] Fix for #212 Signed-off-by: D9ping --- includes/dhcp.php | 49 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/includes/dhcp.php b/includes/dhcp.php index 281da43d..0ffb096b 100755 --- a/includes/dhcp.php +++ b/includes/dhcp.php @@ -12,16 +12,47 @@ function DisplayDHCPConfig() { $status = new StatusMessages(); if( isset( $_POST['savedhcpdsettings'] ) ) { if (CSRFValidate()) { - $config = 'interface='.$_POST['interface'].PHP_EOL - .'dhcp-range='.$_POST['RangeStart'].','.$_POST['RangeEnd'].',255.255.255.0,'.$_POST['RangeLeaseTime'].''.$_POST['RangeLeaseTimeUnits']; - exec( 'echo "'.$config.'" > /tmp/dhcpddata',$temp); - system( 'sudo cp /tmp/dhcpddata '. RASPI_DNSMASQ_CONFIG, $return ); + $errors = ''; + define('IFNAMSIZ', 16); + if (!preg_match('/^[a-zA-Z0-9]+$/', $_POST['interface']) || + strlen($_POST['interface']) >= IFNAMSIZ) { + $errors .= _('Invalid interface name.').'
    '.PHP_EOL; + } - if( $return == 0 ) { - $status->addMessage('Dnsmasq configuration updated successfully', 'success'); - } else { - $status->addMessage('Dnsmasq configuration failed to be updated', 'danger'); - } + if (!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $_POST['RangeStart']) && + !empty($_POST['RangeStart'])) { // allow ''/null ? + $errors .= _('Invalid DHCP range start.').'
    '.PHP_EOL; + } + + if (!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\z/', $_POST['RangeEnd']) && + !empty($_POST['RangeEnd'])) { // allow ''/null ? + $errors .= _('Invalid DHCP range end.').'
    '.PHP_EOL; + } + + if (!ctype_digit($_POST['RangeLeaseTime'])) { + $errors .= _('Invalid DHCP lease time, not a number.').'
    '.PHP_EOL; + } + + if (!in_array($_POST['RangeLeaseTimeUnits'], array('m', 'h', 'd', 'infinite'))) { + $errors .= _('Unknown DHCP lease time unit.').'
    '.PHP_EOL; + } + + $return = 1; + if (empty($errors)) { + $config = 'interface='.$_POST['interface'].PHP_EOL. + 'dhcp-range='.$_POST['RangeStart'].','.$_POST['RangeEnd']. + ',255.255.255.0,'.$_POST['RangeLeaseTime'].$_POST['RangeLeaseTimeUnits']; + exec('echo "'.$config.'" > /tmp/dhcpddata', $temp); + system('sudo cp /tmp/dhcpddata '.RASPI_DNSMASQ_CONFIG, $return); + } else { + $status->addMessage($errors, 'danger'); + } + + if ($return == 0) { + $status->addMessage('Dnsmasq configuration updated successfully', 'success'); + } else { + $status->addMessage('Dnsmasq configuration failed to be updated.', 'danger'); + } } else { error_log('CSRF violation'); } From fb7ba20055738e0e8d73107b5108329beb7d6920 Mon Sep 17 00:00:00 2001 From: D9ping Date: Mon, 6 Aug 2018 01:18:11 +0200 Subject: [PATCH 3/4] Fixed php notices log messages. Signed-off-by: D9ping --- includes/functions.php | 1 + includes/system.php | 2 ++ 2 files changed, 3 insertions(+) diff --git a/includes/functions.php b/includes/functions.php index ba97f147..d2ddd30c 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -332,6 +332,7 @@ function DisplayTorProxyConfig(){ '; } + $arrConfig = array(); foreach( $return as $a ) { if( $a[0] != "#" ) { $arrLine = explode( " ",$a) ; diff --git a/includes/system.php b/includes/system.php index 308b3121..8faefe61 100755 --- a/includes/system.php +++ b/includes/system.php @@ -35,6 +35,8 @@ function RPiVersion() { 'a02082' => 'Pi 3 Model B', 'a22082' => 'Pi 3 Model B' ); + + $cpuinfo_array = ''; exec('cat /proc/cpuinfo', $cpuinfo_array); $rev = trim(array_pop(explode(':',array_pop(preg_grep("/^Revision/", $cpuinfo_array))))); if (array_key_exists($rev, $revisions)) { From 182a6509e9bc2340718ccc00355a3667f350be59 Mon Sep 17 00:00:00 2001 From: D9ping Date: Mon, 6 Aug 2018 15:02:57 +0200 Subject: [PATCH 4/4] Don't allow to read ini file everywhere on filesystem. Signed-off-by: D9ping --- ajax/networking/get_int_config.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ajax/networking/get_int_config.php b/ajax/networking/get_int_config.php index 5e1c9b86..d29ee735 100644 --- a/ajax/networking/get_int_config.php +++ b/ajax/networking/get_int_config.php @@ -5,8 +5,7 @@ include_once('../../includes/functions.php'); if(isset($_POST['interface']) && isset($_POST['csrf_token']) && CSRFValidate()) { - $int = $_POST['interface']; - // FIXME slashes and other forbidden filename characters not stripped. [security] + $int = preg_replace('/[^a-z0-9]/', '', $_POST['interface']); if(!file_exists(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini')) { touch(RASPI_CONFIG_NETWORKING.'/'.$int.'.ini'); }