diff --git a/src/applications/config/check/PhabricatorMySQLSetupCheck.php b/src/applications/config/check/PhabricatorMySQLSetupCheck.php index dad9ba6d7b..a4048cbc33 100644 --- a/src/applications/config/check/PhabricatorMySQLSetupCheck.php +++ b/src/applications/config/check/PhabricatorMySQLSetupCheck.php @@ -382,6 +382,34 @@ final class PhabricatorMySQLSetupCheck extends PhabricatorSetupCheck { new PhutilNumber($delta))); } + $local_infile = $ref->loadRawMySQLConfigValue('local_infile'); + if ($local_infile) { + $summary = pht( + 'The MySQL "local_infile" option is enabled. This option is '. + 'unsafe.'); + + $message = pht( + 'Your MySQL server is configured with the "local_infile" option '. + 'enabled. This option allows an attacker who finds an SQL injection '. + 'hole to escalate their attack by copying files from the webserver '. + 'into the database with "LOAD DATA LOCAL INFILE" queries, then '. + 'reading the file content with "SELECT" queries.'. + "\n\n". + 'You should disable this option in your %s file, in the %s section:'. + "\n\n". + '%s', + phutil_tag('tt', array(), 'my.cnf'), + phutil_tag('tt', array(), '[mysqld]'), + phutil_tag('pre', array(), 'local_infile=0')); + + $this->newIssue('mysql.local_infile') + ->setName(pht('Unsafe MySQL "local_infile" Setting Enabled')) + ->setSummary($summary) + ->setMessage($message) + ->setDatabaseRef($ref) + ->addMySQLConfig('local_infile'); + } + } protected function shouldUseMySQLSearchEngine() { diff --git a/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php b/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php index cf3148b5be..bee2bc91b8 100644 --- a/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php +++ b/src/applications/config/check/PhabricatorPHPConfigSetupCheck.php @@ -112,6 +112,42 @@ final class PhabricatorPHPConfigSetupCheck extends PhabricatorSetupCheck { ->setMessage($message); } + + if (extension_loaded('mysqli')) { + $infile_key = 'mysqli.allow_local_infile'; + } else { + $infile_key = 'mysql.allow_local_infile'; + } + + if (ini_get($infile_key)) { + $summary = pht( + 'Disable unsafe option "%s" in PHP configuration.', + $infile_key); + + $message = pht( + 'PHP is currently configured to honor requests from any MySQL server '. + 'it connects to for the content of any local file.'. + "\n\n". + 'This capability supports MySQL "LOAD DATA LOCAL INFILE" queries, but '. + 'allows a malicious MySQL server read access to the local disk: the '. + 'server can ask the client to send the content of any local file, '. + 'and the client will comply.'. + "\n\n". + 'Although it is normally difficult for an attacker to convince '. + 'Phabricator to connect to a malicious MySQL server, you should '. + 'disable this option: this capability is unnecessary and inherently '. + 'dangerous.'. + "\n\n". + 'To disable this option, set: %s', + phutil_tag('tt', array(), pht('%s = 0', $infile_key))); + + $this->newIssue('php.'.$infile_key) + ->setName(pht('Unsafe PHP "Local Infile" Configuration')) + ->setSummary($summary) + ->setMessage($message) + ->addPHPConfig($infile_key); + } + } }