[External Post] Android Logcat Security

원본 Post : [Drop] Android Logcat Security

본 Post는 원본 Post의 내용을 직접 번역/테스트/버그 수정한 글로 컨텐츠에 대한 저작권은 원본 Post의 저자에게 있습니다.
※ 오역을 알려주시면 확인 후 수정하겠습니다. 
※ 안드로이드 분석에 도움이 되시길 바랍니다. 

0x00 Background Knowledge

개발 버전 : 모든 디버깅 정보를 로그로 남기기 위한 내부 테스트용 베타 버전
공개 버전 : 제한적인 디버깅 정보를 로그로 남기기 위한 사용자 버전
Android.util.Log : 5개의 Export 함수 제공


Android Permission READ_LOG : Log를 읽기 위한 Permission. App 로그는 Android 4.1 이상 버전에서는 READ_LOG Permission을 통해 요청시 접근할 수 있다. 그러나 Google은 Android 4.1이상에서 READ_LOG Permission으로 App 로그에 접근하지 못하는 보안 취약점을 발견했다. Logcat의 Signature가 Android 4.1에서 signature | system | development 로 변경되었다. 이 Signature는 시스템 서명이된 App이나 Root Permission App만 Log에 접근할 수 있음을 의미한다. 보통의 사용자는 ADB를 통해서 모든 로그를 볼 수 있다. 

0x01 test

테스트 방법은 매우 단순하다. SDK에서 제공하는 Monitor나 ADT에서 제공하는 logcat과 같은 툴을 사용한다. 이러한 툴의 디렉토리를 환경변수에 등록하면 더 쉽게 사용할 수 있다. 물론, ADB의 Logcat을 사용하는게 가장 좋다. 
Android 로그는 많은 양의 정보를 포함하고 있어서 관계없는 부분을 필터링할 필요가 있다. 필터는 정규표현식을 지원하므로 password, token, email과 같은 키워드 매칭이 가능하다. 우선 자동 수집툴을 만들었다. 그러나 별도움이 되지 않아 본래의 생각은 포가하고 적당한 logcat을 사용했다. 


[ 실습 ]

ps로 확인해 본 결과 pid 512는 system 프로세스로 system_server이다. 

분명히, 다른 옵션은 직접 전화를 logcat으로 캡쳐하도록 되어 있다. 그러나 위의 결과처럼, App 로그는 반환하지 않았고 심지어 Android 4.1 이후 manifest.xml에 다음과 같은 요청이 추가되었다.

다시말해, 만약 Root Permission이라면, logcat에 접근하기 쉽다. 다른 말로, Google은 Android 4.1 이후 logcat 취약점을 해결하지 않았다는 것을 의미한다. 

0x02 smali injected logcat

이 글 (http://drops.wooyun.org/tips/2986)에서는 logcat에 Inject하기 위해 smali를 이용해 암호화되기 이전의 중요한 정보를 출력해 주는 것을 볼 수 있다. smali inject를 위해 APK를 사용하는 것은 매우 쉽다. 그러나 레지스터를 추가하는 방식은 로직을 훼손하기 때문에 추천하지 않는다. 가장 좋은 방법은 기존의 레지스터를 사용하는 것이다. 
invoke-static {v0, v0}, Landroid/util/Log;->e(Ljava/lang/String; Ljava/lang/String;)I



0x03 Recommendations

사람들은 공개버전에서는 Log를 출력할 수 없다고 생각한다. 그러나 App의 에러를 수집하거나 이상을 피드백 받기 위해 로그 출력은 필수적이다. 그래서 보안 인코딩 스키마를 통해 제공해 문제점을 제어할 수 있다. 

Log.e( ) in/w( )/i( ) : 동작을 출력하기 위해 추천한다. 
Log.d( ) / v( ) : 개발중 로그를 출력하기 위해 추천한다. 

1. Log.e( ) / w( ) / i( ) 대신에 System.out/err를 통해 중요 정보를 출력한다. 
2. Log.d( ) / v( )를 사용해 중요 정보를 출력한다. 
( 사전 작업 : 공개 버전은 제거해야 된다. )

3. Log.d( ) / v( )의 결과값은 사용하지 않는다. ( 개발시 디버깅을 위해서만 사용 )

4. 공개 버전 App은 Log.d( ) / v( ) 코드를 제거한다. 

이클립스에서 ProGuard를 설정한다. 

개발자 버전에서는 모든 로그를 볼 수 있다. 

ProGaurd의 공개 버전은 d/v 로그를 제거했다. 

컴파일러로 확인해 보면, 로그는 제거되었다. 

5. APK 파일은 공개버전이다. 

0x04 Native Code

Android.util.Log의 생성자는 Private이고 Instance가 아니다. 따라서 static property 와 method만 사용할 수 있다. 그러나 Android.util.log는 log.Log.v( ) / Log.d( ) / Log.i( ) / Log.w( ) / Log.e( ) 를 위해 Native Code에서 println_native( )를 사용한다. 

Log.e( String tag, String msg )

println_native( LOG_ID_MAIN, VERBOSE, tag, msg )

write_to_log는 다시 __Android_log_bug_write( )를 호출한다. 

결국 println_native( )는 장치 파일을 열고 데이터를 작성하는 것이다. 


0x05 Something else

1. 이상 Object를 출력하기 위해 Log.d( ) / v( )를 사용한다. ( 예를 들어, SQLiteException은 SQL Injection 문제를 발생시킬 수 있다. )
2. 로그를 출력하기 위해서 android.util.Log 클래스를 사용한다. System.out/err은 추천하지 않는다. 
3. BuildConfig.DEBUG ADT의 버전은 21이상이다.
공개 버전에서는 False로 설정되어 있다. 
4. Activity를 시작할 때, ActivityManager는 다음과 같은 정보를 보여준다. 
     - 대상 패키지 이름
     - 대상 클래스 이름
     - Intent.setData(URL)

5. Exception.printStackTrace( )를 사용하는 것과 같은 연관 정보는 System.out/err를 사용하지 않아도 출력된다. 
6. ProGuard는 다음의 로그를 제거할 수 없다. ("result:" + value )\
7. sdcard에 로그를 저장할 경우 모두 읽을 수 있게 된다.

0x06 Wooyun Cases


0x07 log tools


0x08 reference

http://www.jssec.org/dl/android_securecoding_en.pdf
http://source.android.com/source/code-style.html#log-sparingly
http://developer.android.com/intl/zh-cn/reference/android/util/Log.html
http://developer.android.com/intl/zh-cn/tools/debugging/debugging-log.html
http://developer.android.com/intl/zh-cn/tools/help/proguard.html
https://www.securecoding.cert.org/confluence/display/java/DRD04-J.+Do+not+log+sensitive+information
https://android.googlesource.com/platform/frameworks/base.git/+/android-4.2.2_r1/core/jni/android_util_Log.cpp
이 글은 Evernote에서 작성되었습니다. Evernote는 하나의 업무 공간입니다. Evernote를 다운로드하세요.

댓글

가장 많이 본 글