From 55460e36eec1ed969a8d8400eea7a9430b28f17d Mon Sep 17 00:00:00 2001 From: r4sas Date: Fri, 26 Aug 2022 23:40:48 +0000 Subject: [PATCH] use binding for PDO and arguments escaping in verifier command --- lib/utils.php | 12 ++++++++---- views/add.php | 34 +++++++++++++++++++++++----------- views/all.php | 3 +-- views/api.php | 6 +++--- views/autojump.php | 6 +++--- views/hidden.php | 3 +-- views/home.php | 3 +-- views/jump.php | 6 +++--- views/latest.php | 3 +-- views/search.php | 15 ++++++++------- 10 files changed, 52 insertions(+), 39 deletions(-) diff --git a/lib/utils.php b/lib/utils.php index 3b2de0f..8fa861f 100644 --- a/lib/utils.php +++ b/lib/utils.php @@ -47,7 +47,7 @@ class Utils { * @return string */ private static function b64decode(string $data): string { - return base64_decode(strtr($data, static::b64Trans)); + return base64_decode(strtr($data, static::b64Trans), true); } /** @@ -182,7 +182,7 @@ class Utils { if (strpos($data, "&") !== false) return false; // registration string can't have ampersands - $cmd = dirname(__FILE__) . "/../bin/verifyhost '" . $data . "'"; + $cmd = dirname(__FILE__) . '/../bin/verifyhost ' . escapeshellarg($data); exec($cmd, $output, $retval); if (!$retval) @@ -196,7 +196,7 @@ class Utils { /* Return empty array if no data provided */ if(!strlen($data)) - return $record; + return []; $data = trim($data); @@ -208,7 +208,11 @@ class Utils { /* Return empty array if host or b64 is not set */ if(!isset($host[0]) || !isset($host[1])) - return $record; + return []; + + /* Return if base64 can't be decoded */ + if(self::b64decode($host[1]) === false) + return []; $record["host"] = $host[0]; $record["b64"] = $host[1]; diff --git a/views/add.php b/views/add.php index 6314b8e..a3a9f2b 100644 --- a/views/add.php +++ b/views/add.php @@ -55,7 +55,8 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { } else { if (isset($parsed["commands"]["action"])) { /* Check if such domain name already registered */ - $STH = $pdo->query("SELECT COUNT(*) FROM `hosts` WHERE `host` = '" . $domain . "' LIMIT 1"); + $STH = $pdo->prepare('SELECT COUNT(*) FROM `hosts` WHERE `host` = ? LIMIT 1'); + $STH->execute([$domain]); switch ($parsed["commands"]["action"]) { case 'addsubdomain': @@ -75,18 +76,21 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { if ((sizeof ($darr) - 1) != $i) $dtop .= "."; } + $STH = $pdo->prepare('SELECT COUNT(*) FROM `hosts` WHERE `host` = ? AND `base64` = ? LIMIT 1'); + if (sizeof($darr) < 3) { $result["error"] = "Error while validating: you can't register second level domain (example.i2p) using addsubdomain action."; } else if ($dtop != $parsed["commands"]["oldname"]) { $result["error"] = "Error while validating: oldname value is not same as your higher level domain."; - } else if (!$pdo->query("SELECT COUNT(*) FROM `hosts` WHERE `host` = '" . $parsed["commands"]["oldname"] . "' AND `base64` = '" . $parsed["commands"]["olddest"] . "' LIMIT 1")->fetchColumn()) { + } else if (!$STH->execute([$parsed["commands"]["oldname"], $parsed["commands"]["olddest"]]) || !$STH->fetchColumn()) { $result["error"] = "Error while validating: can't find higher level domain with values from oldname and olddest."; } else { $base32 = $util->b32from64($parsed["b64"]); - if (!$pdo->exec("INSERT INTO `hosts` (`host`, `base64`, `base32`) VALUES ('" . $domain . "', '" . $parsed["b64"] . "', '" . $base32 . "')")) { + + if (!$pdo->prepare('INSERT INTO `hosts` (`host`, `base64`, `base32`) VALUES (?, ?, ?)')->execute([$domain, $parsed["b64"], $base32])) { $result["error"] = "Error happened while inserting record to database. Please try again later."; } else { @@ -107,12 +111,15 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { $result["error"] = "Error while validating: required fields not found. Re-check your registration string."; } else { - if (!$pdo->query("SELECT COUNT(*) FROM `hosts` WHERE `host` = '" . $domain . "' AND `base64` = '" . $parsed["commands"]["olddest"] . "' LIMIT 1")->fetchColumn()) { + $STH = $pdo->prepare('SELECT COUNT(*) FROM `hosts` WHERE `host` = ? AND `base64` = ? LIMIT 1'); + + if (!$STH->execute([$domain, $parsed["commands"]["olddest"]]) || !$STH->fetchColumn()) { $result["error"] = "Error while validating: old base64 and value in olddest field does not match.."; } else { $base32 = $util->b32from64($parsed["b64"]); - if (!$pdo->exec("UPDATE `hosts` SET `base64` = '" . $parsed["b64"] . "', `base32` = '" . $base32 . "' WHERE `host` = '" . $domain . "'")) { + + if (!$pdo->prepare('UPDATE `hosts` SET `base64` = ?, `base32` = ? WHERE `host` = ?')->execute([$parsed["b64"], $base32, $domain])) { $result["error"] = "Error happened while updating record in database. Please try again later."; } else { @@ -143,12 +150,15 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { $olddomain = $parsed["commands"]["oldname"]; } - if (!$pdo->query("SELECT COUNT(*) FROM `hosts` WHERE `host` = '" . $olddomain . "' AND `base64` = '" . parsed["b64"] . "' LIMIT 1")->fetchColumn()) { + $STH = $pdo->prepare('SELECT COUNT(*) FROM `hosts` WHERE `host` = ? AND `base64` = ? LIMIT 1'); + + if (!$STH->execute([$olddomain, parsed["b64"]]) || !$STH->fetchColumn()) { $result["error"] = "Error while validating: base64 does not match for domain in oldname field..."; } else { $base32 = $util->b32from64($parsed["b64"]); - if (!$pdo->exec("INSERT INTO `hosts` (`host`, `base64`, `base32`) VALUES ('" . $domain . "', '" . $parsed["b64"] . "', '" . $base32 . "')")) { + + if (!$pdo->prepare('INSERT INTO `hosts` (`host`, `base64`, `base32`) VALUES (?, ?, ?)')->execute([$domain, $parsed["b64"], $base32])) { $result["error"] = "Error happened while updating record in database. Please try again later."; } else { @@ -167,7 +177,8 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { } else { /* Check if such domain name already registered */ - $STH = $pdo->query("SELECT `host`, `base32`, `base64`, `initial`, `disabled` FROM `hosts` WHERE `host` = '" . $domain . "' LIMIT 1"); + $STH = $pdo->prepare('SELECT `host`, `base32`, `base64`, `initial`, `disabled` FROM `hosts` WHERE `host` = ? LIMIT 1'); + $STH->execute([$domain]); $row = $STH->fetch(PDO::FETCH_ASSOC); if($row && !$row['disabled']) { @@ -189,7 +200,8 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { $log = "[" . date("d-M-Y H:i:s e") . "] Re-registering attempt for " . $row['host'] . "! Next records will be deleted:" . PHP_EOL; /* print all records, which will be deleted*/ - $STH = $pdo->query("SELECT `host`, `base32`, `base64` FROM `hosts` WHERE `host` = '" . $domain . "' OR `host` LIKE '%." . $domain . "'"); + $STH = $pdo->prepare('SELECT `host`, `base32`, `base64` FROM `hosts` WHERE `host` = ? OR `host` LIKE ?'); + $STH->execute(['%'.$domain, '%'.$domain]); $hosts = $STH->fetchAll(PDO::FETCH_ASSOC); foreach ($hosts as $host) { $log .= "Host: " . $host['host'] . PHP_EOL . "Base32: " . $host['base32'] . PHP_EOL . "Base64: " . $host['base64'] . PHP_EOL; @@ -198,14 +210,14 @@ if (isset($_POST["record"]) && !empty($_POST["record"])) { file_put_contents(__DIR__ . '/../logs/reg.log', $log, FILE_APPEND); /* remove domain and subdomains if any found */ - $pdo->exec("DELETE FROM `hosts` WHERE `host` = '" . $domain . "' OR `host` LIKE '%." . $domain . "'"); + $pdo->prepare('DELETE FROM `hosts` WHERE `host` = ? OR `host` LIKE %?')->execute(['%'.$domain, '%'.$domain]); $result["reregister"] = true; } $base32 = $util->b32from64($parsed["b64"]); /* Adding to database 2LD domain */ - if (!$pdo->exec("INSERT INTO `hosts` (`host`, `base64`, `base32`) VALUES ('" . $domain . "', '" . $parsed["b64"] . "', '" . $base32 . "')")) { + if (!$pdo->prepare('INSERT INTO `hosts` (`host`, `base64`, `base32`) VALUES (?, ?, ?)')->execute([$domain, $parsed["b64"], $base32])) { $result["error"] = "Error happened while inserting record to database. Please try again later."; } else { diff --git a/views/all.php b/views/all.php index 883dc95..9c9d157 100644 --- a/views/all.php +++ b/views/all.php @@ -29,8 +29,7 @@ $pages = intdiv($records, $options["tableitems"]) + 1; /* Get records with limit */ $STH = $pdo->query ("SELECT `host`, `base64`, `base32`, `last_seen` FROM `hosts` LIMIT " . $offset . ", " . $options["tableitems"]); -$STH->setFetchMode(PDO::FETCH_ASSOC); -$rows = $STH->fetchAll(); +$rows = $STH->fetchAll(PDO::FETCH_ASSOC); $template = $twig->load('all.twig'); echo $template->render(['current' => $page, 'total' => $pages, 'hosts' => $rows, 'all' => $all]); diff --git a/views/api.php b/views/api.php index c447b28..e2bd086 100644 --- a/views/api.php +++ b/views/api.php @@ -17,8 +17,7 @@ switch ($command) { $STH = $pdo->query ("SELECT `base32`, UNIX_TIMESTAMP(`last_seen`) as `last_seen` FROM `hosts` " . "WHERE `approved` = 1 AND `disabled` = 0" . ($all ? " " : " AND `blacklisted` = 0 ")); - $STH->setFetchMode(PDO::FETCH_ASSOC); - $rows = $STH->fetchAll(); + $rows = $STH->fetchAll(PDO::FETCH_ASSOC); foreach($rows as $row) { $data[$row["base32"] . ".b32.i2p"] = $row["last_seen"]; @@ -31,7 +30,8 @@ switch ($command) { } $q = htmlspecialchars($query); - $STH = $pdo->query("SELECT `host` AS `hostname`, `base64`, `base32`, UNIX_TIMESTAMP(`last_seen`) as `last_seen` FROM `hosts` WHERE `host` = '" . $q . "' LIMIT 1"); + $STH = $pdo->prepare('SELECT `host` AS `hostname`, `base64`, `base32`, UNIX_TIMESTAMP(`last_seen`) as `last_seen` FROM `hosts` WHERE `host` = ? LIMIT 1'); + $STH->execute([$q]); $row = $STH->fetch(PDO::FETCH_ASSOC); if (empty($row)) { diff --git a/views/autojump.php b/views/autojump.php index f75f940..35bcfcc 100644 --- a/views/autojump.php +++ b/views/autojump.php @@ -40,9 +40,9 @@ else if(!empty($domain) && $utils->isValidDomain($domain, $error)) { $pdo = (new App\DB($options))->pdo; - $STH = $pdo->query("SELECT `host`, `base64`, `base32`, `last_seen`, `blacklisted` FROM `hosts` WHERE `host` = '" . $domain . "' LIMIT 1"); - $STH->setFetchMode(PDO::FETCH_ASSOC); - $row = $STH->fetchAll(); + $STH = $pdo->prepare('SELECT `host`, `base64`, `base32`, `last_seen`, `blacklisted` FROM `hosts` WHERE `host` = ? LIMIT 1'); + $STH->execute([$domain]); + $row = $STH->fetchAll(PDO::FETCH_ASSOC); if (empty($row)) { $result["error"] = "No such host is found"; diff --git a/views/hidden.php b/views/hidden.php index 3e2a169..bb3e427 100644 --- a/views/hidden.php +++ b/views/hidden.php @@ -35,8 +35,7 @@ $pages = intdiv($records, $options["tableitems"]) + 1; $STH = $pdo->query ("SELECT `host`, `base64`, `base32`, `last_seen` FROM `hosts` " . "WHERE `approved` = 1 AND `disabled` = 0 AND `hidden` = 0 AND `blacklisted` = 1 " . "LIMIT " . $offset . ", " . $options["tableitems"]); -$STH->setFetchMode(PDO::FETCH_ASSOC); -$rows = $STH->fetchAll(); +$rows = $STH->fetchAll(PDO::FETCH_ASSOC); $template = $twig->load('hidden.twig'); echo $template->render(['current' => $page, 'total' => $pages, 'hosts' => $rows, 'all' => $all]); diff --git a/views/home.php b/views/home.php index 1af3d67..338415a 100644 --- a/views/home.php +++ b/views/home.php @@ -19,8 +19,7 @@ if (isset($_GET["all"])) if ($options['fetcher']) { $STH = $pdo->query ("SELECT `name` FROM `subscriptions` WHERE `active` = 1"); - $STH->setFetchMode(PDO::FETCH_ASSOC); - $subscrs = $STH->fetchAll(); + $subscrs = $STH->fetchAll(PDO::FETCH_ASSOC); } $STH = $pdo->query ("SELECT COUNT(*) FROM `hosts` WHERE `blacklisted` = 1"); diff --git a/views/jump.php b/views/jump.php index 1614f8c..259f9c8 100644 --- a/views/jump.php +++ b/views/jump.php @@ -50,9 +50,9 @@ else if(!empty($domain) && $utils->isValidDomain($domain, $error)) { $pdo = (new App\DB($options))->pdo; - $STH = $pdo->query("SELECT `host`, `base64`, `base32`, `add_date`, `last_seen`, `blacklisted` FROM `hosts` WHERE `host` = '" . $domain . "' LIMIT 1"); - $STH->setFetchMode(PDO::FETCH_ASSOC); - $row = $STH->fetchAll(); + $STH = $pdo->prepare('SELECT `host`, `base64`, `base32`, `add_date`, `last_seen`, `blacklisted` FROM `hosts` WHERE `host` = ? LIMIT 1'); + $STH->execute([$domain]); + $row = $STH->fetchAll(PDO::FETCH_ASSOC); if (empty($row)) { $result["error"] = "No such host is found"; diff --git a/views/latest.php b/views/latest.php index ac6c733..cdcb668 100644 --- a/views/latest.php +++ b/views/latest.php @@ -19,8 +19,7 @@ if (isset($_GET["all"])) /* Get records with limit */ $STH = $pdo->query ("SELECT `host`, `base64`, `base32`, `add_date`, `last_seen` FROM `hosts` WHERE `disabled` = 0" . ($all ? "" : " AND `blacklisted` = 0") . " ORDER BY `add_date` DESC LIMIT " . $options["tableitems"]); -$STH->setFetchMode(PDO::FETCH_ASSOC); -$rows = $STH->fetchAll(); +$rows = $STH->fetchAll(PDO::FETCH_ASSOC); $template = $twig->load('latest.twig'); echo $template->render(['limit' => $options["tableitems"], 'hosts' => $rows, 'all' => $all]); diff --git a/views/search.php b/views/search.php index 4a68839..669e49c 100644 --- a/views/search.php +++ b/views/search.php @@ -34,13 +34,14 @@ if (isset($_POST["all"]) || isset($_GET["all"])) if(!empty($q)) { $pdo = (new App\DB($options))->pdo; - if ($a) - $STH = $pdo->query("SELECT `host`, `base64`, `base32`, `last_seen` FROM `hosts` WHERE (`host` LIKE '%" . $q . "%' OR `base32` LIKE '%" . $q . "%') AND `disabled` = 0 LIMIT " . $options["tableitems"]); - else - $STH = $pdo->query("SELECT `host`, `base64`, `base32`, `last_seen` FROM `hosts` WHERE `host` LIKE '%" . $q . "%' OR `base32` LIKE '%" . $q . "%' LIMIT " . $options["tableitems"]); - - $STH->setFetchMode(PDO::FETCH_ASSOC); - $row = $STH->fetchAll(); + if($a) { + $STH = $pdo->prepare('SELECT `host`, `base64`, `base32`, `last_seen` FROM `hosts` WHERE (`host` LIKE ? OR `base32` LIKE ?) AND `disabled` = 0 LIMIT ' . $options["tableitems"]); + } else { + $STH = $pdo->prepare('SELECT `host`, `base64`, `base32`, `last_seen` FROM `hosts` WHERE (`host` LIKE ? OR `base32` LIKE ?) LIMIT ' . $options["tableitems"]); + } + + $STH->execute(['%'.$q.'%', '%'.$q.'%']); + $row = $STH->fetchAll(PDO::FETCH_ASSOC); if (empty($row)) $result["error"] = "Nothing was found";