osTicket is a widely-used open source support ticket system written in PHP. It has been around for several years and still in active development. It is only officially supported when running on Microsoft IIS or Apache, so an osTicket instance is likely running one of those two backends. It must connect to an external MySQL or MariaDB instance to store all the necessary data.
This guide is intended to provide insightful information on osTicket when encountering this system during a penetration test. I hope to reduce your needed research time and perhaps show various exploitation techniques that you may not have come across. I have also created several Python scripts/payloads to automate vulnerabilities or osTicket-specific scanning.
To determine the version of osTicket in use, try visiting BASE_URL/setup/
(like http://doma.in/setup/
) to determine server version. This directory is only meant for the installation, and after being setup, a message is displayed in the admin dashboard advising the admins to delete this directory. If the directory is deleted, then the server version number isn't easily available - but can still be determined! Publicly-available files like CSS and JS files are often changed between versions, so the versions of the CSS and JS dependencies that are available on the site can give insight into the version of the application.
This whole process is automated in ostVersionScanner.py
. It will first check to see if the /setup/
directory is available and report the version number contained there. If the directory was deleted, it will go through a set up checks to determine the exact version number or range of possible versions. It will determine version numbers unless the application is < 1.11, in which case it will just say Version(s): < 1.11
.
If the version of osTicket is < 1.14.8 or 1.15.x < 1.15.4, then both agent and regular users can be enumerated through brute force (see Proof of Concept here). When requesting a password reset, these older versions would give different messages if the email/username exists, meaning brute-force guessing can result in finding email accounts (note that accounts found through this method will receive emails to their accounts to change their password). Since agents and regular users sign in through different portals, two PoCs were created. Note that most regular users will likely not have a username set since they can only sign up with an email, and have no option to set a username. Agents can add a username for the user if they would like.
It is also possible to enumerate other users through the use of Cross-Site Scripting (XSS) vulnerabilities. Regular users can have their emails leaked, and if an agent or admin falls victim to a XSS payload, all users and agents in the database can be leaked. See XSSPayloads.md for example payloads.
- Access to tickets can be granted without a password if the email and ticket number is known (6-digit number). Then, an "authorized URL" is sent to that email address (not one of your choosing), but this link (if sniffed or stolen) can be used for all eternity, it never expires. You can verify ticket numbers with email addresses by brute force. Assuming a valid email address and 10 req/sec, it would take about 27 hours to try all possible ticket numbers. (osTicket/osTicket#3041)
- XSS
- Regular users can have their ticket numbers and ticket contents enumerated and exfiltrated
- Agents and admins can list all tickets and ticket contents
- Invalid logins are not piped to external logs by default, plugins must be used (osTicket/osTicket#5716)
- You are rate limited, after 5 attempts (default value) you will be blocked for a while and stored in the local database of system errors
- Session cookies are set to HTTPonly in versions < 1.10.2 (https://github.com/osTicket/osTicket/commit/5b2dfce98ac05a68543b7603f3d46afafc09086d)
- Other juicy details from /setup/ directory being available?
- Older versions have "enable external images in tickets" enabled, which allows you to do blind SSRF as long as you put an image extension at the end
By default, anyone can submit a ticket to an osTicket instance as a guest - they don't even need an account. However, creating an account is fairly simple, all you need is a working email address and password. They log in through the normal /login.php
page on the front end.
The staff are split into two categories - agents and admins. Agents work on resolving tickets, while admins are agents with "extra permissions" that can administer the website, see system logs, add/modify other agents, etc. Depending on the setup of the organization, all agents may have admin privileges. In addition, all agents may not necessarily have the same permissions. Agents can be split into different groups and tiers and given different amounts of access on the server.
Since tickets oftentimes have sensitive information that can be useful both inside and outside of the osTicket context, lateral movement is especially important here. If you can get access to other tickets, you may find login credentials, information about infrastructure or setup, security policies, and other juicy details that can give you a good foothold in their environment as a whole.
Cross-Site Scripting is a great way to escalate privileges or move laterally in osTicket since there have been so many XSS vulnerabilities reported. If a regular user falls victim to XSS, you could use a payload that submits a ticket on behalf of the user, asking an agent to change their password to something new (maybe claim that you get errors each time?). If an agent falls victim to XSS, you could use a payload that automatically changes the password of a regular user account to a known value, allowing you full access to that account and all linked tickets. If an admin falls victim to XSS, you could use a payload that will create a new agent with full administrator rights and a known password, giving you complete access over the osTicket instance. See XSSPayloads.md for example payloads.
Versions < 1.15.4 allow external links to be placed inside of <img>
tags by default, and the "Print" functionality of tickets will cause the server to fetch those URLs. This could be used to exploit blind SSRF vulnerabilities, such as Blind SSRF Chains, giving you additional insight into other internal systems.
Vulnerable Version(s) | Attack Type | Severity | Proof of Concept | CVE/GitHub Commit |
---|---|---|---|---|
< 1.15.8, 1.16.x < 1.16.3 | Session Fixation | Unconfirmed | N/A | Commit |
< 1.15.8, 1.16.x < 1.16.3 | Content Injection | Unconfirmed | N/A | Commit |
< 1.15.8, 1.16.x < 1.16.3 | Authentication Bypass | Unconfirmed | N/A | Commit |
< 1.15.8, 1.16.x < 1.16.3 | Stored XSS | Unconfirmed | N/A | Commit |
< 1.15.8, 1.16.x < 1.16.3 | Reflected XSS | Unconfirmed | N/A | Commit |
< 1.14.8, 1.15.x < 1.15.4 | SQL Injection | Unconfirmed | N/A | Commit |
< 1.14.8, 1.15.x < 1.15.4 | Information Disclosure | 5.3 | Link | Commit |
< 1.14.8, 1.15.x < 1.15.4 | Blind SSRF/CSRF | Unconfirmed | N/A | Commit |
< 1.14.8, 1.15.x < 1.15.4 | Stored XSS | Unconfirmed | N/A | Commit |
< 1.14.8, 1.15.x < 1.15.4 | Email Injection | Unconfirmed | N/A | Commit |
< 1.14.8, 1.15.x < 1.15.4 | XSS | Unconfirmed | N/A | Commit |
< 1.14.8, 1.15.x < 1.15.4 | XSS | Unconfirmed | N/A | Commit |
< 1.14.7, 1.15.x < 1.15.3 | Stored XSS | Unconfirmed | N/A | Commit |
< 1.14.7, 1.15.x < 1.15.3 | Reflected XSS | Unconfirmed | N/A | Commit |
< 1.14.6, 1.15.x < 1.15.2 | XSS | Unconfirmed | N/A | Commit |
< 1.14.6, 1.15.x < 1.15.2 | Stored XSS | Unconfirmed | N/A | Commit |
< 1.14.5, 1.15 | Broken Access Control | Unconfirmed | N/A | Commit |
< 1.14.3 | Blind SSRF/CSRF | 7.5 | Link | CVE-2020-24881 |
< 1.14.3 | XSS | 4.3 | N/A | CVE-2020-24917 |
< 1.14.3 | Stored XSS | 3.5 | Link | CVE-2020-16193 |
< 1.14.3 | Stored XSS | Unconfirmed | N/A | Commit |
< 1.14.3 | Stored XSS | Unconfirmed | N/A | Commit |
< 1.12.6, 1.14.1 | Stored XSS | 5.0 | N/A | ExploitDB / Commit |
< 1.12.6, 1.14.1 | Stored XSS | 4.3 | N/A | ExploitDB / Commit |
< 1.12.6, 1.14.1 | Stored XSS | 4.3 | N/A | ExploitDB / Commit |
< 1.12.6, 1.14.1 | XSS | Unconfirmed | N/A | Commit |
< 1.12.6, 1.14.1 | XSS | Unconfirmed | N/A | Commit |
< 1.12.5 | Arbitrary Method Invocation | Unconfirmed | N/A | Commit 1, Commit 2 |
< 1.12.4 | Authentication Bypass | 7.2 | N/A | Commit |
< 1.12.4 | Unrestricted File Upload | Unconfirmed | N/A | Commit |
< 1.12.4 | Remote Code Execution | Unconfirmed | N/A | Commit 1, Commit 2 |
< 1.10.7, 1.11, 1.12 | CSV Injection | 6.8 | Link | CVE-2019-14749 |
< 1.10.7, 1.11, 1.12 | Stored XSS | 4.3 | Link | CVE-2019-14750 |
< 1.10.7, 1.11, 1.12 | Stored XSS | 3.5 | Link | CVE-2019-14748 |
- UserAgent must be the same for all HTTP requests with the same session, or else the session will die (versions < 1.14.7, 1.15.x < 1.15.3) https://github.com/osTicket/osTicket/commit/f71c95482cc12c2a0e6360e916b1bd5495b12738
- Look into plugins
- Look into dependencies
- Font-Awesome
- Currently using two CSS files (
/css/font-awesome-ie7.min.css
and/css/font-awesome.min.css
) from version 3.2.1 - The project is at version 6.1.1
- Only CSS, no security vulnerabilities in old versions that I can find (just more icons lol)
- Currently using two CSS files (
- HTMLawed
- Is a one-file project,
/include/htmLawed.php
, using version 1.2.4.1 - The project is currently 1.2.9
- Definitely worth looking into, this project is not simply focused on security, but more making HTML pretty, readable, and compliant with the HTML5 standard. See if it's being used as a security measure and if possible to bypass.
- Is a one-file project,
- jQuery dropdown
- Site doesn't even exist anymore, from 2011, but looks simple and harmless
- jsTimezoneDetect
- Simply returns timezone of the user, latest version is 1.0.7 and version used is 1.0.4
- No security vulnerabilities have been reported thusfar in adsfdsafsdfasdfsdfsdfa
- mPDF
- PasswordHash
- PEAR
- PEAR/Auth_SASL
- PEAR/Mail
- PEAR/Net_SMTP
- PEAR/Net_Socket
- PEAR/Serivces_JSON
- php-gettext
- phpseclib
- Spyc
- Font-Awesome