Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch to fix IDOR vulnerability in userinfo.php #1541

Draft
wants to merge 8 commits into
base: 2.0.x
Choose a base branch
from

Conversation

emilylwan
Copy link

This PR prevents the existing IDOR vulnerability at the endpoint userinfo.php/?uid=. Currently hackers are able to gain access to profiles by manipulating the uid field in the url to retrieve any profile in the database. We prevent that by changing what is received in the url.

Changes were made to the database structure, the user object, and the redirect urls to userinfo.php to support implementing a new hash_uid variable. The hash_uid variable is a randomly generated 64 character long hex string. It is saved into the databases and replaces the uid that is shown in the url of the userinfo.php page to prevent users from gaining access to another user’s profile through guessing the uid and crafting the url. This hash_uid is also used to verify if a current user is the same as the profile user to enable editing access. It also retrieves the user’s profile. These changes help remove the IDOR vulnerability at the endpoint userinfo.php/?uid= by crafting the uid in the url.

Copy link
Member

@MekDrop MekDrop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the fix! Is very rare for us to get such big PR from first time contributors!

Still I have found few problems that I think should be solved before this can be merged.

@@ -491,6 +491,7 @@ CREATE TABLE tplsource (

CREATE TABLE users (
`uid` mediumint(8) unsigned NOT NULL auto_increment,
`hash_uid` varchar(64) NOT NULL default '',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we use DB field, it should be unique; just add similar line like 'login_name'

*/
public function &getHash($hash_uid) {
$user = FALSE;
$sql = "SELECT * FROM " . $this->db->prefix('users') . " WHERE hash_uid = '" . $hash_uid . "'";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hash_uid should be escaped in case of SQL Injection. $this->db->quote($hash_uid) or $this->db->quoteString($hash_uid) should be used here

*/
public function &getHash($hash_uid) {
$user = FALSE;
$sql = "SELECT * FROM " . $this->db->prefix('users') . " WHERE hash_uid = '" . $hash_uid . "'";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Àdding LIMIT 1 to then end of this SQL can improve execution speed

Comment on lines 211 to 217
$hash_uid = bin2hex(random_bytes(32));
$user->assignVar('hash_uid', $hash_uid);
$sql = sprintf(
"UPDATE %s SET hash_uid = '%s' WHERE uid = '%u'",
$this->db->prefix('users'), $hash_uid, (int) $uid
);
$result = $this->db->query($sql);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure fully how to solve this but I see possible collision for users with same hash_uid problem.

Maybe here everything should be wrapped into transaction that first tries verify if user with such hash_uid exists and then if not try to update. If fails because of unique index violation, retry again.

@@ -39,7 +39,7 @@

$xoopsOption['pagetype'] = 'user';
include 'mainfile.php';
$hash_uid = (int) $_GET['uid'];
$hash_uid = $_GET['uid'];

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The input should be filtered and tested before using. In the original code, we force it to be an integer before proceeding

Copy link
Contributor

@skenow skenow Dec 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little better. I recommend reviewing the icms_core_DataFilter::checkVar() method. Strings can still be malicious and validating input and access are the best defense against breaches. You can view how we've utilized it in a lot of places - includes/finduser.php is a good example.

@skenow
Copy link
Contributor

skenow commented Dec 10, 2023

I should have said this earlier - thank you!

You have done what we encourage everyone to do -

  1. See something that could be improved
  2. Do something about it - not just for yourself, but for everyone

Another thing that makes this important is that you focused on improving security and protecting user data. That is something we are very committed to.

This is not a small thing, and we'd like more time to review on how best to assimilate this into our code base. We are in a release cycle and this is the branch we use for packaging and releasing.

ImpressCMS is a very user-driven platform and just about everything is linked to a user through their ID. To maintain data integrity, we have to exercise due diligence when changing a key field (a primary, in most cases). Some of the questions we have are about handling changes to existing installations, especially the database changes necessary. Once the release of 2.0 is out, we'll have more time to focus on this.

Again - thank you!

@fiammybe fiammybe marked this pull request as draft July 17, 2024 09:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants