stacy 는 전 직원이 자신의 thumb drive 에서 파일들을 지웠다고 생각하고 있습니다.
대부분의 파일들은 대체가 가능하지만, 비밀번호를 저장하고 있는 파일은 필요하다고 합니다.
그래서 stacy 는 drive 를 덤프하여 image를 생성했고, 이 image 에서 비밀번호를 저장한 파일의 복구를 의뢰하였습니다.
 
원본 파일과 다운로드된 파일이 동일한 파일임을 확인하기 위해, 지문에서 제공한 md5checksum 값과 동일한지 확인합니다.

 

압축 파일이 손상없이 다운로드 되었으므로 압축을 풀고, image 파일을 마운트하여 삭제된 파일들이 확인 가능한지 확인해 봅니다.
 
마운트 해보면 stacy 라는 디스크 이름으로 몇개의 폴더들을 확인할 수 있지만, 그 폴더 하위의 파일들은 확인할 수 없습니다.
따라서 winhex 도구를 이용하여 파일들을 복구해 봅니다.
 
복구한 파일들을 일부 확인해 보면, .Trash-1000 폴더 즉 쓰레기통에서 여러 삭제된 파일들이 복구된 것을 확인할 수 있습니다.
그 중 비밀번호와 관련이 있어 보이는 Your new password is.rar 의 압축을 풀어봅니다.
 
하지만 해당 파일에는 비밀번호가 걸려있고, 이에 대한 비밀번호를 찾아야 합니다.
[*] 복구된 파일들을 살펴 보면, 힌트로 사용할 수 있는 음성 파일을 찾을 수 있습니다. (이거 너무 게싱,,,)
 
Voicemail 1.wav 를 들어보면 다음과 같은 내용을 포함하고 있습니다.
...
I sent you a new key over to you.
Use your phone number to access file
...
"새로운 키를 보냈는데, 이 파일은 핸드폰 번호로 열어볼 수 있습니다.”
 
stacy의 핸드폰 번호는 Termination - Allen Smith.docx 라는 제목의 문서에서 확인할 수 있습니다.
 
위에서 찾은 핸드폰 번호를 이용하여 압축파일을 해제하면, 위와 같은 새로운 비밀번호 확인할 수 있습니다.
 

'0x20 Forensics' 카테고리의 다른 글

Dreamhack :: FFFFAAAATTT  (0) 2022.05.17

Intro

[*] 안드로이드 카카오톡을 대상으로 분석하였기에, 아래에 나오는 카카오톡은 안드로이드 버전의 카카오톡을 지칭합니다.
프로젝트를 진행하면서, 재미있어 보였지만 끝까지 하지는 못한 카카오톡 DB의 복호화에 관한 글을 적어 봅니다.
프로젝트 당시에는 많은 제약 조건들로 인하여 복호화 쪽은 다른 것들에 밀려 끝까지 분석해 보지 못했었습니다. 따라서 예전 분석한 것을 바탕으로 이번 기회에 시간을 더 투자하여 다시 한번 복호화를 진행하여 보았습니다. 결과부터 말하자면, 안드로이드 KakaoTalk 의 최신 버전인 v8.5.4 에서 진행하였으며 성공적으로 복호화 하였습니다.
 

메시지 원문

복호화할 대상을 생성하기 위하여 카카오톡 버전에 관한 정보와 DB 파일등을 주고 받았습니다.
카카오톡에서 메시지를 주고 받으면 위와 같이 평문으로 확인을 할 수 있습니다. 여기서 조금 추측을 해보자면 카카오톡이 네트워크에 연결되어 있지 않아도 채팅창에서 평문의 메시지를 확인할 수 있습니다. 따라서 서버에서 키와 관련된 정보는 받아오지 않는 것을 추측해 볼 수 있을 것 같습니다.
 

암호화된 DB

위는 /data/data/com.kakao.talk/databases/KakaoTalk.db 에서 추출한 카카오톡 메시지 관련 DB 입니다.
PC 버전 KakaoTalk의 경우에는 DB 자체가 암호화되어 있습니다. 반면에 안드로이드 KakaoTalk 의 경우에는 모바일이라는 특성 때문인지 messsage 부분과 attachment 부분만 암호화되어 있습니다.
즉 사용자가 주고 받은 메시지와 첨부파일에 대한 정보들만을 암호화하고 있습니다.
 

메시지 복호화

위는 DB를 성공적으로 복호화하여 CSV 형식으로 저장한 것입니다.
리버싱을 통해 암호화 루틴을 파악하고, smali로 되어 있는 코드를 java 코드로 구현하여 복호화를 진행하였습니다.
텍스트 메시지의 경우에는 메시지 부분에, 사진과 같은 첨부파일들은 첨부파일 부분에 카카오톡 파일 서버의 URL 과 같은 정보 등이 저장되어 있는 것을 확인할 수 있습니다.
 

Outro

카카오톡은 대칭키를 사용하여 message 와 attachment 부분을 암호화합니다. 따라서 카카오톡 DB 복호화의 핵심 요소는 암호화와 복호화할 때 사용하는 키입니다.
이 키는 서버에서 받아오거나 로컬에서 생성할 수 있을 텐데, 위에서 추측한 바와 같이 네트워크 연결이 없음에도 평문으로 내용을 확인할 수 있기에 로컬에서 생성할 것입니다. 실제로 DB에 저장되어 있는 값과 여러 고정 값들을 이용하여 키를 생성합니다. 이 부분은 내용이 길어지므로 나중에 별도의 글로 작성하겠습니다.
또한 필자와 같이 리버싱하여 사용자들이 카카오톡의 암호화 알고리즘을 파악할 수 있습니다. 이에 대한 변화가 필요하지만 기존에 암호화한 DB 와의 호환성을 위하여 무작정 암호화 알고리즘를 변경하기도 힘들다고 생각합니다. 따라서 카카오톡은 호환성을 유지하며 버전별로 조금씩 변화를 주며 키를 생성 하고 있습니다. 역시 이에 대한 자세한 내용은 길어질 것 같기에 나중에 별도의 글로 작성하겠습니다.

온라인 도구

PDF 를 합치기 위하여 구글에 검색을 해보면, 수많은 사이트들을 보여준다. 이러한 온라인 도구들을 이용하면 편리하고 간단하지만, 보안상의 이유나 개인적인 이유로 인하여 업로드가 꺼려지는 경우가 있다.
 

Preview

맥에서 파일들을 보기 위하여 사용하는 Preview 라는 어플리케이션을 이용하여 간단히 pdf 를 합칠 수 있다. 엄밀히 말하면 pdf의 페이지를 복사해서 붙여넣기 하는 것이다.
방법은 아래와 같다.
  1. 합칠 2개의 pdf를 띄운다.
  1. 썸네일에서 보이는 작은 페이지를 드래그&드롭으로 원하는 위치에 넣으면 된다.
  2. 그 후 파일을 저장하면 된다.
     
[*] 표지를 pdf 로 만들어 놓고, 필요할 때 넣어서 사용하면 편하다.
[*] 여러개의 썸네일을 선택하여 복수의 페이지를 삽입할 수 있다.

 

'0xF0 ETC >  Tips' 카테고리의 다른 글

[ Tips] Android File Transfer 자동 실행 방지  (0) 2020.03.13
[ Tips] MOV 변환하기  (0) 2019.09.23

0x0 Packer

PE 파일을 unpack 하기 전에 packer 에 대하여 먼저 알아본다.
packer은 사용 용도에 따라 크게 2가지로 나눌 수 있다.

0x01 Compression

  • PE 파일의 용량을 줄이기 위한 용도로 활용

0x02 Protector

  • 리버싱을 방해하기 위하여 사용
  • ex) 카카오톡, 악성코드 등

0x1 Manual Unpacking

_start 함수를 따라가다 보면, 여러 반복문들을 확인할 수 있다.

처음에 kernel32.dll 을 로드하고, 0x409000 에서 0x4994ee 까지 xor 을 하여 복호화를 진행한다.

그 후 VirtualProtect 함수를 이용하여 메모리 영역에서의 실행 권한을 변경한다. 즉 0x405000 부터 0x1000 만큼 변경이 된다.

그리고 0x401000 에서 0x405000 까지 xor 을 하여 복호화를 진행한다.

마지막으로는 0x406000 에서 0x409000 까지 xor 을 하여 복호화를 진행한다.
전반적인 복호화가 끝나고, 0x401150 으로 넘어가게 되고, packing 이 풀어진 코드를 실행한다.

0x2 PEiD

PE 에 대한 정보를 보여주는 프로그램 PEiD 를 이용하여 unpacking 을 해본다.
PEiD 에서 다운로드 받을 수 있다.

PEiD 에서 지원하는 플러그인 중에서 Generic OEP Finder 라는 이름의 플러그인이 존재한다.

해당 플러그인을 이용하면 손쉽게 OEP 를 구할 수 있다.

플러그인 분석

PEiD 의 설치 폴더에 가보면 위와 같이 플러그인을 확인할 수 있다.
이 중에서 GenOEP.dll 라이브러리를 분석해 본다.
[추후 추가 예정]

0x3 Reference

'0x00 Reversing > 0x01 Reversing.kr' 카테고리의 다른 글

Reversing.kr :: Ransomware  (0) 2019.12.09
Reversing.kr :: Easy_ELF  (0) 2019.10.05
Reversing.kr :: Easy_Keygen  (0) 2019.02.26
Reversing.kr :: Easy_Crack  (0) 2019.02.24

루틴 분석


_start 의 마지막 루틴 부분에 보면, __return_addr, var_4, var_8_2 를 인자로 하여 sub_401000 함수를 호출한다.

sub_401000

sub_401000 함수는 크게 4가지로 나눌 수 있다.


Input Name이라는 문자열을 출력하며, 이름을 입력 받는다.


그 후 이름을 이용하여, 어떠한 문자열들을 생성한다.


그리고 Input Serial: 라는 문자열을 출력하고, 시리얼을 입력 받는다.


마지막으로는 이름을 기반으로 생성한 문자열과 시리얼을 비교하고, 이에 대한 결과를 출력한다.
따라서 2번째 과정인 이름을 기반으로 시리얼을 생성하는 과정을 분석해 본다.

시리얼 생성


생성 루틴의 처음을 보면, esi 와 0x3 을 비교한 후 작을 경우에 xor을 생략한다.
처음 루틴에 들어왔을 경우에는 esi 가 0으로 초기화되었기 때문에, xor 루틴을 생략된다. 그리고 esi 는 0 이기에 esp+0xc 를 ecx에 넣는다.


여기서 esp+0xc 에는 0x10이 들어가 있다. 이 값은 esi 의 증가에 따라서 0x10, 0x20, 0x30 으로 변화할 것이다.
그 다음으로는 esp+ebp+0x10의 바이트를 edx에 넣는다. 마찬가지로 ebp 는 0으로 초기화 되어있기에 esp+0x10 의 바이트가 들어갈 것이고, esp+0x10에는 입력받은 문자열의 시작 주소를 가리키고 있다.
따라서 ebp 가 증가함에 따라 edx 에는 입력받은 문자열에서 순서대로 하나씩 문자가 들어갈 것이다.
def name2serial(name):
    xorKey = ["10", "20", "30"]
    serial = []
    for i in range(len(name)):
        ecx = int(xorKey[i%3],16)
        edx = int(name[i].encode('hex'),16)
        serial.append(format(ecx ^ edx,'x'))
    return "".join(serial)
분석한 생성 과정을 바탕으로, 이름에서 시리얼을 생성하는 파이썬 코드는 위와 같다.

이름 복구

생성 방식이 단순히 xor 만을 이용하기에, 시리얼에서 이름을 구하는 코드도 비슷하다.
def serial2name(serial):
    xorKey = ["10", "20", "30"]
    name = []
    for i in range(0,len(serial)/2):
        ecx = int(xorKey[i%3],16)
        edx = int(serial[i*2:i*2+2],16)
        name.append(chr(ecx ^ edx))
    return "".join(name)
시리얼을 문자열 형태로 받고, 이를 이용하여 이름을 복구(?!)한다.


이를 이용하여 이름을 구하면 "K3yg3nm3" 라는 이름으로 나온다.


확인 결과 이름과 시리얼이 일치하는 것을 확인할 수 있다.




'0x00 Reversing > 0x01 Reversing.kr' 카테고리의 다른 글

Reversing.kr :: Ransomware  (0) 2019.12.09
Reversing.kr :: Easy_ELF  (0) 2019.10.05
Reversing.kr :: Easy_Unpack  (0) 2019.03.01
Reversing.kr :: Easy_Crack  (0) 2019.02.24

문자열 확인

본격적인 분석에 앞서 문자열을 확인해 본다.

00406030에 비밀번호가 틀렸을 경우에 나올 문자열이, 00406044에 비밀번호가 맞을 경우에 나올 문자열로 추정되는 문자열이 보인다. 해당 문자열의 Xref를 보면 sub_401080에서 사용이 된다.

루틴 분석

위의 경우에는 비밀번호를 확인하고 그 결과에 따라, Congratulation !! 이라는 메시지박스를 출력 또는 Incorrect Password 라는 메시지박스를 출력합니다.

401080 함수의 시작 부분을 보면, 로컬 스택으로 0x64 만큼 사용한다. 그 후 GetDlgItemText 함수를 호출한다.
UINT GetDlgItemText(
  HWND hDlg, // handle
  int nIDDlgItem, // 컨트롤 ID
  LPTSTR lpString, // 문자열 버퍼
  int nMaxCount // 버퍼의 길이
);
각 인자에 대한 설명은 다음과 같다. 핸들과 컨트롤 ID 를 넘겨주고, 그에 대한 문자열이 반환값이다.
var_64 즉 call 이 끝난 후 cmp 부분에서 esp+0x4는 lpString의 문자열이 들어있다. 따라서 esp+0x5은 lpString[1] 이라는 것을 알 수 있고, 0x61 과 비교를 한다.
[*] password: { _ a }

그 후 스택에 0x2 를 넣고, ecx 에 esp+0x0a 를 넣는다. 여기서 esp+0x0a 에는 lpString[2] 의 값이 들어있다. 왜냐하면 위에서 esp+0x4 에 lpString[0]이였고, 그후 0x2를 넣었기 때문에 esp+0x8 이 lpString[0]이 되었다.

0x406078 을 스택에 넣는데, 해당 주소에는 5y 라는 문자열이 들어있다. 그 후 ecx (lpString[2])를 스택에 넣고, sub_401150 함수를 호출한다. 즉 sub_401150(lpString[2], 0x406078, 2) 이며, 2인자의 주소는 포인터로 보인다.
sub_401150 함수 안에 들어가 보면, 해당 함수는 strncmp 함수 인 것을 알 수 있다. 따라서 lpString[2] 와 5y 2자리를 비교한다.
[*] password: { _ a 5 y }

그 다음으로는 ebx, esi 를 순차적으로 스택에 넣고, esi 에는 R3versing 의 주소 값을 넣는다. 그리고 esp+0x10 을 eax 에 넣는다. 앞에서 push 2번을 하였기에, esp+0x10 에는 lpString[4] 가 들어간다.

그 후에 dl 에 lpString 을, bl 에 R3versing 을 한 글자씩 넣고 이 둘을 비교한다. 그리고 test cl,cl 을 통해 문자열의 끝인지도 확인을 한다.
[*] password: { _ a 5 y R 3 v e r s i n g }

마지막으로 문자열(lpString) 의 처음이 0x45("E") 인지 확인을 한다.
[*] password: { E a 5 y R 3 v e r s i n g }

Reference

'0x00 Reversing > 0x01 Reversing.kr' 카테고리의 다른 글

Reversing.kr :: Ransomware  (0) 2019.12.09
Reversing.kr :: Easy_ELF  (0) 2019.10.05
Reversing.kr :: Easy_Unpack  (0) 2019.03.01
Reversing.kr :: Easy_Keygen  (0) 2019.02.26

+ Recent posts