쉘코드 전체는 위와 같습니다. 이 쉘코드는 크게 함수를 찾아 실행시키는 함수와 연쇄적으로 함수를 호출하는 두 부분으로 나뉩니다. 함수를 찾아 실행시키는 이 함수가 가장 중요하므로 메인 함수라고 부르겠습니다. 맨 밑에는 URL String이라고 주석으로 단 것과 같이 URL 문자열이 들어 있습니다.
[그림 2. 쉘코드 시작 직후 바로 Call 하는 루틴]
우선 함수를 호출하는 부분부터 살펴보면, 쉘코드가 시작하자마자 쉘코드 내의 특정 함수를 Call하는 것을 볼 수 있습니다. Call 명령어의 특징은 JMP 명령과는 달리 실행되면서 자동으로 스택에 다음 명령어의 주소(여기서는 0x30006), 즉 리턴 어드레스를 스택에 Push한다는 점인데, Call된 함수 내부에서는 바로 Pop 명령으로 EBP에 그 값을 저장합니다. 그리고 스택에 몇 가지 인자를 넣고 EBP를 그대로 호출합니다. 첫 번째 인자는 지금은 무엇인지 알 수 없는 4바이트 값이며, 두 번째 인자는 Push ESP를 통해 들어간 문자열 값으로 "urlmon"이라는 값입니다. 이를 알 수 있는 이유는 Push ESP 이전에 두 번의 Push를 통해 스택에 문자열로 "urlmon"을 저장하는 것이 보이기 때문입니다. 이제 EBP에 지정된 함수(0x30006)에 대해 분석해보겠습니다.
[그림 3. 함수를 찾아 실행시키는 메인 함수]
쉘코드 전체에서 위의 빨간 점선 부분이 Call EBP를 통해 호출되는 부분입니다. 바로 이 함수가 위에서 언급한 메인 함수입니다. 분석을 마치고 내린 결론은 이 함수는 인자로 특정 함수명의 해시를 전달받아 이를 찾아 실행시키는 함수라는 점입니다. 차근차근 위에서부터 분석해보겠습니다.
[그림 4. 로드된 모듈과 그 안의 함수 정보를 가져오는 부분]
fs:[0x30]으로 PEB를 가져오고, 거기서 또 0xC만큼의 Offset에 있는 Ldr을 가져옵니다. 여기까지만 봐도 벌써 익숙한 코드여서 그 다음은 분석하기 무척 쉬웠습니다. 메모리에 로드된 DLL 정보가 이중 연결 리스트 형태로 저장되어있는 Ldr 구조체를 참조하여 로드된 DLL 정보와 Base Address를 가져오고, 이를 파싱하여 Export Table을 확인합니다. 만약 Export된 함수가 없을 경우에는 밑으로 점프하는데 밑에서는 참조할 DLL을 다음 것으로 로드한 뒤 다시 위로 돌아옵니다. 위 루틴이 끝난 후에는 ESI에 함수 이름이 저장됩니다. 자세한 내용은 전에 공부하며 정리한 적이 있으므로 아래 링크 두 개를 참조하면 되겠습니다.
그렇게 찾아온 함수를 직접 만든 듯한 루틴에 넣고 돌려 4바이트짜리 해시를 뽑습니다. lodsb 명령의 경우 ESI가 가리키는 값 한 바이트를 al에 복사하고 ESI 값을 1바이트 증가시키는 역할을 합니다. (참고 : https://blog.naver.com/krquddnr37/20193085864) 해싱 함수의 경우 무척 간단해서 파이썬으로 루틴을 작성해봤습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# ROL & ROR Function : https://bbolmin.tistory.com/133
그리고 나온 해시를 [EBP+24]와 비교하는데, 이는 위에서 Call EBP를 통해 이 함수를 호출하기 전에 첫 번째 인자로 넣었던 값입니다. 즉, 메인 함수의 첫 번째 인자는 찾고자 하는 함수명의 해시임을 알 수 있습니다.
[그림 6. 찾은 함수 호출 루틴]
그렇게 찾아낸 함수는 위 루틴을 거쳐 실행시킵니다. 함수로 Jmp하기 전에 Popad와 Pop이 두 번 있는 것을 볼 수 있는데, 그림 3에서 확인할 수 있듯이 메인 함수가 실행된 후 Pushad를 호출했었습니다. Popad로 스택에서 그 부분을 다시 가져오고, pop을 두 번 진행하여 스택에 쌓여 있던 리턴 어드레스와 첫 번째 인자(해싱된 함수명)를 제거합니다. SFP(Saved Frame Pointer)의 경우에는 함수에서 호출되자마자 Push EBP를 통해 스택에 쌓는게 일반적이지만 여기에서는 그런 명령어는 없었으니 논외입니다. 이후 첫 번째로 Pop했던 리턴 어드레스를 다시 Push하고 Call이 아니라 JMP 명령어로 찾아낸 함수를 호출하는데, 이럴 경우 방금 Push한 메인 함수의 리턴 어드레스가 JMP 명령으로 이동할 함수에서 사용할 리턴 어드레스가 되므로 찾아낸 함수가 종료되는 순간 메인 함수를 호출한 다음 명령어로 돌아가게 될 것입니다. (그림 2의 0x300C7) 이렇게 하면 자연스럽게 메인 함수에 넘긴 두 번째 인자부터는 메인 함수 내에서 찾아 호출한 함수의 인자로 들어가게 됩니다.
[그림 7. 메인 함수 호출]
이 쉘코드는 이런식으로 Call EBP를 연쇄적으로 호출하는데, 지금까지의 과정으로 메인 함수의 첫 번째 인자는 호출할 함수명의 해시이며 두 번째부터는 찾아서 호출될 함수에 들어갈 인자들이라는 것을 알 수 있었습니다.
[그림 8. 함수명과 그 해시]
이를 통해 찾아낸 각 해시에 대응하는 함수명들은 위와 같습니다. 이는 위에 파이썬으로 작성해 둔 HashROR 함수로 얻어낸 값입니다. 그림 7에 빨간 점선으로 표시된 값과 일치하는 것을 확인할 수 있습니다. 그림 7에도 주석으로 달려 있지만 이 쉘코드에서 호출할 것이라 예상되는 함수와 그 순서는 다음과 같습니다. (이해를 돕기 위해 중간에 Pseudo-Code도 포함되어있습니다)
1
2
3
4
5
6
7
LoadLibrary("urlmon");
LPVOID p = VirtualAlloc(NULL, 0x400, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
테스트를 위해 실제로 가상머신 내에서 PyCL 랜섬웨어를 돌려 일부러 감염시킨 테스트 파일들입니다.
프로그램 실행 후 복호화 할 파일/폴더의 경로와 키 값을 입력하면 자동으로 해당 경로 하위를 전부 돌면서 감염된 확장자를 확인하고 입력받은 키로 복호화를 시도합니다. 복호화에 실패하더라도 원본 파일을 수정하거나 지우지는 않지만 혹시 모르니 항상 백업은 하고 사용해주시기 바랍니다. 랜섬웨어의 키를 찾는 방법은 이전 포스트의 마지막에 작성해두었습니다.
그림 1의
아이콘과 위의 메타데이터들을 보면 알 수 있듯, 파일 크기가 클 뿐만 아니라 두 샘플 모두 비슷한 크기의
같은 타입, 거의 동일한 SSDeep 해쉬값을 갖고 있습니다. 패커 혹은 래퍼로 감싸져서 그런 것이라고 의심이 가능합니다.
3. 분석
[그림 3. Tkinter 아이콘
확인]
랜섬웨어가
실행되고 나면 위와 같은 창과 메시지박스가 등장하는데, 메시지박스의 아이콘은 파이썬 내장 GUI 라이브러리인 Tkinter의 기본 아이콘입니다. 이름에서 이미 예상했지만 파이썬으로 작성된 프로그램이라는 것을 알게 되었고,
PE 파일로 래핑되어 있으므로 이를 해제하기 위해 무슨 툴을 사용했는지를 알 필요가 있었습니다.
[그림 4. PyInstaller
문자열 확인]
파이썬을
EXE로 래핑하기 위해 가장 많이 사용하는 툴인 PyInstaller와
Py2Exe를 체크해볼 생각이었는데 찾아보니 바로 PyInstaller로
확인되었습니다.
래핑 해제된 파일을 아무리 찾아도 메인 소스코드로
보이는 파일이 보이지 않아서 찾아보다 보니 scriptedhind라는 파일 내부에 랜섬웨어의 소스코드로
보이는 내용이 작성되어 있는 것을 볼 수 있었습니다. 파이썬 소스코드가 원형을 유지하고 있지는 않았지만
하드코딩된 문자열 등은 그대로 나타나 있었기 때문에 대충 어떤 랜섬웨어인지는 파악이 가능했고, 이것만으로는
정보가 불충분하다고 느껴서 파일명인 scriptedhind로 검색을 해봤습니다.
[그림 7. Ransomware
Builder Github]
검색 결과
scriptedhind라는 문자열을 포함하는 Github 주소가 등장했고,
접속해보니 자동으로 랜섬웨어를 만들어 주는 툴을 배포하고 있었습니다.
[그림 8. 책임 회피용
문구]
작성자는
Github에 교육적인 목적으로만 제작된 것으로, 프로그램의 사용에 의한 책임을 지지 않겠다고
작성해놓았습니다. 하지만 이전에 오픈소스 원격관리도구라며 .Net기반 RAT인 Nanocore를 개발한 개발자가 유죄를 선고받은 사례도 있으므로 이게 합법이라고 판단하긴 힘들어
보입니다.
[그림 9. 해당 Github 유저]
ScRipt1337이라는 닉네임을 사용하는
유저는 이외에도 직접 제작한 것처럼 보이는 여러 악성 프로그램을 ‘교육적인 목적’이라는 명목으로 공개해놓고 있습니다.
[그림 10.
Ransomware Builder]
아까 발견한 Ransomware Builder에 존재하는 두 개의 exe 파일은
둘 모두 랜섬웨어와 같이 PyInstaller로 래핑된 파이썬 기반 프로그램이었습니다. Builder.exe 파일을 실행하고 Github에 작성되어 있는
패스워드를 입력하면 위와 같은 창이 등장하고, 원하는 내용을 채워넣으면 이대로 랜섬웨어가 작성됩니다. 결과물은 Python 스크립트로,
단순히 위 항목들을 포맷팅하여 넣은 것에 지나지 않습니다. 드랍된 스크립트를 분석해보겠습니다.
[그림 11. 권한
체크]
생성된 파이썬 파일은 실행된 직후 Admin 권한을 가졌는지 체크하고, 아니라면 UAC 컨트롤로 관리자 권한 획득을 시도합니다.
[그림 12. AntiVM?]
이후 “WMIC
BIOS GET SERIALNUMBER” 명령을 이용해 하드웨어 정보를 가져옵니다. VMware 에서
생성한 VM 내부에서 사용할 경우 stdout으로 “VMware-56 4d 05 69 52 1c d8 fa-86 9e 1c 72 28 bd f5 46”라는 값이
출력되었는데, 저기에서 받는 result는 stdout을 받는 것이 아니라 프로그램의 종료 시 리턴 값을 받는 것이기 때문에 VM 여부에 관계없이 명령어가 성공한 이상 무조건 0이 반환되었습니다.
[그림 13. 작업
관리자 차단]
그림 12의 disabletask 함수 내부에서는 특정 레지스트리 값을 추가하는 것으로 작업 관리자의 사용을 차단합니다.
[그림 14. 실수?]
실수인지
고의인지는 모르겠지만, 이렇게 반환된 0을 int로 형변환한 후 문자열 “0”과 비교하는 어이없는 일을 수행합니다. 이미 타입 자체가 다르기 때문에 무조건 False가 될 수밖에 없고, main이 실행됩니다. 여기서 strongKey는
위의 Builder.exe에서 입력한 암호화 키 값입니다.
[그림 15. main]
main 함수 내에서는 “C:\” 하위의
파일들을 대상으로 총 145개의 확장자를 검색하여 일치하는 파일에 대해 암호화를 수행합니다. 여기서 문제는 파일이 존재할 때마다 바탕화면에 랜섬노트로 추정되는 파일을 계속해서 덮어쓴다는 것입니다. 이 랜섬웨어는 작동하는 속도가 비정상적으로 느려 전부 암호화가 될 때까지 10분
이상이 소요되는데, 이 작업이 거기에 한몫 하는 것으로 보입니다. (그러면서
자기가 작성한 랜섬노트마저 확장자가 .txt라는 이유로 암호화해버립니다;)
[그림 16. 암호화
루틴]
암호화에는 AES CBC를 사용하며, Initialization Vector는
그때그때 랜덤한 값을 뽑아서 사용합니다. 파일의 암호화 전에 파일의 크기와 IV를 총 32바이트 버퍼에 담아서 파일 앞부분에 저장하고, 이후 특정 크기씩 읽어와 블록 암호화를 진행합니다. 입력한 key는 키 그대로가 아니라 sha256으로 한번 해싱하여 AES의 키로 사용합니다. 암호화된 파일의 확장자는 .impect가 추가로 붙습니다.
[그림 17. 복호화
루틴]
바로 밑에 복호화 루틴도 있었는데, 복호화 완료된 파일명을 제대로 복원시켜주는게 아니고 뒤에서 offset -3까지만
가져오기 때문에 [원본파일명].imp 로 변환될 것으로 예상이
가능합니다.
[그림 18. 실수
2?]
이렇게 암호화가 전부 완료되고 나면 try~except 문으로 진입하는데, try문 내에서 특정 파일을
읽어와서 str형태로 변환한 다음 6을 더하는 행위를 하고
있습니다. Javascript도 아니고 str 타입 변수에
int형 상수를 더하는 것이 허용될 리 없으므로 무조건 except로
빠지게 되고, 결국 현재 시간을 작성하는 용도로밖에 쓰이지 않습니다.
except에서 현재 시간을 포맷팅한 후 offset -6까지를 저장하는 것으로 보아 현재의
‘시간’을 작성하는 것이고,
가져온 시간에 6을 더해서 일치할 경우(있을
수가 없는 일이지만) “C:\Users\유저네임” 이하의
모든 파일을 삭제합니다. 결코 발생할 수 없는 루틴이지만 일정 시간 내에 금전을 지불하지 않을 경우
해당 파일들을 전부 삭제하겠다는 류의 협박성 루틴인 것 같습니다.
[그림 19. 작업
표시줄 숨기기]
위 작업이 끝나고 나면 이유는 모르지만 작업
표시줄을 먼저 숨깁니다. 작업 표시줄과 함께 시작 버튼도 같이 숨기려고 하는 것 같은데, Windows 7에서 테스트 해본 결과 제대로 숨겨지지 않았습니다.
[그림 20. 바탕화면
변경 시도]
Builder.exe에서 입력했던 url을
이용하여 이미지 파일을 다운로드 받고, 그것을 이용하여 바탕화면을 변경하려고 시도합니다. 여기서는 64비트인지 체크하여 맞을 경우 SystemParametersInfoW를 사용하고 아닐 경우 SystemParametersInfoA를
사용하는데, 왜 굳이 저렇게 하는지는 잘 모르겠습니다. 윈도우
API에 익숙하지 않은 제작자라는 생각이 듭니다.
[그림 21. GUI 루틴]
위
작업까지 끝나고 나면 그림 3에서 볼 수 있듯이 Tkinter를
이용하여 GUI로 윈도우 하나를 띄우고, 랜섬웨어 감염 사실을 (욕설과 함께)알리고 키를 입력할 수 있는 Entry 칸을 하나 만들어둡니다. Decrypt 버튼을 누르면 runthefuckup 함수가 실행됩니다. 교육적인 목적으로 공개했다고
했는데 전혀 교육적이지 않아 보입니다.
[그림 22. runthefuckup
함수]
입력받은
키 값이 저장된 키 값과 일치할 경우 C:\ 하위를 돌면서 암호화된 파일에 대해 복호화를 수행하고, 다를 경우 욕설이 씌여 있는 메시지 박스를 띄웁니다.
4. 복호화 방법
pyinstxtractor를
이용하여 PyInstaller를 래핑 해제했을 때 메인 소스코드가 정상적으로 나오면 좋은데, 어째선지 제대로 메인 소스코드가 등장하지 않아서 키를 어떻게 찾아야 하는지 고민했었습니다. 단서는 랜섬웨어의 메인으로 보이는 scriptedhind 파일이었는데, pyc 디컴파일러를 돌려봐도 제대로 디컴파일이 되지 않았습니다. 하지만
알고 보니 pyc파일은 맞는데 시그니쳐 부분만 날아갔던 것이었고, 그래서
시그니쳐를 복원하고 디컴파일을 돌려봤더니 정상적으로 디컴파일이 되었습니다.
디컴파일로 추출한 소스코드 내에서 암호화 키를 확인 가능하고, 랜섬웨어가 띄운 창에 입력하면 정상적으로 복호화가 되지만 프로그램 자체가 무척 불안정해서 응답을 하지 않거나
복호화 하는 데에 시간이 상당히 소요됩니다. 복호화를 해주는 툴은 C++로 직접 짜볼 생각이며, 추후 포스팅하여 링크하겠습니다.
PUBG Ransomware는2018년 4월 10일쯤
발견된 랜섬웨어로, 기존에 장난삼아 제작되고 배포되어 이슈가 되었던 동방프로젝트 랜섬웨어(http://thegear.co.kr/14295)와
비슷한 느낌으로 제작된 랜섬웨어입니다. 장난삼아 만들었다고는 하지만 실제로 파일에 대한 암호화를 진행하기
때문에 자칫하면 실제 피해가 발생할 수 있어 주의가 필요합니다. 무척 간단히 분석이 가능할 거라고 예상이
가능했기 때문에 한번 분석해봤습니다.
이번에도 별다른 아이콘은 없고, 또 .NET 기반의 Win32
PE 파일입니다. 파일 크기는 40.5KB로
상당히 작습니다.
[그림 1. PUBG_Ransomware.exe
Exeinfo PE]
Exeinfo PE를 이용하여 분석해본 결과
패킹은 되어 있지 않은 것 같았습니다. 그럼 원본 바이너리 자체 크기가 40KB밖에 되지 않았다는 것인데 랜섬웨어 치고는 너무 작아서 꽤 놀랐습니다.
[그림 2. PUBG_Ransomware.exe
Bintext 분석]
패킹이 전혀 되어 있지 않기 때문에 내부
문자열을 찾아보면 재미있는 문자열이 무척 많이 보이지만, pdb 정보가 박혀 있길래 이를 가져왔습니다. 경로는 "C:\Users\ryank\source\repos\PUBG_Ransomware\PUBG_Ransomware\obj\Debug\PUBG_Ransomware.pdb”
로 지정되어 있으며 유저 이름이 ‘ryank’
인 것으로 보아 제작자는 ‘Ryan K’ 라는 닉네임을 사용하는 사람인 것으로 추정이 가능합니다.
[그림 3. PUBG_Ransomware.exe
dotpeek 디컴파일]
Jetbrain사의 Dotpeek을
이용하여 분석해본 결과 실행 직후 바탕 화면 아래의 특정 파일들을 암호화하도록 되어있는 것을 볼 수 있습니다. 여기서
함수명이 익숙하지 않아 확인해보니 스페인어인 것을 알 수 있었고, 이 랜섬웨어의 제작자는 스페인 국적의 인물인 것으로 추정해볼 수 있었습니다.
암호화를 진행하는 확장자들은 위와 같았습니다. 암호화가
완료된 파일은 뒤에 ‘.PUBG’ 확장자를 추가로 붙입니다.
[그림 4. 암호화
루틴]
AES 256 CBC 암호 방식을 사용하며 Zeros 방식의 패딩을 사용합니다. 이 패딩 방식은 모든 바이트를
0으로 채워 패딩하는 방식입니다. 인자로 넘어가는 문자열을
확인해 보니 항상 Key가 되는 문자열은 “GBUPRansomware”로
동일했습니다.
[그림 5. 프로세스
체크]
메인 Form이
로드됨과 동시에 시작된 루틴에서는 특정 이름을 가진 프로세스를 가져와서 존재할 경우 playtime을
늘리고, 이것이 3이 되는 순간 복호화 루틴으로 들어갑니다. 해당 프로세스 이름은 “TslGame”으로 게임 배틀그라운드의 프로세스
이름입니다. 타이머의 Interval을 1000으로 설정한 후 3번이므로 3초간만
저 프로세스를 켜두면 자동으로 복호화가 되는 로직입니다. 여기서 맹점이 하나 있는 것이, 프로세스 이름으로 체크하는 것이기 때문에 적당히 아무 프로그램이나 파일명을 TslGame.exe로
바꾼 후 실행시키면 알아서 복호화를 해줍니다.
[그림 6. 리소스
내부 그림]
리소스 내에는 Form의 배경에 지정할 이미지 파일 하나만 들어있었습니다. 이외에
딱히 레지스트리를 건드리는 부분도 없었고, 정적 분석이 더 필요한 부분도 없어서 바로 동적 분석으로
들어갔습니다.
바탕
화면 밑의 파일들만 암호화하기 때문에 바탕 화면에 실행 파일과 암호화될 파일들을 함께 둔 후 동적 분석을 시작했습니다.
[그림 8. 랜섬노트(?) 및
암호화된 파일들]
바탕 화면 아래의 파일들만 암호화하는 단순함
때문인지 실행 직후 바로 파일들이 암호화됩니다. Form에는 배틀그라운드 게임을 1시간동안 플레이하거나, ‘s2acxx56a2sae5fjh5k2gb5s2e’라는
키 값을 주면서 이것으로 복구하라고 씌여 있습니다. 하지만 Restore
Code를 입력하는 Input Box와 Restore 버튼은
Disabled 상태라 키 입력이 불가능합니다.
[그림 9. 복호화된 파일들]
정적
분석으로 알아낸 것처럼, 프로세스 이름을 기반으로 게임이 실행 중인지 여부를 판단하기 때문에 적당히
아무 프로그램이나 이름을 ‘TslGame.exe’로 변경 후 실행시키면 3초 뒤 자동으로 복호화를 완료해줍니다. Hex Editor로 열어
봤을 때 정상적으로 복호화된 것을 확인할 수 있었습니다. 이후 랜섬웨어는 자동으로 종료됩니다.
PUBG
Ransomware는 분류는 랜섬웨어가 되겠지만 금전적인 요구는 전혀 하지 않고 사실상 거의 대가 없이 모든 파일을 복호화 해 주는
등 악의가 느껴지지 않는 프로그램입니다. 이전에 장난삼아 개발되었던 다른 ‘게임 플레이 시간에 따라 복호화를 해 주는 랜섬웨어’들과 비슷한 느낌으로
개발된 것으로 보입니다. 악의가 느껴지지 않는다고는 하나 실제로 유저의 파일들을 암호화하여 피해를 줄
수 있는 것은 사실이기 때문에 수많은 안티바이러스 벤더사에서 악성으로 탐지하고 있습니다.
패킹도
프로텍팅도 전혀 되어 있지 않고 .NET 기반 프로그램인데다 난독화 처리도 되어 있지 않아서 그냥 정적
문자열 패턴 기반으로도 충분히 탐지가 가능하며, 바탕화면의 특정 파일들을 암호화하는 행위 자체도 무척
뚜렷합니다. 하지만 랜섬노트를 따로 드랍하거나 보여주는 행위가 없어 자동 분석은 약간 힘들 수도 있겠습니다. 네트워크 행위도 전혀 하지 않고, 단순히 암호화 및 복호화 행위만
수행합니다.
패킹
및 프로텍팅이 되어 있지 않다는 점을 보면 분석에 익숙하지 않은 분들이나 간단히 분석할 수 있는 .NET 기반
악성코드를 찾아보고 있는 사람들에게는 좋은 샘플일 것 같습니다.
그림 3을 확인해 보면 “mssecsvc2.0”이라는 서비스를 열어서 특정
함수의 인자로 넘기고, ServiceStartTable의 lpServiceProc에
다른 함수를 등록한 뒤 StartServiceCtrlDispatcherA함수를 호출하여 해당 함수를
실행시키는 것을 볼 수 있습니다.
[그림 4. SERVICE_CONFIG_FAILURE_ACTION
설정]
위에서
넘어간 특정 함수는 서비스가 특정 상황일 때 어떤 동작을 할 지를 설정하는 부분입니다. 여기에는 ChangeServiceConfig2라는 API가 사용되는데, 이 API의 세번째 인자는 두번째 인자에 따라 달라지며, 현재 그림 5에서 보이는 2는
서비스가 SERVICE_CONFIG_FAILURE_ACTIONS, 즉 서비스가 실행 도중 실패할 때를
나타냅니다.
[그림 5. SERVICE_FAILURE_ACTIONS
구조체]
세번째
인자인 SERVICE_FAILURE_ACTIONS 구조체의 lpsaActions
멤버를 보면 특정 상황일 때 어떤 Action을 취할 지 설정할 수 있습니다. 그림 4에서 scAction.Type에 1을 지정하는 것은 SC_ACTION_RESTART이므로 서비스를
재시작하는 것이라고 볼 수 있으며, 1000 * delaySec으로 실행 딜레이를 지정하는데 60이 인자로 넘어왔으므로 서비스가 실행 도중 실패할 경우 60초 후
서비스를 재시작하도록 설정하는 것이라고 볼 수 있습니다.
[그림 6. SMB
Exploit Thread]
그림
3에서 StartServiceCtrlDispatcher 함수에
넘기는 구조체에 설정된 disseminateServiceProc 함수 내부를 확인해 보면 위와 같은
부분이 있습니다. 내부에서 랜덤하게 IP Address를
생성하여 SMB Exploit을 시도하기 때문에 위와 같이 함수를 네이밍 해두었습니다.
[그림 7. SMB
Exploit Function]
내부에선 랜덤하게 IP Address를 생성하여 SMB 포트인 445포트로 접속을 시도한 후, 접속에 성공하면 해당 IP의 마지막 1바이트를 1~254까지
바꿔가며 접속 및 Exploit을 시도합니다. SMB 익스플로잇의
경우 EternalBlue 라고 명명된 CVE-2017-0144를
사용하는데 이는 따로 분석하지 않겠습니다. 이 방식으로 수많은 취약한 호스트를 자동으로 공격하고 전파되는
방식을 사용했기 때문에 첫 등장 이후 큰 이슈가 되었습니다.
인자가
존재하지 않을 경우 “mssecsvc2.0” 서비스를 생성하고 실행합니다. 어디서 많이 본 서비스인데요, 위에 인자가 존재할 경우에 실행된
루틴에서 핸들을 가져와 SERVICE_FAILURE_ACTIONS를 정의한 그 서비스입니다. CreateService 함수의 인자인 Binary Path에는
“argv[0] –m security” 형식이 되어 인자가 들어간 상태로 실행되도록 설정되어 있습니다. 이러면 자동으로 새로 생성된 서비스가 직접 스스로에게 SERVICE_FAILURE_ACTIONS를
정의하고 SMB Exploit을 하는 Thread를 만들어서
계속 실행될 것입니다.
[그림
9. 리소스 드랍 및 실행]
서비스
생성을 마친 후 “C:\Windows\tasksche.exe” 파일을 “C:\Windows\qeriuwjhrf” 파일로 옮긴 후, 리소스
영역에서 PE 파일을 가져와 “C:\Windows\tasksche.exe”에
드랍합니다. 이후 CreateProcess를 이용하여 실행합니다. 이 파일은 tasksche.exe 라고 부르겠습니다. 분석해본 결과 실제 파일을 암호화하고 랜섬노트를 드랍하는 랜섬웨어의 행위는 여기서 드랍된 tasksche.exe에서 실행되었습니다.
WannaCry.exe의
리소스 영역에서 그대로 드랍된 파일입니다. 파일 크기가 거의 변화가 없는 것으로 보아 WannaCry.exe의 거의 대부분은 이 파일이 차지하고 있었던 것으로 보입니다. 이 파일을 드랍한 후 WannaCry.exe의 나머지 부분은 서비스를
만들어서 특정 Host에 EternalBlue취약점을 이용하여
SMB Exploit으로 전파되는 행위를 수행했습니다. 이
파일에서는 실제로 랜섬웨어의 행위를 진행합니다.
[그림
10. 자가복제 작업]
tasksche.exe 파일은 실행되고 나면 argv[1]을 검사하여 “/i”와 일치하는지 확인합니다. Anti-Sandbox 기법인지는 모르겠으나 이 값이 없을 경우 아무것도 하지 않고 종료됩니다.
[그림
11. 랜덤 문자열 생성 루틴]
SetRandomString_by_PCName이라고
이름 붙인 함수 내부에서는 PC 이름에 따라 8~15글자의
소문자 알파벳 + 3글자의 대문자 알파벳으로 이루어진 문자열을 생성하여 파라미터로 전달받은 포인터에
저장합니다. 이 값은 특정 루틴 내에서 PC 이름을 이용해
seed를 생성하고, 이를 이용해 srand한 후 생성한 문자열이므로 PC 이름이 같을 경우 다른 환경에서도
똑 같은 값을 뽑아낼 것입니다. 이후 그림 10의 루틴을
계속 타면서 “C:\Windows\ProgramData\<RANDOM>”,
“C:\Windows\Intel\<RANDOM>”, “C:\Windows\<RANDOM>”,
“%TEMP%..\<RANDOM>” 경로에 순차적으로 시도해가면서 디렉토리를 생성하고 CurrentDirecotry를
설정합니다. 그 다음 CopyFile API를 이용해 자가복제하고
복제한 파일을 서비스 또는 프로세스를 이용하여 새 프로세스로 생성하고, 다시 원래 디렉토리로 돌아옵니다. 그리고 현재 실행되고 있는 디렉토리를 “HKEY_CURRENT_USER\Software\WannaCrypt0r”,
“HKEY_LOCAL_MACHINE\Software\WannaCrypt0r”에 등록합니다.
[그림
12. 리소스 unzip]
unzipResource라고 이름붙인 함수 내에서는 리소스 파일을 하나
가져와서 unzip을 수행합니다. 인자로 넘어간 s_WNcry_2o17의 값은 “WNcry@2ol7”로, 압축파일의 비밀번호에 해당했습니다. 해당 리소스를 덤프하여 확인해
보면 확실히 zip 압축 파일이었고, 압축을 해제하면 여러
파일들이 드랍됩니다.
[그림
13. 리소스 내부 파일들]
[그림
14. msg 내부]
msg 폴더 내부에는 PC 언어
환경에 따라 다른 메시지를 보여줄 수 있도록 다양한 언어로 랜섬노트가 작성되어 있습니다.
[그림
15. b.wnry]
b.wnry 파일은 BMP 포맷
이미지 파일로, 파일 암호화가 완료된 뒤 이것으로 바탕 화면을 변경할 것으로 보입니다.
[그림
16. c.wnry]
c.wnry 파일은 Tor브라우저
관련 설정이 들어 있는 파일로, 도메인과 토르 브라우저를 다운받을 수 있는 URL이 적혀 있었습니다.
[그림
17. r.wnry]
r.wnry 파일은 랜섬노트 텍스트 파일이었습니다.
[그림
18. s.wnry]
s.wnry 파일은 zip 포맷
압축 파일로, 내부에는 토르 브라우저 관련 파일들이 들어 있었습니다.
[그림 19. 랜섬 행위 시작]
현재 디렉토리를 숨김 설정하고 모든 사용자에게 폴더 접근 권한 준 후 t.wnry 파일을 읽고 랜섬 행위를 시작합니다. t.wnry 파일은
리소스에도 존재하지 않았고 어디서 드랍되는지 찾을 수가 없어 분석이 불가능했습니다. 핵심 부분은 그림
19의 p_CustomFuncPointer에 접근해야 알
수 있는데, 이는 t.wnry 파일에서 가져온 버퍼이기 때문에
내용을 알 수 없었으며 분석하는 도중 깨달은 것이지만 정상적으로 실행되지도 않기 때문에 동적으로 분석하는 것도 불가능했습니다. 마지막으로 문자열 내부를 확인하여 랜섬행위를 진행하는 확장자명을 뽑아 보았는데, 이는 다음과 같습니다.
API Monitor를 이용하여 동작을 확인해 보니 정적 분석에서 확인한
것처럼 “mssecsvc2.0”으로 서비스를 만들고,
“C:\Windows\tasksche.exe”에 리소스 드랍 후 CreateProcess로
실행시키지만 드랍한 파일이 정상이 아닌지 제대로 시작되지 않는 것을 볼 수 있습니다. 이 문제로 실제
암호화 행위를 진행하는 부분은 분석이 불가능한 상태에 있습니다.
[그림
21. WannaCry.exe 동적 분석 - 2]
서비스로 등록되어 실행된 루틴을 보니 수많은 쓰레드들이 계속해서 생성되면서
무언가 작업을 진행하고 있었습니다.
[그림
22. 등록된 mssecsvc2.0 서비스]
mssecsvc2.0 이름으로 등록하는 루틴이 존재했던 것과 같이 서비스가
등록되어 실행되고 있었습니다.
[그림
23. WannaCry.exe 네트워크 분석]
네트워크로는 수많은 호스트의 445포트로
연결을 시도하고, SMB 익스플로잇을 시도하는 내용이 보입니다. 드랍했던
파일인 tasksche.exe도 동적으로 분석하고 싶었지만 위에 언급한 대로 정상적인 실행이 되지 않았기
때문에 분석이 불가능했습니다.
WannaCry.exe는 2017년
5월경 등장하여 SMB 취약점을 이용한 강력한 자가 전파
능력으로 전 세계에 큰 충격을 안겨줬던 랜섬웨어입니다. 처음에 연결을 시도한 도메인은 킬
스위치였던 모양입니다. 어떤 방식으로 접속에 성공할 경우 전파되지 않는지는 잘 모르겠지만, 기사는 이렇게 나와 있습니다. ( http://www.itworld.co.kr/news/104756
)
분석을 시작하기 전까진 몰랐지만 패킹이나 프로텍팅이 전혀 되어 있지 않은
깔끔한 바이너리였고, 따라서 정적으로 분석하는 데에 큰 무리는 없었습니다. 그냥 문자열 패턴만으로도 내부에 “*.wnry”와 여러 확장자명들, 킬 스위치로 사용된 도메인 등이 들어 있기 때문에 정적으로도 무리 없이 탐지가 가능할 것으로 보입니다. tasksche.exe 내부 리소스로 zip파일에 암호를 걸어서
넣어둔 것은 데이터를 자동 분석으로 뽑아내기는 어렵게 만들었지만 zip 파일 구조 특성상 파일, 디렉토리명 등은 전혀 암호화가 되지 않기 때문에 정적으로 탐지하는 데에 전혀 지장을 주지 않았습니다. 또한 동적 분석으로도 특정 이름의 서비스를 등록하거나, 파일을 드랍하거나, 특정 포트로의 수많은 접근을 시도하는 등 뚜렷한 행위가 나타났기 때문에 탐지에 큰 어려움이 없을 것으로 보입니다. 탐지 가능한 지표에는 대표적으로 “C:\Windows\tasksche.exe” 파일을 생성하고, “mssecsvc2.0” 서비스를 등록하거나, “*.wnry” 확장자의 파일을
읽고 쓰는 행위 등이 있겠습니다.
요약하면, 이 샘플은 취약점을
Exploit하여 네트워크를 통해 자동으로 전파되는 기능을 가진 랜섬웨어입니다. 정상 파일로 위장하기 위해 “mssecsvc2.0”이라는 이름의 서비스를 생성하고 실패시 자동으로 다시 시작하는 루틴을 만들고, 여러 프로세스와 파일을 넘나들며 실행되는 것을 보면 상당히 정교하게 만들어져 있습니다. 하지만 그럼에도 패킹이나 프로텍팅이 전혀 되어있지 않아 정적 분석에 어려움이 별로 없었다는 점이 특징이며, 리소스에서 드랍된 tasksche.exe는 실제 VirusTotal등에서 수많은 벤더가 악성으로 진단하고 있는 상황임에도 정상 동작하지 않았습니다. 정적 시그니쳐는 물론이고 패턴, 문자열 등으로 충분히 악성 판단이
가능하고, 동적으로도 서비스 등록 및 네트워크를 통한 Exploit 등
특징이 두드러지기 때문에 쉽게 악성 판단이 가능한 샘플인 것으로 보입니다.
IDA를 이용하여 정적 분석을 하다 보면 악성코드가 직접 만든 custom struct들을 자주 만나게 됩니다. 특히 이번에 분석했던
WannaCry의 경우는 그게 더 심했는데요, 1000바이트가
넘어가는 크기의 struct를 선언하고 사용하는 경우가 있어 이를 직접 만들긴 힘들어 보여 idapython을 사용하였습니다. idapython은 IDA와 연동하여 사용할 수 있는 일종의 Python 라이브러리인데, IDA를 켰을 때 아래에 있는 커맨드라인 입력 창에서 인터프리트 형식으로 사용이 가능합니다. 예를 들어, 크기가 상당히 큰 Struct이고
멤버 변수를 모두 4바이트 DWORD로 선언하고 싶은 경우
다음과 같이 사용이 가능합니다.
[그림
24. idapython 사용]
IDA 에서 Python 스크립트를
이용하는 것은 2~3년쯤 전 BoB를 하면서 배웠었지만 지금까지
실감하지 못하고 있었는데 상당히 강력한 도구인 만큼 잘 활용하면 분석에 큰 도움이 될 것으로 보입니다.
게임 핵으로 위장한 악성코드를 분석해보자는
생각이 들어서 초록 검색창에 ‘배틀그라운드 핵 다운’ 이라고
검색하여 딱 봐도 수상해 보이는 블로그 포스트에서 수상해 보이는 압축 파일을 다운받았습니다. 비밀번호까지
걸려있는 걸로 봐선 악성코드임이 거의 확실해 보여서 분석에 들어갔습니다.
[그림 2. 압축파일
내부]
내부에는 EXE로
보이는 파일 하나 뿐이고, 압축파일의 비밀번호는 블로그에 적힌 대로 ‘PUBGH‘
였습니다. 하나밖에 없으니 대상을 고를 것도 없이 바로 분석에 들어갑니다.
Exeinfo PE라는 툴을 이용하여 분석
대상을 조사해본 결과 Safeengine
Shielden 2.3.9.0버전으로 패킹되어 있는 것을 확인할 수 있었습니다. 실제 IDA로 열어 보면 라이브러리나 함수 섹션보다 파싱하지 못한
데이터 영역이 매우 크고, EntryPoint 지점의 함수가 xor 연산으로
끝나는 것을 확인할 수 있습니다. 내부에서 언패킹 후 실제 PE파일을
실행시키는 부분이 있는 것으로 예측이 가능합니다. 패킹된 상태로 정적 분석은 불가능에 가까우므로 PE Tools를 이용하여 언패킹된 바이너리를 덤프합니다.
[그림 4. PUBG H.exe
PE Tools Dump]
PE Tools를 실행한 후 대상 파일을
실행시키고, 생성된 프로세스를 그대로 풀 덤핑합니다. 악성코드가
실제로 실행되는 것이므로 VM 내에서 진행하며 미리 스냅샷을 찍어 덤프 전 상태로 돌아갈 수 있도록
합니다. 여기서 덤프된 파일을 Dumped_PUBG_H.exe라고 부르겠습니다.
언패킹 전인 PUBG H.exe 파일보다 크기가 좀 더 커졌고, 파일 타입이 .NET 으로 바뀐 것을 볼 수 있습니다. .NET 실행 파일의 경우
Reflector나 Jetbrain사의 dotpeek을 이용하여 쉽게 디컴파일이 가능하므로 dotpeek으로
시도해 보았습니다.
[그림 5.
Dumped_PUBG_H.exe dotpeek 디컴파일]
무려 프로젝트명부터 ‘NanoCore Client’로 네이밍되어 있는 것을
확인할 수 있습니다. NanoCore는 해외에서 개발된 오픈소스 악성 프로그램으로, NanoCore의 개발자는 이것을 합법적이라고 주장했지만 결국 2017년
7월에 유죄를 선고받았습니다. (기사: https://www.thedailybeast.com/nanocore-coder-pleads-guilty-to-aiding-and-abetting-hackers)
NanoCore는 RAT(Remote Access Trojan)으로, 감염된 PC를 외부에서 원격조작하여 중요 정보를 탈취하거나, 추가로 악성 프로그램, 스크립트를 내려 받아 실행하게 하거나, DDoS 공격을 수행하도록 할 수도 있습니다.
소스코드 내부에 드래그하여 표시해둔 부분을
보면 변수명이 무려 ‘#=qzDzg9a$HVGG1G5cdhqbdwO3OG_SFijGXN8Towa37$TQ=’ (으악)인 것을 볼 수 있습니다. 이 변수 뿐만 아니라 거의 모든 변수와
함수, 클래스명이 위와 같은 형태로 난독화되어 있기 때문에 코드 분석이 무척이나 까다롭습니다. 정적으로 계속 분석하기 위해서는 난독화를 해제할 필요성이 있고, 이를
해결하기 위해 de4dot이라고
하는 프로그램을 사용했습니다. (Github: https://github.com/0xd4d/de4dot)
[그림 6. Deobfuscate
Dumped_PUBG_H.exe]
de4dot의 난독화 해제 기능을 이용해
본 결과 Eazfuscator.Net
3.3버전을 사용하여 난독화된 것을 확인할 수 있었습니다. 난독화 해제된 파일을 Deobfuscated_PUBG_H.exe라고 부르겠습니다.
[그림 7. Obfuscated
vs Deobfuscated]
왼쪽이 난독화가 적용된 상태의 샘플, 오른쪽은 난독화가 해제된 상태의 샘플입니다. 확실히 읽고 분석하기
편해진 것을 볼 수 있습니다. 이제 난독화 해제된 파일을 분석할 차례입니다.
.NET 디컴파일 툴은 reflector와 dotpeek 두 개가 대표적이고, 둘 모두 VS Project로 디컴파일한 소스를 export할 수 있는 기능을 갖추고 있습니다. dotpeek을 이용하여 VS Project로 내보내어 Visual Studio를 이용해 IDA의 Hex-rays 기능을 이용하듯이 하나하나 이름을 변경해가며
분석하면 그냥 소스만 보고 분석하는 것보다 훨씬 이해하기 쉽게 분석이 가능합니다.
[그림 8. Main
Function]
Main
함수를 찾아보면 바로 아래 ClientLoaderForm_Shown 함수 내에서 Class8의 정적 멤버 함수인 RunMalware를 실행하는 모습이
보입니다. 원래는 Class8.smethod_8() 이지만
보기 쉽도록 직접 코드를 분석하면서 함수 네이밍을 어느 정도 다시 해 뒀습니다. 그 위에서는 실행된
것이 보이지 않도록 Visible을 False로 설정하는
부분도 있으며, Form이 닫힐 경우 자동적으로 악성 행위에 사용한 각종 설정 값들을 저장하는 부분도
존재합니다.
[그림 9. RunMalware
Function]
앞서
언급했다시피 함수 네이밍을 어느 정도 해둔 상태이기 때문에 이제 함수 명만 보고도 어느정도는 행위를 파악하는게 가능합니다. 코드를 피킹해 둔 부분을 보면 Exception이 발생했을 때 이를
전부 로깅하는 코드가 존재함을 알 수 있습니다. 코드를 분석하면서 알게 된 점은 이 프로그램은 악성코드이지만
익셉션 핸들링이나 로깅 등이 매우 충실히 잘 이루어지고 있는 상당히 수준 높은 구조를 가지고 있다는 것입니다.
[그림 10. Decrypt Resource]
코드
길이가 상당히 방대하고 이를 하나하나 다 짚으면서 보고서를 쓰면 끝이 없기 때문에 가장 중요한 부분만 작성하기로 했습니다. 이 파일은 리소스 영역에 딱 하나의 리소스를 가지고 있는데, 이
리소스는 암호화되어 있기 때문에 복호화를 해야 읽을 수 있고 사용 가능한 데이터가 나타납니다.
[그림 11. Save
Resource to Dict]
복호화
루틴을 지나면서 복호화가 완료된 데이터는 함수 내에서 클래스 멤버 변수인 dictionary_1에 뽑아낸
키와 값으로 각각 저장됩니다. 내부에 저장된 데이터는 Key와
Value값을 가진 Json Object 형태의 데이터일
것이라고 예상이 가능합니다.
[그림 12. GetValueWithKey
Function]
dictionary_1에서 Key를 이용해 Value를 받아오는 함수가 존재하여 GetValueWithKey라고 이름 붙이고 사용되는 부분을 모두 찾아보았더니
Key값들의 이름이 Timeout이나 Delay,
Server 주소 등 Configuration과 관련된 내용들인 것을 확인할 수 있었습니다. 이 리소스를 복호화하는 것이 가능하다면 이 악성코드가 어떻게 동작할지 예측하는 것이 가능할 것입니다.
[그림 13. 리소스
첫 부분 복호화]
복호화
루틴을 살펴보면 리소스 영역을 한번에 전부 복호화하는 것이 아니라 첫 4바이트를 읽고, 그 값만큼을 다시 읽어와서 특정 키를 이용하여 먼저 복호화한 후 그 값을 나머지 리소스 영역 복호화를 위한 Initialization Vector와 Key값으로 사용하는 것을
알 수 있습니다. DES 암호화를 사용하며, IV를 사용하는
것에서도 알 수 있듯이 64비트 크기의 블록 암호입니다.
[그림 14. 리소스
첫 부분 복호화 키 루틴]
리소스
복호화 루틴의 경우 모두 코드 형태로 존재하였기에 새로 C# 프로젝트를 생성하고 코드를 그대로 가져다가
완성하였지만, C#에 대한 이해가 부족하여 그림 13, 및
그림 14에서 Class8.DecryptBuffer 함수의
두 번째 인자로 들어가는 Guid 값의 경우 똑같이 작성해도 복호화 도중 익셉션이 발생하는 문제가 있었습니다.
[그림 15.
CustomAttribute Guid]
GetCustomAttributes의 어감에서도 추측할 수 있듯이 코드
내부 어딘가에 Guid값이 Set 되어 있을 것이라고 보고
파일들을 뒤져가며 찾아보니 지정된 Guid 문자열을 발견할 수 있었습니다.
[그림 16. Set
Decrypt Key]
발견한
값으로 Guid를 만들어서 같은 복호화 루틴에 Key로 설정해
둔 코드입니다. 이후 복호화 루틴을 돌려서 나온 결과를 Dictionary
자료형에 담게 되는데, 이 변수를 Json으로
덤프하면 다음과 같은 결과를 볼 수 있습니다. (복호화에 사용한 .NET
소스코드는 블로그 포스트에 첨부하였습니다)
{
"BuildTime":
"2018-02-08T03:06:08.3425287Z",
"Version": {
"Major": 1,
"Minor": 2,
"Build": 2,
"Revision": 0,
"MajorRevision": 0,
"MinorRevision": 0
},
"Mutex":
"19d9428a-7d48-4c41-b850-2e92448ad594",
"DefaultGroup":
"Default",
"PrimaryConnectionHost":
"TestZb.Ze.Am",
"BackupConnectionHost":
"TestZb.Ze.Am",
"ConnectionPort": 54984,
"RunOnStartup": true,
"RequestElevation": false,
"BypassUserAccountControl": false,
"ClearZoneIdentifier": true,
"ClearAccessControl": false,
"SetCriticalProcess": false,
"PreventSystemSleep": true,
"ActivateAwayMode": false,
"EnableDebugMode": false,
"RunDelay": 0,
"ConnectDelay": 4000,
"RestartDelay": 5000,
"TimeoutInterval": 5000,
"KeepAliveTimeout": 30000,
"MutexTimeout": 5000,
"LanTimeout": 2500,
"WanTimeout": 8000,
"BufferSize": 65535,
"MaxPacketSize": 10485760,
"GCThreshold": 10485760,
"UseCustomDnsServer": true,
"PrimaryDnsServer":
"8.8.8.8",
"BackupDnsServer":
"8.8.4.4"
}
중요하다고 생각되는 데이터에는 볼드 + 붉은
색 처리를 하였습니다. 접속을 시도하는 서버 도메인과 그 포트, 자동
실행 프로그램으로 등록 여부, UAC 우회 여부 등 여러 옵션을 선택할 수 있는 것을 알 수 있습니다. 아무래도 TestZb.Ze.Am:54984로 접속 시도를 할 것으로 보입니다.
[그림 17. 도메인
VirusTotal 조회 결과]
접속하는
서버의 메인 도메인에 대한 정보를 알아보기 위해 VirusTotal에 조회 및 직접 접속해 보니 2018년 2월 7일까지
URL Shortener 서비스를 운영한 한국인의 도메인인 것으로 추정되었습니다. 서브 도메인을 확인해 보니 다음과 같았습니다.
spr17.ze.am
youcy111.ze.am
www.hasangwook.ze.am
spr1.ze.am
www.xn----qz5e7tr56dq9g2qdzxr3ue56g.ze.am
www.xn----rz5e7t44s3tj2ik5nc1ummty2pj.ze.am
spr18.ze.am
unlocker.ze.am
video.ze.am
shyyset.ze.am
xn--o39az1zdmbpa021j2ufp8f.ze.am
excel.ze.am
ekfak15.ze.am
spr39.ze.am
deim.ze.am
sgddos.ze.am
www.xn----c28e37pwzi89ex7av7h7zzdtdxyc.ze.am
www.play21.ze.am
coca-cola.ze.am
cuzz.ze.am
fileup.ze.am
lillllili.ze.am
compcomp.ze.am
njj.ze.am
minoo.ze.am
mj.ze.am
zombie24.ze.am
hdream.ze.am
deabakgam.ze.am
daumpotlncoder.ze.am
agwgsdgd.ze.am
spectre.ze.am
lmj.ze.am
val.ze.am
naverddos.ze.am
ktv.ze.am
www.agwgsdgd.ze.am
hwalang0929.ze.am
kisa5323.ze.am
spynote.ze.am
ddosattack.ze.am
teeluk.ze.am
sel.ze.am
ysc3514.ze.am
xink.ze.am
bggonline.ze.am
djtmdgh5517.ze.am
adminwww.ze.am
web.dkfate.ze.am
batmanblog.ze.am
nutri999.ze.am
enal153.ze.am
ssul5.ze.am
4shared.ze.am
www.dbns.ze.am
spr99.ze.am
spr.25.ze.am
qer.ze.am
gooddoctor.ze.am
mingkey.ze.am
nutrino20.ze.am
xn--299ayym43bd2d8zctu1ay7f.ze.am
dbns.ze.am
dinte.ze.am
spr68.ze.am
zb.ze.am
dkssudak11.ze.am
www.iam.ze.am
swoo.ze.am
pora.ze.am
soulms.ze.am
netbot.ze.am
godofwarv502.ze.am
xn--lg3bujr1jg5w.ze.am
djchoice.ze.am
bfz.ze.am
nutrino19.ze.am
spr40.ze.am
ipzero123.ze.am
dltjwns.ze.am
VirusTotal에 등록된 서브 도메인만 총 99개이며, 개중에는 ddos,
naverddos, netbot, zombie24 등 노골적으로 악성임을 드러내는 이름이 다수 존재했습니다. 도메인 서비스의 계정을 탈취당해 해커에 의해 서브 도메인이 다수 만들어지고,
해커의 서버 혹은 탈취된 다른 서버로 연결된 것으로 보입니다.
[그림 18. 서버에서
받은 데이터 처리]
서버에
연결하여 받아온 데이터는 그림 18의 함수에 인자로 넘어가며, 리소스를
복호화 할 때 사용한 함수와 같은 함수를 사용하여 데이터를 복호화하고 파싱합니다.
[그림 19. 파싱된
데이터 값 처리]
파싱된
데이터는 여러 개의 switch 문을 거치면서 값에 따라 다른 명령을 처리하는데, 대표적인 타입이 그림 19에 나타난 FileCommand 입니다. 네 번째 인자는 타입 내의 구체적인 명령
Offset, 다섯 번째 인자는 해당 명령에 대한 인자로 보입니다.
[그림 20. Command
Type]
그림
20에 나타나 있듯이 이 악성코드에는 현재 BaseCommand, FileCommand,
PluginCommand의 세 가지 타입이 존재하며 서버에서 받아온 값에 따라 저 중에서 명령을 선택적으로 수행합니다. PluginCommand라는 타입에서 유추할 수 있듯이 이 악성코드는 플러그인을 이용해 선택적으로 특정 명령을
추가 및 제거할 수 있습니다. 서버에 연결하여 명령어를 받아와 실행하는 것을 보면 RAT(Remote
Access Trojan)이며 상당히 고도화되어 있음을 알 수 있습니다.
일반적으로
패킹이나 난독화는 동적 분석의 결과에 영향을 미치지 않으므로 처음 다운받은 샘플 그대로 VM 내의 Cuckoo 자동분석시스템에 넣고 돌려봤습니다.
[그림 21. 실행
후 스크린샷]
정적분석에서
예상했던 대로 Visible 값이 False가 되어있기 때문에
스크린샷에는 아무런 창도 나타나지 않았습니다.
[그림 22. 네트워크
분석]
눈에
띄는 DNS 주소는 리소스 복호화를 통해 알아낸 TestZb.Ze.Am
입니다. DNS 조회를 통해 1.241.72.196이라는
IP 주소를 알아냈습니다. 하지만 TCP 연결 목록에는 눈에 띄지 않았고, Cuckoo 특성상 접속 실패의
경우 TCP 탭에 표시하지 않으므로 접속 시도는 했으나 성공하지 못한 것으로 예상할 수 있습니다.
[그림 23. 네트워크 pcap 분석]
pcap 파일을 직접 다운로드 받아서 분석해 본 결과 해당 IP와 리소스 내에서 찾아낸 54984 포트로 접속을 시도하기 위해
SYN 패킷을 계속 발신하지만 응답은 RST/SYN으로 해당
포트는 닫혀 있는 것을 확인할 수 있습니다. 현재는 악성코드 서버가 동작하지 않고 있다는 의미입니다.
[그림 24. GeoIP 결과]
GeoIP를 이용하여 IP 주소를
가진 서버의 위치를 확인해 보니 국내에 위치한 서버였습니다. Whois 조회에서는 SK Broadband에 할당되었다고 합니다.
[그림 25. 드랍한
버퍼]
버퍼
내에서 드랍한 세 파일 중 두 파일은 VirusTotal에서 결과가 존재했으며 둘 모두 NanoCore Client에서 사용되는 .NET 기반 DLL 파일인 것으로 확인되었습니다.
‘PUBG
H.exe’ 파일은 대한민국 최대 포털 사이트의 블로그를 통해 유포되고 있었으며, 공격에
사용된 해커의 서버 또한 접속되지는 않았지만 국내에 위치한 서버였습니다. 유포할 때 포스트 제목을 유명
게임인 배틀그라운드 핵을 공유하는 것처럼 위장한 것으로 보아 국내 게이머들을 타겟팅 한 것으로 보입니다. 언패킹된
샘플이 .NET 기반이며 NanoCore Client 라는
네이밍이 되어 있고, 실제 NanoCore가 사용하는 DLL과 플러그인을 사용하며 특정 서버로의 접속을 시도하고 받아온 값에 따라 정의된 명령을 수행하는 것으로 보아
오픈소스인 NanoCore의 소스를 이용하여 제작한 RAT(Remote Access Trojan)로 분류할 수 있습니다.
이
샘플은 컴파일 이후 난독화와 패킹 과정을 거치면서 본래 .NET 기반 실행 파일이었던 사실까지 알아채기
힘들게 변형된 후 배포되고 있었습니다. 따라서 언패킹을 하지 않는 이상 정적으로는 시그니쳐 방식을 제외하고는
탐지하기 어려울 것으로 보입니다. 또한 네트워크 상에서도 암호화된 리소스 영역을 복호화한 후 그 내부에
미리 설정된 값들을 로드하여 접속할 서버, 포트 등을 정해 악성 행위를 수행하기 때문에 접속하는 서버와
포트는 샘플마다 쉽게 변경될 수 있고, 패킷 송/수신에도
암호화를 사용하여 탐지하기 상당히 어렵습니다. 남은 것은 동적 행위 분석 뿐인데, 다행인 것은 C&C 서버와의 통신이나 따로 악성 행위를 하지
않아도 '%APPDATA%\<Guid>\run.dat’
파일을 생성하고, 이 파일의 크기는 항상 8바이트라는
점입니다. run.dat 파일은 준비 과정에서 존재하지 않을 경우 생성하여 현재 Datetime을 구하고 이를 저장하도록 되어 있습니다. 그 외에도
행위가 수행되면 catalog.dat, storage.dat, task.dat, settings.bin중 일부 파일들이 위 경로에 드랍되며 이를 탐지 지표로 사용할 수 있겠습니다. 또한 실행 후 메모리 상에서 언팩이 완료된 후에는 NanoCore나 NanoCore.ClientPlugin등의
문자열이 드러나기도 합니다.
요약하면, 이 샘플은 .NET 기반 오픈소스인 NanoCore를 이용하여 제작한 RAT이고 유명 게임 배틀그라운드의
핵으로 위장하여 국내 게이머들을 타겟팅하였으며 난독화와 패킹을 통해 휴리스틱, 패턴 기반 탐지를 우회하고자
하였습니다. 따라서 동적 분석으로 드랍되는 파일과 메모리에서 발견되는 문자열 등을 통해 악성 여부를
판단할 수 있겠습니다.
아래 첨부파일은 악성코드 내부의 리소스를 복호화하는 데에 사용했던 C# 프로젝트 소스코드입니다.