학회_공부해요/기술_스터디

[S2W] Detailed Analysis of DocSwap Malware Disguised as Security Document Viewer

yenas0 2025. 4. 6. 17:45
반응형

https://medium.com/s2wblog/detailed-analysis-of-docswap-malware-disguised-as-security-document-viewer-218a728c36ff

 

Detailed Analysis of DocSwap Malware Disguised as Security Document Viewer

Author: HyeongJun Kim | S2W TALON

medium.com


바이러스 토탈에서 문서열람 인증앱이라는 악성 앱이 분석되었음

APT 그룹이랑 관련되어있다고 보았고 멀웨어 샘플을 분석함.

멀웨어는 난독화된 APK 파일 복호화 한 뒤에 내부에 저장된 DEX 파일에서 코드를 실행한다.

기존 코드에서 XOR 연산이 도입되었는데 APK 복호화 과정에서 사용되는 LoadedApkPlugin이다.

이렇게 복호화된 파일을 DEX 파일을 로드 및 실행해서 악성행위를 수행할 수 있게된다.

 

 

 

악성 앱 설치 및 초기 행위

사용자 인터페이스(UI): 보안문서 열람을 위해 설치가 필요하다는 안내를 통해 사용자를 속인다. UI는 정상적인 문서 뷰어처럼 보이지만 실제론 악성코드가 포함되어있다.

파일구조: 앱 내부에는 assets/security.db라는 파일이 있는데 해당 파일을 XOR 키를 사용해서 복호화되고 DEX포맷이 포함되어 있다. 복호화된 DEX 파일은 앱 실행 시 DexClassLoader를 통해 동적으로 로딩된다.

public void loadPluginAPK() {
    File file = new File(String.format("%s/security.db", MyApp.getInstance().getFilesDir().getAbsolutePath()));
    utils.dumpFile("security.db", file.getAbsolutePath()); // XOR 연산 수행
    Class class0 = Class.forName("android.app.ActivityThread");
}

public static void dumpFile(String assetsPath, String destPath) {
    File destFile = new File(destPath);
    if (!new File(destFile.getParent()).exists()) {
        new File(destFile.getParent()).mkdirs();
    }

    try {
        if (!destFile.exists()) {
            destFile.createNewFile();
        }

        InputStream inputStream0 = MyApp.getInstance().getAssets().open(assetsPath);
        FileOutputStream out = new FileOutputStream(destFile);
        byte[] tmpt = new byte[0x400];
        int v;
        while((v = inputStream0.read(tmpt)) != -1) {
            for(int i = 0; i < 0x400; ++i) {
                tmpt[i] = (byte)(tmpt[i] ^ 0xFFFFFFC9);
            }
            out.write(tmpt, 0, v);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

security.db 파일을 복호화한거다

이 앱은 매니페스트 파일에 선언된 권한을 검색해서 승인 안된 권한을 부여하도록 요청한다.

자세히 정리하면 아래와 같음

 

 

악성 기능 및 C2 통신

1. C2연결

- 앱은 실행 후 C2 서버에 접속하여 명령을 수신한다. 주요 C2 주소는 naverapi.duckdns.org같은 위장도메인에 8080포트를 사용한다.

 

2. 악성 기능

- 내부 저장소에서 파일을 수집하여 서버로 전송하는 파일전송

- 접근성 권한을 이용해 사용자의 키 입력을 기록하는 키로깅

- 사진촬영 오디오 녹음

- 특정 앱의 실행 여부를 확인하고 제어함

- 연락처나 SMS 정보를 탈취함

- 스크린 캡쳐

 

3. 접근성 권한 사용

- 사용자로 하여금 접근성 서비스 권한은 허용하도록 유도

- 권한이 주어지면, 이후 앱 제어 및 키 입력 모니터링 가용

 

4. 지속성

- 부팅 시에 자동 실행되도록 설정

- 접근성 권한이 제거되면 다시 허용을 요청하는 루틴이 존재한다.

 

 

 

피싱페이지 & Kimsuky 연계 가능성

공격자는 앱뿐 아니라, 피싱 페이지를 통해 공격을 병행한다. 이 페이지는 앱과 동일한 서버에서 호스팅되며, 사용자 입력을 수집한다. 일부 페이지에서는 "Milllion OK !!!!" 메시지 및 Naver 파비콘이 존재한다. 이는 김수키 그룹의 스타일과 유사함..

 

악성코드 흐름을 보면 아래와 같다.

[설치]  
 ↓  
[MainActivity 실행]  
 ↓  
[XOR 복호화 수행: security.db → DEX 파일 추출]  
 ↓  
[DexClassLoader로 DEX 동적 로드]  
 ↓  
[com.security.library.MainService 시작]  
   ↓  
   ├─ 접근성 권한 요청 (키로깅 위해)  
   ├─ 알림 생성 (포어그라운드 서비스 유지)  
   └─ 소켓 통신 초기화 (C2 접속)  
         ↓  
         [C2로부터 명령 수신 → 악성 행위 수행]  
             ├─ 키로깅  
             ├─ 파일 수집 및 전송  
             ├─ 사진 촬영  
             ├─ 오디오 녹음  
             ├─ 앱 정보 수집  
             └─ 기타 정보 탈취

모든 명령은 하드코딩된 C2 서버로부터 소켓 기반으로 전달된다.

총 57개의 악성 명령이 식별 되었다고 한다.

해당 내용은 본문을 참고해서 열어보는게 좋을 듯.

 

 

 

MITRE ATT&CK 매핑

 Tactic Technique
Persistence T1541 - 부팅 자동 실행
Discovery T1420 - 시스템 정보 수집
Collection T1417 - 입력 키 감시
T1429 - 오디오 캡쳐
Exfiltration T1041 - 외부 서버로 정보 전송
Defense Evasion T1406 - 정식 앱으로 위장
Command & Control T1219 - 원격 명령 제어, 소켓 통신

 

악성앱 이름도 한국어고 한국어 문자열이 있다는 점을 감안했을 때 한국의 모바일 기기 사용자를 표적으로 삼은 것으로 의심된다. 

 

 


아무거나 가지고 있는 apk 파일하나 확인해보았다.

https://github.com/yenas0/HealthyRoutine

 

GitHub - yenas0/HealthyRoutine

Contribute to yenas0/HealthyRoutine development by creating an account on GitHub.

github.com

전에 개발했던 안드로이드 앱인데....

여기 코드를 봤다.

 

오늘은 그냥 AndroidManifest만 확인해보는걸로

 

저 링크에서 들어가서 확인하면된다. (과제로 만든거라.. 허점이 많으니 그냥 알아서들 ..)

 

지금보니까 exported 액티비티가 엄청 많았네 8개나 있었다

<activity android:name=".SignUpActivity" android:exported="true">
<activity android:name=".HomeActivity" android:exported="true">
<activity android:name=".MyPageActivity" android:exported="true">
<activity android:name=".MonthlyStatsActivity" android:exported="true">
<activity android:name=".RecommendActivity" android:exported="true">
<activity android:name=".BoardActivity" android:exported="true">
<activity android:name=".RankingActivity" android:exported="true">
<activity android:name=".AuthCodeHandlerActivity" android:exported="true">

 

보다보니까 시작 화면 그럼 로그인페이지 말고 다른데부터 강제로 시작하는게 가능할까 싶어 봤는데 실행된다ㅋ...ㅋ..ㅋ.

 

실행하는 명령어는 알아서 시도 해보시길.. 어차피 스토어에 올린 앱도 아니니^^,,

이래서 장려상 받았나 싶었다.ㅎㅎ,,,,

반응형