The other day I received a phishing email masquerading as a message from LinkedIn. It stated I had just changed my email address and needed to confirm. I decided to practice my analysis skills. Below is what I found.
I will start with a basic comparison of a phishing email with a legit one. Then I will dig into the malicious link and show what I was able to discover.
Luck was on my side. A coworker of mine happened to just have changed his LinkedIn email address and was able to provide me with a legitimate notification from LinkedIn to use as a comparison.
Here is a screen shot of the legitimate LinkedIn email received by my coworker:
And here is a screen shot of the Phishing email I received.
As you see very similar. What threw flags for me were:
1. I had not changed my email address at LinkedIn ( My first thought was that my account had been hacked).
2. I don't use my work email on my LinkedIn account. (So I probably was not hacked).
3. The To: field was not me. (I have it redacted here)
4. It states that if the link does not work "copy and paste the below link into a browser". There is not link to copy and paste.
5. Looking at the destination of the "Click here" showed it did NOT point back to LinkedIn.
So a comparison of the properties of the "Click here" links showed that the legitimate link pointed to:
hXXps://www.linkedin.com/e/csrf_EeY/-3dz43t-h2vzqvqm-t/cnf/unc7Ghd0QuINCFs9fUQpREDACTED
This link matched to one provided to paste into my browser.
The malicious link pointed to:
hXXp://yaraticifikir.com/report.htm
For good measure I also looked at the header information of the too emails:
Here is the header from the legitimate email:
Received: from XXXX.XXXX.com (###.###.###.###) by XXXX.XXXX.XXXX.LOCAL
(###.###.###.###) with XXXX id #.#.#; Thu, 31 May 2012
10:40:48 -0500
X-WSS-ID: 0M4W8U8-01-0BJ-01
X-TMWD-Spam-Summary: TS=20120531153944; ID=1; SEV=2.4.2; DFV=B2012041615; IFV=NA; AIF=B2012041615; RPD=5.07.0001; ENG=NA; RPDID=dfssd; CAT=NONE; CON=NONE; SIG=AAABAKR1FwAAAAAAAAAAAEASBgoAAAE=
X-TMWD-IP-Reputation: SIP=###.###.###.###; IPRID=7469643D303030312E30413032303330322E34464337393046452E30313230; CTCLS=R6; CAT=Unknown
Received: from XXXX.com (XXXX.XXXX.com [###.###.###.###]) by
XXXX.XXXX.com (XXXX) with SMTP id 21D6B1180D5 for
; Thu, 31 May 2012 10:39:43 -0500 (CDT)
Received: from maila-ab.linkedin.com ([69.28.147.141]) by
XXXX.XXXX.com ([###.###.###.###]) with SMTP; Thu, 31 May 2012 10:40:47
CDT
DomainKey-Signature: q=dns; a=rsa-sha1; c=nofws;
s=prod; d=linkedin.com;
h=DKIM-Signature:Sender:Date:From:To:Message-ID:Subject:MIME-Version:Content-Type:X-LinkedIn-Template:X-LinkedIn-Class:X-LinkedIn-fbl;
b=NWOWcIF+2nB1OHtTlcbKEjz3uXD1yIl6mwgxvNv1a5BZE4r9HQyhUU8NeFJe2gsi
M1Uy0PY/UYpDXYMu0Lkk15hpaMzy2yEkm5tdQl2BIh8GMAv2NN0IlIkbc5p9b5+d
DKIM-Signature: v=1; a=rsa-sha1; d=linkedin.com; s=proddkim; c=relaxed/relaxed;
q=dns/txt; i=@linkedin.com; t=1338478846;
h=From:Subject:Date:To:MIME-Version:Content-Type:X-LinkedIn-Class:X-LinkedIn-fbl:
X-LinkedIn-Template;
bh=Bos5wwGOMp06O6taWlF78p04rCQ=;
b=h9yVSfYyn5O0C+lkhR0peBuRj9LPCWOoTBnI3nFFdB/efURH5prae2sTGdVQsK+A
c3K5v5dnh9eSgxce+fhJkdqH8wEYiickRbluHWkq1hZZ4HqudMPKeYI03BbaG2Jk;
Sender:
Date: Thu, 31 May 2012 15:40:46 +0000
From: LinkedIn Email Confirmation
To: "XXXX"
Message-ID: <295900650.2579567.1338478846575.JavaMail.app@ela4-bed78.prod>
Subject: Please confirm your email address
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_2579566_278032838.1338478846574"
X-LinkedIn-Template: email_confirm
X-LinkedIn-Class: ACCT-ADMIN
X-LinkedIn-fbl: s-X39FxNh3lf7HEqL8X9_80bUZR57bEdA8X5_vfPnalJZ_JzpDowC5Eq
X-pstn-levels: (S:99.90000/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:95.5423 C:98.6951 )
X-pstn-dkim: 1 skipped:not-enabled
X-pstn-status: off
Return-Path:
s-X39FxNh3lf7HEqL8X9_80bUZR57bEdA8X5_vfPnalJZ_JzpDowC5Eq@bounce.linkedin.com
Here is the header from the phishing email:
Received: from XXXX.XXXX.com (###.###.###.###) by XXXX.XXXX.local
(###.###.###.###) with XXXX Server id #.#.#.#; Fri, 1 Jun 2012
07:52:43 -0500
X-WSS-ID: 0M4XVPZ-01-6FI-01
X-TMWD-Spam-Summary: TS=20120601125135; ID=1; SEV=2.4.2; DFV=B2012041615; IFV=NA; AIF=B2012041615; RPD=5.07.0001; ENG=NA; RPDID=ygyuguy; CAT=NONE; CON=NONE; SIG=AAABAKR1FwAAAAAAAAAAAEASBg0AAAI=
X-TMWD-IP-Reputation: SIP=###.###.###.###; IPRID=7469643D303030312E30413032303330322E34464338423935422E30303741; CTCLS=R5; CAT=Unknown
Received: from YYYY.com (YYYY.YYYY.com [###.###.###.###]) by
XXXX.XXXX.com (XXXXX) with SMTP id 2C14B1180D9; Fri, 1
Jun 2012 07:51:33 -0500 (CDT)
Received-SPF: none (google.com: AfricChubbuck@metroiw.com does not designate permitted sender hosts) client-ip=119.154.121.49;
Received: from Khalid-PC ([119.154.121.49]) by YYYY.YYYY.com
([###.###.###.###]) with SMTP; Fri, 01 Jun 2012 05:52:38 PDT
Received: from maild-aa.linkedin.com ([69.28.147.158]) by
mx5.biz.mail.yahoo.com; Fri, 1 Jun 2012 11:52:38 +0500
Sender:
Date: Fri, 1 Jun 2012 11:52:38 +0500
From: LinkedIn Email Confirmation
To: emailXXX
Message-ID: <885503274.9062496.6229627163370.JavaMail.app@ela3-app2659.prod>
Subject: Please confirm your email address
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_Part_2261235_0574152891.4606584408472"
X-LinkedIn-Template: email_confirm
X-LinkedIn-Class: ACCT-ADMIN
X-LinkedIn-fbl: s-1PMC9IWJT1DY8CPDE6UIZZPPNA8E9VI05FMXSD-M8AEPF440WP1FXG
Return-Path: s-1PMC9IWJT1DY8CPDE6UIZZPPNA8E9VI05FMXSD-M8AEPF440WP1FXG@bounce.linkedin.com
X-OriginalArrivalTime: Fri, 1 Jun 2012 11:52:38 +0500 FILETIME=[372CCC03:A54BD8E6]
X-pstn-neptune: 500/438/0.88/100
X-pstn-levels: (S:55.09949/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:95.5423 C:98.6951 )
X-pstn-dkim: 0 skipped:not-enabled
X-pstn-status: off
As you can see, they are quite different, along with some more red flags that I placed in bold text.
So what does that hxxp://yaraticifikir.com/report.htm look like? I used the tool WGET in my BackTrack VM to pull the file down locally.
Here is a screen shot of the page:
Notice in the bottom of the browser Firefox prevented a script from running. So next I decided to peek at the web page's source. Which showed this:
Notice in the web page's source a script tag is seen. It reads as one long line so I copied it out into a text editor and formatted it to be a little more reader friendly. This is what I came up with:
The above code is javascript. And at a quick review it appeared that there was simple obfuscation implemented. The following is what I made of the code:
By the way obfuscation (the result of obfuscating) as defined by by merriam-webster is to be evasive, unclear, or confusing.
I am not a javascript programmer so I was not familiar with the "Try / Catch" statements. I referred to w3schools.com to get me up to speed. w3schools explains try...catch as:
"The try...catch statement allows you to test a block of code for errors.
The try block contains the code to be run, and the catch block contains
the code to be
executed if an error occurs."
I was also not familiar with the appendChild() method. This is explained by w3schools as a method that appends a node to the last child of a node. Here are w3schools examples. However; in this code, appendChild() purposefully has nothing to do with execution.
Obfuscation Examples
The attacker purposefully inserts incorrect code in the the "try" block so that the code in the in the "catch" block will be executed. In the first "try" block "q" is not defined and so passes on to "catch". In the second "try" block the string prototype is not defined and so the code in the second "catch" block is executed.
Also note in the above code the "catch" functions contain parameters:
The first: "catch(qw)"
The second: "catch(b43gds)"
These appear to only be further measures of obfuscation.
Another attempt at obfuscation is that the attacker is assigning and appending variables all over the place. This is just a further attempt to make it a bit challenging to follow.
The first example is very simple. "h" is declared and assigned the value "-012/5" up on the"catch" block then used in the "for" loop later.
There are also multiple other examples of variables being assigned then either appended to or concatenated together and using multiple further techniques to obfuscate the codes final output.
Notice the variable "f" in the below screenshot:
1. "f" is being assigned a concatenated string of fromCh
2. then "f" is being appended to with the characters "arC", so now "f" stands for "fromCharC"
3. Finally "f" is being appended to one more time, among more obfuscation. This little line is using what is known as a conditional operator "?" which in layman's terms reads
(test a condition) ? :
In this case:
- "append to f", (which so far is "fromCharC")
- Test to see if "h" exists and "zz" exists. They do exist as we see at the top of the code h=-012/5 and just two lines up with "zz" being assigned to more obfuscated code.
- ? is the conditional operator.
- If h" and "zz" exists append the letters "ode" to "fromCharC"
- : is the break between "do if true else do if false"
- then finally if "h" and "zz" did not exists then append nothing as seen as ""
So now we see that "f" is a variable housing the phrase "fromCharCode".
f = fromCharCode
But notice we see "f" one more time just two more lines down in the code:
e=w(f.substr(11)+zz)
So what is going on here? Before I answer that I want to step back and mention what substr is doing and discover what the "zz" is.
Referring back again to w3schools they give a concise and effective explanation of the "string" object, its properties, and methods. I have substr pointed out in the image below.
A simplified example of substr would be:
x = "example";
y = x.substr(2);
Printing out "y" would show ample
So if "y" was printed out it would read "ample" because in the string "example" e is in the 0's place, x in the 1's, a in the 2's in the 3's etc... So y=x.substr(2) basically says take the characters starting at the 2's position and assign them to y.
Hopefully substr is understood so lets look at what is going on with its use in the obfuscated code.
1. "zz" is being assigned the concatenated characters "a+l", so "zz" is "al".
2. There is a little obfuscation in this line. That attacker is assigning "zz" a new value by using the substr method on the string "zv". The attacker then appends the current value of zz ("al") to that. Notice in the line there is (123-122); this is simply a mathematical operation which means the same thing as (1). This means the string could be simplified (de-obfuscated) as all of the following mean the same thing:
zz='zv'.substr(123-122)+zz
zz='zv'.substr(1)+zz
zz='zv'.substr(1)+'al'
Based on what we know about substr "zv" in this case has "z" in the 0's place and "v" in the 1's. What is happening here is that the attacker is stripping off the z and appending the letter "v" to "al". All that now makes "zz" assigned "val"
zz = val
3. Now we know:
f = fromCharCode
z = val
Next I will break down some of the line "e=w[f.substr(11)+zz]". These all mean the same thing:
e=w[f.substr(11)+zz]
e=w[fromCharCode(11)+zz]
e=w[fromCharCode(11)+'val'
Working our substr with "f" in the 0's place, "r" in the 1's etc we determine that the 11's place character is "e"; the last character of the string "fromCharCode". The line then appends that "e" to "val". Now have the word "eval"!
e=w[eval]
What is the significance of "eval"? It is a javascript global function, and again, more info from w3schools; if the argument for the eval() function is a javascript statement, eval() executes that statement!
Now about that "w" in front of the brackets...
1. "this", is a javascript keyword that took me a bit of time to understand, but thanks to an article at Digital Web Magazine it finally has clicked, (or flickered). The "this" keyword localizes execution context to a particular scope in javascript code. (I am merely regurgitating Digital Web's article, if you want to understand "this" better then read their article by Mike West who did a great write up) The attacker has not assigned the "this" keyword to any context nor any object. In this case, Mike West states in his article; the ""this" defaults to reference the most global thing it can: for web pages, this is the "window" object. It is within this object the eval() function will be used.
2. Here the variable "e" is being assigned. De-obfusctating the line may make it a little more clear. All of the following perform the same action:
e=w[f.substr(11)+zz]
e=this[f.substr(11)+zz]
e=this[eval]
e=this.eval
Unfortunately I am unable to determine why the [ ... ] are working in place of the " . ". I assumed them to be reserved for arrays. If anybody reading this can help me out please contact me.
3. Finally we see the variable "e" (which is literally the function "eval()") being used to call the command housed by the variable "ss"
Now I want to show what the SS variable is housing, but first I want to step back and clear up some more obfuscated code of the mathematical variety.
Starting back near the top of the code we have seen that:
h=-012/5
Typical math would have "h" looking like this:
h = -2.4
But the code is not declaring this to be a floating point integer. Javascript defaults the number to just be an integer so we lose the ".4" and we are left with:
h = -2
We will visit the "h" variable again in just a bit but next I want to tackle the "for" loop.
1. Traditionally a "for" loop is written something like:
for( i=0; i < 10; i++)
{
print i
}
The code in the malicious script is similar if one just does the math.
Starting with "i ="
6-2-1-2-1 = 0
so this could be written as
i = 0
Then moving to -645+i != 2-2 we clean this up a bit and find it looks like this (by the way != means not equal to)
-645+i != 0
cleaning up some more we could write this as
i < 645
and at the end we have the standard i++
So the entire initiation of the "for" loop could be written as
for(i=0; i < 645; i++)
2. Next there is a simple assignment of k = i. In this case there is not a need for this. We could just stick with "i"
3. Here we see "k" again which was assigned to "i" above, but as mentioned we could do without the "k" and just place "i" here. With these few changes the code begins easier to understand as the above could be written as:
for(i=0; i < 645; i++)
{
ss=ss+String["from"+CharCode"](-1*4*h*(5+1*n[i]))
}
Next I want clean up that line of code in the "for" loop. The first stop is the "h" variable I wrote about above.
h = -2
So the line can be written as:
ss=ss+String["from"+CharCode"](-1*4*-2*(5+1*n[i]));
Continuing to clean up that part of formula we see:
-1 * 4 * -2
Since this is multiplication the two negatives cancel each other out so this can also be written as:
1 * 4 * 2
Now notice the 1 is pointless since:
1 * 4 * 2 = 8
and
4 * 2 = 8
This shows that the
ss=ss+String["from"+CharCode"](-1*4*-2*(5+1*n[i]));
can be written as:
ss=ss+String["from"+CharCode"](8*(5+1*n[i]));
Now taking a look inside the next set of parenthesis I use mathematical precedence to help clean this up.
(5+1*n[i])
Multiplication happens before addition. Above we see that 1 is being multiplied by "n[i]" (I will get to what is going on with "n[i]" in just a moment). 1 multiplied by any number will equal that number; so will remove it too. With this;
(5+1*n[i])
becomes
(5+n[i])
Now stepping back we see that:
ss=ss+String["from"+CharCode"](8*(5+1*n[i]));
becomes:
ss=ss+String["from"+CharCode"](8*(5+n[i]));
Next I move a bit to the left and see that a simple concatenation is occurring:
["from" + "CharCode"]
This can be written as:
["fromCharcode"]
So with that change notice the line of code that started as:
ss=ss+String["from"+CharCode"](-1*4*-2*(5+1*n[i]));
can be written as:
ss=ss+String["fromCharCode"](8*(5+n[i]));
and again with the square brackets... so actually the code will work if written as
ss=ss+String.fromCharCode(8*(5+n[i]));
Now I want to address the "fromCharCode" and again I refer to w3schools. fromCharCode() is a method of the "string" object in javascript that converts Unicode values into in characters. For example "65" is unicode for "A".
x = string.fromCharCode(65);
Now if I printed out "x" I would see "A"
Earlier in this write up I had a screen shot of the entire malicious javascript but after that I have been using screen shots with a chunk of the code missing. The code that was missing was a an array of numbers that are fed into the "for" loop I just presented. When the formula is run it creates a unicode value that is then converted into a character.
Here is the entire code set again:
1. Here the "ss" is being declared as an empty array that is to be filled in during the "for" loop. Then the array is called again at the end of the program.
2. "n" is declared here as an array and is filled with numbers that will be fed into the "for" loop formula as part of the creation of the unicode value.
I want revisit the line of code in the "for" loop. I am going to use the line that I presented as de-obfuscated to make understanding what is going on a little more simple. I will start with a bit on arrays and for loops. Here is just an example of an array
x = [ "dog", "cat", "bird"] is an array of animals. Similar to the "string" position the array has positions too. In this case "dog" is in position 0, "cat" is in position 1 and "bird" is in position 2. I now present a sample loop that would print these out. (NOTE this code is not completely accurate I just want to get the idea of what is happening).
x = [ "dog", "cat", "bird"]
for(i=0; i < 2; i++)
{
print x[i];
}
As the array loops through it is read as:
print x[0] which prints "dog" from the "x" array in position 0 because at this time i = 0.
next "i++" increments "i" from 0 to 1 so the next pass through the loop is
print x[1] which prints "cat". "i++" increments again and now "i" becomes 2
print x[2] which prints "bird". Now when "i" is incremented again it is 3, which is greater than 2 so the loop exits.
Hopefully this lays a foundation of understanding for how the "n" array and the "for" loop in the malicious script works.
2. The blue box in the above image encompasses the entire array of "n". I am just going to look at the first few items of the array to demonstrate what exactly is happening with it and the "for" loop.
The array starts out
n = [-3.875, -3.875, 8.125, 7.75 ..... ]
As we have seen the "n" array is addressed in the "for" loop
ss=ss+String.fromCharCode(8*(5+n[i]));
Now it is time to explain "n[i]" as I promised earlier. As I have just pointed out in the for loop example, "n" is the array name and at this time it is calling for the item in the "0" position; which is -3.875. So the array at this time now is read as
ss=ss+String.fromCharCode(8*(5+(-3.875)));
Breaking it down we start with:
5 + (-3.875) = 1.125
Then:
8 * 1.125 = 9
Now the string at this iteration of the "for" is the same as this:
ss=ss+String.fromCharCode(9);
Recall this line is taking 9 as a unicode value and converting it to a character value. The character value for 9 unicode is an empty space. Check out Uncle Jim's Web Designs for a handy tool to convert unicode to characters
The next object in the "n" array is also -3.875. So it too becomes 9 unicode and thus represents an empty space character.
The third object in the "n" array is 8.125 plugging it in looks like this:
ss=ss+String.fromCharCode(8*(5+(8.125)))
and this formula gives us:
ss=ss+String.fromCharCode(8*(5+(8.125))) = 105
105 unicode converts to the character "i"
The fourth object is 7.75 and plugging it in:
ss=ss+String.fromCharCode(8*(5+(7.75)))
Gives us the unicode value:
ss=ss+String.fromCharCode(8*(5+(7.75))) = 102
With that we have:
"9,9,105,102" unicode
This converts to
" if" character
So far see that:
ss = [ if]
This next image shows what we get if we iterate through the entire loop. Now we see what the entire "ss[]" array contains:
This is a little hard to read so I will clear it up with some formatting in the next image.
The above images show that unicode was converted into further javascript. This code consists of an "if / else" statement and a "function" the attacker wrote and named "iframer".
1. The if statement starts by calling the "document object's" "getElementsByTagName()" function. w3schools describes this method but I also found a nice explanation at about.com. What this is looking for is the "body"
tag in the html document. In my experience there is most always a "body" tag as it is part of the basic HTML4 page structure. You can right click and view the source of this page to see an example or just peek at my quick mock up here.
If the "body" tag is found then function "iframer" is called.
2. If the "body" tag is not found then the document object's write() method is used to create an iframe. The write() method writes HTML or javascript code to a document; as explained at w3schools. More about what this iframe code is doing is described in part 3.
3. This is the iframer() function. It's purpose to is create an iframe 10 x 10 in pixel size. However the frame is hidden so this will operate in the background, and, as the attacker hopes, go undetected. Most importantly notice what web page address the iframe is going to load; a Russian domain web page at he piloramamosko.ru site.
Now I know what is loaded in the variable "ss". I also know what is loaded in the variable "e". So one more visit to the malicious code shows what comes next, which hopefully by now is obvious.
1. This is the command to execute the code that will create the invisible iframes. Thus calling the malicious website and possibly downloading malware to the victim's computer.
e(ss)
Could be interpreted as:
There you have it!
If there is something in this write up that I am mis-communicating, corrections that need to be made, or any other feedback please let me know.
.