| Current Path : /home/smartconb/www/armencom33/plugins/content/gpfirewall/ |
| Current File : /home/smartconb/www/armencom33/plugins/content/gpfirewall/gpfirewall.php |
<?php
/**
* @package gpfirewall.Plugin
* @subpackage Content.gpfirewall
* @plugin gpfirewall
* @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
*/
defined('_JEXEC') or die;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Session\Session;
use Joomla\CMS\Version;
class PlgContentGPfirewall extends CMSPlugin
{
############# NEVER CHANGE BELOW CODE ###############
const WAF_V = '1.0.0';
private $WAF_TOKEN;
private $WAF_FRONT;
private $WAF_BACK;
private $WAF_TOWER;
private $WAF_HUB;
private $WAF_CHECKPOINT;
private $WAF_SIDE;
private $WAF_POST;
private $WAF_SESSION;
private $WAF_CSRF;
private $WAF_XFRAME;
private $WAF_HEADERS;
private $url;
private $WAF_APP_NAME;
private $plugin_page;
private $WAF_AUTOUPDATE;
private $WAF_update_url;
private $WAF_update_performed;
private $WAF_update_backup_created;
private $WAF_update_tmp_created;
private $WAF_update_run;
private $WAF_update_log;
protected $session;
function __construct()
{
// If called while plugin disabled, exit and unset the calling hook point.
if (\Joomla\CMS\Plugin\PluginHelper::isEnabled('content', 'gpfirewall') != 1) {
$this->wafDisable();
return;
}
// Front/Back office side Get/Set
$app = Joomla\CMS\Factory::getApplication();
if ($app->getName() == 'administrator') {
$this->WAF_SIDE = -1;
} else {
$this->WAF_SIDE = 1;
}
$this->session = \Joomla\CMS\Factory::getSession();
// Check if plugin is enabled & Get plugin params
$this->plugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('content', 'gpfirewall');
$this->pluginParams = new \Joomla\Registry\Registry($this->plugin->params);
$this->WAF_TOKEN = strip_tags($this->pluginParams->get('WAF_TOKEN'));
if ($this->isValidToken($this->WAF_TOKEN) === false) {
$this->WAF_TOKEN = '';
$this->UpdatedRecord("WAF_TOKEN", null);
}
$this->WAF_FRONT = strip_tags($this->pluginParams->get('WAF_FRONT'));
$this->WAF_BACK = strip_tags($this->pluginParams->get('WAF_BACK'));
$this->WAF_TOWER = $this->pluginParams->get('WAF_TOWER');
$this->WAF_HUB = $this->pluginParams->get('WAF_HUB');
$this->WAF_CSRF = $this->pluginParams->get('WAF_CSRF');
$this->WAF_XFRAME = $this->pluginParams->get('WAF_XFRAME');
$this->WAF_POST = $this->pluginParams->get('WAF_POST');
$this->WAF_SESSION = $this->pluginParams->get('WAF_SESSION');
$this->WAF_HEADERS = $this->pluginParams->get('WAF_HEADERS');
$this->WAF_CHECKPOINT = $this->pluginParams->get('WAF_CHECKPOINT');
$this->WAF_update_url = 'https://hub.geniusplugin.com/pub/joomla_version.php?v=';
$this->WAF_update_run = false;
$this->WAF_AUTOUPDATE = true; // Assume auto-update is enabled by default
$this->WAF_update_performed = false;
$this->WAF_APP_NAME = 'j';
// refresh data once per 20mn
if (!empty($this->WAF_TOKEN) && (empty($this->WAF_HUB) || $this->WAF_CHECKPOINT != date('YmdH') . substr(date('i'), 0, 1))) {
if (empty($this->WAF_HUB) || (date('YmdH') . substr(date('i'), 0, 1)) % 2 == 0)
$this->getTower();
// Check if plugin is enabled & Get plugin params
$this->plugin = \Joomla\CMS\Plugin\PluginHelper::getPlugin('content', 'gpfirewall');
$this->pluginParams = new \Joomla\Registry\Registry($this->plugin->params);
$this->WAF_TOKEN = $this->pluginParams->get('WAF_TOKEN');
$this->WAF_FRONT = $this->pluginParams->get('WAF_FRONT');
$this->WAF_BACK = $this->pluginParams->get('WAF_BACK');
$this->WAF_TOWER = $this->pluginParams->get('WAF_TOWER');
$this->WAF_HUB = $this->pluginParams->get('WAF_HUB');
$this->WAF_CSRF = $this->pluginParams->get('WAF_CSRF');
$this->WAF_XFRAME = $this->pluginParams->get('WAF_XFRAME');
$this->WAF_POST = $this->pluginParams->get('WAF_POST');
$this->WAF_SESSION = $this->pluginParams->get('WAF_SESSION');
$this->WAF_HEADERS = $this->pluginParams->get('WAF_HEADERS');
$this->WAF_CHECKPOINT = $this->pluginParams->get('WAF_CHECKPOINT');
}
// Get this plugin id
$plugid = $this->plugin->id;
$this->url = Uri::getInstance()->toString();
// Set the current page is this plugin edit page from backend
if (strpos($this->url, 'com_plugins&view=plugin&layout=edit&extension_id=' . $plugid) !== false) {
$this->plugin_page = 1;
} else {
$this->plugin_page = 0;
}
// Deploy the firewall whatever the token is/Not empty
$this->header_modify();
// Set default result of license request
$wafCheck = -1;
$isroot = \Joomla\CMS\Factory::getApplication()->isClient('administrator');
$app = \Joomla\CMS\Factory::getApplication();
// run once the plugin settings view on this plugin backoffice page.
if ($this->WAF_SIDE == -1 && $this->plugin_page == 1 && $isroot === true) {
if (!empty($this->WAF_TOKEN)) {
$wafCheck = json_decode($this->check_license(), true);
if (is_array($wafCheck) && $wafCheck[0] == 200 && isset($wafCheck[1]) && !empty($wafCheck[1])) {
// Display first activation welcome message
if (isset($wafCheck[2]) && !empty($wafCheck[2])) {
echo '<div id="system-message-container" aria-live="polite"><noscript><div class="alert alert-success">' . $wafCheck[2] . '</div></noscript><joomla-alert type="success" close-text="Close" dismiss="true" role="alert" style="animation-name: joomla-alert-fade-in;"><button type="button" class="joomla-alert--close" aria-label="Close"><span aria-hidden="true">×</span></button><div class="alert-heading"><span class="success"></span><span class="visually-hidden">success</span></div><div class="alert-wrapper"><div class="alert-message">' . $wafCheck[2] . '</div></div></joomla-alert></div>';
}
// Notify user if asked for by the plugin.
if (isset($wafCheck[4]) && $wafCheck[4] == 1) {
// Notifier once per session and n times remotely
if (!$this->session->get('WAF_NOTIFIER') || $this->session->get('WAF_NOTIFIER') != date('Ymd')) {
$this->session->set('WAF_NOTIFIER', date('Ymd'));
echo '<p>' . $this->notify_user();
}
}
// Get a snapshot map of the current attacks and legitimate visitors
echo '<div id="ifr"><span style="padding-left:25px">' . $wafCheck[3] . '</span><p>' . file_get_contents($this->WAF_HUB . '/noc-r.php?app='. $this->WAF_APP_NAME.'&token=' . $this->WAF_TOKEN) . '</p></div>';
}
}
// Display error message on empty token or invalid token
if (empty($this->WAF_TOKEN) || $wafCheck == -1 || !isset($wafCheck[0]) || $wafCheck[0] != 200) {
// Disable the firewall
$this->UpdatedRecord("WAF_FRONT", null);
$this->UpdatedRecord("WAF_BACK", null);
$this->WAF_FRONT = null;
$this->WAF_BACK = null;
$this->jsValidateForm();
$systemmessage = 'License token is invalid. Please fill the below field with your GP Firewall token, then clic on the submit button. <a href="https://cloud.geniusplugin.com/order.php?step=1&productGroup=1" target="_blank">Need a free license token?</a>';
echo '<div id="system-message-container" aria-live="polite"><noscript><div class="alert alert-warning">' . $systemmessage . '</div></noscript><joomla-alert type="warning" close-text="Close" dismiss="true" role="alert" style="animation-name: joomla-alert-fade-in;"><button type="button" class="joomla-alert--close" aria-label="Close"><span aria-hidden="true">×</span></button><div class="alert-heading"><span class="warning"></span><span class="visually-hidden">success</span></div><div class="alert-wrapper"><div class="alert-message">' . $systemmessage . '</div></div></joomla-alert></div>';
return;
}
// Display warning message if silence is the only thing we get from remote server
if ($wafCheck == NULL) {
// Disable the firewall
$this->UpdatedRecord("WAF_FRONT", null);
$this->UpdatedRecord("WAF_BACK", null);
$this->WAF_FRONT = null;
$this->WAF_BACK = null;
$this->jsValidateForm();
$systemmessage = 'There was a temporary problem. Please check your token, then try again or contact support.';
echo '<div id="system-message-container" aria-live="polite"><noscript><div class="alert alert-warning">' . $systemmessage . '</div></noscript><joomla-alert type="warning" close-text="Close" dismiss="true" role="alert" style="animation-name: joomla-alert-fade-in;"><button type="button" class="joomla-alert--close" aria-label="Close"><span aria-hidden="true">×</span></button><div class="alert-heading"><span class="warning"></span><span class="visually-hidden">success</span></div><div class="alert-wrapper"><div class="alert-message">' . $systemmessage . '</div></div></joomla-alert></div>';
return;
}
$this->gp_css_js();
}
}
/**
* sanitize the token and remove any potentially harmful content
*
* @param string $input
* @return boolean
*/
function isValidToken($input)
{
if (strlen($input) > 42) {
return false;
}
$sanitizedInput = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
if ($sanitizedInput !== $input) {
return false;
}
if (preg_match('/<[^>]*>/', $input)) {
return false;
}
$pattern = '/^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+){0,8}$/';
return preg_match($pattern, $input) === 1;
}
/**
* Set/Update this plugin params with no form use
*
* @param [string] $paramToUpdate
* @param [void] $value
* @return void
*/
private function UpdatedRecord($paramToUpdate, $value)
{
$table = \Joomla\CMS\Table\Table::getInstance('extension');
// Look up extension id
$id = $table->find(array('element' => 'gpfirewall'));
if ($id === false) {
$this->setError($table->getError());
return false;
}
// Load the previous data
if (!$table->load($id)) {
$this->setError($table->getError());
return false;
}
// Get the params
$params = $table->params;
$params = json_decode($params);
$params->$paramToUpdate = $value;
$params = json_encode($params);
$table->params = $params;
// Check the data.
if (!$table->check()) {
$this->setError($table->getError());
return false;
}
// Store the data.
if (!$table->store()) {
$this->setError($table->getError());
return false;
}
}
/**
* Returns the id of this plugin
*
* @param [string] $name (plugin name)
* @param [string] $type (plugin,..)
* @param [string] $element (plugin name)
* @param [string] $folder (plugin type - content)
* @return num|false
*/
function getId($name, $type, $element, $folder)
{
$db = \Joomla\CMS\Factory::getDBO();
$query = $db->getQuery(true);
$query
->select($db->quoteName('a.extension_id'))
->from($db->quoteName('#__extensions', 'a'))
->where($db->quoteName('a.name') . ' = ' . $db->quote($name))
->where($db->quoteName('a.type') . ' = ' . $db->quote($type))
->where($db->quoteName('a.element') . ' = ' . $db->quote($element))
->where($db->quoteName('a.folder') . ' = ' . $db->quote($folder));
$db->setQuery($query);
$db->execute();
if ($db->getNumRows()) {
return $db->loadResult();
}
return false;
}
/**
* Function to Crypt data
*
* @param [void] $data
* @param [string] $key
* @return string
*/
function encryptClientData($data, $key)
{
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC'));
$encrypted = openssl_encrypt($data, 'AES-256-CBC', $key, 0, $iv);
$encoded = base64_encode($encrypted . '::' . $iv);
return $encoded;
}
/**
* Get application and plugins name, version, status and slug
* @return string
*/
function app_version()
{
define('_JEXEC', 1);
define('JPATH_BASE', __DIR__);
require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';
jimport('joomla.version');
// Get Joomla version
$jversion = new Version;
$WAF_APPV['Core'] = $jversion->getShortVersion();
$db = \Joomla\CMS\Factory::getDBO();
$query = $db->getQuery(true)
->select('name, element, type, manifest_cache, enabled')
->from('#__extensions')
->where('type IN (' . $db->quote('plugin') . ', ' . $db->quote('component') . ', ' . $db->quote('module') . ')');
$db->setQuery($query);
$extensions = $db->loadAssocList();
foreach ($extensions as $extension) {
if ($extension['enabled'] == 1) {
$manifest = json_decode($extension['manifest_cache'], true);
$WAF_APPV[$extension['name']] = $manifest['version'] . ';' . $extension['element'] . ';' . $extension['type'];
}
}
return json_encode($WAF_APPV);
}
/**
* Main Firewall header modify and implementation. Changes the header of any page, sends request to tower then allow/deny access to user.
* @param int $this->WAF_SIDE
* @return void
*/
function header_modify()
{
$this->session = \Joomla\CMS\Factory::getSession();
$input = \Joomla\CMS\Factory::getApplication()->input;
// Exit if no token, tower or disabled side
if (empty($this->WAF_TOKEN)) return;
if (empty($this->WAF_TOWER)) return;
if ($this->WAF_SIDE == 1 && $this->WAF_FRONT != 1) return;
if ($this->WAF_SIDE == -1 && $this->WAF_BACK != 1) return;
if ($this->WAF_CHECKPOINT != date('YmdH') . substr(date('i'), 0, 1)) {
if ((date('YmdH') . substr(date('i'), 0, 1)) % 2 == 0)
$this->getTower();
}
if (isset($this->WAF_XFRAME) && !empty($this->WAF_XFRAME) && $this->WAF_XFRAME != -1) {
$XFRAME = json_decode(base64_decode($this->WAF_XFRAME), true);
if (is_array($XFRAME)) {
foreach ($XFRAME as $key => $value) {
if ($key === 'X-Powered-By') {
header_remove('X-Powered-By');
} elseif ($key === 'Server') {
header_remove('Server');
} elseif ($key === 'Hmaxsize') {
$headerSize = 0;
foreach ($_SERVER as $name => $value) {
if (strpos($name, 'HTTP_') === 0) {
$headerSize += strlen($name) + strlen($value);
}
}
if ($headerSize > $value) {
exit;
}
} else {
header($key . ": " . $value);
}
}
}
}
if ($this->session->get('uniquehash') === true) {
$this->session->set('uniquehash', false);
$this->checkHash(json_encode($input->post->getArray()));
exit;
}
$this->session->set('uniquehash', false);
if (isset($this->WAF_CSRF) && !empty($this->WAF_CSRF) && $this->WAF_CSRF == 1 && $this->WAF_SIDE == 1) {
if ($input->server->get('REQUEST_METHOD') === 'GET' && $input->get->count() > 1 && !$input->get->isEmpty()) {
$csrfToken = $input->get->get('csrf_token', '');
$csrfStamp = $input->get->get('csrf_stamp', '');
if (empty($csrfToken) || empty($csrfStamp) || $csrfToken !== hash('sha256', $this->WAF_TOKEN . $csrfStamp)) {
die('Invalid request.');
}
}
if ($input->getMethod() === 'POST' && $input->post->count() > 1 && !$input->post->isEmpty()) {
$csrfToken = $input->post->get('csrf_token');
$csrfStamp = $input->post->get('csrf_stamp');
if (empty($csrfToken) || empty($csrfStamp) || $csrfToken != hash('sha256', $this->WAF_TOKEN . $csrfStamp)) {
die('Invalid request.');
}
}
$csrf_stamp = substr(microtime(true) * 1000, 0, 13);
$csrf_token = hash('sha256', $this->WAF_TOKEN . $csrf_stamp);
?>
<script>
document.addEventListener("DOMContentLoaded", function() {
var forms = document.getElementsByTagName("form");
for (var i = 0; i < forms.length; i++) {
var form = forms[i];
var csrfInput = document.createElement("input");
csrfInput.setAttribute("type", "hidden");
csrfInput.setAttribute("name", "csrf_token");
csrfInput.setAttribute("value", "<?php echo $csrf_token; ?>");
form.appendChild(csrfInput);
var csrfInput = document.createElement("input");
csrfInput.setAttribute("type", "hidden");
csrfInput.setAttribute("name", "csrf_stamp");
csrfInput.setAttribute("value", "<?php echo $csrf_stamp; ?>");
form.appendChild(csrfInput);
}
// Get all anchor tags on the page
var anchorTags = document.getElementsByTagName('a');
// Loop through each anchor tag
for (var i = 0; i < anchorTags.length; i++) {
var href = anchorTags[i].getAttribute('href');
// Check if the href contains a query parameter
if (href.indexOf('?') !== -1) {
// Check if the csrf_token and csrf_stamp variables already exist in the URL
if (href.indexOf('csrf_token=') === -1 || href.indexOf('csrf_stamp=') === -1) {
// Add the csrf_token and csrf_stamp variables to the URL
var updatedHref = href + (href.indexOf('?') === -1 ? '?' : '&');
if (href.indexOf('csrf_token=') === -1) {
updatedHref += 'csrf_token=' + '<?php echo $csrf_token; ?>' + '&';
}
if (href.indexOf('csrf_stamp=') === -1) {
updatedHref += 'csrf_stamp=' + '<?php echo $csrf_stamp; ?>';
}
// Update the href attribute with the modified URL
anchorTags[i].setAttribute('href', updatedHref);
}
}
}
});
</script>
<?php
}
$test_ip = '';
$agent = '';
$user_ip = $_SERVER['REMOTE_ADDR'];
$server_ip = (isset($_SERVER['SERVER_ADDR'])) ? $_SERVER['SERVER_ADDR'] : '';
if (isset($_SERVER['HTTP_Forwarded-For']) && !empty($_SERVER['HTTP_Forwarded-For'])) {
$_SERVER['HTTP_Forwarded-For'] = trim(current(explode(',', $_SERVER['HTTP_Forwarded-For'])));
if (filter_var($_SERVER['HTTP_Forwarded-For'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_Forwarded-For'];
}
}
if (isset($_SERVER['HTTP_X-Client-IP']) && !empty($_SERVER['HTTP_X-Client-IP'])) {
$_SERVER['HTTP_X-Client-IP'] = trim(current(explode(',', $_SERVER['HTTP_X-Client-IP'])));
if (filter_var($_SERVER['HTTP_X-Client-IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_X-Client-IP'];
}
}
if (isset($_SERVER['HTTP_X-Cluster-Client-Ip']) && !empty($_SERVER['HTTP_X-Cluster-Client-Ip'])) {
$_SERVER['HTTP_X-Cluster-Client-Ip'] = trim(current(explode(',', $_SERVER['HTTP_X-Cluster-Client-Ip'])));
if (filter_var($_SERVER['HTTP_X-Cluster-Client-Ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_X-Cluster-Client-Ip'];
}
}
if (isset($_SERVER['HTTP_Client-IP']) && !empty($_SERVER['HTTP_Client-IP'])) {
$_SERVER['HTTP_Client-IP'] = trim(current(explode(',', $_SERVER['HTTP_Client-IP'])));
if (filter_var($_SERVER['HTTP_Client-IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_Client-IP'];
}
}
if (isset($_SERVER['HTTP_CF_CONNECTING_IP']) && !empty($_SERVER['HTTP_CF_CONNECTING_IP'])) {
$_SERVER['HTTP_CF_CONNECTING_IP'] = trim(current(explode(',', $_SERVER['HTTP_CF_CONNECTING_IP'])));
if (filter_var($_SERVER['HTTP_CF_CONNECTING_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
}
}
if (isset($_SERVER['HTTP_X_REAL_IP']) && !empty($_SERVER['HTTP_X_REAL_IP'])) {
$_SERVER['HTTP_X_REAL_IP'] = trim(current(explode(',', $_SERVER['HTTP_X_REAL_IP'])));
if (filter_var($_SERVER['HTTP_X_REAL_IP'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_X_REAL_IP'];
}
}
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$_SERVER['HTTP_X_FORWARDED_FOR'] = trim(current(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])));
if (filter_var($_SERVER['HTTP_X_FORWARDED_FOR'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
$user_ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
}
if ($user_ip == $server_ip || $user_ip == '::1' || $user_ip == '127.0.0.1' || $user_ip == $_SERVER['SERVER_ADDR'] || empty($user_ip)) {
return;
}
// Check if the 'ip' parameter is set and not empty
if ($input->get('ip', '', 'STRING') !== '') {
$test_ip = $input->get('ip', '', 'STRING');
}
$protocol = 'http';
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 443) $protocol = 'https';
if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) $protocol = 'https';
if (isset($_SERVER['HTTP_X_FORWARDED_PORT']) && $_SERVER['HTTP_X_FORWARDED_PORT'] == 443) $protocol = 'https';
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') $protocol = 'https';
$page = $protocol . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$agent = base64_encode($_SERVER['HTTP_USER_AGENT']);
}
if ($this->WAF_POST == 1) {
$filteredPost = $input->post->getArray();
/*
$dismissedKeys = ['key1', 'key2', 'key3'];
foreach ($dismissedKeys as $dismissedKey) {
unset($filteredPost[$dismissedKey]);
}
*/
$sendrequests = $this->encryptClientData(base64_encode(json_encode($filteredPost)), $this->WAF_TOKEN);
} else {
$sendrequests = '';
}
if ($this->WAF_SESSION == 1) {
setcookie('session_cookie', 'value', ['expires' => time() + 3600, 'path' => '/', 'domain' => '', 'secure' => true, 'httponly' => true, 'samesite' => 'Lax']);
$sessionid = base64_encode(session_id());
} else {
$sessionid = '';
}
if ($this->WAF_HEADERS == 1) {
$filteredServer = getallheaders();
/*
$dismissedHeaders = ['HTTP_USER_AGENT', 'HTTP_REFERER'];
foreach ($dismissedHeaders as $dismissedHeader) {
unset($filteredServer[$dismissedHeader]);
}
*/
$waf_headers = $this->encryptClientData(base64_encode(json_encode($filteredServer)), $this->WAF_TOKEN);
} else {
$waf_headers = '';
}
$data = array(
'token' => $this->WAF_TOKEN,
'ip' => $user_ip,
'side' => $this->WAF_SIDE,
'tip' => $test_ip,
'ag' => $agent,
'page' => base64_encode($page),
'requests' => $sendrequests,
'session' => $sessionid,
'headers' => $waf_headers,
'wafapp' => $this->app_version()
);
$url = $this->WAF_TOWER . '?app='. $this->WAF_APP_NAME.'&v=' . self::WAF_V . '&token=' . $this->WAF_TOKEN;
$responseText = $this->postData($url, $data);
if ($this->WAF_update_run === true) {
try {
$this->waf_CheckForUpdates(); // Trigger the update check
//print_r($this->WAF_update_log); // Error Logs for support
} catch (Exception $e) {
// No error message displayed for security reasons.
}
}
if (!empty($responseText)) {
$response = $responseText;
// Send email if user asked for alert on denied access
if (strpos($responseText, '-WAFMAIL-') !== false) {
$response = explode('-WAFMAIL-', $responseText)[0];
$mailer = explode('-WAFMAIL-', $responseText)[1];
$mailer = json_decode(base64_decode($mailer));
mail($mailer[0], $mailer[1], $mailer[2]);
}
// Refresh servers on demand
if (strpos($responseText, '-WAFREDIRECT-') !== false) {
$response = explode('-WAFREDIRECT-', $responseText)[0];
$this->getTower();
}
// Deny access to the page
if ($response == 'deny') {
exit;
} elseif ($response == '501') {
// Disable the firewall
$this->UpdatedRecord("WAF_FRONT", null);
$this->UpdatedRecord("WAF_BACK", null);
return;
} else {
// Process firewall options
if (strpos($response, 'uniquehash') !== false) {
$this->session->set('uniquehash', true);
}
echo $response;
exit;
}
}
}
private function checkHash($hashes)
{
$url = $this->WAF_TOWER . '?app='. $this->WAF_APP_NAME.'&v=' . self::WAF_V;
$data['hashes'] = $hashes;
$responseText = $this->postData($url, $data);
if (!empty($responseText)) {
echo $responseText;
exit;
}
return;
}
/*
* Output informations on dashboard top; hits limit notification here
* @return void
*
*/
function notify_user($dashboard = 0)
{
$ch = curl_init($this->WAF_HUB . '/license.php?v=' . self::WAF_V . '&app='. $this->WAF_APP_NAME.'§ion=' . $dashboard . '&action=pluginboard&token=' . $this->WAF_TOKEN);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$check_result = curl_exec($ch);
curl_close($ch);
if (!empty($check_result)) {
return base64_decode($check_result);
}
}
function wafDisable()
{
$callin_firewall_admin = 'if(!class_exists("PlgContentGPfirewall")){include_once ("../plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS';
file_put_contents(JPATH_ADMINISTRATOR . "/includes/app.php", str_replace($callin_firewall_admin, "\r\n", file_get_contents(JPATH_ADMINISTRATOR . "/includes/app.php")));
$callin_firewall = 'if(!class_exists("PlgContentGPfirewall")){include_once (JPATH_BASE . "/plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS';
file_put_contents(JPATH_BASE . "/includes/app.php", str_replace($callin_firewall, "\r\n", file_get_contents(JPATH_BASE . "/includes/app.php")));
}
// Add protection to any page witout a hook
function hooksPoints()
{
$callin_firewall_admin = PHP_EOL . 'if(!class_exists("PlgContentGPfirewall")){include_once ("../plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS' . PHP_EOL . '$app->execute();';
if (strpos(file_get_contents(JPATH_ADMINISTRATOR . "/includes/app.php"), 'GPNOHOOKS') === false) {
file_put_contents(JPATH_ADMINISTRATOR . "/includes/app.php", str_replace('$app->execute();', "\r\n" . $callin_firewall_admin, file_get_contents(JPATH_ADMINISTRATOR . "/includes/app.php")));
}
$callin_firewall = PHP_EOL . 'if(!class_exists("PlgContentGPfirewall")){include_once (JPATH_BASE . "/plugins/content/gpfirewall/gpfirewall.php");new PlgContentGPfirewall();}//GPNOHOOKS' . PHP_EOL . '$app->execute();';
if (strpos(file_get_contents(JPATH_BASE . "/includes/app.php"), 'GPNOHOOKS') === false) {
file_put_contents(JPATH_BASE . "/includes/app.php", str_replace('$app->execute();', "\r\n" . $callin_firewall, file_get_contents(JPATH_BASE . "/includes/app.php")));
}
}
/*
* Get (new) tower and/or (new) dashboard set for the license.
* @return void
*
*/
function getTower()
{
$this->session = \Joomla\CMS\Factory::getSession();
$this->hooksPoints();
$ch = curl_init('https://hub.geniusplugin.com/license.php?v=' . self::WAF_V . '&app='. $this->WAF_APP_NAME.'&action=gettower&token=' . $this->WAF_TOKEN);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$result = curl_exec($ch);
curl_close($ch);
if (!empty($result)) {
$server = json_decode($result);
if (is_array($server)) {
$this->WAF_TOWER = $server[0];
$this->WAF_HUB = $server[1];
$this->WAF_CSRF = $server[3];
$this->WAF_XFRAME = $server[4];
$this->WAF_POST = $server[5];
$this->WAF_SESSION = $server[6];
$this->WAF_HEADERS = $server[7];
$this->UpdatedRecord("WAF_TOWER", $this->WAF_TOWER);
$this->UpdatedRecord("WAF_HUB", $this->WAF_HUB);
$this->UpdatedRecord("WAF_CSRF", $this->WAF_CSRF);
$this->UpdatedRecord("WAF_XFRAME", $this->WAF_XFRAME);
$this->UpdatedRecord("WAF_POST", $this->WAF_POST);
$this->UpdatedRecord("WAF_SESSION", $this->WAF_SESSION);
$this->UpdatedRecord("WAF_HEADERS", $this->WAF_HEADERS);
if (isset($server[8]) && strpos($server[8], '-WAFMAIL-') === 0) {
$mailer = explode('-WAFMAIL-', $server[8])[1];
$mailer = json_decode(base64_decode($mailer));
mail($mailer[0], $mailer[1], $mailer[2]);
}
if (isset($server[9]) && $server[9] === '-WAFUPDATE-') {
$this->session->set('WAF_AUTOUPDATE', true);
// Trigger the update check waf_CheckForUpdates();
$this->WAF_update_run = true;
} else {
$this->session->set('WAF_AUTOUPDATE', false);
}
}
}
$this->UpdatedRecord("WAF_CHECKPOINT", date('YmdH') . substr(date('i'), 0, 1));
}
/**
* Automatic license check
* @return string
*/
function check_license()
{
$ch = curl_init($this->WAF_HUB . '/license.php?v=' . self::WAF_V . '&app='. $this->WAF_APP_NAME.'&action=licensecheck&token=' . $this->WAF_TOKEN);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
$check_result = curl_exec($ch);
curl_close($ch);
return $check_result;
}
function jsValidateForm()
{
echo "
<script>
document.addEventListener('DOMContentLoaded', function() {
frontside = '" . $this->WAF_FRONT . "';
backside = '" . $this->WAF_BACK . "';
if(frontside != 1) { document.getElementById('jform_params_WAF_FRONT').checked = false;}
if(backside != 1) {document.getElementById('jform_params_WAF_BACK').checked = false;}});</script>
";
}
/**
* Add css and js
*
* @return void
*/
function gp_css_js()
{
$style = "
.waf-live {
display: inline-block;
vertical-align: top;
box-sizing: border-box;
margin: 1px 10px -1px 2px;
padding: 0 5px;
min-width: 18px;
height: 18px;
border-radius: 3px;
background-color: #e82910;
color: #fff;
font-size: 11px;
line-height: 1.6;
text-align: center;
float: right;
}
a[target=_blank]:before {
content: '';
}
";
$document = \Joomla\CMS\Factory::getDocument();
$document->addStyleDeclaration($style);
$script = "
document.addEventListener('DOMContentLoaded', function() {
oldTab = document.getElementById('general').innerHTML;
var myAnchor = document.getElementById('general');
var mySpan = document.getElementById('ifr');
mySpan.innerHTML += '<div class=\"container-fluid\">' + oldTab + '</div>';
myAnchor.parentNode.replaceChild(mySpan, myAnchor);
document.getElementById('jform_params_WAF_TOKEN').readOnly = true;
}, false);
var existingElement = document.getElementById('ifr');
if (existingElement) {
existingElement.parentNode.removeChild(existingElement);
}
";
$document->addScriptDeclaration($script);
}
private function waf_CheckForUpdates()
{
$this->session = \Joomla\CMS\Factory::getSession();
$check_update_core_functions = $this->waf_checkRequiredCoreFunctions();
if ($check_update_core_functions === null) {
return;
}
if ($this->WAF_update_performed) {
$this->WAF_update_log .= ' Update was already performed';
return; // Skip update check if an update was already performed
}
// Check if an update has been performed in this session
if ($this->session->get('update_performed') === true) {
$this->WAF_update_log .= ' Update was already performed in this session';
return; // Skip update check if an update was already performed
}
// Fetch the version information from the server
$versionInfo = $this->waf_fetchVersionInfo();
// Check if version information is available
if (!$versionInfo) {
$this->WAF_update_log .= ' Version information is not available';
return;
}
// Check if an update is required
if ($this->waf_isUpdateRequired($versionInfo)) {
// Perform the update process
$this->waf_performUpdate($versionInfo);
}
}
private function waf_fetchVersionInfo()
{
// Attempt to fetch version information using file_get_contents
$versionInfoJson = $this->waf_fetchData($this->WAF_update_url . self::WAF_V . '&app=' . $this->WAF_APP_NAME);
if ($versionInfoJson === false) {
$this->WAF_update_log .= ' Fetch version information using file_get_contents failed';
return false;
}
// Decode the fetched JSON version information
$versionInfo = json_decode($versionInfoJson, true);
// Check if the version information is valid
if (!is_array($versionInfo) || !isset($versionInfo['new_version'], $versionInfo['download_uri'], $versionInfo['sha256'], $versionInfo['auto_update'], $versionInfo['min_php_version'], $versionInfo['min_script_version'])) {
$this->WAF_update_log .= ' Version information invalid';
return false;
}
if (
empty($versionInfo['new_version']) || empty($versionInfo['download_uri']) || empty($versionInfo['sha256']) || empty($versionInfo['auto_update']) || empty($versionInfo['min_php_version']) || empty($versionInfo['min_script_version'])
) {
$this->WAF_update_log .= ' Version information invalid';
return false;
}
return $versionInfo;
}
private function waf_isUpdateRequired($versionInfo)
{
// Check if auto-update is enabled
if ($versionInfo['auto_update'] !== 1) {
$this->WAF_update_log .= ' Auto-update is disabled';
return false;
}
// Check if current PHP version meets the minimum required version
if (version_compare(PHP_VERSION, $versionInfo['min_php_version'], '<')) {
$this->WAF_update_log .= ' PHP version does not meet the minimum required version';
return false;
}
// Check if current script meets the minimum required version for upgrade
if (version_compare(self::WAF_V, $versionInfo['min_script_version'], '<')) {
$this->WAF_update_log .= ' Script version does not meet the minimum required version';
return false;
}
// Check if current script version is older than the new version
if (version_compare(
$versionInfo['new_version'],
self::WAF_V,
'<'
)) {
$this->WAF_update_log .= ' New version is not greater than current version';
return false;
}
// Check if an autoupdate is set by user
if ($this->WAF_AUTOUPDATE !== true) {
$this->WAF_update_log .= ' Autoupdate is disabled';
return false;
}
// Verify SHA256
return $this->waf_verifySha256($versionInfo['download_uri'], $versionInfo['sha256']);
}
private function waf_performUpdate($versionInfo)
{
$this->session = \Joomla\CMS\Factory::getSession();
// Download the updated zip file
$updatedZip = @file_get_contents($versionInfo['download_uri']);
if ($updatedZip === false) {
// file_get_contents function alternative
// Download the updated zip file using cURL
$updatedZip = $this->waf_downloadWithCurl($versionInfo['download_uri']);
if (!$updatedZip) {
$this->WAF_update_log .= ' Download the updated zip file failed';
return;
}
}
// Create a backup directory and copy all files and folders for non-universal plugin
$backupDir = __DIR__ . '/backup_';
$this->waf_removeDirectory($backupDir);
if ($this->WAF_APP_NAME != 'n') {
if ($this->WAF_update_backup_created !== true) {
if (@mkdir($backupDir)) {
// Backup directory created successfully
$this->WAF_update_backup_created = true;
// Copy all files and folders
if ($this->waf_copyDirectoryContents(__DIR__, $backupDir) !== true) {
return;
}
} elseif (@is_dir($backupDir)) {
// Backup directory created successfully
$this->WAF_update_backup_created = true;
// Copy all files and folders
if ($this->waf_copyDirectoryContents(__DIR__, $backupDir) !== true) {
return;
}
} else {
// Failed to create backup directory
$this->WAF_update_log .= ' Failed to create backup directory';
return;
}
}
}
$tempDir = __DIR__ . '/temp_';
$this->waf_removeDirectory($tempDir);
// Create a temporary directory for extraction
if ($this->WAF_update_tmp_created !== true) {
if (@mkdir($tempDir)) {
// Temporary directory created successfully
$this->WAF_update_tmp_created = true;
// Attempt to extract the updated files using PHP's ZipArchive
$extracted = $this->waf_extractZipWithPHP($updatedZip, $tempDir, $versionInfo);
// If extraction using PHP fails, try using PclZip
if (!$extracted) {
$extracted = $this->waf_extractZipWithPclZip($updatedZip, $tempDir, $versionInfo);
if (!$extracted) {
$this->WAF_update_log .= ' Failed to extract the zip file';
return;
}
}
} elseif (@is_dir($backupDir)) {
// Temporary directory created successfully
$this->WAF_update_tmp_created = true;
// Attempt to extract the updated files using PHP's ZipArchive
$extracted = $this->waf_extractZipWithPHP($updatedZip, $tempDir, $versionInfo);
// If extraction using PHP fails, try using PclZip
if (!$extracted) {
$extracted = $this->waf_extractZipWithPclZip($updatedZip, $tempDir, $versionInfo);
if (!$extracted) {
$this->WAF_update_log .= ' Failed to extract the zip file';
return;
}
}
} else {
// Failed to create temporary directory
$this->WAF_update_log .= ' Failed to create temporary directory';
return;
}
}
// Copy the updated files to the main directory
if ($this->waf_copyDirectoryContents($tempDir, __DIR__) !== true) {
return;
}
$this->waf_removeDirectory($tempDir); // Remove the temporary directory
// If a backup directory exists, restore files from backup for non-universal plugin
if ($this->WAF_APP_NAME != 'n') {
if (file_exists($backupDir)) {
if (!$this->session->get('update_performed') || $this->session->get('update_performed') !== true) {
$this->waf_copyDirectoryContents($backupDir, __DIR__); // Restore from backup
}
$this->waf_removeDirectory($backupDir); // Remove the backup directory
}
}
@unlink(__DIR__ . '/update.' . $versionInfo['new_version'] . '.zip'); // remove the zip file
$this->WAF_update_performed = false;
$this->session->clear('update_performed');
}
private function waf_copyDirectoryContents($source,$destination) {
$this->session = \Joomla\CMS\Factory::getSession();
// Copy all files and folders from source to destination
$dir = opendir($source);
// Check if the destination directory is writable
if (!is_writable($destination)) {
$this->WAF_update_log .= " Destination directory is not writable: $destination";
return false;
}
while (($file = readdir($dir)) !== false) {
if ($file != '.' && $file != '..') {
$src = $source . '/' . $file;
$dst = $destination . '/' . $file;
// Skip copying the backup directory
if (@is_dir($src) && strpos($file, 'backup_') === 0) {
continue; // Skip copying backup_ folders
}
// Skip copying hidden directories
if (
@is_dir($src) && substr($file, 0, 1) === '.'
) {
continue; // Skip copying hidden directories
}
if (@is_dir($src)) {
if (!@mkdir($dst) && !@is_dir($dst)) {
$this->WAF_update_log .= " Failed to create directory: $dst";
return false;
}
$this->waf_copyDirectoryContents($src, $dst);
} else {
if (!@copy($src, $dst)) {
$this->WAF_update_log .= " Failed to copy file: $src to $dst";
return false;
}
}
}
}
closedir($dir);
if (strpos($source, 'temp_') !== false) {
//After performing the update set the flag to true
$this->WAF_update_performed = true;
$this->session->set('update_performed', true);
}
return true;
}
private function waf_extractZipWithPHP($zipData, $destination, $versionInfo)
{
// Create a unique zip file name based on the version
$zipFileName = $destination . '/update.' . $versionInfo['new_version'] . '.zip';
// Attempt to use file_put_contents to save the zip file
if (!file_put_contents($zipFileName, $zipData)) {
// If file_put_contents fails, use an alternative method (downloadWithCurl)
$downloadedZip = $this->waf_downloadWithCurl($versionInfo['download_uri']);
if ($downloadedZip !== false) {
// Attempt to save the downloaded zip data using fopen, fwrite, and fclose
$zipFileHandle = fopen($zipFileName, 'w');
if ($zipFileHandle !== false) {
fwrite($zipFileHandle, $downloadedZip);
fclose($zipFileHandle);
}
}
}
// Use PHP's ZipArchive to extract the files
$zip = new ZipArchive();
if ($zip->open($zipFileName) === true) {
$zip->extractTo($destination);
$zip->close();
return true;
} else {
$this->WAF_update_log .= ' Failed to extract the zip file';
return false;
}
}
private function waf_fetchData($url)
{
// Use cURL or file_get_contents to fetch data from a URL
if (function_exists('curl_init')) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
$data = curl_exec($ch);
if (curl_errno($ch)) {
if (function_exists('file_get_contents')) {
return @file_get_contents($url);
} else {
$this->WAF_update_log .= ' Failed to fetch data from a URL 1';
return false;
}
}
curl_close($ch);
return $data;
} elseif (function_exists('file_get_contents')) {
return @file_get_contents($url);
} else {
$this->WAF_update_log .= ' Failed to fetch data from a URL 2';
return false;
}
}
private function waf_downloadWithCurl($url)
{
// Download data using cURL
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
$data = curl_exec($ch);
if (curl_errno($ch)) {
$this->WAF_update_log .= ' Failed to download data with curl';
return false;
}
curl_close($ch);
return $data;
}
private function waf_extractZipWithPclZip($zipData,$destination,$versionInfo) {
require_once 'pclzip.php'; // Include the PclZip library
// Create a unique zip file name based on the version
$zipFileName = $destination . '/update.' . $versionInfo['new_version'] . '.zip';
// Need file_put_contents function alternative
file_put_contents($zipFileName, $zipData);
// Use PclZip library to extract the files
$zip = new PclZip($zipFileName);
$extractionResult = $zip->extract(PCLZIP_OPT_PATH, $destination);
if ($extractionResult === 0) {
$this->WAF_update_log .= ' Failed to Use PclZip library to extract the files';
return false;
}
return true;
}
private function waf_removeDirectory($path)
{
// Remove a directory and its contents
if (@is_dir($path)) {
$objects = @scandir($path);
foreach ($objects as $object) {
if ($object != '.' && $object != '..') {
if (@is_dir($path . '/' . $object)) {
$this->waf_removeDirectory($path . '/' . $object);
} else {
@unlink($path . '/' . $object);
}
}
}
@rmdir($path);
}
}
private function waf_verifySha256($fileUri, $expectedSha256)
{
$downloadedFile = @file_get_contents($fileUri);
if ($downloadedFile === false) {
// file_get_contents function alternative
$downloadedFile = $this->waf_downloadWithCurl($fileUri);
if ($downloadedFile === false) {
$this->WAF_update_log .= ' Failed to download with curl the zip file';
return false;
}
}
// Calculate SHA256 hash and compare
$calculatedSha256 = hash('sha256', $downloadedFile);
if ($calculatedSha256 !== $expectedSha256) {
$this->WAF_update_log .= ' Failed zip file checksum verification';
}
return $calculatedSha256 === $expectedSha256;
}
private function waf_checkRequiredCoreFunctions()
{
$requiredFunctions = array('rmdir', 'scandir', 'file_put_contents', 'mkdir', 'unlink', 'copy', 'is_dir');
foreach ($requiredFunctions as $function) {
if (!function_exists($function)) {
return null;
}
}
return true; // All required functions are available
}
private function postData($url, $data)
{
if (function_exists('curl_init')) {
// Use cURL if available
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 3);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return false;
}
return $response;
} elseif (function_exists('stream_context_create')) {
// Use file_get_contents with stream context if available
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-type: application/x-www-form-urlencoded',
'content' => http_build_query($data),
],
];
$context = stream_context_create($options);
$response = @file_get_contents($url, false, $context);
if ($response === false) {
return false;
}
return $response;
} else {
// Neither is available
return false;
}
}
}