Patched
This XSS vulnerability has been patched in v0.4.4.1
Thanks a ton to @ejedev for finding this and reporting it!
Summary
Starting in version 0.4.4 of raptor-web, it is possible to craft a malicious URL that will result in a reflected cross-site scripting vulnerability. A user controlled URL parameter is loaded into an internal template that has autoescape disabled.
Details
To show the flow of this vulnerability we will start off with a request made to /announcements?server=test
The base template is loaded, located here: https://github.com/zediious/raptor-web/blob/d53f46bed260ed23742a89e6a414228b75dab797/raptorWeb/templates/raptormc/base.html
It builds the following htmx
object, which on load
will automatically send a GET
request to raptormc/api/html/announcements?server=test
|
<div hx-get="/raptormc/api/html/{{request.path|strip_slash}}{% if request.GET %}?{% for param in request.GET %}{{param}}={% get_param param %}{% endfor %}{% endif %}" |
|
hx-trigger='load' |
|
hx-target='#home' |
|
hx-swap="innerHTML" |
|
hx-indicator="#mainLoadingspinner"> |
|
</div> |
The TemplateView
for announcements
is rendered here:
|
class Announcements(TemplateView): |
|
""" |
|
Page containing the last 30 announcements from Discord |
|
""" |
|
template_name: str = join( |
|
TEMPLATE_DIR_RAPTORMC, 'defaultpages/announcements.html') |
|
|
|
def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: |
|
if not DefaultPages.objects.get_or_create(pk=1)[0].announcements: |
|
return HttpResponseRedirect('/404') |
|
|
|
if request.headers.get('HX-Request') != "true": |
|
return HttpResponseRedirect('/404') |
|
|
|
return super().get(request, *args, **kwargs) |
|
|
|
def get_context_data(self, **kwargs: dict[str, Any]) -> dict[str, Any]: |
|
context: dict[str, Any] = super().get_context_data(**kwargs) |
|
if self.request.GET: |
|
context['opened_server_pk'] = self.request.GET.get('server') |
|
return get_or_create_informative_text( |
|
context = context, |
|
informative_text_names = ["Announcements Information"]) |
The get_context_data
method sets opened_server_pk
equal to the URL parameter server
.
|
context['opened_server_pk'] = self.request.GET.get('server') |
This template is not accessible directly, and requires the header HX-Request
to be set to true
. This is done by the hx-get
div loaded in the base.
The announcements
template itself is located here: https://github.com/zediious/raptor-web/blob/2776281eb12fa04eca177bbfe92a4cfcd74ba391/raptorWeb/templates/raptormc/defaultpages/announcements.html
It notably sets {% autoescape off %}
for the majority of the template:
The template attempts to build a second htmx
object, making a call to the server_announcements_poll
endpoint:
|
<div id="server_announcements" |
|
hx-get="{% url 'gameservers:server_announcements_poll' %}{% if request.GET %}?server={{opened_server_pk}}{% endif %}" |
|
hx-trigger="load" |
|
hx-target="#server_announcements" |
|
hx-swap="outerHTML"></div> |
|
</div> |
However, since there is no autoescape enabled, we are able to inject Javacript as we have full control over the opened_server_pk
value being rendered. The original hx-get
call from the base template will inject the results of this secondary template as innerHTML
, rendering it for the user.
PoC
We'll make the following request to the server: /announcements?server=%22%3E%3Cscript%3Ealert(%22XSS%22)%3C%2fscript%3E
. When URL decoded, it looks like this:
/announcements?server="><script>alert("XSS")</script>
This results in the base
template rendering an htmx
object that looks like this:
<div hx-get="/raptormc/api/html/announcements?server="><script>alert("XSS")</script>"
hx-trigger='load'
hx-target='#home'
hx-swap="innerHTML"
hx-indicator="#mainLoadingspinner">
</div>
Once the page loads, it makes a GET
request to /raptormc/api/html/announcements?server=%22%3E%3Cscript%3Ealert(%22XSS%22)%3C/script%3E
.
This request renders the announcements
template, and includes an htmx
object that looks like this:
<div id="server_announcements"
hx-get="/api/servers/html/server_announcements_poll/?server="><script>alert("XSS")</script>"
hx-trigger="load"
hx-target="#server_announcements"
hx-swap="outerHTML"></div>
As we can see, we were able to escape from the hx-get
attribute as the template does not have autoescape enabled. We injected a script
object which is then returned all the way to the original base
template and executed, causing a cross-site scripting vulnerability to occur.
The PoC url to test this is https://SITE.COM/announcements?server=%22%3E%3Cscript%3Ealert(%22XSS%22)%3C%2fscript%3E
Impact
This is a cross-site scripting vulnerability that affects all deployments of raptor-web
on version 0.4.4
. Any victim who clicks on a malicious crafted link will be affected.
Patched
This XSS vulnerability has been patched in v0.4.4.1
Thanks a ton to @ejedev for finding this and reporting it!
Summary
Starting in version 0.4.4 of raptor-web, it is possible to craft a malicious URL that will result in a reflected cross-site scripting vulnerability. A user controlled URL parameter is loaded into an internal template that has autoescape disabled.
Details
To show the flow of this vulnerability we will start off with a request made to
/announcements?server=test
The base template is loaded, located here: https://github.com/zediious/raptor-web/blob/d53f46bed260ed23742a89e6a414228b75dab797/raptorWeb/templates/raptormc/base.html
It builds the following
htmx
object, which onload
will automatically send aGET
request toraptormc/api/html/announcements?server=test
raptor-web/raptorWeb/templates/raptormc/base.html
Lines 79 to 84 in d53f46b
The
TemplateView
forannouncements
is rendered here:raptor-web/raptorWeb/raptormc/views.py
Lines 52 to 74 in 2776281
The
get_context_data
method setsopened_server_pk
equal to the URL parameterserver
.raptor-web/raptorWeb/raptormc/views.py
Line 71 in 2776281
This template is not accessible directly, and requires the header
HX-Request
to be set totrue
. This is done by thehx-get
div loaded in the base.The
announcements
template itself is located here: https://github.com/zediious/raptor-web/blob/2776281eb12fa04eca177bbfe92a4cfcd74ba391/raptorWeb/templates/raptormc/defaultpages/announcements.htmlIt notably sets
{% autoescape off %}
for the majority of the template:raptor-web/raptorWeb/templates/raptormc/defaultpages/announcements.html
Line 26 in 2776281
The template attempts to build a second
htmx
object, making a call to theserver_announcements_poll
endpoint:raptor-web/raptorWeb/templates/raptormc/defaultpages/announcements.html
Lines 51 to 56 in 2776281
However, since there is no autoescape enabled, we are able to inject Javacript as we have full control over the
opened_server_pk
value being rendered. The originalhx-get
call from the base template will inject the results of this secondary template asinnerHTML
, rendering it for the user.PoC
We'll make the following request to the server:
/announcements?server=%22%3E%3Cscript%3Ealert(%22XSS%22)%3C%2fscript%3E
. When URL decoded, it looks like this:/announcements?server="><script>alert("XSS")</script>
This results in the
base
template rendering anhtmx
object that looks like this:Once the page loads, it makes a
GET
request to/raptormc/api/html/announcements?server=%22%3E%3Cscript%3Ealert(%22XSS%22)%3C/script%3E
.This request renders the
announcements
template, and includes anhtmx
object that looks like this:As we can see, we were able to escape from the
hx-get
attribute as the template does not have autoescape enabled. We injected ascript
object which is then returned all the way to the originalbase
template and executed, causing a cross-site scripting vulnerability to occur.The PoC url to test this is
https://SITE.COM/announcements?server=%22%3E%3Cscript%3Ealert(%22XSS%22)%3C%2fscript%3E
Impact
This is a cross-site scripting vulnerability that affects all deployments of
raptor-web
on version0.4.4
. Any victim who clicks on a malicious crafted link will be affected.