모두의 dream

Onyx Ransomware Analysis Report 본문

분야/malware Analysis

Onyx Ransomware Analysis Report

오리꽥이로 2022. 5. 9. 18:50
Contents 접기

공부를 하며 정리한 내용으로 잘못된 내용이 있을 수 있습니다.

dnSpy를 이용하여 분석했습니다. (닷넷 디컴파일)

1. 정적분석

Windows7 32bit 에서 분석했다.

 

detect it easy 에서 확인한 결과 .NET 기반으로 제작된 악성코드이다. (C#으로 개발됨.)

 

새로운 랜섬웨어 오닉스, 파일들을 파괴한다 (boannews.com)

최근기사에서 소개하고 있는 Onyx 랜섬웨어이다.

2. 동적분석

readme 파일이 생성되고 파일들이 암호화된다. (소유한 파일 중 hwp, mp4는 암호화 되지 않았다.)

혹시 몰라서 Windows7 64bit 환경에서 실행해봤는데 32bit 에서는 암호화되지 않은 mp4 확장자는 암호화되었다. (hwp는 여전히 멀쩡하다.)

 

암호화된 파일은 확장자가 바뀐다. (암호화 후 확장자는 ampkcz로 고정이다.)

 

바이너리를 여러 번 실행해 봤는데 한 번 암호화되면 이중 암호화는 되지 않는다.

 

Process monitor에서 확인해본 결과 랜섬웨어에서 자주 사용되는 ReadFile, CreateFile 등이 사용되고 있었다. 또한 모든 악성 행위가 종료되면 Onyx 랜섬웨어는 프로세스에서 사라진다.

3. 상세분석

Main 함수는 위와 같다.

 

 

가장 위에 있는 AlreadyRunning 함수를 분석해봤다.

GetProcesses: 현재 컴퓨터의 모든 프로세스 정보를 가져옴.

GetCurrentProcess: 현재 실행중인(자신) 프로세스 정보를 가져옴.

현재 프로세스에 동일한 프로세스가 동작중인지 실행 파일명과 PID 비교를 통해 확인한다.

동작중이라면 return 1, 아니라면 return 0 -> main 함수에서 1일 경우 Environment.Exit(1)로 프로세스가 종료된다.

 

다음으로 나오는 함수는 CheckSleep 이다.

기본값이 False로 지정되어 있고, 만약 True가 된다면 아래 코드가 작동된다.

10초 동안 sleep이 진행되는데, 

 

다음은 checkAdminPrivilage가 진행된다. (이것도 기본값은 False 이므로 코드가 작동되지 않음.)

기본값이 False 이므로 실행되지 않고 아래 코드로 넘어간다.

 

 

만약 False일 경우 else if 문으로 인해 CheckCopyRoaming 과정이 진행된다.

svchost.exe 문자열이 copyRoaming 함수 인자값으로 전달된다.

friendlyName 변수에 앱도메인? 값을 가져온다는데 악성 바이너리의 확장자를 포함한 실행파일명을 가져온다.

location 변수에 악성 바이너리의 경로를 가져온다.

text 변수에는 ApplicationData 폴더의 경로를 가져온다. (C:\Users\<user name>\AppData\Roaming)

text2 변수에는 text 변수에 매개변수로 받아온 svchost.exe 문자열이 추가된다.

friendlyName 변수와 processName 변수가 다르거나 location 변수와 text2 변수가 다르면 if 문 내부로 들어간다.

그리고 text2 변수의 주소에 svchost.exe 파일이 없을 경우에 if문 안으로 들어간다.

 

File.Copy 를 이용해서 악성 바이너리를 svchost.exe라는 이름으로 ApplicationData 폴더에 복사한다.

(svchost.exe로 위장하기 위해서 하는 작업임을 예상하게 되었다.)

 

그리고 svchost.exe를 process start를 이용해서 바로 실행시켜버린다.

성공적으로 start를 진행하면 현재 실행중인 프로세스는 바로 종료된다.

 

그래서 복사된 svchost.exe를 이용해서 디버깅을 진행했다.

그럼 위에 있는 악성 바이너리를 svchost.exe로 복사하는 과정을 건너 뛰고 그 다음을 디버깅할 수 있다.

 

checkStartupFolder 과정을 진행한다. (기본값 True)

아래는 True일 경우 진입하는 addLinkToStartup 함수 내부이다.

folderPath 변수에 startup(시작프로그램) 위치를 가져온다.

(@"C:\Users\<user name>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup")

str 변수에 현재 프로세스의 이름을 가져온다. (svchost)

그리고 folderPath 주소에 svchost.url 파일이 만들어진다.

 

location 변수에는 현재 실행중인 파일인 svchost.exe의 경로가 저장된다.

"[InternetShortcut], URL=file:///<svchost.exe 경로>, IconIndex=0, IconFile=<svchost.exe 경로>" 문자열들이 svchost.url 파일에 아래와 같이 저장된다.

 

다음은 lookForDirectories 함수가 호출된다.

DriveInfo.GetDrives를 이용해서 드라이브의 이름을 검색하고, C드라이브 이외의 드라이브는 모두 if문 안쪽encryptDirectory 함수로 진입한다. (C드라이브는 foreach문 밖에서 별도로 encrypt가 진행된다.)

 

C드라이브 이외에 D드라이브라던가 등등의 드라이브가 발견되면 encryptDirectory 함수로 인해 모든 파일들이 암호화된다. C드라이브는 선택적으로 암호화를 하기 위해서 별도로 코드를 둔 것 같다.

 

location ~ location13 변수에 들어간 문자열들의 위치에 있는 파일들과 ApplicationData, 공용폴더에 있는 파일들을 대상으로 암호화를 진행한다.

 

encryptDirectory 함수를 분석해봤다.

함수 전체

 

files 문자열에 location에 존재하는 모든 파일명을 가져온다.

그리고 폴더에 있는 파일의 개수만큼 반복문이 돌아간다.

 

extension, filename 변수에 각각 파일의 확장자명과 이름을 가져온다.

그리고 파일의 확장자를 악성 바이너리에 하드코딩되어 있는 확장자 리스트에 있는지 확인한다.
(hwp 확장자는 없으므로 암호화되지 않는다.)

 

하드코딩 되어있는 모습

 

그리고 파일명이 readme.txt가 아닌지 확인한다.

확장자명이 배열에 존재하고, 파일명이 readme.txt가 아니라면 if문 내부로 진입하게 된다.

 

그리고 파일의 정보들을 불러온다.

 

만약 파일의 크기가 2117152 byte (2MB?) 보다 작으면 EncryptFile 함수가 실행된다.

ReadAllBytes를 이용해서 암호화할 파일을 바이트 단위로 읽어온다.

그리고 CreatePassword 함수를 이용해서 랜덤 문자열을 생성한다.

랜덤 문자열은 위와 같고 주어진 문자열에서 20개를 랜덤으로 뽑는다.

 

다시 EncryptFile 함수로 복귀해서 20개의 랜덤 문자열을 Encoding.UTF8.GetBytes을 이용해서 byte 형식으로 바꾼다.

그리고 AES_Encrypt 함수를 이용해서 파일을 랜덤으로 뽑은 20개의 문자열을 이용해서 AES 암호화한다.

 

AES_Encrypt 함수 내부인데 자세한 분석은 추후로 미룬다.

 

다시 EncryptFile 함수로 돌아와서 WriteAllText를 이용해서 암호화한 파일을 저장시켜준다.

(AES 암호화에 사용한 랜덤 키값은 RSA로 암호화해서 파일의 앞에 작성하고, AES로 암호화된 파일의 구조는 base64로 다시 인코딩한다.)

그리고 Move를 이용해서 새로운 확장자를 붙여준다. (RandomStringForExtension 함수 사용)

근데 랜덤이라고 적혀있지만 ampkcz 값으로 고정이다.

 

최종적으로 파일 암호화 및 확장자 변경이 끝나면 아래 과정이 진행된다.

각 location의 첫번째 암호화가 진행된 후에만(최초 1번) 위에 보이는 코드가 실행된다.

readme.txt 파일 생성과 함께 파일 내부에 안내글(?)을 작성하게 된다.

 

파일들 말고 폴더들도 접근해서 폴더 안에 있는 파일들도 모두 암호화한다.

 

2117152(2.1MB) 보다 작은 경우가 끝났고, 남은 케이스는 2가지이다.

 

파일의 크기가 200000000(190MB) 보다 작고 2117152(2.1MB)보다 큰 경우에는 파일의 크기(byte 값)을 가지고 랜덤으로 문자열을 만들어 낸다. 

 

randomEncode 부분인데 plaintext가 사실상 base64 인코딩할때만 사용되므로 위에 부분은 상관이 없는게 아닌가 싶다.

기존 파일에 암호화를 한 것도 아니고 문자열 크기값에 4를 나눠서 만든 암호인데, 복호화가 불가능한 것 같다.

암호화 부분

 

파일의 크기가 200000000(190MB) 보다 큰 경우.

length 변수에 200000000~300000000 사이의 숫자를 넣는다.

나머지는 위와 동일하다. (복호화를 할 수가 없다.)

 

둘 다 아예 기존 파일과는 전혀 다른 값을 집어넣는 것 같다.

 

마지막으로 addAndOpenNote() 함수는 readme.txt 를 실행시켜준다.

 

이후 프로세스에서 계속 실행된 상태로 남아있는다.

 

'분야 > malware Analysis' 카테고리의 다른 글

HermeticWiper Malware Analysis Report  (2) 2022.04.28
HermeticWiper Malware (Detail)  (0) 2022.04.22
Comments