웹 모의해킹 시 개발자도구를 이용한 웹 애플리케이션 분석으로 로직에 허점을 발견하거나 DOM영역에 대한 변조를 통해 취약점을 찾는 등 분석을 하기 위해서는 다양한 방법이 존재합니다. 모바일 웹도 이처럼 브라우저를 이용하여 디버깅을 하거나 로직을 분석할 수 있는 방법이 있어 소개하고자 합니다.


주제: 크롬 브라우저를 이용한 모바일 웹 디버깅 및 분석 방법 소개

 1. 환경구성

 2. inspect를 이용한 mobile web remote debugging

 3. 크롬브라우저를 이용한 mobile web debugging


1. 환경구성

 - Chrome 버전 32 이상 설치 된 PC

 - 안드로이드 4.4 이상에서 크롬 설치

 - USB 디버깅 허용


2. Inspect를 이용한 Mobile web remote debugging

PC와 스마트폰을 연결 후 환경구성이 되면 크롬 브라우저 주소창에 chrome://inspect 를 입력합니다.

그 후 안드로이드 기기에서 크롬 브라우저를 실행 후 분석하고자 하는 대상 사이트로 접속합니다.

<그림1> 모바일에서 크롬브라우저 실행


inspect 버튼을 누르면 모바일에서 실행되는 사이트에 대한 remote debugging을 할 수 있게 됩니다.

<그림2> 크롬 브라우저 inspect 실행


다음과 같이 모바일 웹에 대한 디버깅 혹은 로직 분석이 가능하게 됩니다.

간단하게 breakpoint를 설정하고 모바일 웹에 대한 로직 분석을 하였습니다.

<그림3> 모바일 웹 디버깅 및 로직 분석


모바일 웹 사이트에 대한 함수 분석이나 스탭별 실행을 하여 로직 분석에 용이합니다.

<그림4> 모바일 웹 사이트 함수 및 실행 로직 분석


쿠키값 혹은 리소스 정보들을 확인할 수 있습니다.

<그림5> 모바일 사이트 내 리소스 정보 확인

 

Webview를 사용하는 앱에 대해서 분석할수 있습니다.

앱에 Webview debugging이 활성화 되어있어야 합니다. 코드패치나 소스수정을 통해 webview debugable을 true로 설정합니다.

<그림6> WebView를 사용한 앱에 대한 분석


inspect 버튼을 누르면 다음과 같이 디버깅 할 수 있는 화면에 접근하게 됩니다.

<그림7> Webview를 사용하는 모바일 앱에 대한 분석


3. 크롬브라우저를 이용한 mobile web debugging

모바일 웹에 대해서 스마트폰을 이용해서 분석을 할 수도 있지만 크롬 브라우저 내에 설정을 변경하여 모바일 웹에 대한 디버깅 및 분석을 할 수있는 방법도 존재합니다.


먼저 크롬 브라우저에서 F12 버튼을 누른 후 아래 그림과 같이 스마트폰 모양의 아이콘을 클릭합니다.

그 후에 Device 선택을 할 수 있는데, 환경에 맞는 Device를 설정하면 됩니다.

<그림8> 모바일 사이트 분석을 위한 크롬브라우저 설정 변경


breakpoint를 적용하여 로직 분석하거나 DOM영역에 대한 분석이 가능합니다.

<그림9> 모바일 사이트 로직 분석


콘솔로 정의된 함수를 확인하거나 파라미터 값들을 확인합니다.

<그림10> 모바일 웹 함수 분석



Async를 활성화해서 콜스택을 살펴봅니다.

<그림11> 호출 스택 확인 및 디버깅



이렇게 크롬 브라우저를 이용하여 모바일 웹에 대한 분석을 하고 다양한 방법으로 취약점에 대한 접근을 할 수 있게 됩니다.

모바일 웹에 대한 분석 환경은 크롬 브라우저를 통한 방법 이외에도 다양하게 있고, 저희 팀크랙에서는 상황에 맞춰 보다 효율적인 방법으로 취약점을 찾고 있습니다.

감사합니다.


참고자료

https://developer.chrome.com/devtools/docs/remote-debugging


저작자 표시 비영리 변경 금지
신고

안드로이드 애플리케이션 점검 시 디컴파일이나 리패키징 등의 작업을 좀 더 간편하게 하기 위해 도구를 제작하였습니다.

점검 시 유용하게 사용하시길 바라며 아래와 같이 공유합니다.

 

파일 정보 (분할 압축 해제한 파일)

버전: 1.2

파일크기: 37.6MB

MD5: 0695ef2faef52c47b9e0cdcefeb99d17

 

Android_Auto_Analysis_Tool_TEAMCR@K_v1.2.zip.001

Android_Auto_Analysis_Tool_TEAMCR@K_v1.2.zip.002

Android_Auto_Analysis_Tool_TEAMCR@K_v1.2.zip.003

Android_Auto_Analysis_Tool_TEAMCR@K_v1.2.zip.004

 

 

기능

1. Android App Decompile

   - apk 디컴파일, log 출력 및 초기화

2. Android App repackage

   - 앱 리패키징, 임의 서명, adb push로 단말기 내 apk 파일 생성, log 출력 및 초기화

3. AndroidMenifest.xml 파일 분석 자동화

   - 단말기 내 설치된 apk/package 목록 확인, apk 파일 추출, 디컴파일, menifest 파일 파싱, app이 사용하는 권한 확인

4. 화면 캡처

   - 단말기 화면 캡처 및 저장, log 출력 및 초기화

 

사용법 소개

 

툴의 main UI 입니다.

 

<그림 1> main UI 확인

 

 

툴 최초 실행 시 AppRepack 폴더 내에 기능에 필요한 도구들을 생성합니다. (C:\AppRepack)

  

<그림 2> 기능에 필요한 도구 생성

 

 

apktool 실행 시 필요한 '1.apk' 파일의 버전을 맞추기 위해 '1.apk' 파일을 생성합니다. (C:\Users\Account\apktool\framework\1.apk)

※ 기존에 사용하던 apktool을 사용하고자 하시는 분은 해당 폴더 내에 생성된 '1.apk' 파일을 삭제 후에 사용하시면 됩니다. 

 

<그림 3> '1.apk' 파일 생성 

 

 

1. 디컴파일

 

 

'decompile' 탭에서 'decode' 옵션 체크 후 'File Open' 버튼을 눌러 디컴파일 할 애플리케이션의 apk 파일을 선택합니다.

 

<그림 4> apk 파일 선택 

 

 

apk 파일 선택 후 'start' 버튼 클릭 시 디컴파일이 진행됩니다.

 

<그림 5> 디컴파일 진행

 

 

디컴파일 시 log 창에 결과가 나타나며, 성공 시 Success 메시지가 출력됩니다. (실패 시 실패한 log도 출력)

 

<그림 6> 디컴파일 시 log 확인 

 

 

해당 툴이 위치한 폴더와 동일한 폴더에 디컴파일된 apk 파일의 파일명으로 폴더가 생성됩니다.

 

<그림 7> 디컴파일된 apk 파일의 파일명으로 폴더 생성

 

 

해당 폴더 내에서 디컴파일된 파일들을 확인할 수 있습니다.

 

<그림 8> 디컴파일된 파일 확인

 

 

2. 리패키징

 

 

'decompile' 탭에서 'build' 옵션 체크 후 'Folder Open' 버튼을 눌러 리패키징 할 애플리케이션 폴더를 선택합니다.

 

<그림 9> 리패키징할 폴더 선택

 

 

폴더 선택 후 start 버튼을 클릭합니다. (안드로이드 단말기가 연결되어 있지 않을 경우 adb push는 수행되지 않음)

 

<그림 10> 폴더 선택 후 리패키징 수행

 

 

리패키징 성공 시 log 창에 Success 메시지가 출력됩니다. (실패 시 실패 log도 출력)

 

<그림 11> 리패키징 시도 시 log 확인

 

 

연결된 안드로이드 단말기 내에 apk 파일이 생성된 것을 확인할 수 있습니다.

 

  

<그림 12> 안드로이드 단말기 내 apk 파일 생성 확인

 

 

3. AndroidMenifest.xml 분석 자동화

※ AndroidMenifest.xml - 응용 프로그램의 구성과 관련된 모든 정보를 담고 있는 파일

 

 

'menifest' 탭에서 UI를 확인합니다.

 

<그림 13> 'AndroidMenifest.xml' 분석 UI 확인

 

 

'Get App List' 버튼 클릭 시 단말기 내에 설치된 apk와 package 목록이 출력됩니다. (단말기 연결 필수)

 

<그림 14> 단말기 내 설치된 apk와 package 목록 확인

 

 

출력된 리스트 중 원하는 앱 선택 후 'Get App' 버튼을 클릭하여 로컬에 apk 파일을 받을 수 있습니다.

 

<그림 15> apk 파일 추출 시도

 

 

해당 툴이 위치하고 있는 폴더 내에 apk 파일이 생성된 것을 확인할 수 있습니다.

 

<그림 16> 추출한 apk 파일 확인

 

 

'Open App' 버튼을 클릭 후 apk 파일을 선택합니다.

 

<그림 17> apk 파일 선택

 

 

apk 파일이 디컴파일 됩니다.

 

<그림 18> apk 파일 디컴파일

 

 

'activity' 버튼 클릭 시 manifest 파일을 파싱하여 리스트로 출력합니다.

 

<그림 19> manifest 파일 파싱 및 리스트 출력

 

 

'permission' 버튼 클릭 시 해당 app이 사용하는 권한을 출력하며 영어와 한글로 된 설명을 출력합니다.

 

<그림 20> app 사용 권한 및 설명 출력

 

 

4. 화면 캡처

 

 

'capture' 탭에서 해당 기능의 UI를 확인할 수 있습니다.

 

<그림 21> 화면 캡처 기능 UI 확인

 

 

'Capture' 버튼 클릭 시 현재 단말기의 화면이 출력됩니다.

 

<그림 22> 현재 단말기 화면 출력

 

 

'Save' 버튼을 눌러 캡쳐된 사진을 저장할 수 있습니다.

 

<그림 23> 캡처 파일 저장

 

 

생성된 캡처 파일을 확인할 수 있습니다.

 

<그림 24> 생성된 캡처 파일 확인

 

 

이 툴은 모바일 앱 점검 시 하게 되는 작업들을 자동화하여 좀 더 간편하게 점검하기 위해 제작되었으며, 오픈소스를 이용하였습니다.

 

저희는 금감원, 금융위 체크리스트 기반 점검이나 모바일 모의해킹 프로젝트 수행 시 앱 분석 및 변조, 앱이 사용하고 있는 권한 확인 등의 점검에 이 툴을 활용하고 있습니다. 

저희처럼 앱 점검 또는 모바일 모의해킹을 수행해야 하는 분이나 이 쪽으로 공부를 하고 계신 분들은 이 툴을 활용해 보시면 좋을 것 같습니다.

추후 지속적으로 기능을 추가하고 수정하여 업데이트하도록 하겠습니다.

감사합니다.

저작자 표시 비영리 변경 금지
신고

OWASP Mobile Top 10 - 2014 정리

스마트폰 2014.11.21 21:50 Posted by TEAMCR@K

1. 개요

OWASP Mobile Top 10 이 2014년 초 리-릴리즈 되었습니다. 그동안 금융권 및 기업들의 모바일 자산들에 대해 자사의 모바일 모의해킹 방법론과 금융위, 금감원 체크리스트 그리고 OWASP Mobile Top 10 리스트를 포함 하여 다수의 모의해킹 프로젝트를 수행하였습니다. 이번에 OWASP Mobile Top 10 List 에 대해 간단하게 정리할 기회가 생겨 블로그에 작성하게 되었습니다.

 

<그림1> OWASP Mobile Top 10 List

 

간단하게 Top 10 Risk를 살펴보면 다음과 같습니다.

 

○ M1 - 서버사이드에서 발생할 수 있는 취약점
            대부분의 앱이 서버와의 통신으로 이루어지고 개발시 하이브리드 앱으로 많이 개발되기 때문에 클라이언트에서 파라미터

            값 변조를 통한 웹에서 발생 할 수 있는 취약점들이 도출될 수 있습니다.
○ M2 -  중요정보들이 스마트폰 내에 저장되는 경우
            스마트폰 분실 혹은 공격자에 의해 권한 탈취 시 해당 중요정보들 또한 공격자에게 전달됩니다.
○ M3 -  민감한 정보 평문 전송
             개인정보 혹은 중요정보들이 네트워크상에서 평문으로 전송될때 발생하게 됩니다.
○ M4 -  의도하지 않은 데이터 누출
             타 앱에서 접근 가능한 데이터영역에 민감한 정보를 저장시 발생할 수있는 리스크 입니다.
○ M5 -  인증 및 인가 검증 미흡
             클라이언트 내부에서 인증 시 우회 가능하기 때문에 인증 검증을 서버사이드에서 인증 절차를 확인해야 합니다.
○ M6 -  취약한 암호화
             개발 시 암호화 기술에 대한 적정성 여부를 판단하여 적용해야 합니다.
○ M7 -  클라이언트 사이드 인젝션
             클라이언트에서 발생할 수 있는 인젝션 공격입니다.
○ M8 -  신뢰할 수 없는 입력 값에 의한 보안 의사결정
             프로세스간 통신 시 발생 할 수 있는 취약점입니다.
○ M9 -  부적절한 세션 관리
             서버에서 부여받은 세션 관리에 대해 나와있습니다.
○ M10 - 바이너리 보호 미흡
             앱과 서버와 통신 시 앱에 대한 무결성 검증이 필요합니다.

 

 

2. Risk List 상세

2.1 M1: Weak Server Side Controls

모바일 역시 서버와 통신하여 데이터를 받아오게 됩니다. OWASP Mobile top 10에서 첫번째는 Weak Server Side Controls입니다.
해당 방법론은 OWASP에서는 기존 web과 cloud 에 해당되는 OWASP Top 10 취약점을 포함한 서버사이드에서의 취약점을 Mobile Risk top 1으로 꼽았습니다.
자사에서의 방법론 또한 해당 항목을 포괄적으로 적용하여 보고서 및 수행계획서에 포함하여 모의해킹을 진행 합니다.

<그림2> OWASP Top 10 (Web, Cloud)

 

 

시큐어 코딩과 중요 로직 등 서버사이드에서 동작할수 있도록 해야하며, 자세한 정보는 OWASP Top 10 web, cloud 프로젝트를 참고합니다.
OWASP Top 10 Web: https://www.owasp.org/index.php/Top10#tab=Main
OWASP Top 10 Cloud: https://www.owasp.org/index.php/Category:OWASP_Cloud_%E2%80%90_10_Project

 

<그림 3> OWASP에서 보는 모바일 애플리케이션 취약점 리스트

 

 

3.2 M2: Insecure Data Storage

두번째 Insecure Data Storage는 기존 금감원, 금융위 점검 체크리스트에도 포함된 스마트폰에 중요정보 저장금지 항목과 동일합니다. 자사에서도 해당 항목에 대해 빠른 점검을 위해 현재 소스코드 및 데이터 안에 중요 문자열 검색 자동화 툴을 제작하고 있습니다.
또한 앱 소스코드안에 하드코딩되어있는 계정정보 혹은 테스트 서버 주소 등 또한 자동화된 툴로 찾아낼수 있도록 하여 컨설턴트가 앱 점검시 보다 효과적이고 빠르게 점검할 수 있도록 프로세스화 할 예정입니다.

 

중요 데이터 저장 확인 리스트
- SQLite databases
- Log Files
- Plist Files
- XML Data Stores or Manifest Files
- Binary data stores
- Cookie stores
- SD Card
- Cloud synced

 

대응방안으로는 다음과 같습니다.
기본적으로 중요데이터는 필요한 데이터를 제외하고는 모바일 디바이스 안에 저장하지 않아야 합니다.

 

iOS
 - 계정(자격증명)을 파일시스템 안에 저장해서는 안되며, 웹 또는 api 로그인 방식(https)을 통해 인증하고 세션시간은 사용자의

    사용 시간을 고려한 최소한의 시간으로 설정해야합니다.
 - 중요정보 저장시 iOS 표준 암호화 방식인 CommonCrypto를 사용하며, whitebox cyptography 솔루션을 이용하는것도 하나의

    방법입니다.
 - Sqlite data 암호화를 위해 SQLcipher를 사용합니다.
 - 개발시 NSUserDefualtes 에 중요정보를 저장하지 않아야 합니다.
 - NSManagedObects를 사용하여 데이터를 저장할 경우 암호화 되지 않은 데이터들이 저장되는 것을 주의해야 합니다.
 - 중요정보 저장 시 하드코딩된 암호화 또는 암호화 해독키에 의존하지 말아야 합니다.
 - OS에서 제공된 기본 암호화 메커니즘 이외 추가적인 암호화 계층을 고려해야 합니다.

 

Andorid
 - 기기관리자 API를 이용하여 local storage에 setStorageEncryption을 사용하여 암호화 할 수 있습니다.
 - javax.crypto의 라이브러리를 이용하여 SD카드 저장 시 암호화 할 수 있습니다. 가장 쉬운 방법은 마스터 암호 및 AES 128과

   일반 텍스트를 암호화 하는 것입니다.
 - 앱사이에 정보공유가 필요하지 않은 경우 공유설정 속성을 NOT MODE_WORLD_READABLE 해야 합니다.
 - 중요정보 저장 시 하드코딩된 암호화 또는 암호화 해독키에 의존하지 말아야 합니다.
 - OS에서 제공된 기본 암호화 메커니즘 이외 추가적인 암호화 계층을 고려해야 합니다.

 

 

3.3 M3: Insufficient Transport Layer Protection

해당 항목은 서버와의 통신시 암호화 여부를 확인하는 항목으로 금감원, 금융위 체크리스트에 포함된 항목으로 중요 정보 전송 시 네트워크 구간에서 암호화 여부를 확인하는 항목입니다. 네트워크 암호화에 대한 정당성 여부를 해당 항목에서 확인합니다.

 

- 네트워크 계층에 보안 없다면 도청에 취약하다고 가정합니다.
- 민감한정보, 세션토큰등을 전송하기 위해서 SSL/TLS를 적용합니다
- 적절한 키길이와 업계표준의 암호화 방식을 사용합니다.
- 신뢰할 수있는 CA 공급자에 의해 서명 된 인증서를 사용합니다.
- 항상 SSL chain 확인이 필요합니다.
- 모바일 앱이 잘못된 인증서를 발견할 경우 UI를 통해 사용자에게 알려야 합니다.
- 대체 채널 (SMS, MMS, 또는 알림)를 통해 민감한 데이터를 전송하지 않습니다.
- 가능하면 민감한 정보에 대해서는 암호화하고 SSL 통신을 적용합니다. SSL에서 취약점이 발견될 경우 이차적인 방어를

   제공합니다.

 

 

3.4 M4: Unintended Data Leakage

네번째 항목은 의도치 않은 데이터 누출 입니다. 개발자가 개발 당시 타 앱에서 쉽게 접근 할수 있는 영역에 취약한 앱이 민감한 정보를 저장할때 발생 할 수  있는 취약점 입니다. 개발 시 아래항목에 대해 민감한 정보 저장여부를 확인하여 접근 가능한 타 앱들을 제어하여 민감한 정보 노출을 최소화 해야 합니다.

- URL Caching (Both request and response)
- Keyboard Press Caching
- Copy/Paste buffer Caching
- Application backgrounding
- Logging
- HTML5 data storage
- Browser cookie objects
- Analytics data sent to 3rd parties

 

3.5 M5: Poor Authorization and Authentication

다섯번째는 취약한 인가 및 인증 입니다.
제한된 앱에 대한 사용, 인증된 유저만 사용 할 수 있는 기능에 대한 우회 등 바이너리 변조를 통해 인증 및 권한을 획들할 수있습니다.

모든 클라이언트 인증은 악의적인 사용자에 의해 우회가 가능합니다. 따라서 가능하다면 서버 측에서 인증 및 권한부여를 해야 합니다. 바이너리 변조에 대한 무결성 검증을 하지 않을 경우 내부 로직 변경으로 인증우회가 가능합니다. M10(Lack of Binary Protections)에 관련되어서도 추가로 확인해야합니다.

 


3.6 M6: Broken Cryptography

앱에 대한 데이터 보호를 위해 취약한 암호화 방식을 적용할 경우 나타날 수 있는 취약점입니다.
현재 사용하기 불충분한 알고리즘은 다음과 같습니다.
RC2 ,MD4, MD5, SHA1

두번째로는 올바른 알고리즘을 선택하여도 동작하는 프로토콜에 대해 적용 미흡으로 발생합니다.
예를 들어, 컨텐츠와 중요 키를 함께 저장할 경우, 공격자가 해당 키를 이용하여 중요 정보를 해독할 수 있습니다.
해당 항목에 대해서는 암호화 방식이 명시된 개발 명세서(Specification)를 통해 확인 가능합니다.


3.7 M7: Client Side Injection

일곱번째 클라이언트 사이드 인젝션은 모바일 앱 에서 모바일 디바이스에 실행시키기 위해 사용자 입력 값에 악성코드를 삽입하는 취약점입니다.

서버사이드 취약점과 반대로 클라이언트 사이드에서 발생하는 취약점입니다.

위협되는 취약점으로는 다음과 같습니다.
SQLite Injection, Local File Inclusion, XML injection, javascript injection(xss, etc), Binary injection 등등

 

 

3.8 M8: Security Decisions Via Untrusted Inputs

여덟번째 내용은 Security Decisions Via Untrusted Inputs(신뢰할수 없는 입력값에 의한 보안 의사결정) 입니다.
프로세스 간의 통신 (IPC) 매커니즘에서  발생할 수 있는 취약점입니다. 민감한 정보는 IPC매커니즘을 사용하지 않아야 하며,
iOS 앱 간의 통신 시 Pasteboard 방식과 handleOpenURL 방식을 지향하며, 필요 시 openURL방식을 통해 앱 간의 통신을 해야 합니다. openURL 방식은 sourceApplication 이 명시되어 있어 제한된 앱에서만 통신할 수 있습니다.

 

 

3.9 M9: Improper Session Handling

아홉번째로 Improper Session Handling 입니다.
인증 후 세션을 부여받았을때, 한개의 세션에 한개의 모바일 디바이스가 허용되도록 해야합니다. 또한 모바일 앱 코드에서 사용자 세션을 보호해야 합니다.

아래는 올바른 세션 핸들링 입니다.
- Failure to Invalidate Sessions on the Backend: 많은 개발자들이 세션 파기시 모바일 앱에서만 세션을 파기하는데 해당 세션

   탈취 시 서버와 통신을 이어갈 수 있어 서버 측에서 또한 세션을 파기해야 합니다.
- Lack of Adequate Timeout Protection: 세션 timeout을 설정해야 합니다. 세션 timeout설정하여 악의적인 사용자가 존재하는

   세션을 탈취 시 타 사용자 권한을 획득하는 것을 막을수 있습니다.
- Failure to Properly Rotate Cookies: 인증 상태 변경 시 이전 세션에서 사용되었던 쿠키가 허용되지 않도록 파기해야 합니다.
- Insecure Token Creation: 토큰 생성시 guessing /anticipation attack 에 노출되지 않도록 개발자는 잘 적립된 암호화

   알고리즘을 통해 암호화 해야 합니다.

 


3.10 M10: Lack of Binary Protections

마지막 열번째는 Lack of Binary Protections 입니다.
금감원, 금융위 점검 시 함께 하는 애플리케이션 무결성 검증과 동일한 항목으로 바이너리 변조를 통해 보안솔루션 우회, 권한상승

등 애플리케이션 로컬에 존재하는 로직들을 공격자가 변조할 수 있게 됩니다. 변조된 애플리케이션은 서버 측에서는 해당 앱에 대해 변조된 앱인지 확인하지 않으면 정상적인 요청으로 인지하여 다양한 종류의 risk가 존재하게 됩니다.

자사에서는 보안솔루션 우회, MDM솔루션 정책 해제, 루팅 및 탈옥탐지 우회, 게임크랙 등 바이너리 변조를 이용한 시나리오 기반 점검 방법론을 통해 모바일 모의해킹을 수행하고 있습니다.

 


4. 결론
지금까지 OWASP에서 발표한 모바일 Top 10 Risk에 대해 간단하게 살펴 보았으며, 모바일 Top 10 리스크는 취약점 도출뿐만 아니라 개발 시 해당 리스트를 고려하여 개발 할 수 있도록 10가지 위협에 대한 가이드 라인이 나와있습니다.
모의해킹 시나리오는 다양하게 존재하지만, 10가지 위협에 대한 기술 및 정책 수렴을 통해 개발 혹은 취약점 도출 시 기준점을 시사할 수 있겠습니다. 자세한 내용을 살펴보려면 아래 링크를 확인해 주시길 바랍니다.
https://www.owasp.org/index.php/Projects/OWASP_Mobile_Security_Project_-_Top_Ten_Mobile_Risks

마지막으로 블로그에 간단하게 정리한 내용이 개발자 혹은 모의해킹 컨설턴트들에게 유용한 정보가 되었으면 합니다.
감사합니다.

 

 

저작자 표시 비영리 변경 금지
신고

루팅된 Android 환경에서 특정 모바일 애플리케이션을 조작하는 방법은 크게 세가지 정도로 구분할 수 있습니다.


1. ptrace() 시스템 콜 사용

2. LD_PRELOAD 환경변수 사용

3. LKM (Loadable Kernel Module) 사용


다른 방법이 더 존재할지는 모르겠지만 크게 위와 같은 맥락에서 움직이고 있는 것 같습니다.

위 방법들 중에서 오늘은 LD_PRELOAD에 대해 조금 말씀드릴까 합니다.


Android 환경에서 애플리케이션이 실행될때에는 zygote라는 프로세스에 의해 apk파일이 로드되며 실행되는데, 이러한 zygote 프로세스는 전체적으로 애플리케이션의 권한 할당이나 프로세스 생성에 관여하게 됩니다.

zygote 프로세스는 애플리케이션이 실행되는 가장 기본적인 환경이므로 init (pid 1번 프로세스) 프로세스에 의해 관리되고 있으며, init 프로세스는 zygote 프로세스가 정상적인 동작을 하지 않거나 외부환경에 의해 동작을 멈추면 즉시 재시작하도록 되어있습니다.


init 프로세스는 부팅 초기에 init.rc 파일을 읽어들여 환경설정과 함께 zygote 프로세스를 생성하도록 수행합니다.

다음은 init.rc 파일의 일부분입니다.

...

> snip <

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys

    class main

    socket zygote stream 660 root system

    onrestart write /sys/android_power/request_state wake

    onrestart write /sys/power/state on

    onrestart restart media

    onrestart restart netd

> snip <

...


zygote의 실제 실행프로그램은 /system/bin/app_process 이며, 옵션에 따라 zygote 프로세스 역할을 수행하는 것으로 보입니다.

zygote프로세스가 실행될 때 LD_PRELOAD 환경변수를 추가하여 실행되도록 하면 특정 라이브러리 함수들을 후킹하여 변조하는 기법이 존재하는데, 대부분 이를 위해 init.rc 파일을 수정하게 됩니다.

그러나 init.rc 파일을 수정하기 위해서는 boot 이미지파일의 압축해제, 수정 및 변조, 재 압축, boot 이미지파일 overwrite 등의 과정을 거쳐야 하므로, 귀찮은 작업이 될 수도 있습니다.

그래서 다른 방법이 없을까 고민해 보다가 다음과 같이 환경변수를 injection 하는 방법을 구상해보았습니다.


[그림 1] LD_PRELOAD injection


"zygote가 정상적인 실행상태가 아니면 init 프로세스에서 zygote 프로세스를 재 시작한다"는 점에 착안하여, 먼저 init 프로세스를 ptrace로 감지하면서 기존에 실행되고 있던 zygote 프로세스에 SIGKILL 시그널을 보냅니다.

그러면 zygote의 부모프로세스인 init 프로세스에서는 SIGCHLD 시그널을 받게 되고, zombie 프로세스가 되지 않도록 zygote가 사용하고 있던 리소스들을 kernel에 반환 후 zygote 프로세스의 재 시작 작업을 수행합니다.

zygote 프로세스의 재시작은 fork 시스템 콜을 수행하여 새로운 프로세스를 생성 한 후, execve 시스템 콜을 사용하여 zygote 바이너리를 실행하는 구조로 되어 있습니다.

바이너리 실행에 사용되는 execve 시스템 콜의 원형은 다음과 같습니다.


int execve(const char *filename, char *const argv[], char *const envp[]);


execve 시스템 콜의 3번째 인자가 envp라고 되어 있는데 바로 이 envp 인자가 실행되는 프로그램의 환경변수를 결정하게 됩니다.

따라서 zygote를 실행하기 위한 execve 시스템 콜 실행 직전에 LD_PRELOAD 환경변수를 injection한다면 zygote는 변조된 환경변수를 가진 상태에서 실행될 수 있습니다.

다음은 이러한 시나리오를 가지고 만든 injector 소스코드의 일부입니다.


/*

* god_daewoong.c

*

* Version: v1.0

* Date: 2014.09.10

*

* You can compile using gcc with -D option: -D_SO_PATH=\"${SO_PATH}\"

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <ctype.h>

#include <errno.h>

#include <sys/wait.h>

#include <sys/ptrace.h>

#include <linux/user.h>

#include <linux/ptrace.h>


#define EXTRA_ENVIRON   "LD_PRELOAD="_SO_PATH

#define ZYGOTE_PATH     "/system/bin/app_process"


long internal_ptrace(int, pid_t, void *, void *);

#define PTRACE(r,p,a,d) internal_ptrace(r,p,a,d)

#define SYSCALL_REGISTER(r) r.ARM_r7

#define IP_REGISTER(r) r.ARM_ip

#define RESULT_REGISTER(r) r.ARM_r0

#define ENV_REGISTER(r) r.ARM_r2


#define MAX_BUFFER_SIZE 1024

#define MAX_PROC_PID    65536


int init_pid = 1;


void sigint(int signo)

{

        fprintf(stdout, "[!] Received Ctrl+C signal.\n");

        if(init_pid != 0) {

                if(PTRACE(PTRACE_DETACH, init_pid, (void*)1, 0) < 0)

                        fprintf(stderr, "[!] PTRACE_DETACH error\n");

        }

        exit(0);

}


long internal_ptrace(int request, pid_t pid, void *addr, void *data)

{

        int ret, stat;


        errno = 0;


        while(1) {

                stat = 0;

                ret = waitpid(pid, &stat, WNOHANG);

                if((ret == pid && WIFEXITED(stat)) || (WIFSTOPPED(stat) && !WSTOPSIG(stat))) {

                        fprintf(stderr, "[!] Killed Process: %d\n", pid);

                        return -1;

                }

                if((ret = ptrace(request, pid, addr, data)) == -1) {

                        switch(request) {

                        case PTRACE_DETACH:

                        case PTRACE_SYSCALL:

                        case PTRACE_KILL:

                                return 0;

                        default:

                        break;

                        }

                } else {

                        break;

                }

        }

        return ret;

}

int doPunchLine(void)
{
        struct pt_regs regs;
        siginfo_t sig;
        int zygote_path_check = 0;
        char buf[128];
        int i, ret = -1;
        int zygote = 0;

        fprintf(stdout, "[*] Get the zygote pid..... ");
        if((zygote = get_zygote_pid()) < 0) {
                fprintf(stdout, "failed\n");
                return -1;
        }
        fprintf(stdout, "%d\n", zygote);

        if(PTRACE(PTRACE_ATTACH, init_pid, (void*)1, 0) < 0) {
                fprintf(stderr, "[!] PTRACE_ATTACH error\n");
                return -1;
        }

        fprintf(stdout, "[*] Attached the init process successfully: %d\n", init_pid);

        kill(zygote, SIGKILL);
        fprintf(stdout, "[*] Sending a SIGKILL signal to zygote\n");

        // XXX: tracing...
        while(1) {
....
> snip <
...
        }

failed:
        if(PTRACE(PTRACE_DETACH, init_pid, (void*)1, 0) < 0) {
                fprintf(stderr, "[!] PTRACE_DETACH error\n");
        }

        return ret;
}

int get_zygote_pid(void)
{
        char fname[64];
        char status[64];
        int i, zygote_pid;
        FILE *fp = NULL;

        zygote_pid = -1;

        for(i = 0; i < MAX_PROC_PID; i++) {
                snprintf(fname, sizeof(fname), "/proc/%d/status", i);
                if((fp = fopen(fname, "r")) == NULL)
                        continue;
                if(fgets(status, sizeof(status), fp) != NULL) {
                        if(strstr(status, "zygote") != NULL) {
                                zygote_pid = i;
                                fclose(fp);
                                break;
                        }
                }
                fclose(fp);
        }
        return zygote_pid;
}

int HerpoongIs0Per(int pid)
{
        void *environ, *mem, *sp, *init_sp, *data;
        int text, j, newdata, empty = 0;
        const char *add = EXTRA_ENVIRON;
        struct pt_regs regs;

        if(PTRACE(PTRACE_ATTACH, pid, (void*)1, 0) < 0) {
                fprintf(stderr, "[!] PTRACE_ATTACH error\n");
                return -1;
        }

        // XXX: Finding execve() syscall
        while(1) {
                if(PTRACE(PTRACE_GETREGS, pid, 0, &regs) < 0) {
                        fprintf(stderr, "[!] PTRACE_GETREGS error\n");
                        goto failed;
                }

                // XXX: execve() sys-call number is '11'
                if(SYSCALL_REGISTER(regs) == 11 && IP_REGISTER(regs) == 0) {
                        environ = (void*)ENV_REGISTER(regs);
                        fprintf(stdout, "[*] Environ: %p\n", environ);
                        break;
                }
                if(PTRACE(PTRACE_SYSCALL, pid, (void*)1, 0) < 0) {
                        fprintf(stderr, "[!] PTRACE_SYSCALL error\n");
                        goto failed;
                }

        }
...
> snip <
...
        if(PTRACE(PTRACE_DETACH, pid, NULL, NULL) < 0) {
                fprintf(stderr, "[!] PTRACE_DETACH error\n");
        }
failed:
        return 0;
}


int main(void)
{
        int new_zygote;

        signal(SIGINT, sigint);

        fprintf(stdout,
                "*****************************************************\n"
                "************ Android LD_PRELOAD Injector ************\n"
                "*****************************************************\n"
                "                Implemented by TeamCR@K in A3Security\n\n"
                "  Greetz to: 1ndr4, bash205, blpark, fr33p13, alrogia\n"
                "                              kgyoun4, maz3, rhaps0dy\n\n");

        if((new_zygote = doPunchLine()) != -1) {
                HerpoongIs0Per(new_zygote);
        }
        fprintf(stdout, "[*] Done\n");
        return 0;
}


악의적으로 사용될 수 있는 우려로 인해 전체 소스코드를 올리지 못하는 점 양해 부탁드립니다.

위 코드를 컴파일 하여 실행하면 다음과 같이 재시작된 zygote의 실행환경에서 특정 라이브러리가 적재되어 실행되는것을 볼 수 있습니다.


[그림 2] Injector 실행 전 zygote의 기본 환경변수


[그림 3] Injector 실행 후 재 시작된 zygote 프로세스에 적용된 LD_PRELOAD 환경변수


[그림 4] LD_PRELOAD에 의해 적재된 libopen.so 라이브러리가 정상적으로 동작한 화면


LD_PRELOAD로 로딩한 Shared Object의 소스코드는 다음과 같습니다.


/* libopen.c */

#include <stdio.h>

#include <stdlib.h>

#include <stdarg.h>

#include <unistd.h>

#include <dlfcn.h>


#define LIBC_PATH       "/system/lib/libc.so"

#define LOG_PATH        "/data/test/openhook.log"


static int (*orig_open)(const char *f, ...) = NULL;


int open(const char *f, ...)

{

        int fd = 0, flags = 0, mode = 0;

        void *dl = NULL;

        va_list args;

        FILE *fp = fopen(LOG_PATH, "a+");


        if(fp == NULL) fp = stdout;


        fprintf(fp, "[HOOK-LIB] Executed open() system call: %s\n", f);

        if((dl = dlopen(LIBC_PATH, RTLD_LAZY)) == NULL) {

                fprintf(fp, "[!] dlopen() function error.\n");

                return -1;

        }

        orig_open = dlsym(dl, "open");

        if(orig_open == NULL) {

                fprintf(fp, "[HOOK-LIB] dlsym() function error.\n");

                return -1;

        }

        va_start(args, f);

        flags = va_arg(args, int); // 2nd argument of open() syscall (flags)

        mode = va_arg(args, int); // 3rd argument of open() syscall (mode)

        va_end(args);

        if((fd = orig_open(f, flags, mode)) < 0) {

                fprintf(fp, "[HOOK-LIB] orig_open() function error: %s\n", f);

                return -1;

        }

        dlclose(dl);

        fclose(fp);

        return fd;

}


zygote 프로세스가 실행되는 시점에 환경변수를 추가하여 실행하는 형태의 인젝션 방식은 init.rc 파일을 손상시킬 우려가 없으며, 모바일 기기를 재시작하면 본래의 시스템 환경으로 동작하게 됩니다.

injector의 Full Source code를 올려드리지는 못하지만 특정 환경변수를 추가하여 zygote를 실행하도록 되어 있는 pre-compiled binary를 대신 올려드립니다.


god_daewoong-poc


위 바이너리를 실행하면 다음과 같이 특정이름의 환경변수가 추가되어 동작하는 zygote를 확인 하실 수 있습니다.


[그림 5] 테스트 injector 동작 화면


본 injector 프로그램은 루팅된 Android 버전에서 테스트 되었으며, 다음과 같은 디바이스 정보를 가진 기기에서 테스트 되었습니다.


[그림 6] 테스트 환경


감사합니다.

저작자 표시 비영리 변경 금지
신고

지난 9월 4일 목요일 저희 회사인 에이쓰리시큐리티에서 보안 전략 세미나 SMS 2014를 진행하였습니다.

너무나 많은 분들이 자리를 빛내주신 점에 대해 이 자리를 빌어 다시 한번 감사의 말씀을 드리고자 합니다.


저희 TeamCR@K에서는 "모바일 금융거래 애플리케이션의 보안대책 우회 기법"이라는 주제로 시연을 진행했었고, 이에 대해 기술적인 부분에서 조금 더 많은 내용을 공유해 볼까 합니다.


시연의 주제는 모바일 애플리케이션의 실행 흐름 조작을 통한 보안대책들을 우회하는 기법으로써 다음과 같은 내용을 준비하였습니다.


[그림 1] 임의의 시스템 콜을 사용한 모바일 앱 실행 플로우 변조



[그림 2] 임의의 함수 후킹을 통한 모바일 앱 실행 플로우 변조


임의의 시스템 콜을 사용하는 방법은 ptrace() 시스템 콜을 사용하여 특정 시스템 콜의 실행 전 인자 정보 조작이나 실행 후 반환 값 조작을 통해 모바일 앱 실행에 조작을 가하는 방법을 의미합니다.

임의의 함수 후킹을 통한 방법으로는 LD_PRELOAD 환경 변수를 init 프로세스에 적용하여 특정 라이브러리의 함수 로직에 대해 조작을 가하는 방법입니다.

일반적으로 시스템 콜이라는 단어와 함수라는 단어를 혼재하여 사용하기도 하지만 개인적으로 시스템 콜이란 kernel에 직접 interrupt를 일으키는 구조이고 함수라는건 그보다 상위에 포진되어 라이브러리 형태로 존재하는 형태라고 생각하기에 구분지어 이야기 하도록 하겠습니다. 양해 부탁드립니다.


LD_PRELOAD에 대해서는 별도의 Shared Object를 제작하고 SSL-Strip을 구현하는 방법으로 시연하였습니다.

해당 환경변수를 이용한 프로그램 실행 로직의 조작방법은 이미 많이 알려져 있기에 별도로 추가적인 내용은 말씀드리도록 하지 않겠습니다.


ptrace() 시스템 콜을 사용하는 공격 기법의 경우 처음에는 "프로그램 및 디바이스 변조 탐지"를 우회하기 위한 목적으로 진행했던 내부 프로젝트였습니다.

그러나 시간이 흐르고 점점 프로젝트의 성향도 많은 케이스의 우회 방안을 포함하다 보니 툴 제작까지 하게 되었습니다.

아래는 해당 툴의 실행 모습입니다.


[그림 3] 안드로이드 애플리케이션 실행 변조 툴 (A.K.A ardb)


프로젝트 시작점 자체가 "프로그램 및 디바이스 변조 탐지"를 우회하기 위한 목적으로 시작되어서 툴 이름도 "Android Rooting Detection By Pass Tool" 입니다.

툴은 -p 옵션과 -f 옵션을 사용하도록 되어 있습니다.

-p 옵션은 package 이름을 인자로 받게 되며, -f 옵션은 일반 console 상에서 실행 할 프로그램 경로 정보를 인자로 받게 됩니다.

위의 경우 com.testbank 프로그램이 실행되면 이를 추적하고, fork() 시스템 콜 실행을 탐지하여 그 결과 값을 -1로 조작하도록 한 화면입니다.

루팅 탐지 케이스의 경우 특정 경로의 파일이 존재하거나 실행되는 경우를 루팅되었다고 판별하기도 하고, 탐지 루틴을 Shared Object 안에 구현 후 해당 Object의 내부 함수를 실행하여 판별하기도 합니다.

저희가 모의해킹 할 때에 이러한 여러 케이스들에 대항하기 위해 아예 변조시킬 Rule을 설정파일로 만들어 관리하기로 하였습니다.

다음은 설정파일의 내용입니다.


[그림 4] 툴 설정파일

설정파일의 지시자는 FUNCTION과 VETO 두 가지가 존재합니다.

FUNCTION 지시자의 경우 시스템 콜을 기준으로 변조 여부를 결정하며, VETO 지시자의 경우 문자열을 기준으로 처리합니다.

우선 첫번째 FUNCTION 지시자 설정은 fork 시스템 콜 실행 후  결과 레지스터를 -1로 변경한다  는 설정이고, 두번째 FUNCTION 지시자의 경우, execve 시스템 콜 실행 전 첫번째 인자의 주소값을 변경한다 는 설정입니다.

VETO 지시자의 경우는 인자 값에 /system/xbin/su 문자열을 예외처리 하는 내용들로 되어 있습니다.

앞으로 더 많은 모바일 애플리케이션 케이스를 진단하다 보면 Rule도 지속적으로 늘어 날 것 같습니다.

다음은 실행하며 남기는 로그 화면입니다.


[그림 5] 로그파일의 내용


툴을 실행할 때의 콘솔화면에서는 간략하게 탐지 된 내용만 출력되게 하고 실제 탐지되는 모든 내용은 로그파일에 남도록 구현하였습니다.

로깅 루틴을 구현하다 보니 strace 개발자가 존경스러워 집니다.

본 툴은 기본적으로 zygote 프로세스에서 fork() 시스템 콜을 지속적으로 추적하도록 되어있는데, 아래와 같은 형태로 구현이 되어 있습니다.


/*

* - Name: Zygote_Trace.c

* - Date: 2014.09.06

* Implemented by TeamCR@K in A3Security

*/

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <ctype.h>

#include <errno.h>

#include <getopt.h>

#include <sys/wait.h>

#include <sys/ptrace.h>

#include <linux/user.h>

#include <linux/ptrace.h>


long internal_ptrace(int, pid_t, void *, void *);


#define ZYGOTE_NAME     "zygote"

#define MAX_PROC_PID    65536

#define PTRACE(r,p,a,d) internal_ptrace(r,p,a,d)

#define SYSCALL_REGISTER(r) r.ARM_r7

#define IP_REGISTER(r) r.ARM_ip

#define RESULT_REGISTER(r) r.ARM_r0


int zygote_pid;


void sigint(int signo)

{

        fprintf(stdout, "[!] Received INTERRUPT signal.\n");

        if(zygote_pid != 0) {

                if(PTRACE(PTRACE_DETACH, zygote_pid, (void*)1, 0) < 0)

                        fprintf(stderr, "[!] PTRACE_DETACH error\n");

        }

        exit(0);

}


int get_zygote_pid(void)

{

        char fname[64];

        char status[64];

        int i;

        FILE *fp = NULL;


        zygote_pid = -1;


        for(i = 0; i < MAX_PROC_PID; i++) {

                snprintf(fname, sizeof(fname), "/proc/%d/status", i);

                if((fp = fopen(fname, "r")) == NULL)

                        continue;

                if(fgets(status, sizeof(status), fp) != NULL) {

                        if(strstr(status, ZYGOTE_NAME) != NULL) {

                                zygote_pid = i;

                                fclose(fp);

                                break;

                        }

                }

                fclose(fp);

        }

        return zygote_pid;

}


long internal_ptrace(int request, pid_t pid, void *addr, void *data)

{

        int ret, stat;


        errno = 0;


        while(1) {

                ret = waitpid(pid, &stat, WNOHANG|WUNTRACED);

                if((ret == pid && WIFEXITED(stat)) || (WIFSTOPPED(stat) && !WSTOPSIG(stat))) {

                        fprintf(stderr, "[!] Killed Process: %d\n", pid);

                        return -1;

                }

                if((ret = ptrace(request, pid, addr, data)) == -1) {

                        switch(request) {

                        case PTRACE_DETACH:

                        case PTRACE_SYSCALL:

                        case PTRACE_KILL:

                                return 0;

                        default:

                        break;

                        }

                } else {

                        break;

                }

        }

        return ret;

}


int do_trace_zygote(void)

{

        struct pt_regs regs;


        if(PTRACE(PTRACE_ATTACH, zygote_pid, (void*)1, 0) < 0) {

                fprintf(stderr, "[!] PTRACE_ATTACH error\n");

                return -1;

        }


        fprintf(stdout, "[*] Attached the zygote process successfully: %d\n", zygote_pid);


        // XXX: tracing...

        while(1) {

                if(PTRACE(PTRACE_GETREGS, zygote_pid, 0, &regs) < 0) {

                        fprintf(stderr, "[!] PTRACE_GETREGS error\n");

                        goto failed;

                }


                // XXX: fork()'s system call number is '2'

                if(SYSCALL_REGISTER(regs) == 2 && IP_REGISTER(regs) == 1) {

                        fprintf(stdout, "[*] Created a new process from zygote successfully: %ld\n", RESULT_REGISTER(regs));

                }

                if(PTRACE(PTRACE_SYSCALL, zygote_pid, (void*)1, 0) < 0) {

                        fprintf(stderr, "[!] PTRACE_SYSCALL error\n");

                        goto failed;

                }

        }


failed:

        if(PTRACE(PTRACE_DETACH, zygote_pid, (void*)1, 0) < 0) {

                fprintf(stderr, "[!] PTRACE_DETACH error\n");

        }


        return -1; // it always return -1

}


int main(void)

{

        signal(SIGINT, sigint);


        fprintf(stdout, "[- ZYGOTE TRACING -]\n");

        if(get_zygote_pid() < 0) {

                fprintf(stderr, "[!] Could not find process id of zygote\n");

                return -1;

        }

        do_trace_zygote();

        fprintf(stdout, "[*] Done\n");

        return 0;

}


위 소스코드를 컴파일 한 후 실행하면 아래와 같이 zygote에서 fork 되는 프로세스 정보를 실시간으로 얻어올 수 있습니다.


[그림 6] Zygote에서 실행되는 fork를 실시간으로 탐지하는 예제 프로그램


처음 "루팅 탐지 우회"에서 출발한 툴 제작이 조금 비대해진 느낌입니다.

GCC가 GNU C Compiler 였다가 이제는 GNU Compiler Collection이라고 명칭을 바꾼 것 처럼 이제는 저희가 제작한 툴 이름도 바꿔야 될 것 같기도 합니다....

이상 안드로이드 스마트 폰 삽질기였습니다..


읽어주셔서 감사합니다..

저작자 표시 비영리 변경 금지
신고

모바일 모의해킹 프로젝트 수행 중 안드로이드 메모리에 민감한 정보 평문 저장여부를 확인하기 위해 필요한 어플리케이션을 제작하였습니다. 점검 시 유용하게 사용하시길 바라며 아래와 같이 공유합니다.


버전: beta

빌드날짜: 2013. 9. 11

파일크기: 258KB

MD5: d0736e78ec7affb0ab5d89aca233fcd8


Memory_Dump.apk



사용법

 

해당 어플리케이션을 사용하기 위해서는 우선적으로 루팅되어 있는 스마트폰에서 실행해야 합니다. 


제작 당시 jni로 구성하지 않고 binary execute로 제작하여 어플리케이션 실행시 지속적으로 권한을 요청하는 단점이 있습니다.

superuser 어플리케이션에서 설정 > 보안 > 자동응답 > 허가 로 변경하여 사용하면 자동으로 권한을 부여 받아 사용할 수 있습니다.


    

<그림1> 루트권한 요청 변경




   

<그림2> 자동응답 설정 변경



위와 같이 루트권한을 설정 후 첨부된 어플리케이션을 설치 후 실행합니다.


   

<그림3> 어플리케이션 실행





Attach 버튼을 눌러 실행중인 프로세스에 Attach 합니다.


   

<그림4> 프로세스 Attach




Maps 버튼을 누른 후 덤프할 메모리 영역을 선택합니다.


    

<그림5> 덤프할 메모리 영역 선택



덤프 전 선택된 메모리 영역을 메모리 뷰 버튼을 통해 볼 수 있습니다.


<그림6> 선택된 영역 메모리 뷰



메모리 덤프된 파일이 저장될 위치를 선택합니다. 현재 에러로 새폴더가 생성되지 않습니다. 추후에 수정예정입니다.


   

<그림7> 덤프 후 저장될 디렉터리 경로 설정



디렉터리 선택 후 Memory Dump 버튼을 눌러 덤프를 실행 합니다.


   

<그림8> 선택된 디렉터리에 덤프파일 저장




저장된 파일은 선택된 폴더에 PID_시작주소-끝주소 형식으로 저장됩니다.

해당 파일을 PC에서 다운로드로 핵사에디터로 확인합니다.


<그림9> 덤프파일 확인




메모리 영역에 문자열 검색을 위해 테스트 어플리케이션을 생성하여 살펴보겠습니다.


   

<그림10> 테스트 어플리케이션 실행




Attach 버튼을 눌러 PID를 선택 후 Maps 버튼을 눌러 덤프 주소값을 설정합니다.

이때, RW Select  버튼을 눌러 쓰기권한이 존재하는 부분만 선택하여 해당 주소의 메모리 값을 덤프합니다.


    

<그림11> PID, 주소값 선택




저장될 폴더를 선택후 Memory Dump 버튼을 눌러 메모리 덤프를 합니다.

해당 테스트 어플은 75메가 정도의 크기 덤프파일이 생성되었으며 2~3분 정도 시간이 경과된 후 완료 되었습니다.




    

<그림12> 메모리 덤프파일 생성



저장된 파일을 PC에 옮겨 살펴봅니다.


<그림13> 덤프파일 생성 확인





grep 명령어를 이용하여 파일들의 문자열을 검색합니다.


<그림14> 문자열 검색


7744_0000b000-00252000 파일에 검색된 문자열이 존재하는 것을 확인 할 수 있습니다.

핵사 에디터로 메모리 영역에 저장되어 있는 문자열을 확인 할 수 있습니다.

<그림15> 문자열 확인



메모리 덤프 시 새로운 어플리케이션 메모리 덤프할 경우 어플리케이션을 종료후 다시 실행해야 에러나지 않습니다.

주소 받아오는 부분에서 새로운 PID 선택시 배열을 초기화하지 않해서 그런듯 싶습니다. 추가적으로 시간이 주어진다면 개선하여 블로그에 올리도록 하겠습니다.


어플이 허접하다며 아이콘 만들어준 하모군에게 감사하며(흰화면에 기본아이콘이였음) 포스팅을 마치겠습니다.

감사합니다.






저작자 표시 비영리 변경 금지
신고

Online Analyzers 

Sandroid : http://sanddroid.xjtu.edu.cn/

 

Sandroid는 온라인을 이용한 안드로이드 APK 파일 분석을 해주는 사이트로 APK 파일 업로드 안에 정적 동적 분석 보고서를 리포트해 줍니다.


정적 분석 항목

· 권한 분석(Permission Analysis)

· 구성 요소 분석(Component Analysis)

· 악성 코드 탐지(Malware Detection)

· 카테고리별 분류(Classification Analysis)


동적 분석 항목

· 응용프로그램이 실행되는 동안 파일 작업, 네트워크 행동, 개인정보 노출 등의 동적 행동들을 모니터링하여 분석

 

1. Sandroid를 이용한 APK 파일 분석


분석할 안드로이드 APK 파일을 추출하여 Sandroid 웹 페이지(http://sanddroid.xjtu.edu.cn/)를 통해 해당 파일을 업로드 시도합니다. 분석 결과를 메일로 받기 위해서 메일 주소를 포함시킵니다.

[그림 1] 분석할 APK 파일 업로드

 


파일 업로드 완료 , 완료 메시지를 확인 가능하며 FileMD5 값을 확인할 있습니다.

[그림 2] 업로드 성공 확인

 


, 분석 결과 URL 포함한 메일을 수신할 있습니다.

[그림 3] 분석 결과 URL 확인

 


분석 결과를 통해 일반적인 정보의 확인과 정적 동석 분석 결과를 확인할 있습니다.

[그림 4] 일반적인 정보 정적, 동적 분석 결과 확인

 


정적 분석 항목 Activity Services 정보, 권한 분석(Permission Analysis) 등을 확인할 있습니다.

[그림 5] Activity Services 정보, 권한 분석 확인

 


권한 분석(Permission Analysis) 경우 APK 파일을 apktool 이용한 Decoding , AndroidManifest.xml 파일 상의 권한 확인 결과 동일함을 확인할 있습니다.

[그림 6] AndroidManifest.xml 권한 확인

 


사용중인 API 정보, 포함하고 있는 URL 정보 등을 확인할 있습니다.

[그림 7] API, URL 정보 확인



API 포함하는 URL 경우 dex2jar 이용한 .dex 파일의 .jar 파일로의 변환 jd-gui 이용한 .jar 파일의 .class 파일을 .java Decompile 결과 동일한 URL 찾을 있음을 확인할 있습니다.

[그림 8] Decompile URL 정보 확인

 

Sandroid에서 지원하는 분석 항목 모바일 어플리케이션 점검 기준이 되는 권한 분석을 통한 불필요한 권한 부여 여부, 중요 정보 노출과 관련해 특정 문자열 검증 부분을 지원해 줌 확인 가능합니다. 또한, Activity, Services, 사용중인 API 정보를 통해 해당 APK 파일 분석에 있어 유용한 정보를 가져올 있습니다.

 


2. Online Analyzers 사이트


·  AMAT (http://dunkelheit.com.br/amat/analysis/index_en.php)

·  Anadroid (http://pegasus.cs.utah.edu:8080/) - static analysis

·  AndroTotal (http://andrototal.org/) - AV scanning

·  Comdroid (http://www.comdroid.org/)

·  CopperDroid (http://copperdroid.isg.rhul.ac.uk/copperdroid)

·  Dexter (https://dexter.bluebox.com/) - static analysis

·  Mobile-Sandbox23 (http://mobile-sandbox.com)

·  Stowaway http://www.android-permissions.org/

·  App360scan http://www.app360scan.com/

 


3. 참고 자료


·  http://ashishb.net/security/android-security-related-tools/

저작자 표시 비영리 변경 금지
신고

Android Device를 이용한 동적 디버깅

스마트폰 2013.04.26 04:23 Posted by TEAMCR@K

본 문서는 Android APK 파일을 Device에서 동적 디버깅 방법에 대해 작성 하였습니다.

안드로이드 기반 동적 디버깅 환경 구축(emulator): http://teamcrak.tistory.com/342

 

테스트 환경은 아래와 같습니다.

  • OS: Window 7
  • Java version: jdk6
  • APKTools: 1.4.1
  • NetBeans IDE: 7.3
  • APK Sign tool
  • Galaxy S2

APKTool 1.4.1 버전 사용 이슈

APK Tool 1.4.1 이상 버전부터 디버그모드(-d) 일 때 java파일이 생성되지 않아 동적 디버깅을 할 수 없다고 합니다.

http://i5on9i.blogspot.kr/2012/10/smali-apk-debugger.html

 

우선 APKTool 1.4.1 다운로드 합니다.

APKTool 1.4.1: https://android-apktool.googlecode.com/files/apktool1.4.1.tar.bz2

기존 APKTool을 사용하고 있었다면 다음경로의 파일을 삭제해야 에러가 발생하지 않습니다.

C:\Users\<USER_NAME>\apktool\framework\1.apk

다운로드 후 디버깅옵션으로 smali code를 생성합니다.

apktool.bat d –d <file>.apk

[그림1] APKTool 을 이용한 smali code 생성

 

AndroidManifest.xml 파일에서 아래 항목을 추가해줍니다.

Android:debuggable="true" //디버깅 허용

-------------------------------------------------------------------------------------------------------

<intent -filter="-filter">

<action android:name="android.intent.action.MAIN">

// 테스크의 첫 액티비티로 액티비티를 시작한다.

<category android:name="android.intent.category.LAUNCHER">

//액티비티가 어플리케이션의 런처에 표시되고 테스크의 첫 액티비티가 될 수 있다.

</intent>

 

[그림2] AndroidManifest.xml 패치

 

추가 및 패치하기 전 DDMS 화면을 보면 attach 할 수 있는 프로세스가 없습니다.

[그림3] attach 프로세스 유무 확인

 

다시 apktool로 패키징 후 코드사인 합니다.

[그림4] 패치후 리패키징

 

패치 된 APK 설치 전 디바이스에서 환경설정 > 개발자 옵션 > USB디버깅 체크해줍니다.

[그림5] USB 디버깅 모드

 

어플리케이션 설치 후 연결된 디바이스에서 attach 할 수 있는 프로세스를 확인할 수 있습니다.

[그림6] 접근 가능한 프로세스 확인

 

NetBeans 7.3 버전들 다운로드 후 설치합니다.

NetBeans Download: https://netbeans.org/downloads/

NetBeans 설정은 다음과 같이 진행합니다.

[그림7] 새 프로젝트 작성

 

[그림8] 프로젝트 위치 지정

 

APKTool 1.4.1 로 디코딩 한 smali 경로를 설정해 줍니다.

[그림9] smali code 위치 설정

 

[그림10] API Level에 맞춰 라이브러리를 설정

 

[그림11] API Level에 맞춰 라이브러리 추가

 

[그림12] 테스트로 작성된 어플리케이션 실행

 

Debug > Attach Debugger 를 선택합니다.

[그림13] Attach Debugger

 

[그림14] 호스트, 포트 입력

 

Attach 에 성공하면 형광색 아이콘이 생겨 디바이스에서 디버깅을 시작할 수 있습니다.

[그림15] 디버깅 시작

 

지금까지 디버깅 환경 설정을 살펴보았습니다.

이제부터 실제로 디버깅을 시작하기 위해 어플리케이션 실행 시부터 디버깅 할 수 있는 방법에 대해 알아보겠습니다.

디버깅을 어플리케이션이 시작과 동시에 하기 위해서 smali code에서 onCreate 메소드 호출 시 'invoke-static {}, Landroid/os/Debug;->waitForDebugger()V' 를 삽입해 줍니다.

[그림16] 디버깅 대기를 위한 코드패치

 

코드 패치 + 리패키징 + 코드사인 후 어플리케이션을 설치합니다.

어플리케이션을 실행하게 되면 DDMS 에서 붉은색 아이콘이 생성되며 attach 전까지 대기하게 됩니다.

[그림17] 디버깅 대기

 

[그림18] 디버깅 전 화면

 

NETBeans에서 attach 하기 전 ctrl+shift+F8 단축키를 눌러 bp를 설정합니다.

[그림19] break point 설정

 

Attach 시 debugging wait 에서 벗어나 호출된 함수에서 break point 가 걸리게 됩니다.

[그림20] break point 지점 확인

 

[그림21] 라인별로 smali code, java code를 보며 디버깅을 시작

 

[그림22] 어플리케이션 시작

 

버튼 이벤트 발생 시 break point를 설정하여 디버깅 할 수 있습니다.

Ctrl+shift+F8 단축키를 이용하여 break point 지점을 설정합니다.

[그림23] 버튼 이벤트 메소드 확인

 

[그림24] 버튼 이벤트 동작

 

[그림25] 동작 지점 확인

 

[그림26] 디버깅 메뉴를 이용하여 분석

 

이상으로 디바이스에서 APK 동적 디버깅 환경을 살펴 보았습니다.

 

마지막으로 APK 동적 디버깅 순서 정리하면 아래와 같습니다.

  1. APKTool을 이용한 디코딩 (Apktool d –d <file>.apk)
  2. Device 설정(USB디버깅 모드) 및AndroidManifest.xml 수정
  3. MainActivity에 debugging wait 함수 추가
  4. 어플리케이션 리패키징 및 코드사인 후 설치
  5. NETBeans설정 후 호출되는 Method break point 설정
  6. Attach Debug 후 디버깅을 시작

 

 

참고자료

http://d-kovalenko.blogspot.kr/2012/08/breakpoints-in-smali-code.html

http://d-kovalenko.blogspot.kr/2012/08/debugging-smali-code-with-apk-tool-and.html

http://dztall.blogspot.kr/2011/01/blog-post.html

http://i5on9i.blogspot.kr/2012/10/smali-apk-debugger.html

http://code.google.com/p/android-apktool/issues/detail?id=339

 

신고

 

    

얼마 전 TeamCR@K 팀원 스마트폰으로 한 통의 문자 메시지가 왔습니다.

누가 봐도 문자 메시지 피싱(SMS phsing, 스미싱) 공격이라는 것을 알 수 있는 쿠폰 문자 메시지가 한 통 도착 하였습니다.

          

[그림1] 스미싱 공격 문자메시지 수신

 

URL을 접속하면 해당 apk 파일을 다운로드 하게 됩니다.

 

해당 apk 파일을 APKinspector를 이용하여 어떤 동작을 하는지 살펴보도록 하겠습니다.

APKinspector는 python으로 작성된 The Honeynet Project중 하나인 GUI 툴입니다.

APKinspector Download: https://github.com/honeynet/apkinspector/

우선 설치를 위해서 Ubuntu 11.10 버전을 설치합니다.

[그림2] 설치 시 버전 요구

 

Ubuntu 11.10에서 APKinspector를 다운로드 후 install.sh로 필요한 python 패키지를 설치합니다.

[그림3] 패키지 설치

 

APKinspector 실행 시 다음과 같은 에러메시지를 볼 수 있습니다.

$ python startQT.py

Traceback (most recent call last):

File "startQT.py", line 18, in <module>

from GetMethods import *

File "/home/dev/Desktop/apkinspector/GetMethods.py", line 20, in <module>

import androguard, analysis, androlyze

File "/home/dev/Desktop/apkinspector/androguard/androlyze.py", line 35, in <module>

import IPython.ipapi

ImportError: No module named ipapi

 

iPython 패키지가 업데이트 되면서 모듈위치가 바뀌어서 위와 같은 에러메시지가 나오게 됩니다.

버전에 맞도록 아래 사이트에서 iPython 모듈을 다운로드 후 설치합니다.

iPython Download: http://archive.ipython.org/release/0.10.2/

 

설치가 완료되었다면 python startQT.py 를 실행하여 APKinspector를 실행합니다.

[그림4] 악성 어플리케이션 오픈

 

[그림5] 디바이스 권한 확인

프로그램 실행 시 해당 어플리케이션이 문자메시지 권한을 요청하는 경고 창을 볼 수 있습니다.

통화핸들링 접근이나 혹은 녹음기능 권한을 요청하는 어플리케이션을 불러올 시 같은 경고 창을 볼 수 있습니다.


[그림6] Proguard 난독화 적용 확인

Proguard 적용으로 난독화 되어있는 것을 확인할 수 있습니다.

원하는 메소드를 더블클릭 하게 되면 그래픽컬한 화면을 볼 수 있습니다.


[그림7] CFG 확인

Dalvik byte code단위로 흐름도를 한눈에 볼 수 있습니다.

해당 코드를 선택 후 Space bar를 누르면 Dalvik byte code로 이동하게 됩니다.


[그림8] Dalvik byte code 확인

반대로 오른쪽 마우스버튼으로 goto CFG 메뉴로 흐름도를 볼 수 있습니다.


[그림8] Permission 확인

주요 권한을 요청 시 어느 Method에서 호출하는지 확인 할 수 있습니다.


[그림9] 어플리케이션 설치 시 권한 확인

어플리케이션 설치 시 요청하는 권한들을 살펴보면 다음과 같습니다.

주요 요청 권한을 살펴보면 스마트폰 시작 시 백그라운드 서비스로 동작되며 문자 메시지 전송, 확인 등 해당 어플리케이션에서 사용하는 권한들은 아래 사이트에서 살펴 볼 수 있습니다.

권한확인: http://developer.android.com/reference/android/Manifest.permission.html

 

어플리케이션의 동작을 smali 코드 단위로 살펴보면 유포자의 서버를 확인 할 수 있습니다.

[그림10] smali code 확인

 

전송되는 서버 주소를 확인 할 수 있습니다.

[그림11] 서버주소 확인


현재 해당 서버가 운영 중에 있음을 확인하였습니다.

[그림12] 서버주소 decoding

 

토르 브라우저를 이용하여 해당 서버를 접속하였습니다.

[그림13] 공격자 서버 접속

 

이상 APKinspector 를 이용하여 APK 동작부분을 간단히 살펴 보았습니다.

APKinspector를 이용하여 악성 어플리케이션으로 의심되는 어플리케이션의 동작을 간단하게 살펴 볼 수 있습니다.

 

신고

모바일 서비스 보안 위협 시나리오

스마트폰 2012.04.04 16:34 Posted by TEAMCR@K

스마트폰 사용자가 2000만명을 돌파한 가운데, 이를통한 서비스 뿐만아니라 서비스 이용 사용자가 빠르게 증가하고 있습니다.
사용자 증가 및 편리성으로 인하여 보안 위협이 더욱 높아지고 있으며 이에 따라 많은 연구자들이 보안 위협에 따른 취약점을 연구하고 있습니다.

저희 또한 연구를 꾸준히 진행하고 있으며, 모바일 서비스에 대한 기본적으로 발생가능한 취약점 진단을 실시하고 있습니다.

모바일 서비스의 취약점이 발생할 수 있는 부분은 다음과 같이 분류 됩니다.

 

모바일 디바이스

모바일 서비스(서버)

모바일 서비스 어플리케이션(클라이언트)

 

기본적으로 웹 서비스의 성격을 띄며 어플리케이션의 경우 정보조회 입력 수정 삭제등의 기능을 수행합니다.
이를 통해서 취약점 진단을 할수 있는 항목은 다음과 같습니다.

 

모바일

디바이스

권한 상승 디바이스에서 어플리케이션 실행 여부 점검

모바일

서비스

사용자 정보 평문전송 점검

사용자 인증 정보 우회 가능성 점검

입력 검증 미흡

모바일

어플리케이션

모바일 어플리케이션 무결성 검증 (어플리케이션 위변조)

어플리케이션 구동 사용자 입력 값으로 인한 비정상 작동 행위 가능성 검증

어플리케이션 설정파일, 로컬 리소스 등에서 중요 정보 노출 가능성 검증

 

그중 하나인 모바일 어플리케이션 무결성 검증에 대한 위협 시나리오 및 동영상을 제작하였으며, 본 동영상의 화면 및 서버 환경은 실제서비스와는 무관함을 알려드립니다.

시나리오 : 배포중인 어플리케이션 변조를 통한 사용자 개인정보 노출(도청)
1. 타겟 어플리케이션 설정 및 다운로드
2. 어플리케이션 변조 후 배포
3. 피해자 어플케이션 설치, 도청을 통한 개인 정보 유출


 

 

저작자 표시 비영리 변경 금지
신고