복호화 가능한 iswr 랜섬웨어 국내 유포중

ASEC(AhnLab Security Emergency response Center)은 모니터링 중 최근 iswr 랜섬웨어가 유포중인 것을 확인하였다.

iswr 랜섬웨어는 파일 암호화 시 파일명 뒤에 iswr이라는 확장자가 추가로 붙는 특징을 가지고 있으며, 해당 랜섬웨어의 랜섬노트는 STOP 랜섬웨어와 똑같은 형태를 가지고 있지만, 암호화 방식이나 암호화 대상 확장자 및 폴더와 같은 랜섬웨어 동작 루틴이 STOP 랜섬웨어와 많이 다르다.

[그림 1] iswr 랜섬웨어의 랜섬노트

암호화는 랜섬웨어가 실행되고 25초 후 작동하며, 파일 크기가 대체적으로 작은 확장자를 가진 파일들을 먼저 암호화 시키고, 그 다음 파일 크기가 대체적으로 큰 확장자를 가진 파일들을 암호화 시킨다. 암호화 대상은 아래와 같다.

  • 암호화 대상 : 모든 드라이브 내 아래 확장자를 가진 모든 파일
  • 파일 크기가 작은 암호화 대상 확장자 목록 : pdf, doc, docx, jpeg, png, jpg, ai, aep, eps, psd, dwg, odt, odp, odb, docm, xls, xlsx, xlsm, xlsb, xlk, ppt, pptx, mdb, pst, dxf, rtf, pdd, indd, cdr, dng, arw, sr2, crw, pst, nef, raw, rwl, rw2, rw2, r3d, crw, sr2, crw, x3f, max, 3DS, skp
  • 파일 크기가 큰 암호화 대상 확장자 목록 : mp4, zip, rar
[그림 2] 랜섬웨어 감염 후 암호화 된 파일

iswr 랜섬웨어의 암호화 방식은 다른 랜섬웨어의 암호화 방식과 다르게 비대칭키와 대칭키 두 가지를 섞어서 이용한 방식이 아닌 오직 비대칭키를 이용하여 암호화를 진행하며, 랜덤으로 만든 키 값(6바이트)을 이용하여 256바이트의 키 박스를 생성하고 결국에는 키 박스에 특정 연산을 한 후 데이터와 XOR 연산을 통하여 암호화 시킨다.

암호화 방식이 굉장히 단순하여 복호화가 가능하지만, 실제 감염되는 사용자들은 파일을 분석해보지 않는 이상 암호화 루틴을 알 수 없기 때문에 공격자에게 값을 지불하여 복호화 툴(확실히 복호화 툴을 받을 수 있을지는 알 수 없음)을 받거나 포맷을 할 수 밖에 없는 상황에 처하게 된다.

ASEC에서는 iswr 랜섬웨어에 대한 복호화 할 수 있는 스크립트를 제작하여 배포하고자 한다. 해당 복호화 스크립트는 Python 3.x 환경에서 작동하며, 스크립트 코드는 아래와 같다.

import sys
import os
import ctypes

key = ""
keyBox = []

suc_cnt = 0
fail = []

def genKeyBox():
    global key, keyBox
    
    k_arr = []
    
    for i in range(0, 256):
        keyBox.append(i)
        k_arr.append(key[i % 6])

    num = 0
    for i in range(0, 256):
        num = (num + keyBox[i] + ord(k_arr[i])) % 256
        keyBox[i], keyBox[num] = keyBox[num], keyBox[i]


def decrypt(filePath):
    global keyBox, suc_cnt, fail
    
    keyBoxCp = keyBox[:]
    
    file_ori = filePath[0:-5]
    
    try:
        fr = open(filePath, mode='rb')
        
        data = fr.read()
        
        num = 0
        num2 = 0
        res = bytearray()
        
        for i in range(0, len(data)):
            num2 = (num2 + 1) % 256
            num = (num + keyBoxCp[num2]) % 256
            keyBoxCp[num], keyBoxCp[num2] = keyBoxCp[num2], keyBoxCp[num]
            num3 = keyBoxCp[(keyBoxCp[num2] + keyBoxCp[num]) % 256]
            res.append(num3 ^ data[i])

        fr.close()

        fw = open(file_ori, mode='wb')
        fw.write(res)
        
        fw.close()
        
        os.remove(filePath)
        
        suc_cnt += 1   
    except Exception as e:
        fail.append(filePath)


def search_dir(path):
    num = 0
    
    for (root, dirs, files) in os.walk(path):
        for file in files:
            if file[-5:]==".iswr":
                num += 1
    
    if num == 0:
        return
        
    print("[+] Number of encrypted files : " + str(num) + "\n")
    
    cnt = 0
    
    for (root, dirs, files) in os.walk(path):
        for file in files:
            if file[-5:]==".iswr":
                cnt += 1
                print("\r[+] Progress : %0.1f%% (%d/%d)"%(cnt / num * 100, cnt, num), end='')
                filePath = os.path.join(root, file)
                decrypt(filePath)

    
def help():
    print("Usage : decryptor.py [Personal_ID] [Recovery_Directory_Path]\n")
    print("Personal_ID : Personal ID at the bottom of the ransom note (44 characters)")


def main():
    global key, suc_cnt, fail
    print("iswr Decryptor v1 by ASEC Analysis Team\n")
    
    arg = sys.argv
    
    if len(arg) < 3:
        print("[-] Invalid parameter\n")
        help()
        return

    if len(arg[1]) != 44:
        print("[-] Invalid Personal ID\n")
        help()
        return
        
    if os.path.isdir(arg[2]) == False:
        print("[-] Not exist directory\n")
        help()
        return

    print("[+] Personal ID : " + arg[1])
    
    key = arg[1][-6:]
    
    print("[+] Key : " + key + "\n")

    genKeyBox()

    search_dir(arg[2])
    
    total = suc_cnt + len(fail)
    
    print("\n[+] Total : " + str(total) + " / Success : " + str(suc_cnt) + " / Fail : " + str(len(fail)) + "\n")
    
    if len(fail) > 0:
        print("[-] Fail list\n")
    
        for failFile in fail:
            print(failFile)
    
    print("\n[+] End")
        
    
main()

스크립트 실행 시 아래와 같은 파라미터를 주어 실행하여야 하며, Personal_ID의 경우 랜섬노트 맨 마지막에 있는 44자리 글자를 입력하면 된다. 파라미터를 주어 실행하면 자동으로 파일들이 복호화되며, 원본 암호화된 파일은 자동으로 삭제된다.

decryptor.py [Personal_ID] [복구 대상 폴더]

랜섬웨어 예방을 위하여 출처가 불분명한 파일 실행에 주의해야 하며, 의심스러운 파일의 경우 백신을 통한 검사 및 백신 최신 업데이트가 필요하다.

V3에서는 아래와 같이 진단하고 있다.

[그림 3] V3 제품 탐지 결과

[파일 진단]

  • Ransomware/Win.Generic.C5387930 (2023.02.25.01)

[행위 진단]

  • Ransom/MDP.Decoy.M1171

[IOC 정보]

  • f791d1cf335353ea57c9475a69b261b0

연관 IOC 및 관련 상세 분석 정보는 안랩의 차세대 위협 인텔리전스 플랫폼 ‘AhnLab TIP’ 구독 서비스를 통해 확인 가능하다.

5 5 votes
별점 주기
Subscribe
Notify of
guest

0 댓글
Inline Feedbacks
View all comments