그냥 전에 올렸던 PyV8을 이용한 스크립트 분석기를 계속 개발하다 보니 여러 모로 개선해야 할 점이 많아서 좀 끄적거려본다.
특정 상황에만 행위를 하거나 True/False를 체크하여 행위를 한다거나 하는 악성코드도 있어서 이런걸 커스터마이징할 수 있도록 해 볼 예정... 또 자바스크립트 내에 주석 등을 통해 Dummy Code를 넣는다거나 하는 경우도 있는데 이런것도 정규식을 이용하던지 해서 좀 제거해봐야 할 듯 하다...
여기에 작성된 글을 보고 이것을 이용하면 난독화된 악성 스크립트를 안전하고 효율적으로 분석이 가능하겠다는 생각이 들어서 비슷한 방식으로 만들어보기로 마음먹었다.
[PyV8은 여기에서 다운받을 수 있다. 마지막 업로드가 2012년인 것이 조금 걸리지만...]
PyV8은 구글에서 만든 자바스크립트 엔진인 V8의 파이썬 래퍼로, 자바스크립트 코드를 해석하고 실행하여 그 결과를 파이썬에서 받아볼 수 있다. 하지만 PyV8은 자바스크립트 문법을 해석해 줄 뿐 운영체제의 API에 연결되어 있지 않기 때문에, 악성 스크립트에서 자주 사용하는 WScript.Shell 등을 사용하면 정의되지 않았다면서 에러가 발생한다. 그래서 직접 더미 API를 만들어서 넘겨주어야 하는 필요성이 있고, 위에서 언급했던 블로그에서는 각 모듈과 함수들을 직접 정의하여 넘겨주는 방식으로 제작했었다. 그런데 그렇게 만들게 되면 모든 모듈과 함수에 대응하는 클래스 및 메서드를 직접 다 만들어서 전달해야 한다는 불편함이 있었고, 결국 내가 원하는 것은 '어떤 함수가 어떤 인자를 받아서 실행되었는가' 이기 때문에 전부 간단하게 추상화시킬 수 있다고 판단하여 결국 간단하게 추상화 하는 것에 성공하였다. 자세한 내용은 소스코드를 보면서 작성하겠다.
추상화에 성공하여 무척 간결해져 버린 Global 클래스의 소스코드이다. 원래라면 클래스 멤버 변수로 각 모듈들에 대응하는 클래스의 인스턴스를 가지고 있어야 하지만, 어떤 모듈을 호출할 지 모르므로 __getattr__ 메서드를 정의하는 것으로 한번에 해결해 버렸다. __getattr__ 메서드는 classA.not_exist_value 처럼 클래스 내부에 존재하지 않는 변수, 혹은 메서드에 접근했을 경우 호출되는 함수이다. 현재 Global 클래스 내부에 저 함수 외에는 아무것도 정의되지 않았으므로 Javascript 내에서 어떤 모듈 혹은 Global 함수를 호출하던 간에 AbstractType(name) 을 리턴받게 될 것이다. AbstractType은 직접 작성한 타입으로, 다음 소스코드에서 확인이 가능하다.
이번에 추상화에서 얻어낸 가장 큰 산물인 AbstractType 클래스이다. 생성자에서 호출한 이름을 인자로 받으며(Global.py 참고), __call__ 메서드를 정의하여 인스턴스가 함수로써 사용될 경우 *args, **kwargs 등 가변 길이 변수를 받아서 print로 이름과 함께 로깅하도록 하였다. 또한 Global.py에서처럼 __getattr__ 메서드를 정의하여 모듈 내의 함수에 접근하는 것과 같은 행위를 할 경우 현재 이름에 새 이름을 붙여 AbstractType 클래스를 새로 생성해 리턴하는 것으로 함수의 경우 위에서 정의한 __call__ 에 의해 자동으로 로깅이 되도록 하였다.
이를 이용하면 따로 모듈과 함수를 직접 구현해주지 않고도 호출하는 문자열을 이용해 그때그때 상황에 맞는 AbstractType을 생성하여 로깅하는 것이 가능해지며, 악성 스크립트 분석에 큰 도움이 될 수 있다.
[실제 악성 스크립트 분석 결과]
실제로 스크립트 분석 결과 구체적인 모듈이나 함수 정의는 전혀 하지 않았음에도 모듈 및 함수, 그 인자까지 전부 로깅되는 것을 볼 수 있다. 한 언어에 대한 이해가 깊어지면 이렇게 효율적이고 추상적인 코드 작성이 가능해진다는 것을 제대로 느낄 수 있는 프로젝트였다. 현재는 print로밖에 로깅을 진행하지 않지만 이후 파일이나 리턴 값으로 받을 수 있게 하면 자동 분석에도 응용이 가능할 것으로 보인다. 좀 더 고도화를 진행해 볼 예정이다.
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 기반
악성코드를 찾아보고 있는 사람들에게는 좋은 샘플일 것 같습니다.
쉑터 아포칼립스... 서스테이너가 달려 있는 상당히 고급진 모델입니다. 분명 몇달 전에 여기에 포스팅한 것과 같이 펜더 머스탱을 사서 기뻐하면서 열심히 치고 다녔는데, 아무 생각 없이 뮬 중고장터에서 돌아다니다가 이 모델을 반값 수준으로 팔고 있는 것을 보고 지름신이 강림하셔서 즉시 문자넣고 약속잡아서 사버렸습니다.
[집에 모셔둔 펜더 머스탱과 투샷]
이렇게 놓고 보니까 확실히 24프렛 슈퍼스트랫이라 그런지 스케일이 훨씬 기네요. 핑거보드는 에보니 지판입니다.
[바디 부분 확대샷]
사진에선 찍히지 않았지만 보통은 지판 정면에 그대로 박히는 프렛 마커가 이 기타에서는 왼쪽 측면, 즉 연주시 보이는 부분에 박혀 있습니다. 인레이에는 정삼각형 모양으로 15, 24프렛에 박혀있네요. 이 기타의 가장 큰 특징인 서스테이너는 건전지로 작동하는 액티브 픽업인데, 직접 써보니까 그냥 소리가 끊기지가 않습니다; 계속 쭉 뻗어서 소름이 돋더라구요. 머스탱은 스케일도 짧고 서스테인도 상당히 짧은 편이라 불만이 좀 있었는데 험버커 픽업 + 서스테이너까지 하니까 만족감이 확 차올랐습니다.
노브는 볼륨 + 볼륨 + 톤으로 이루어져 있습니다. 3단계 픽업 스위치가 위쪽에, 아래에는 서스테이너 On/Off를 설정하는 2단계 토글 스위치와 세 가지 서스테이너의 모드를 설정하는 3단계 토글 스위치가 있습니다. 픽업은 역시 험버커로, Schecter USA Apocalypse-VI 라고 합니다. 잘은 모르겠지만 앰프 연결해놓고 쳐봤을때 험버커라 그런지 엄청 강력한 소리를 내주긴 하더군요.
[헤드 확대샷]
헤드부분은 쉑터에서 흔히 보이는 모양이고 쉑터 다이아몬드 시리즈라고 박혀있습니다. 멋있네요.
사실 쉑터를 사고 싶었던 이유는 이 분이 한동안 쉑터 캘리포니아 커스텀을 가지고 기타를 치셨는데 그게 너무 멋있었기 때문입니다. 지금은 다른 기타들도 많이 사용하고 계시지만 이분 영상을 제일 처음 접한게 캘컴 쓰실 적 영상이라 기억에 강하게 남았네요.
매우 저렴한 가격으로 이런 좋은 기타를 구하게 되어서 너무 좋습니다. 아직 기타의 가치를 손이 따라가지 못하고 있지만 열심히 배워서 멋지게 곡을 연주할 수 있도록 해야겠습니다 :D
그림 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를 하면서 배웠었지만 지금까지
실감하지 못하고 있었는데 상당히 강력한 도구인 만큼 잘 활용하면 분석에 큰 도움이 될 것으로 보입니다.
File "c:\Python27\lib\logging\handlers.py", line 77, in emit
self.doRollover()
File "c:\Python27\lib\logging\handlers.py", line 142, in doRollover
os.rename(self.baseFilename, dfn)
WindowsError: [Error 32] The process cannot access the file because it is being used by another process
doRollOver는 TimedRotatingFileHandler에 지정한 기간이 지났을 경우 사용하던 파일을 백업하고 새로운 로그 파일을 생성하도록 하는 함수이다. Error 32는 다른 프로세스나 스레드에서 같은 파일의 핸들러를 가지고 있기 때문에 변경이 불가능할 때 발생하는 에러이다. 당시 Multiprocessing 환경에서 사용중이었기 때문에 이것이 문제인가 싶어서 프로세스별로 다른 Logger를 사용하도록 변경해 보았으나 그래도 마찬가지로 발생하였고, 이를 해결하려고 수없이 돌아다녔다.
=== [2019-04-03] 업데이트
한동안 발생하지 않아서 방심하고 있었는데 여전히 버그는 발생했다. Error 32가 뜻하는 바도 그렇고 분명 뭔가 멀티프로세스 환경에서 다른 프로세스가 핸들을 물고 있어서 Rotating이 되지 않는 것이 분명했으므로 이를 확인하기 위해 테스트 코드를 짜 봤다.
1분마다 Rotating하도록 설정하여 돌려봤는데, 아니나다를까 Main-Process 로거에서 doRollOver 에러가 발생한다. multiprocessing.Process로 생성한 자식 프로세스에서 main의 mainLogger 핸들러를 물고 있는 것이 아닌가 하는데...
돌려놓고 Rotating이 발생하기 전에 Process Hacker를 이용해 파일 핸들러를 찍어본 모습이다. Main과 Sub 모두 자신의 핸들러를 가지고 있는데, Sub에서 Main의 핸들러를 물고 있는 것을 볼 수 있다.
doRollOver Error32가 발생한 이후 찍은 모습이다. Main에서는 Rotating을 위해 핸들러를 닫았지만 Sub에서는 계속 물고 있는 것을 볼 수 있다. 이래서 Error32가 발생한 것으로 파악할 수 있었다. 문제는 이걸 어떻게 해결하냐는 것인데... 파이썬 logging 라이브러리 자체가 멀티 프로세싱 환경을 고려하지 않고 만들어졌기 때문에 발생한 일이라 간단하게 해결하긴 힘들어 보인다. 여기(https://docs.python.org/ko/3/howto/logging-cookbook.html)에서는 소켓에 로그를 작성하고 이를 읽어서 기록하는 스레드를 따로 만들어 두고 돌리는 방식으로 처리가 가능함을 설명하고 있으며 실제로 multilog(https://pypi.org/project/multilog/)라고 하는 모듈이 이미 존재한다. 어느 쪽이든 로깅 모듈이 쓰이던 곳이 한두군데가 아니었기 때문에 고치기는 힘들겠지만 최대한 노력해 봐야겠다 (._.
몇달 전에 구매한 일펜 머스탱의 셋업을 맡기기 위해서 건대입구역 근처에 위치한 닥터에이에 다녀왔습니다. 뮤직포스에서 리페어 팀장직을 맡고 계시다가 2013년에 마치시고 작업실을 오픈하셨다고 하십니다. (뮤직포스는 잘은 모르지만 무척 고가의 하이엔드 기타를 취급하는 곳이라고만 알고 있습니다.) 네이버에서 블로그 운영도 하고 계시네요.
대학교 동아리에서 기타 치는 친구가 추천해줘서 가게 되었는데, 인터넷으로 검색해보니 실력이 정말 좋다는 말도 많지만 조금 권위적이고 불친절하다는 말도 가끔 보여서 조금 불안했습니다. 하지만 직접 가서 느껴본 바로는 전혀 그런 것 없이 친절하셨습니다 xD.
[닥터에이 위치]
2호선 건대입구역 1번출구로 나와서 대략 10분정도 걸어가면 도착할 수 있는 위치에 있습니다. 먼 거리는 아니지만 제가 간 날은 하필이면 비가 와서 기타를 메고 가는 데에 조금 힘들었네요. (들어갈 때 문이 닫혀있고 외출중 팻말이 걸려있어서 아직 오픈하지 않은 줄 알았는데 아니었더군요)
기타 치는 데에 큰 문제가 있는 것은 아니었지만 줄도 새로 갈고 싶었고 인토네이션이 맞지 않는 문제도 있어서 그 부분을 말씀드렸고, 줄은 엘릭서 010으로 교체했습니다. 사실 줄의 차이도 잘 모르지만(010이 009에 비해서 장력이 좀 더 강하다는 것만 압니다...) 엘릭서가 코팅이 되어 있어 오염에 강한 비싼 줄이라는 것을 어디서 주워들었기 때문에 이왕 하는거 좀 비싸더라도 좋은 걸로 하고 싶었습니다. 전화로 미리 예약 후 방문하면 되고 간단한 점검과 셋업은 1시간 내로 끝납니다. 그동안 나갔다가 와도 되고, 안에서 기다려도 됩니다. 저는 안에서 기다리는 것을 택했고, 처음으로 와본 리페어샵이라 주변을 둘러보는데 신기하기만 했습니다.
[셋업 받으면서 찍은 기타]
PRS나 존써 등 인터넷에서 사진과 영상으로만 봤던 고가의 악기들도 있었습니다. 위 사진의 가운데에 있는 PRS는 탑이 너무 예쁘고 취향이라 꼭 갖고 싶었던 녀석이네요.
블로그에서 보면 테스트용 장비들이기 때문에 기다리면서 마음껏 쳐봐도 된다고는 하셨지만 일렉기타를 시작한지 얼마 되지도 않은 초보이기도 하고 저런 비싼 장비를 건드리는 것은 조금 무서워서 구경만 했습니다. 나중에 여유가 생기고 실력도 늘면 이런 기타로 멋들어지게 칠 수 있지 않을까 하는 기대감도 들었습니다.
기타 구경하면서 돌아다니다 보니 셋팅이 모두 끝났고, 커다란 앰프에 물려서 테스트해보라고 넘겨주셨는데 사실 테스트라고 해도 아직 일렉기타를 잘 모르는 저에게는 '소리가 잘 나고, 드라이브 잘 먹고, 연습했던 곡 음색만 맞게 나오는지' 보는게 다였기 때문에 적당히 몇번 쳐보고, 드라이브 걸고 몇번 쳐보고 금방 테스트를 끝냈습니다. 앰프 소리는 확실히 무지막지하게 좋았습니다. 집이 원룸이라 앰프를 크게 틀어놓고 칠 수가 없어서 늘 헤드폰을 끼고 치는데, 정말 연습실을 하나 빌려서 쓰고 싶다는 생각까지 들 정도였습니다. 가격은 위에 링크해둔 블로그에 잘 나와 있으니 참고하시면 되겠습니다.
몇달 치고는 있지만 아직도 일렉기타에 대해서는 잘 모르기 때문에 얼마나 주기를 가지고 셋업을 받는 것이 좋은지 등을 전혀 모르지만 나중에 셋업 받을때도 여기로 갈 것 같습니다. 실력이 좀 늘면 고가의 기타는 어떤 연주감이고 어떤 소리를 내는지도 한번 쳐보면서 느껴보고 싶네요. :D
게임 핵으로 위장한 악성코드를 분석해보자는
생각이 들어서 초록 검색창에 ‘배틀그라운드 핵 다운’ 이라고
검색하여 딱 봐도 수상해 보이는 블로그 포스트에서 수상해 보이는 압축 파일을 다운받았습니다. 비밀번호까지
걸려있는 걸로 봐선 악성코드임이 거의 확실해 보여서 분석에 들어갔습니다.
[그림 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# 프로젝트 소스코드입니다.
2018년을 맞이해서 열심히 풀기 시작했던 Codefights.com 의 Arcade - Python 부분의 모든 문제를 클리어하였다.
전 문제가 영어로 나오는데다 가끔 문제 수준이 언어에 대한 이해도가 상당히 높아야 해결 가능한 경우가 있어서 여러 번 막혔지만, 그래도 몇시간 붙잡고 풀다 보니 전부 푸는데 성공할 수 있었다.
그 중에서도 가장 재밌었던 챕터를 꼽으라면 55~64번째번째 문제가 속한 Drilling the Lists 가 아닐까 싶다. 그림에서도 보다시피 map, filter, reduce 및 lambda를 자유자재로 활용하여 짧고 간결하고 효율적인 코드를 작성하는 방법에 대한 문제들이다. 실제로 여기서 문제를 풀다 보니 회사에서 사용하는 파이썬 코드도 좀 더 간결하고 효율적으로 짤 수 있게 되었고, 활용의 폭이 매우 넓어졌다고 느끼고 있다. 매일 한 문제 이상 푸는 것을 목표로 풀어나가고 있는데, 이 속도대로라면 이번 년도가 끝나기 전 Arcade를 전부 클리어 가능하지 않을까 하고 기대하고 있다.
함수와 그 인자를 넘겨 함수 시작 전, 함수가 끝난 후에 경계선을 출력하도록 하는 새로운 함수를 만들고, 그것을 이용해 각자의 함수를 실행하도록 변경해 보았다. 원하던 대로 결과가 나오기는 하지만, 무엇인가 불편한 기분이 드는 것은 여전하다. 호출하고 싶은 함수는 HelloName, GoodbyeName, HowAreYouName 인데 실제 호출하는 함수는 AddLine이고, 인자의 전달도 직관적으로 눈에 들어오지 않는다.
직관적으로 HelloName 함수를 실행하는 것이 보이면서 인자의 전달도 깔끔하게 정리할 수 있는 방법이 없을까?
AddLine 함수 내에 wrapper라는 이름으로 다른 함수 하나를 선언하고, 내부에서 인자로 전달받은 함수를 실행하기 전, 실행이 끝난 후에 줄을 추가로 출력하도록 한 후, AddLine 함수가 끝날 때 wrapper 함수 자체를 반환하도록 만들었다. 이제 main 에서 AddLine 함수에 원하는 출력 함수를 넣은 후 리턴된 함수를 받아와서 사용해주면 된다.
정답에 아주 가까워졌지만 여전히 불편한 점이 몇가지 있다. 내가 선언한 함수는 HelloName인데 새로 newHelloName을 만들어서 사용해주어야 한다는 점, 함수마다 전부 저 작업을 추가로 해주어야 한다는 점 등이다. 선언한 함수를 그냥 사용할 수 없다는 점에서 또 직관성이 떨어지는 코드이기도 하다.
이 모든 문제점을 해결하기 위해 사용하는 것이 데코레이터(Decorator)이다. 다른 함수들의 시작 전이나 후에 특정한 장식(Decoration)을 붙여 주는 것이다. 여기의 예제에서는 위아래에 붙은 경계선이 '장식' 되시겠다.
wrapper 에서 받는 인자가 *args, **kwargs 가 되어서 당황할 수 있지만, 사실 이는 가변 인자를 넘겨주기 위한 것으로 생각보다 간단한 개념이다. 여기에 잘 설명되어 있으므로 참고.
AddLine 함수는 달라진 점이 전혀 없고, 각 함수 위에 @AddLine 한 줄씩이 추가된 것을 볼 수 있다. @AddLine은 데코레이터 AddLine을 이 함수에 적용시키겠다는 의미이다. 각 함수들은 선언 순간 데코레이터 AddLine이 적용되어 리턴된 wrapper 함수를 자기 자신으로서 갖게 되고, 따라서 사용할 때는 별도의 작업 없이 선언한 함수를 그대로 사용하면 된다.
이것이 가장 기초적인 데코레이터의 사용법이다.
이제 여기서 한 계단만 더 올라가보자.
데코레이터를 사용하다 보면 데코레이터 자체가 인자를 받는 모습을 볼 수 있다. 예를 들면 Flask를 이용한 REST API 개발을 해본 사람이라면, 다음과 같은 코드가 함수 앞에 붙는 것을 봤을 것이다.
딱 봐서는 blah_blah 라는 함수에 app.route라는 데코레이터를 적용하는 코드로 보이는데, 지금까지 보지 못한 부분이 추가되었다.
바로 app.route에 ("/file", methods=["GET"]) 로 인자를 받는 부분이 추가되었다는 것이다.
생각해 보면 지금까지 작성한 예시에서 데코레이터가 하는 일을 나타내어 봤을 때 '함수 시작 전과 끝난 후에 특정 줄을 하나씩 출력한다'라고 표현할 수 있다. 그런데, 모든 함수가 다 같은 줄만을 출력하는 것이 아닌 특정 문자열을 출력하고 싶은 것일 수도 있다. 즉, 같은 데코레이터를 이용하여 다른 내용을 출력할 수 있도록 만들고 싶을 수 있는 것이다.