News:

Bored?  Looking to kill some time?  Want to chat with other SMF users?  Join us in IRC chat or Discord

Main Menu

security hole in privacy for title threads ( mod: Show Local Url Titles)

Started by _sebas_, September 28, 2013, 11:43:24 PM

Previous topic - Next topic

_sebas_

I found a serious security problem, very easy to break, for a person without knowledge. In mod
Show Local Url Titles
http://www.simplemachines.org/community/index.php?topic=250317.0

transforms  url like  www.yoursite.com/index.php?topic=1
to
url like   "this is a secret thread"

A user anyone without access to a Board,  can put random TOPIC numbers
.../index.php?topic=XXX
trying until you get one that exists and is in restricted board.

This Mod, however, will give the title of the thread in full in restricted board !, ... in some cases this can be very engaging.
Can you solve?
What code should add? for a user without permission can not see those titles.

I think this is a major problem. I'm worried

Arantor

Firstly, this isn't an issue in 1.1.x as a whole, this is an issue with the mod. Can it be fixed? Not really without a *major* performance overhead. I saw you already posted in the mod's thread, there's absolutely nothing more to be gained by reposting it here.

If it bothers you, disable the mod.

_sebas_


ok! thanks  ( and sorry )
difficult to erase the Mod, by the benefits.
I try to act directly in the code manually, blocking the function, if the board, referenced the message is pointing to forum staff and moderators

( Any clue? )

Arantor

I don't think that's possible to do without major rewriting of the mod, depending on what version of the mod you're using.

_sebas_

my forum:  SMF 1.1.18

from this, I extract the important part,  added in   Subs.php

<id>LHVWB:ShowLocalUrlTitles</id>
<version>1.1</version>
<file name="$sourcedir/Subs.php">
modifications_smf1.1.5.xml






// Function to Turn a url into a title, if possible.
function get_ShowUrlTitle($url)
{
global $db_prefix, $scripturl, $context;

// Firstly strip the internal location variable of 'www.' and 'http://'.
$location = $scripturl;
if(substr($location, 0, 7) == 'http://')
$location = substr($location, 7);
if(substr($location, 0, 4) == 'www.')
$location = substr($location, 4);

// Do we have an internal url? If not, then just pass the url back.
if(!preg_match('/(http:\/\/)(www\.)?('.addcslashes($location, '/`\=+*{},[]^$.-!').')(.)*$/i'. ($context['utf8'] ? 'u' : ''), $url, $match))
return $url;

// We only need the part after the boardurl for the message searching.
$after_url = substr($url, strlen($location)+7+(($match[2] == 'www.') ? 4 : 0));

// Make sure that its a valid internal url, otherwise just pass the url back.
if(!in_array(substr($after_url, 0, 1), array('/', '?')))
return $url;

// Firstly check for a topic ID/title.
if(in_array(substr($after_url, 1, 6), array('topic=', 'topic,'))
&& ($id_topic = intval(substr($after_url, 7))))
{
// Get the title for the message.
$request = db_query("
SELECT m.subject
FROM {$db_prefix}messages m, {$db_prefix}topics t
WHERE t.ID_TOPIC = '$id_topic'
AND m.ID_MSG = t.ID_FIRST_MSG", __FILE__, __LINE__
);

$data = mysql_fetch_assoc($request);
mysql_free_result($request);

// Do we have a valid topic?
if(!empty($data))
{

// If we have some data for a topic, we might as well check for a message title.
if((($pos = strpos($after_url, '#msg', 7)) || ($pos = strpos($after_url, '.msg', 7)))
&& ($id_msg = intval(substr($after_url, $pos+4))))
{
// Try to get the title for the message.
$msg_request = db_query("
SELECT subject
FROM {$db_prefix}messages
WHERE ID_MSG = '$id_msg'
AND ID_TOPIC = '$id_topic'", __FILE__, __LINE__
);

$msg_data = mysql_fetch_assoc($msg_request);
mysql_free_result($msg_request);

// Check for a valid message subject and return it if possible.
if(!empty($msg_data))
return $msg_data['subject'];
}

// Well, we tried to find a message... Just return the title of the topic.
return $data['subject'];
}
}

// Finally check for a board ID/title.
if(in_array(substr($after_url, 1, 6), array('board=', 'board,'))
&& ($id_board = intval(substr($after_url, 7))))
{
// Get the title for the message.
$request = db_query("
SELECT name
FROM {$db_prefix}boards
WHERE ID_BOARD = '$id_board'", __FILE__, __LINE__
);

$data = mysql_fetch_assoc($request);
mysql_free_result($request);

// Check for a valid name and return it if possible.
if(!empty($data))
return $data['name'];
}

// Return the url normally if all else fails, so if its an internal url like and action or something else...
return $url;
}


have 3 easy query's for 3  starting assumptions for
$id_msg
$id_topic
$id_board


I should get on board for the first two,
and then prevent obtaining for a particular board
(Example 56.     ......./index.php?board=56.0)
*   fortunately, not all internal subforums are compromising   *


what I would do: it's ugly and programmed directly in the code, but my skills in SQL is a basic course
(I have more experience in PHP)



therefore, if I had any extra indication would be great, 
mainly on how to get the id_board, properly
(I try in various ways and I get an array problem ... but I need more level)


$msg_request = db_query("
SELECT subject
FROM {$db_prefix}messages
WHERE ID_MSG = '$id_msg'
AND ID_TOPIC = '$id_topic'", __FILE__, __LINE__
);


$request = db_query("
SELECT m.subject
FROM {$db_prefix}messages m, {$db_prefix}topics t
WHERE t.ID_TOPIC = '$id_topic'
AND m.ID_MSG = t.ID_FIRST_MSG", __FILE__, __LINE__
);



Arantor

-sigh- That wasn't actually what I asked you, seeing that there are three different versions of the mod, and I asked you which one, though you already pulled out the relevant code by the looks of it.

I *think* you should be able to do it with changing the queries to:

global $user_info;
$msg_request = db_query("
SELECT subject
FROM {$db_prefix}messages AS m
INNER JOIN {$db_prefix}boards AS b ON (m.ID_BOARD = b.ID_BOARD)
WHERE ID_MSG = '$id_msg'
AND ID_TOPIC = '$id_topic'
AND {$user_info[query_see_board]}", __FILE__, __LINE__
);


global $user_info;
$request = db_query("
SELECT m.subject
FROM {$db_prefix}topics AS t
INNER JOIN {$db_prefix}messages AS m ON (m.ID_MSG = t.ID_FIRST_MSG)
INNER JOIN {$db_prefix}boards AS b ON (t.ID_BOARD = b.ID_BOARD)
WHERE t.ID_TOPIC = '$id_topic'
AND {$user_info[query_see_board]}", __FILE__, __LINE__
);



But I don't use 1.1.x (mostly because 2.0 has so many more useful features, and that 1.1.x is now 7 years old and sooner rather than later we're going to stop supporting it), and I have NOT tested the above changes. Use at your own risk.

Advertisement: