상세 컨텐츠

본문 제목

[Android Reversing] Insecure Webview implementation (WebView 취약점)

REVERSING/Android

by koharin 2021. 7. 6. 22:22

본문

728x90
반응형

WebView


  • 웹브라우저 기능을 앱 안에 포함할 수 있는 위젯
  • AndroidManifest.xml 파일에서 Permission을 지정해야 한다.
    • <application> 행 위에 <uses-permission android:name="android.permission.INTERNET"/> 추가

WebView API

  • setWebViewClient(WebViewClient client)
  • addJavascriptInterface(Object object, String name)
  • getSettings().setJavaScriptEnabled(...)
    • setJavaScriptEnabled() 함수를 WebSetting 내(getSettings())에서 호출해서 웹페이지 내 JavaScript 실행을 허용할 수 있다. 디폴트로 JavaScript execution이 안 된다.

WebSettings (JavaScript와 파일 접근)

  • 각 WebView는 WebSetting을 가지고 있다.
  • setAllowFileAccess() : WebView에서 파일을 로딩하기 위해 로컬의 파일 시스템에 접근을 허용할 수 있다. 디폴트로, WebView는 파일 시스템 접근이 가능하다.
  • setAllowFileAccessFromFileURLs() : file scheme URI 컨텐트 내에서 JavaScript 실행으로 파일에 접근하도록 한다. 디폴트로 Jelly Bean 이전 API 버전에 대해 WebView는 이 접근이 가능하다.
  • SetAllowUniversalAccessFromFileURLs() : 어떤 content origin이든 상관없이 file scheme URI에서의 JavaScript 실행으로 내용 접근이 가능하도록 한다. Jelly Bean 버전 이전의 API 버전에서 디폴트로 가능하다.

WebViewClient

  • WebView에 대한 동작(사용자가 WebView에서 링크를 클릭했을 때의 동작 등 )을 정의해야 한다. 개발자는 WebView에 WebViewClient를 사용하면 shouldOverrideUrlLoading() 메소드를 재정의하여 URI의 내용에 따라 다른 동작이 이루어지도록 한다.
  • 만약 해당 메소드를 재정의하지 않거나, return false로 반환하는 경우 URI는 WebView에서 실행되고, Return true나 shouldOverrideUrlLoading()을 재정의했으면 재정의된 내용에 따라 동작이 이루어진다.

Interface (Code access)

  • addJavaScriptInterface(Object object, String name) 를 호출하여 애플리케이션의 내부 Java 코드를 web content에서 접근할 수 있도록 할 수 있다.
WebView webView = new WebView(); 
webView.getSettings().setJavaScriptEnabled(true); 
webView.addJavascriptInterface(new MyClass(), "mycls"); 
webView.loadURL("<http://www.foo.com>");

위와 같이 WebView를 생성하면, WebView 내 웹페이지에서 <script>mycls.method();</script> 와 같이 메소드를 호출할 수 있다.

 

AndroidManifest.xml


  • AndroidManifest.xml 파일에 WebView를 사용할 수 있도록 <uses-permission android:name="android.permission.INTERNET"/> 이 포함되어 있다.
  • 컴포넌트가 intent filter를 가질 때, exported="false" 속성이 없다.
    • Intent filter
      • 인텐트 객체 내 정보들과 각 컴포넌트의 정보를 비교하여 호출할 가장 적절한 컴포넌트를 찾아야 하는데, AndroidManifest.xml 파일에 각 컴포넌트가 받을 수 있는 인텐트 종류를 intent filter에 정의한다. 인텐트 해석이 필요한 implicit intent를 받을 때만 intent filter가 필요하고, 호출하는 컴포넌트가 명시되어 있는 explicit intent는 intent filter가 없어도 대상 컴포넌트를 호출할 수 있다.
      • intent filter에서 주로 필터링하는 정보는 action, data(데이터 주소 유형, 데이터 타입), category 이다.
      • intent filter는 AndroidManifest.xml 파일에서 각 컴포넌트 태그 내에 정의되어 안드로이드 시스템에서 미리 알고 있어야 다른 애플리케이션에서 해당 애플리케이션의 컴포넌트를 필요로 하는 인텐트를 발생시켜도 해당 컴포넌트를 실행시킬 수 있다.
      • LoginActivity에서 action.MAIN은 주요 진입 지점임을 나타내고, 어떠한 인텐트 데이터도 기대하지 않음을 나타낸다.
      • LoginAcvitity에서 category.LAUNCHER 카테고리는 LoginActivity의 아이콘이 시스템의 앱 시작 관리자에 배치되어야 한다는 것을 의미한다. 해당 <activity> 요소에서 아이콘을 지정하지 않은 경우, 시스템은 <application> 요소에서 가져온 아이콘을 사용한다.

 

 

 

Vulnerability


1. 평문으로 url 로딩

  • WebView에서 평문으로 로딩을 하면 MiTM(Man in the Middle attack, 중간자 공격)와 같은 공격에 취약하다.

 

2. 로컬 리소스에 접근

jd-gui로 Java 코드를 확인했다.

ViewStatement.class

  • jar 파일에서 ViewStatement.class에서 WebView 사용을 확인할 수 있다.
  • WebView를 통한 애플리케이션 내에서 JavaScript 실행을 허용하는 것은 공격자가 임의의 JavaScript 코드를 실행할 수 있도록 한다.
webView.getSettings().setJavaScriptEnabled(true);

setJavaScriptEnabled(true)로 설정하여 JavaScript 코드를 webview를 통해 실행 가능하도록 (XSS, SSTI 등 가능) 설정하여 취약하다.

 

Exploit


로그인 시 View Statement 메뉴가 있으므로, 해당 메뉴에서 사용되는 코드일 것이다.

PostLogin.class

PostLogin 코드에서도 statement_button을 클릭하는 경우 viewStatement 함수를 호출하는 것을 확인할 수 있다.

 

View Statement을 누르면 Toast 메시지로 Statement does not Exist!! 를 출력한다.

Statements_<uname>.html 파일이 존재하지 않기 때문에 해당 Toast 메시지가 출력됨을 알 수 있다.

Statements_<uname>.html 파일이 있는 경우, file://<ExternalStorageDirectory>/Statements_<uname>.html 형태의 url을 로드 해준다.

 

Environment.getExternalStorageDirectory() : 외부 저장소(SD카드)의 최상위 경로로, /mnt/sdcard 또는 /storage/emulated/0 등에 해당한다.

 

uname이 username이라고 예측을 하고, /mnt/sdcard 경로에 Statements_jack.html 파일과 Statements_dinesh.html 파일을 만들었다.

html 파일이 로드된 것을 확인할 수 있다.

 

JavaScript가 Enabled 되어 있고, WebView에서 사용하는 file schema가 file:// 이므로, 애플리케이션 내 정보를 불러오도록 코드를 작성할 수 있다.

 

어디에서 exploit 코드를 작성할 수 있을까?

DoTransfer.class 코드를 보면, From과 To, Amount에서 값을 가져와서 해당 내용을 Statements_<username>.html 파일에 저장한다. Transfer Failed이어도 실패한 계좌이체 정보를 저장한다.

 

From, To, Amount 모두 임의의 JavaScript 코드를 작성하여 실행할 수 있고, Amount에 alert 창을 띄우는 코드를 작성한 후 Transfer을 클릭했다.

 

View Statement에서 위와 같이 JavaScript 코드가 실행되어 alert 창을 띄우는 것을 확인할 수 있다. (XSS 취약점)

(한 번 생성된 Statement 파일을 계속 사용하기 때문에, 다른 스크립트를 넣어서 테스트 해보려면 /mnt/sdcard/ 경로의 Statement_<uname>.html 파일을 삭제해야 한다.)

 

DoTransfer.class

DoTransfer 코드에서 SharedPreferences sharedPreferences = DoTransfer.this.getSharedPreferences("mySharedPreferences", 0); 으로 mySharedPreferences로 SharedPreferences 객체를 생성하고, mySharedPreferences.xml 파일에는 superSecurePassword가 저장되어있는 것을 확인할 수 있다. SharedPreference는 데이터를 파일 이름으로 xml 파일 형태로 저장해서 관리한다. data/data/(package_name)/shared_prefs/ 경로에 위치한다. 패키지 이름이 com.android.insecurebankv2이므로, /data/data/com.android.insecurebankv2/shared_prefs/mySharedPreferences.xml 에 superSecuredPassword 값을 확인할 수 있을 것이다.

 

<script>
location.href="/data/data/com.android.insecurebankv2/shared_prefs/mySharedPreferences.xml"
</script>

base64로 인코딩된 superSecurePassword 값을 확인할 수 있다.

디코딩 시 각각 사용자 이름, 패스워드의 민감한 정보임을 알 수 있다.

 

 

대응방안


  1. Disable JavaScript
    1.  setJavaScriptEnabled(false)
  2. 개발자는 WebView의 동작을 제한하는 코드 작성
    • 링크를 통해 로드하는 컨텐트만 제한 가능하고, 컨텐트 내 frame이나 JavaScript와 같은 document는 제한할 수 없다.
  3. API 제한
    • 필요한 인터페이스만 등록해서 노출되는 API를 제한한다.
  4. WebView 이외의 다른 Android 메커니즘 사용

 

 

Reference


Exploiting Android WebView Vulnerabilities

Android WebView Vulnerabilities

https://people.eecs.berkeley.edu/~daw/papers/bifocals-wisa13.pdf

728x90
반응형

관련글 더보기