From 1816218c64da5881c681808893ce8a9dc7eb54db Mon Sep 17 00:00:00 2001 From: Michael Save Date: Fri, 15 Mar 2013 00:40:02 +1100 Subject: Fix: Critical security vulnerability --- inc/mod/pages.php | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 0ea97fe8..4d588030 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -114,26 +114,37 @@ function mod_dashboard() { } else { $ctx = stream_context_create(array('http' => array('timeout' => 5))); if ($code = @file_get_contents('http://tinyboard.org/version.txt', 0, $ctx)) { - eval($code); - if (preg_match('/v(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) { - $current = array( - 'massive' => (int) $matches[1], - 'major' => (int) $matches[2], - 'minor' => (int) $matches[3] + $ver = strtok($code, "\n"); + + if (preg_match('@^// v(\d+)\.(\d+)\.(\d+)\s*?$@', $ver, $matches)) { + $latest = array( + 'massive' => $matches[1], + 'major' => $matches[2], + 'minor' => $matches[3] ); - if (isset($m[4])) { - // Development versions are always ahead in the versioning numbers - $current['minor'] --; - } - // Check if it's newer - if (!( $latest['massive'] > $current['massive'] || - $latest['major'] > $current['major'] || - ($latest['massive'] == $current['massive'] && - $latest['major'] == $current['major'] && - $latest['minor'] > $current['minor'] - ))) + if (preg_match('/v(\d+)\.(\d)\.(\d+)(-dev.+)?$/', $config['version'], $matches)) { + $current = array( + 'massive' => (int) $matches[1], + 'major' => (int) $matches[2], + 'minor' => (int) $matches[3] + ); + if (isset($m[4])) { + // Development versions are always ahead in the versioning numbers + $current['minor'] --; + } + // Check if it's newer + if (!( $latest['massive'] > $current['massive'] || + $latest['major'] > $current['major'] || + ($latest['massive'] == $current['massive'] && + $latest['major'] == $current['major'] && + $latest['minor'] > $current['minor'] + ))) + $latest = false; + } else { $latest = false; + } } else { + // Couldn't get latest version $latest = false; } } else { -- cgit v1.3 From 64ae123739c39567447bfc16fc95deb556786671 Mon Sep 17 00:00:00 2001 From: Michael Save Date: Sat, 16 Mar 2013 18:27:24 +1100 Subject: Mod log in ?/IP (ie. ban history) --- inc/config.php | 3 +++ inc/mod/ban.php | 15 ++++++++++++--- inc/mod/pages.php | 9 +++++++++ templates/mod/view_ip.html | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 3 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/config.php b/inc/config.php index cedf3e06..8d37e601 100644 --- a/inc/config.php +++ b/inc/config.php @@ -986,6 +986,9 @@ $config['mod']['createusers'] = ADMIN; // View the moderation log $config['mod']['modlog'] = ADMIN; + // View relevant moderation log entries on IP address pages (ie. ban history, etc.) + // Warning: Can be pretty resource exhaustive if your mod logs are huge. + $config['mod']['modlog_ip'] = MOD; // Create a PM (viewing mod usernames) $config['mod']['create_pm'] = JANITOR; // Read any PM, sent to or from anybody diff --git a/inc/mod/ban.php b/inc/mod/ban.php index 9c93d70e..30234157 100644 --- a/inc/mod/ban.php +++ b/inc/mod/ban.php @@ -80,16 +80,25 @@ function ban($mask, $reason, $length, $board) { modLog('Created a new ' . ($length > 0 ? preg_replace('/^(\d+) (\w+?)s?$/', '$1-$2', until($length)) : 'permanent') . - ' ban (#' . $pdo->lastInsertId() . ') for ' . + ' ban on ' . + ($board ? '/' . $board . '/' : 'all boards') . + ' for ' . (filter_var($mask, FILTER_VALIDATE_IP) !== false ? "$mask" : utf8tohtml($mask)) . + ' (#' . $pdo->lastInsertId() . ')' . ' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason')); } -function unban($id) { +function unban($id) { + $query = prepare("SELECT `ip` FROM `bans` WHERE `id` = :id"); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + $mask = $query->fetchColumn(); + $query = prepare("DELETE FROM `bans` WHERE `id` = :id"); $query->bindValue(':id', $id); $query->execute() or error(db_error($query)); - modLog("Removed ban #{$id}"); + if ($mask) + modLog("Removed ban #{$id} for " . (filter_var($mask, FILTER_VALIDATE_IP) !== false ? "$mask" : utf8tohtml($mask))); } diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 4d588030..db51324a 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -600,6 +600,15 @@ function mod_page_ip($ip) { $args['notes'] = $query->fetchAll(PDO::FETCH_ASSOC); } + if (hasPermission($config['mod']['modlog_ip'])) { + $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM `modlogs` LEFT JOIN `mods` ON `mod` = `mods`.`id` WHERE `text` LIKE :search ORDER BY `time` DESC LIMIT 20"); + $query->bindValue(':search', '%' . $ip . '%'); + $query->execute() or error(db_error($query)); + $args['logs'] = $query->fetchAll(PDO::FETCH_ASSOC); + } else { + $args['logs'] = array(); + } + mod_page(sprintf('%s: %s', _('IP'), $ip), 'mod/view_ip.html', $args, $args['hostname']); } diff --git a/templates/mod/view_ip.html b/templates/mod/view_ip.html index c49880ae..562a0140 100644 --- a/templates/mod/view_ip.html +++ b/templates/mod/view_ip.html @@ -161,3 +161,43 @@ {% include 'mod/ban_form.html' %} {% endif %} + +{% if logs|count > 0 %} +
+ History + + + + + + + + {% for log in logs %} + + + + + + + {% endfor %} +
{% trans 'Staff' %}{% trans 'Time' %}{% trans 'Board' %}{% trans 'Action' %}
+ {% if log.username %} + {{ log.username|e }} + {% elseif log.mod == -1 %} + system + {% else %} + {% trans 'deleted?' %} + {% endif %} + + {{ log.time|ago }} + + {% if log.board %} + {{ config.board_abbreviation|sprintf(log.board) }} + {% else %} + - + {% endif %} + + {{ log.text }} +
+
+{% endif %} -- cgit v1.3 From bb54605eb7ef65c5e415aba7bcc94eed928e185e Mon Sep 17 00:00:00 2001 From: Fredrick Date: Wed, 20 Mar 2013 07:46:48 -0400 Subject: Fix per-board name not being used --- inc/config.php | 4 ++-- inc/mod/pages.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/config.php b/inc/config.php index 8d37e601..8eed50fa 100644 --- a/inc/config.php +++ b/inc/config.php @@ -858,8 +858,8 @@ $config['mod']['shadow_mesage'] = 'Moved to %s.'; // Capcode to use when posting the above message. $config['mod']['shadow_capcode'] = 'Mod'; - // Name to use when posting the above message. - $config['mod']['shadow_name'] = $config['anonymous']; + // Name to use when posting the above message. If false, the default board name will be used. If something else, that will be used. + $config['mod']['shadow_name'] = false; // Wait indefinitely when rebuilding everything $config['mod']['rebuild_timelimit'] = 0; diff --git a/inc/mod/pages.php b/inc/mod/pages.php index db51324a..5d736a1a 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -912,7 +912,7 @@ function mod_move($originBoard, $postID) { 'mod' => true, 'subject' => '', 'email' => '', - 'name' => $config['mod']['shadow_name'], + 'name' => (!$config['mod']['shadow_name'] ? $config['anonymous'] : $config['mod']['shadow_name']), 'capcode' => $config['mod']['shadow_capcode'], 'trip' => '', 'password' => '', -- cgit v1.3 From b4ff535128e6c169d2b4966e6227faa511780621 Mon Sep 17 00:00:00 2001 From: undido Date: Tue, 16 Apr 2013 19:09:58 -0300 Subject: update to pages.php minor exploit A lot of bans can be removed from a tinyboard database because it isn't limited A staff member could select 100 users all at once with a simple javascript function and unban them all this needs to be limited because a staff member on an image board if they feel hostile they can just remove all bans on the tinyboard site easily without being limited to how many people they can unban at a time, this adds an option to limit it. --- inc/mod/pages.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 5d736a1a..6a780474 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -651,7 +651,8 @@ function mod_bans($page_no = 1) { if (preg_match('/^ban_(\d+)$/', $name, $match)) $unban[] = $match[1]; } - + if (isset($config['mod']['unban_limit'])){ + if (count($unban) <= $config['mod']['unban_limit'] || $config['mod']['unban_limit'] == -1){ if (!empty($unban)) { query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error()); @@ -659,7 +660,21 @@ function mod_bans($page_no = 1) { modLog("Removed ban #{$id}"); } } + } else { + error(sprintf($config['error']['toomanyunban'], $config['mod']['unban_limit'], count($unban) )); + } + + } else { + + if (!empty($unban)) { + query('DELETE FROM `bans` WHERE `id` = ' . implode(' OR `id` = ', $unban)) or error(db_error()); + + foreach ($unban as $id) { + modLog("Removed ban #{$id}"); + } + } + } header('Location: ?/bans', true, $config['redirect_http']); } -- cgit v1.3 From 3bcc87caf294cd67f221854d1dc13065706f5a81 Mon Sep 17 00:00:00 2001 From: Macil Tech Date: Wed, 27 Mar 2013 22:09:39 +0800 Subject: Fix PM count caching. cache::get() returns null if the key wasn't found (at least when using the Redis cache backend). --- inc/mod/auth.php | 2 +- inc/mod/pages.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/auth.php b/inc/mod/auth.php index f594af4b..d4a2ea1c 100644 --- a/inc/mod/auth.php +++ b/inc/mod/auth.php @@ -125,7 +125,7 @@ if (isset($_COOKIE[$config['cookies']['mod']])) { function create_pm_header() { global $mod, $config; - if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) !== false) { + if ($config['cache']['enabled'] && ($header = cache::get('pm_unread_' . $mod['id'])) != false) { if ($header === true) return false; diff --git a/inc/mod/pages.php b/inc/mod/pages.php index cf06e7d9..726ed735 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -89,7 +89,7 @@ function mod_dashboard() { } } - if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) === false) { + if (!$config['cache']['enabled'] || ($args['unread_pms'] = cache::get('pm_unreadcount_' . $mod['id'])) == false) { $query = prepare('SELECT COUNT(*) FROM `pms` WHERE `to` = :id AND `unread` = 1'); $query->bindValue(':id', $mod['id']); $query->execute() or error(db_error($query)); -- cgit v1.3 From be1e55b9d63bd4cdb910206e9e99ecf83ca7ffde Mon Sep 17 00:00:00 2001 From: Macil Tech Date: Fri, 1 Mar 2013 05:56:44 +0800 Subject: Fix result page after installing theme getting doubled up. --- inc/mod/pages.php | 1 + 1 file changed, 1 insertion(+) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 726ed735..22018d31 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -1832,6 +1832,7 @@ function mod_theme_configure($theme_name) { 'result' => $result, 'message' => $message, )); + return; } $settings = themeSettings($theme_name); -- cgit v1.3 From 23b27d805740599b968d41e08d726f2a0dc5bdde Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Tue, 16 Jul 2013 01:38:24 -0400 Subject: Add clean() to mod_move function --- inc/mod/pages.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 86f5ee52..fddf63c7 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -906,8 +906,10 @@ function mod_move($originBoard, $postID) { modLog("Moved thread #${postID} to " . sprintf($config['board_abbreviation'], $targetBoard) . " (#${newID})", $originBoard); - // build new hread + // build new thread buildThread($newID); + + clean(); buildIndex(); // trigger themes -- cgit v1.3 From 2144d43f2b114ac697d57d23300f51bf7d078b3b Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Tue, 16 Jul 2013 02:27:20 -0400 Subject: Fix issue #24 --- inc/mod/pages.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index fddf63c7..899f2611 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -217,6 +217,19 @@ function mod_edit_board($boardName) { $query = prepare('DELETE FROM `antispam` WHERE `board` = :board'); $query->bindValue(':board', $board['uri']); $query->execute() or error(db_error($query)); + + // Remove board from users/permissions table + $query = query('SELECT `id`,`boards` FROM `mods`') or error(db_error()); + while ($user = $query->fetch(PDO::FETCH_ASSOC)) { + $user_boards = explode(',', $user['boards']); + if (in_array($board['uri'], $user_boards)) { + unset($user_boards[array_search($board['uri'], $user_boards)]); + $_query = prepare('UPDATE `mods` SET `boards` = :boards WHERE `id` = :id'); + $_query->bindValue(':boards', implode(',', $user_boards)); + $_query->bindValue(':id', $user['id']); + $_query->execute() or error(db_error($_query)); + } + } } else { $query = prepare('UPDATE `boards` SET `title` = :title, `subtitle` = :subtitle WHERE `uri` = :uri'); $query->bindValue(':uri', $board['uri']); -- cgit v1.3 From 7302fc57a8f83c6fe40f9c751259d9c616ebdaec Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Tue, 16 Jul 2013 02:32:44 -0400 Subject: Automatically dismiss all reports regarding a thread after it is locked. --- inc/config.php | 3 +++ inc/mod/pages.php | 7 +++++++ 2 files changed, 10 insertions(+) (limited to 'inc/mod/pages.php') diff --git a/inc/config.php b/inc/config.php index da9309e8..83b98c2b 100644 --- a/inc/config.php +++ b/inc/config.php @@ -881,6 +881,9 @@ // Edit raw HTML in posts by default $config['mod']['raw_html_default'] = false; + // Automatically dismiss all reports regarding a thread when it is locked + $config['mod']['dismiss_reports_on_lock'] = true; + // Probably best not to change these: if (!defined('JANITOR')) { define('JANITOR', 0, true); diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 899f2611..3f823d3d 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -738,6 +738,13 @@ function mod_lock($board, $unlock, $post) { buildIndex(); } + if ($config['mod']['dismiss_reports_on_lock']) { + $query = prepare('DELETE FROM `reports` WHERE `board` = :board AND `post` = :id'); + $query->bindValue(':board', $board); + $query->bindValue(':id', $post); + $query->execute() or error(db_error($query)); + } + header('Location: ?/' . sprintf($config['board_path'], $board) . $config['file_index'], true, $config['redirect_http']); if ($unlock) -- cgit v1.3