XSS Worm Definition and Practical Analysis
The last blog analyzed the classification and basic combat methods of XSS, and this time I will continue to accept an XSS virus.
Definition
First, let’s analyze what is the XSS worm virus.
It is a cross-site scripting virus, mostly written in JavaScript, to break through the security restrictions of the browser, it is based on social engineering to induce users to click on the malicious invitation link to visit the site on the site to infect users, infected users and then send content containing worms to continue to infect secure users.
General principles
Based on stored XSS vulnerabilities, attackers implant malicious code on web pages.
- Send fake invitation links.
- The user clicks on the link to be infected.
- Send fake invitation link to friends of newly infected users.
This is a spread, spread mode, infection efficiency is very high, XSS worm infection speed is with the Web application user visits geometric increase
The xss worm is based on xss, so the functions that xss can exploit. Worms can exploit, and because xss worms are more propagable and harmful than stored XSS vulnerabilities.
The first worm: Samy
At the age of 19, Samy Kamkar launched an attack on the MySpace.com (social networking site). Samy Kamkar’s worm was executed by more than a million people in 20 hours. Everyone added a sentence after their self-introduction: “but most of all, Samy is my hero.”
In 2005, Samy Kamkar was struggling to make friends with his new account on the Myspace social networking site. His initial idea was to make his account page more flashy so that more girls would follow him. During his exploration of the Myspace.com page, he found that the page could embed javascript code, so his idea changed from “make the account page more flashy” to, every user who browses his account page will add him as a friend, and every user who adds his friend’s account page will embed the same code, and friends of friends will also add him as a friend… In less than a day, Samy’s worm infected 1 million users, making it the largest XSS worm in the history of web security.
Prerequisite for entry into force, MySpace website analysis
Well, let’s dive a little bit deeper into how these issues arise, the context in which it occurs, and how it works in general.
- The Myspace website filters many tags. In fact, they seem to only keep the ‘< a >’ tag, ‘< img >’ tag, and ‘< div >’ tag… there may be others. They prohibit the ‘< script >’ tag, < body > tag, onClick tag attribute, all tag attributes prefixed with on, href attribute containing javascript code, etc. However, some browsers (IE, some versions of Safari, etc.) allow javascript code in CSS tags. For example:
<div style="background:url('javascript:alert(1)')">
- Because we have used single and double quotes, we can no longer use quotes in the < div > tag. This makes JS code very difficult to write. To solve this problem, we use an expression to store JS code and then execute it through the name query:
<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">
3) Very good! Now we can use single quotes in javascript code. However, Myspace filters sensitive words such as “javascript”. To get around this limitation, we learned that some browsers parse “java\ nscript” as “javascript” (i.e. java < newline > script):
<div id="mycode" expr="alert('hah!')" style="background:url('java script:eval(document.all.mycode.expr)')">
4) OK, even if we make single quotes work, sometimes we need double quotes. We can escape double quotes, for example: "foo" bar ". But Myspace guessed I would do it… They filter all escaped quotes, whether single or double quotes. However, we can convert numerical values to ASCII code in javascript to generate quotes:
1 | <div id="mycode" expr="alert('double quote: ' + String.fromCharCode(34))" style="background:url('java |
- In order to submit the code to the user’s account page, we need to get the source code of the page. Aha, we can use document.body.innerHTML to get the source code of the page, and the account page will keep the ID of the user who viewed the page (even once). Myspace guessed my idea again and filtered all “innerHTML”. To get around this limitation, we use eval () to call two strings, splice them together, and combine them into “innerHTML”:
alert(eval('document.body.inne' + 'rHTML'));
6) It’s time to visit other pages. We may think of using the iframe tag, but many times (even when hidden), iframes are not that effective, and users will obviously be aware that “something” is happening. So, we use AJAX (XML-HTTP) to construct GET and POST requests. However, the Myspace website filters the necessary keyword for an XML-HTTP request: “onreadystatechange”. Again, we use eval to bypass it. Another reason for choosing XML-http is that the necessary cookies for performing operations on Myspace websites can easily be sent to the background:
eval('xmlhttp.onread' + 'ystatechange = callback');
7) It’s time to send a GET status to the user’s account page so we can get their current watchlist. We don’t want to delete any friends we follow, we just want to add ourselves to their watchlist. If our GET request gets their account page, we can grab their hero and save it for later use. As mentioned earlier, this is easy to do with XML-HTTP, but we must get the ID of the user browsing the page. As we said above, we can achieve this by obtaining the page source code. However, now we need to search for a special word on this page. So we start searching, and if we do, the search will always find the code we wrote ourselves, because our code contains the word we are looking for… We tell the computer “If this page contains the word’foo ', then do the following”, and this statement will always return true, because it will always find the word in the code that performs the search. We get around this problem by combining eval () with string:
var index = html.indexOf('frien' + 'dID');
8) So far, we’ve got the watchlist. Next, add me as a friend by constructing an XML-http POST request to send to the Add Friends page. Oh come on, this doesn’t work! Why doesn’t it work? We’re on profile.myspace.com, but POST requests to add friends can only be requested on www.myspace.com. Not a big deal, but XML-HTTP doesn’t allow cross-domain GET/POST requests. To get around this restriction, we’ll jump to the same url www.myspace.com. You can still access the account page on the www.myspace.com, so reload the page to the domain name we can POST:
if (location.hostname 'profile.myspace.com') document.location = 'http://www.myspace.com' + location.pathname + location.search;
9) We can finally make a POST request! However, when we send a POST request, it will not successfully add a friend. Why is this happening? The Myspace website generates a random hash value for the page that needs to be POST (for example, the “Are you sure you want to add this user as a friend” page). If this hash value is not included in the POST request, the request will not take effect. In order to solve this problem, we pretend to be a browser. Before adding friends, we use GET to obtain the corresponding page, parse its source code to obtain this hash value, and then attach this hash value when constructing a POST request.
When the POST request is complete, we also add a follower to the watchlist and attach the worm code. The code is placed in the same place as the new follow, so we only need to send a POST request. To get the new hash value, we need to GET the request to the page, but before that, we have to regenerate the worm code sent by POST. The easiest way is to grab the source code in our account page, parse the worm code, and then POST it out. This can be done, but now all the code is garbled! Ah, we need to URL encode or escape the code so that the POST request can send this code correctly. Strange, still not working. Obviously, the URL encoding and escape functions of javascript do not escape everything necessary, so we need to manually perform some substitutions to allow key data to be successfully escaped. We added a short paragraph of text “But most importantly, samy is my idol”. Immediately afterwards, we added all the worm code. Now, we have a “self-replicating” code, which you can call a worm if you want.
There are also some restrictions, such as the maximum length of label attribute assignment, which will cause other problems, and require compressed code, no spaces, vague variable names, functions to reuse
Source code analysis
1 | <div id=mycode style=”BACKGROUND: url('javascript:eval(document.all.mycode.expr)')” expr=” |