I was tricked on Facebook into downloading an obfuscated script

This is a typical obfuscated JavaScript malware which targets the Windows Script Host to download the rest of the payload. In this case, it downloads what appears to be mainly a Chrome Extension (manifest.json and bg.js), the autoit Windows executable, and some autoit scripts which install them. All of these files are named with .jpg extensions on the (likely-compromised) server they are hosted, to be less-conspicuous.

The malware appears to be partially incomplete or otherwise underdeveloped or perhaps based off some other malware (quality is very low). Many of the autoit scripts don't actually do anything, and what appears to be a ZIP meant to contain a Firefox extension is actually empty. The autoit scripts are a ton of includes combined into a single file, but only one (ekl) actually has a payload at the end.

The one active autoit script which runs on infection replaces the Chrome, IE, and possibly other browser shortcuts with a shortcut to Chrome with the necessary arguments to run the malicious Chrome extension.

The Chrome extension is mainly how this malware is being propagated. It does some nasty things like blacklisting antivirus software domains, and sending Facebook messages automatically. Actually there was a webservice back end at http://appcdn.co/datajs serving some scripts which would be injected on any page a user visited based on the URL currently being viewed, which was how the Facebook messages were being posted. This service is now offline, likely taken down.

Is this an exploit on Facebook?

Not exactly, more-like abuse of Facebook. Facebook's code hasn't been exploited, your friend just has an infected browser phishing their contacts on their behalf.

Is it possible that my friend got a virus which targets their contacts by tagging them on malicious links?

Yep, that's exactly how this malware is spreading itself.

Should I report this to Facebook? If so, how?

Yes, see How to Report Things in the Facebook help center.

Getting the following URL's taken offline by contacting their hosts would also be good.

http://userexperiencestatics.net/ext/Autoit.jpg
http://userexperiencestatics.net/ext/bg.jpg
http://userexperiencestatics.net/ext/ekl.jpg
http://userexperiencestatics.net/ext/ff.jpg
http://userexperiencestatics.net/ext/force.jpg
http://userexperiencestatics.net/ext/sabit.jpg
http://userexperiencestatics.net/ext/manifest.jpg
http://userexperiencestatics.net/ext/run.jpg
http://userexperiencestatics.net/ext/up.jpg
http://whos.amung.us/pingjs/?k=pingjse346
http://whos.amung.us/pingjs/?k=pingjse3462
http://appcdn.co/datajs

Unfortunately, CloudFlare still has not taken the userexperiencestatics.net URL's down though I contacted then shortly after posting this answer, and I don't know who is actually hosting these files. CloudFlare just emailed me to say they restricted access to the files, and says they will notify the host.

UPDATE:

After I and likely others reported the .jse URL to Google, they appear to have taken down the file. If you find any more copies, those should also be reported. It seems people have been receiving the files from numerous sources.

MORE INFO:

This malware and post is getting a lot of attention, so I'll add some more info to address people's questions:

Will this file automatically run when downloaded?

Probably not unless you have configured your browser to do so. It is meant to trick you into opening it.

Can it infect my phone, or non-Windows computer.

As far as I know, Windows is the only OS which can run this malware. As I mentioned, it uses the Windows Script Host. I don't believe even Windows phone is vulnerable, though I don't know much about Windows phone.

UPDATE ON RANSOMWARE:

Previously it was assumed the autoit scripts contained ransomware, however after further inspection this appears not to be the case. There is just a bunch of unused crypto function obscuring the actual payload, which I've mostly deobfuscated to this.

UPDATE ON CHROME EXTENSION:

The unpacked Chrome extension code can be viewed here. Details on what it did integrated above.

UPDATE FOR JSE SCRIPT:

My de-obfuscated comment_24016875.jse script can be viewed here.


I haven't got the time to fully reverse-engineer what this script does, but it seems to link to several .jpg files that are actually not images but text, and then references some .au3 files, suggesting that it actually saves those .jpg files under that extension.

Those .au3 files seem to match AutoIt's file extension and indeed they look like valid AutoIt scripts. Here's a part of one, the ekl.jpg:

Func _crypt_startup()
    If __crypt_refcount() = 0 Then
        Local $hadvapi32 = DllOpen("Advapi32.dll")
        If $hadvapi32 = -1 Then Return SetError(1, 0, False)
        __crypt_dllhandleset($hadvapi32)
        Local $iproviderid = $prov_rsa_aes
        Local $aret = DllCall(__crypt_dllhandle(), "bool", "CryptAcquireContext", "handle*", 0, "ptr", 0, "ptr", 0, "dword", $iproviderid, "dword", $crypt_verifycontext)
        If @error OR NOT $aret[0] Then
            Local $ierror = @error + 10, $iextended = @extended
            DllClose(__crypt_dllhandle())
            Return SetError($ierror, $iextended, False)
        Else
            __crypt_contextset($aret[1])
        EndIf
    EndIf
    __crypt_refcountinc()
    Return True
EndFunc

Func _crypt_shutdown()
    __crypt_refcountdec()
    If __crypt_refcount() = 0 Then
        DllCall(__crypt_dllhandle(), "bool", "CryptReleaseContext", "handle", __crypt_context(), "dword", 0)
        DllClose(__crypt_dllhandle())
    EndIf
EndFunc

Func _crypt_derivekey($vpassword, $ialg_id, $ihash_alg_id = $calg_md5)
    Local $aret = 0, $hbuff = 0, $hcrypthash = 0, $ierror = 0, $iextended = 0, $vreturn = 0
    _crypt_startup()
    Do
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptCreateHash", "handle", __crypt_context(), "uint", $ihash_alg_id, "ptr", 0, "dword", 0, "handle*", 0)
        If @error OR NOT $aret[0] Then
            $ierror = @error + 10
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        $hcrypthash = $aret[5]
        $hbuff = DllStructCreate("byte[" & BinaryLen($vpassword) & "]")
        DllStructSetData($hbuff, 1, $vpassword)
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptHashData", "handle", $hcrypthash, "struct*", $hbuff, "dword", DllStructGetSize($hbuff), "dword", $crypt_userdata)
        If @error OR NOT $aret[0] Then
            $ierror = @error + 20
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptDeriveKey", "handle", __crypt_context(), "uint", $ialg_id, "handle", $hcrypthash, "dword", $crypt_exportable, "handle*", 0)
        If @error OR NOT $aret[0] Then
            $ierror = @error + 30
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        $vreturn = $aret[5]
    Until True
    If $hcrypthash <> 0 Then DllCall(__crypt_dllhandle(), "bool", "CryptDestroyHash", "handle", $hcrypthash)
    Return SetError($ierror, $iextended, $vreturn)
EndFunc

Func _crypt_destroykey($hcryptkey)
    Local $aret = DllCall(__crypt_dllhandle(), "bool", "CryptDestroyKey", "handle", $hcryptkey)
    Local $ierror = @error, $iextended = @extended
    _crypt_shutdown()
    If $ierror OR NOT $aret[0] Then
        Return SetError($ierror + 10, $iextended, False)
    Else
        Return True
    EndIf
EndFunc

Func _crypt_encryptdata($vdata, $vcryptkey, $ialg_id, $bfinal = True)
    Local $ireqbuffsize = 0, $aret = 0, $hbuff = 0, $ierror = 0, $iextended = 0, $vreturn = 0
    _crypt_startup()
    Do
        If $ialg_id <> $calg_userkey Then
            $vcryptkey = _crypt_derivekey($vcryptkey, $ialg_id)
            If @error Then
                $ierror = @error + 100
                $iextended = @extended
                $vreturn = -1
                ExitLoop
            EndIf
        EndIf
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptEncrypt", "handle", $vcryptkey, "handle", 0, "bool", $bfinal, "dword", 0, "ptr", 0, "dword*", BinaryLen($vdata), "dword", 0)
        If @error OR NOT $aret[0] Then
            $ierror = @error + 20
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        $ireqbuffsize = $aret[6]
        $hbuff = DllStructCreate("byte[" & $ireqbuffsize & "]")
        DllStructSetData($hbuff, 1, $vdata)
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptEncrypt", "handle", $vcryptkey, "handle", 0, "bool", $bfinal, "dword", 0, "struct*", $hbuff, "dword*", BinaryLen($vdata), "dword", DllStructGetSize($hbuff))
        If @error OR NOT $aret[0] Then
            $ierror = @error + 30
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        $vreturn = DllStructGetData($hbuff, 1)
    Until True
    If $ialg_id <> $calg_userkey Then _crypt_destroykey($vcryptkey)
    _crypt_shutdown()
    Return SetError($ierror, $iextended, $vreturn)
EndFunc

Func _crypt_decryptdata($vdata, $vcryptkey, $ialg_id, $bfinal = True)
    Local $aret = 0, $hbuff = 0, $htempstruct = 0, $ierror = 0, $iextended = 0, $iplaintextsize = 0, $vreturn = 0
    _crypt_startup()
    Do
        If $ialg_id <> $calg_userkey Then
            $vcryptkey = _crypt_derivekey($vcryptkey, $ialg_id)
            If @error Then
                $ierror = @error + 100
                $iextended = @extended
                $vreturn = -1
                ExitLoop
            EndIf
        EndIf
        $hbuff = DllStructCreate("byte[" & BinaryLen($vdata) + 1000 & "]")
        DllStructSetData($hbuff, 1, $vdata)
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptDecrypt", "handle", $vcryptkey, "handle", 0, "bool", $bfinal, "dword", 0, "struct*", $hbuff, "dword*", BinaryLen($vdata))
        If @error OR NOT $aret[0] Then
            $ierror = @error + 20
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        $iplaintextsize = $aret[6]
        $htempstruct = DllStructCreate("byte[" & $iplaintextsize & "]", DllStructGetPtr($hbuff))
        $vreturn = DllStructGetData($htempstruct, 1)
    Until True
    If $ialg_id <> $calg_userkey Then _crypt_destroykey($vcryptkey)
    _crypt_shutdown()
    Return SetError($ierror, $iextended, $vreturn)
EndFunc

Func _crypt_hashdata($vdata, $ialg_id, $bfinal = True, $hcrypthash = 0)
    Local $aret = 0, $hbuff = 0, $ierror = 0, $iextended = 0, $ihashsize = 0, $vreturn = 0
    _crypt_startup()
    Do
        If $hcrypthash = 0 Then
            $aret = DllCall(__crypt_dllhandle(), "bool", "CryptCreateHash", "handle", __crypt_context(), "uint", $ialg_id, "ptr", 0, "dword", 0, "handle*", 0)
            If @error OR NOT $aret[0] Then
                $ierror = @error + 10
                $iextended = @extended
                $vreturn = -1
                ExitLoop
            EndIf
            $hcrypthash = $aret[5]
        EndIf
        $hbuff = DllStructCreate("byte[" & BinaryLen($vdata) & "]")
        DllStructSetData($hbuff, 1, $vdata)
        $aret = DllCall(__crypt_dllhandle(), "bool", "CryptHashData", "handle", $hcrypthash, "struct*", $hbuff, "dword", DllStructGetSize($hbuff), "dword", $crypt_userdata)
        If @error OR NOT $aret[0] Then
            $ierror = @error + 20
            $iextended = @extended
            $vreturn = -1
            ExitLoop
        EndIf
        If $bfinal Then
            $aret = DllCall(__crypt_dllhandle(), "bool", "CryptGetHashParam", "handle", $hcrypthash, "dword", $hp_hashsize, "dword*", 0, "dword*", 4, "dword", 0)
            If @error OR NOT $aret[0] Then
                $ierror = @error + 30
                $iextended = @extended
                $vreturn = -1
                ExitLoop
            EndIf
            $ihashsize = $aret[3]
            $hbuff = DllStructCreate("byte[" & $ihashsize & "]")
            $aret = DllCall(__crypt_dllhandle(), "bool", "CryptGetHashParam", "handle", $hcrypthash, "dword", $hp_hashval, "struct*", $hbuff, "dword*", DllStructGetSize($hbuff), "dword", 0)
            If @error OR NOT $aret[0] Then
                $ierror = @error + 40
                $iextended = @extended
                $vreturn = -1
                ExitLoop
            EndIf
            $vreturn = DllStructGetData($hbuff, 1)
        Else
            $vreturn = $hcrypthash
        EndIf
    Until True
    If $hcrypthash <> 0 AND $bfinal Then DllCall(__crypt_dllhandle(), "bool", "CryptDestroyHash", "handle", $hcrypthash)
    _crypt_shutdown()
    Return SetError($ierror, $iextended, $vreturn)
EndFunc

Func _crypt_hashfile($sfile, $ialg_id)
    Local $btempdata = 0, $hfile = 0, $hhashobject = 0, $ierror = 0, $iextended = 0, $vreturn = 0
    _crypt_startup()
    Do
        $hfile = FileOpen($sfile, $fo_binary)
        If $hfile = -1 Then
            $ierror = 1
            $vreturn = -1
            ExitLoop
        EndIf
        Do
            $btempdata = FileRead($hfile, 512 * 1024)
            If @error Then
                $vreturn = _crypt_hashdata($btempdata, $ialg_id, True, $hhashobject)
                If @error Then
                    $ierror = @error
                    $iextended = @extended
                    $vreturn = -1
                    ExitLoop 2
                EndIf
                ExitLoop 2
            Else
                $hhashobject = _crypt_hashdata($btempdata, $ialg_id, False, $hhashobject)
                If @error Then
                    $ierror = @error + 100
                    $iextended = @extended
                    $vreturn = -1
                    ExitLoop 2
                EndIf
            EndIf
        Until False
    Until True
    _crypt_shutdown()
    If $hfile <> -1 Then FileClose($hfile)
    Return SetError($ierror, $iextended, $vreturn)
EndFunc

Func _crypt_encryptfile($ssourcefile, $sdestinationfile, $vcryptkey, $ialg_id)
    Local $btempdata = 0, $hinfile = 0, $houtfile = 0, $ierror = 0, $iextended = 0, $ifilesize = FileGetSize($ssourcefile), $iread = 0, $breturn = True
    _crypt_startup()
    Do
        If $ialg_id <> $calg_userkey Then
            $vcryptkey = _crypt_derivekey($vcryptkey, $ialg_id)
            If @error Then
                $ierror = @error
                $iextended = @extended
                $breturn = False
                ExitLoop
            EndIf
        EndIf
        $hinfile = FileOpen($ssourcefile, $fo_binary)
        If @error Then
            $ierror = 2
            $breturn = False
            ExitLoop
        EndIf
        $houtfile = FileOpen($sdestinationfile, $fo_overwrite + $fo_createpath + $fo_binary)
        If @error Then
            $ierror = 3
            $breturn = False
            ExitLoop
        EndIf
        Do
            $btempdata = FileRead($hinfile, 1024 * 1024)
            $iread += BinaryLen($btempdata)
            If $iread = $ifilesize Then
                $btempdata = _crypt_encryptdata($btempdata, $vcryptkey, $calg_userkey, True)
                If @error Then
                    $ierror = @error + 400
                    $iextended = @extended
                    $breturn = False
                EndIf
                FileWrite($houtfile, $btempdata)
                ExitLoop 2
            Else
                $btempdata = _crypt_encryptdata($btempdata, $vcryptkey, $calg_userkey, False)
                If @error Then
                    $ierror = @error + 500
                    $iextended = @extended
                    $breturn = False
                    ExitLoop 2
                EndIf
                FileWrite($houtfile, $btempdata)
            EndIf
        Until False
    Until True
    If $ialg_id <> $calg_userkey Then _crypt_destroykey($vcryptkey)
    _crypt_shutdown()
    If $hinfile <> -1 Then FileClose($hinfile)
    If $houtfile <> -1 Then FileClose($houtfile)
    Return SetError($ierror, $iextended, $breturn)
EndFunc

Func _crypt_decryptfile($ssourcefile, $sdestinationfile, $vcryptkey, $ialg_id)
    Local $btempdata = 0, $hinfile = 0, $houtfile = 0, $ierror = 0, $iextended = 0, $ifilesize = FileGetSize($ssourcefile), $iread = 0, $breturn = True
    _crypt_startup()
    Do
        If $ialg_id <> $calg_userkey Then
            $vcryptkey = _crypt_derivekey($vcryptkey, $ialg_id)
            If @error Then
                $ierror = @error
                $iextended = @extended
                $breturn = False
                ExitLoop
            EndIf
        EndIf
        $hinfile = FileOpen($ssourcefile, $fo_binary)
        If @error Then
            $ierror = 2
            $breturn = False
            ExitLoop
        EndIf
        $houtfile = FileOpen($sdestinationfile, $fo_overwrite + $fo_createpath + $fo_binary)
        If @error Then
            $ierror = 3
            $breturn = False
            ExitLoop
        EndIf
        Do
            $btempdata = FileRead($hinfile, 1024 * 1024)
            $iread += BinaryLen($btempdata)
            If $iread = $ifilesize Then
                $btempdata = _crypt_decryptdata($btempdata, $vcryptkey, $calg_userkey, True)
                If @error Then
                    $ierror = @error + 400
                    $iextended = @extended
                    $breturn = False
                EndIf
                FileWrite($houtfile, $btempdata)
                ExitLoop 2
            Else
                $btempdata = _crypt_decryptdata($btempdata, $vcryptkey, $calg_userkey, False)
                If @error Then
                    $ierror = @error + 500
                    $iextended = @extended
                    $breturn = False
                    ExitLoop 2
                EndIf
                FileWrite($houtfile, $btempdata)
            EndIf
        Until False
    Until True
    If $ialg_id <> $calg_userkey Then _crypt_destroykey($vcryptkey)
    _crypt_shutdown()
    If $hinfile <> -1 Then FileClose($hinfile)
    If $houtfile <> -1 Then FileClose($houtfile)
    Return SetError($ierror, $iextended, $breturn)
EndFunc

Func _crypt_genrandom($pbuffer, $isize)
    _crypt_startup()
    Local $aret = DllCall(__crypt_dllhandle(), "bool", "CryptGenRandom", "handle", __crypt_context(), "dword", $isize, "struct*", $pbuffer)
    Local $ierror = @error + 10, $iextended = @extended
    _crypt_shutdown()
    If $ierror OR (NOT $aret[0]) Then
        Return SetError($ierror, $iextended, False)
    Else
        Return True
    EndIf
EndFunc

Func __crypt_refcount()
    Return $__g_acryptinternaldata[0]
EndFunc

Func __crypt_refcountinc()
    $__g_acryptinternaldata[0] += 1
EndFunc

Func __crypt_refcountdec()
    If $__g_acryptinternaldata[0] > 0 Then $__g_acryptinternaldata[0] -= 1
EndFunc

Func __crypt_dllhandle()
    Return $__g_acryptinternaldata[1]
EndFunc

Func __crypt_dllhandleset($hadvapi32)
    $__g_acryptinternaldata[1] = $hadvapi32
EndFunc

Func __crypt_context()
    Return $__g_acryptinternaldata[2]
EndFunc

Func __crypt_contextset($hcryptcontext)
    $__g_acryptinternaldata[2] = $hcryptcontext
EndFunc

As you can see there is crypto-related code suggesting this is a (quite crappy and amateur) ransomware. Feel free to reverse engineer everything else.


From what it looks like, a malicious actor leverage what is known as a XML External Entity vulnerability (XXE) and then a Server-Side Request Forgery (SSRF).

Facebook's servers were tricked into linking a malicious XML file from another domain, processing it and served it up to you. Here is the XXE cheat sheet and SSRF bible's cheat sheet, if you're interested you can study up on it.

Think about it...your obfuscated script had the following (msxml2.XMLhttp method and stated it came from google).

Specifically, it used "the ADODB.Stream Object to Send Binary Files to the Browser through ASP."

In short, yes, it leveraged an XXE (via asp writing an xml document) and forged (SSRF) it stating it came from google.