Insecure Bank 어플리케이션을 녹스에 다운받아 취약점 분석을 진행한다.
1. 수행환경
공격자 환경 : NoxPlayer
피해자 : InsecureBankv2.apk
가상환경 : python 2.7
목적 : 취약점 점검
1.1 진단 도구
Android Studio
Burp Suite
GDA
ADB.jar
Drozer
Base64 인코더 디코더
AES Encryption
LogFilter
APK Easy Tool
2. 환경설정
2.1 Conda Python 환경설정
Conda는 최신버전을 설치했다.
하지만 InsecureBank의 경우 python 2 버전 이 후로는 개발이 되지 않아 python 2.7버전으로 가상환경을
설정한다.
#conda prompt 에서 실행하면 된다.
#작성자는 python2.7 버전을 사용하므로 가상환경 명도 py2.7로 설정했다.
conda create -n py2.7 python=2.7 -y
정상적으로 환경이 설정되었다면, 아래와 같이 설정된다.
위의 그림과 같이 가상환경의 활성화 비활성화 방법을 보여준다
#가상환경 활성화
conda activate (가상환경명)
#가상환경 비활성화
conda deactivate (가상환경명)
2.2 InsecureBank 다운로드
google 에 insecurebank를 검색하면 github에서 다운로드를 할 수 있다.
다운로드 이 후, zip 파일을 확인해본다.
2.3 Conda에서 Insecurebank 실행
내부 파일 구조확인이 끝났다면, AndroLabServer의 경로로 콘다를 이동해준다.
실행을 위한 모듈을 requirements.txt에 저장하고 있으므로 pip 명령어를 사용해서 다운로드 해준다.
#모듈 다운로드
pip install -r requirements.txt
모듈의 다운로드가 완료되었다면, app.py를 실행 해준다.
포트가 할당되며, 실행하는 것을 확인할 수 있다.
2.4 Nox에 Insecurebank 설치
[그림1.2-2]의 APK를 Nox 플레이어에 드래그 해서 옮겨주면 다운로드가 실행된다.
정상적으로 작동되는 것을 확인할 수 있다.
마지막으로 Insecurebank 어플리케이션이 conda_prompt 로 이동하도록 IP를 설정해준다.
우측 상단 설정 > Preferences
이제 접속을 해야한다.
이때 ID/Password 는 Github에 적혀져있으니 참고하자
콘다에서도 정상적으로 동작하는지 마지막으로 확인한다.
정상적으로 작동중인 것을 확인할 수 있다.
3. 취약점 점검
3.1 중요정보 저장 취약점
사용자 계정 노출 취약점
Insecurebank의 코드 내부, 주석처리된 주요 정보를 확인할 수 있다.
위치는 ChangePassword.java에 노출되었으며, username/password를 확인하여, 로그인이 가능하다.
key 값 노출
양방향 통신을 위한 key 값이 어플리케이션 내부에 존재하는 것을 확인할 수 있다.
외부 저장소 정보노출
안드로이드 내부 저장소와 외부 저장소로 나뉘는데 SD카드는 외부저장소로 모든 어플리케이션이 접근할 수 있는 영역이다.
SD카드에 중요 정보가 다른 어플리케이션에 의해 노출될 수 있다.
Nox adb Shell 로 접속하여, 외부 저장소로 접속한다.
외부 저장소에 admin 명으로 되어있는 Statements_dinesh.html 을 확인할 수 있다.
cat 명령어로 html을 읽으면 Insecurebank 내부 statement 변경에 대한 정보가 적제되어 있다.
- 중요 정보 저장 시 외부 저장소가 아닌 내부 저장소에 저장하도록 코드를 변경한다.
- 중요 정보는 반드시 암호화 될 수 있도록 조치한다.
3.2 비밀번호 구현 취약점
비밀번호 변경에서의 로직이 잘못 설정되어 있어, ID의 값을 알고있을 시, Password를 임의로 변경할 수 있다.
Changepassword에서 현재 사용중인 username인 jack이 평문으로 보이는 것을 확인할 수 있다.
username을 존재하는 다른 값으로 변경하여 password가 변경되는지 확인한다.
다른 username의 Password가 변경된 것을 확인할 수 있다.
취약한 액티비티 컴포넌트
취약점 진단 순서는 아래와 같다.
- AndroidManifest.xml에 있는 <Activity> 컴포넌트 점검
- Activity 컴포넌트가 구현된 해당 클래스의 OnCreate( ) 메소드 부터 전체 코드 점검
- adb shell -> am start -n com.android.insecurebankv2/.ChangePassword
액티비티 명을 확인한 이 후, CMD 에서 액티비티를 직접 호출을 진행한다.
#액티비티 직접 호출
adb shell am start -n com.android.insecurebankv2/.ChangePassword
Drozer로 권한 검사
#drozer export=true 확인 명령어
run app.activity.info -a com.android.insecurebankv2
액티비티에 권한이 없는 것을 확인할 수 있다.
이를 확인하여 호출한다.
#Insecurebank ChangePassword 호출
run app.activity.start --component com.android.insecurebankv2 com.android.insecurebankv2.ChangePassword
# username에 jack 을 포함시켜서 호출
run app.activity.start --component com.android.insecurebankv2 com.android.insecurebankv2.ChangePassword --extra string uname jack
3.3 컴포넌트 취약점
다른 어플리케이션에서 DB나 파일에 접근 가능하도록 인터페이스를 제공해주는 역활이 컨텐츠 프로바이더이다.
어플리케이션은 ContentResolver를 통해 콘텐츠 프로바이더에 접근 가능하고, URI를 이용한다.
콘텐츠 프로바이더가 외부에 노출될 경우, 외부에서 데이터를 조회하거나 변경이 가능하다.
Insecurebank의 URI를 확인하기 위해 디컴파일 후 "content://" 가 포함된 항목이 있는지 검색
찾은 URI 값에 외부에서 접근하기위해 nox_adb shell content 명령어를 사용해서 DB를 확인해본다
#쿼리문 삽입
nox_adb shell content query --uri content://com.android.insecurebankv2.TrackUserContentProvider/trackerusers
결과는 아래와 같다
한번더 정보를 확인해보자
#Provider 등 정보 출력
run app.provider.info -a com.android.insecurebankv2
마지막으로 Query 문을 대입 확인을 위해 scan을 진행한다.
#쿼리문 실행 확인
run scanner.provider.finduris -a com.android.insecurebankv2
이제 SQL Injection을 시도한다.
# error_base SQL Injection
run app.provider.query content://com.android.insecurebankv2.TrackUserContentProvider/trackerusers --projection "'"
# 테이블명 출력 SQL Injection
run app.provider.query content://com.android.insecurebankv2.TrackUserContentProvider/trackerusers --projection "* from SQLITE_MASTER where type='table';--"
# name 테이블 출력 SQL Injection
run app.provider.query content://com.android.insecurebankv2.TrackUserContentProvider/trackerusers --projection "* from names;--"
SQL Injection이 성공한 것을 확인할 수 있다.
3.4 브로드캐스트 취약점
- 브로드캐스트 리시버는 디바이스에서 발생하는 이벤트 신호를 받아 처리하는 역할
- Androidmanifest.xml의 <receiver></receiver> 항목에 정의
- 공격자는 임의의 브로드캐스트 신호를 생성하여 사용자가 받는 알림(메세지, 전화 등)을 가로 채거나, 특정 상황에서 발생하는 작업을 우회하여 수행한다.
Androidmanifest .xml에 선언된 브로드캐스트 리시버 확인
- 브로드캐스트 리시버 클래스 : .MyBroadCastReceiver
- 브로드캐스트 이름 : theBroadcast
- android:exported : 외부 어플리케이션으로부터 intent 수신
내부 소스코드의 출력문을 확인한다.
Logcat을 통한 취약점
#theBroadcast라는 액션을 가진 브로드캐스트 인텐트를 com.android.insecurebankv2 패키지의
#MyBroadCastReceiver 클래스에 보내는 것입니다
nox_adb shell am broadcast -a theBroadcast -n com.android.insecurebankv2/.MyBroadCastReceiver
위와 같이 단순 브로드캐스트를 실행하면, result=0으로 출력된다.
브로드캐스트의 실행을 Logcat에서 바라봐야 한다.
위의 Logcat을 보게된다면,
Phone number is null 에러와 com.android.commands.am.Am 을 호출하는 것을 찾아볼 수 있다.
#ADB를 이용하여 파라미터가 포함된 브로드캐스트를 생성
# -e 옵션으로 파라미터를 포함시켜 정상작동 처리
#adb shell am broadcast -a [action] -n [package name/component name] -e <KEY> <VALUE>
adb shell am broadcast -a theBroadcast -n com.android.insecurebankv2/.MyBroadCastReceiver -e phonenumber 5555 -e newpass test
위와 같이 정상 작동이 된다면, Nox 플레이어에는 알림창이 생성된다.
이렇게 발생하는 과정은 아래의 소스코드를 확인해야 한다.
class MyBroadCastReceiver에 포함되어있는 코드가 실행된다.
그중 우리는 -e 옵션으로 phonenumber와 newpass 값을 삽입했다.
public void onReceive(Context context,Intent intent){
try{
String phn = intent.getStringExtra("phonenumber");
// -e 옵션으로 phonenumber 5555
String newpass = intent.getStringExtra("newpass");
// -e 옵션으로 newpass test
}catch{
}
}
그 후, 매개변수를 받은 함수는 정상적으로 실행되며, [그림 3.4-7]의 빨간색 박스의 내용이 실행된다.
문자열 textMessage 는 decryptedPassword를 포함하고 있다.
코드에서 decryptedPassword는 superSecurePassword라는 키 값을 가진 SharedPreferences 객체를 가리키며, 암호화를 헤제하는 로직을 거쳐 변수로 할당되어 있는 것을 유추할 수 있다.
고로 브로드캐스트를 통해서 패스워드 정보가 노출되는 것을 의미한다.
Drozer를 통한 브로드캐스트 취약점 분석
필자는 Drozer를 통한 취약점 분석이 훨씬 간편하다고 생각한다.
#drozer 브로드캐스트 정보 확인
dz> run.app.broadcast.info -a com.android.insecurebankv2
# 전의 방식과 동일하게 phonenumber 값과 newpass 값을 대입한다.
# 하지만 drozer에서는 --extra로 파라미터를 대입한다.
run app.broadcast.send --component com.android.insecurebankv2 com.android.insecurebankv2.MyBroadCastReceiver --extra string phonenumber 12345 --extra string newpass test
아래는 실행 결과 값이다.
3.5 백업 취약점
adroid:allowBackup 속성이 true 로 설정되어 있을 시, 중요 정보 및 인증 정보를 노출하게 된다.
단말기를 잃어버릴 경우, 제3자에게 노출될 수 있는 취약점이다.
우선 설정 파일은 AndroidManifest.xml 파일에서 백업 속성을 확인한다.
백업 설정이 true 인 것을 확인했으면, 이제 백업파일을 생성하도록 요청한다.
#안드로이드 백업 파일 생성
adb backup -f <생성할 파일명> <패키지 URI>
필자는 insecurebank.ad 파일로 생성했다.
이 생성된 ad 파일을 abe.jar 파일로 변환시켜 내부를 확인한다.
#생성한 파일 abe.jar로 변환
java -jar abe.jar unpack <파일명> <저장할 파일명>
필자는 .ad 파일을 .tar 파일로 변환 후, 압축을 풀어 확인했다.
tar 파일에는 db 와 sp 파일로 나뉘어져 있으며, db 파일의 mydb, mydb-journal을 sp 파일로 옮겨 한번에 보여주고 있다.
그중 mySharePreferences.xml 을 확인해보도록 하자
내부에 암호화된 이름과 패스워드가 저장되어 있는 것을 확인할 수 있다.
3.6 로컬 암호화 취약점
취약점 진단 순서는 아래와 같다
- 앱의 기능들을 실행해보고 탐색한다. (ex. ID, PW 저장 등의 기능들이 있다면 확인해본다.)
- DB 추출 후 중요정보 암호화 확인
- DB 외의 파일들에서 중요정보 암호화 확인
- 클라이언트 단 소스코드 점검 및 암호화 로직 확인
[그림 3.5-4] 의 파일을 사용하여 진단한다.
[그림 3.5-5]의 암호화된 문자열을 base64로 추측하여 디코딩을 실행한다.
디코딩을 시작하면
amFjaw== 는 jack 으로 변환되며, pw의 경우는 암호화가 진행이 되어있는 것을 확인할 수 있다.
3번(암호화 확인) 까지 진행되어 이제 소스코드 점검을 시작한다.
소스코드를 확인하면 username의 경우 base64 사용하고 UTF-8로 변환시켜 대입한다.
하지만, Password는 crypt 메소드를 추가로 사용하기에 추가적으로 메소드를 확인해본다.
saveCreds 메서드에서 editor를 불러와 암호화를 한 base64username과 superSecurePassword를 commit() 실행하고 있다.
사용자 계정 목록화
[그림 3.5-4] 에서 mydb를 열어보면 사용자 계정을 확인할 수 있다.
로컬 암호화 취약점과 비슷한 취약점이다.
3.7 취약한 웹 뷰 구현 ( XSS )
웹 뷰상에 UI 또는 패킷에서 자바스크립트 코드가 강제적으로 실행되게 함으로써 다른 사용자의 중요정보를 탈취하는 취약점
만약 다른 사용자에게 자바스크립트 코드를 보낼 수 있다면, 다른 사용자의 중요정보를 탈취할 수 있는 취약점이 될 것.
취약점 진단 순서는 아래와 같다.
- 앱 구동 후 웹뷰가 사용되거나 웹뷰와 연관이 있는 기능들을 검토한다.
- 웹뷰가 사용되고 있는 코드들을 검토한다.
- <script>alert("XSS")</script>와 같은 자바스크립트를 실행할 수 있는 명령어들을 웹뷰와 연관되어 있는 UI에 대입해본다.
프로젝트 전체에서 Webview 를 검색한다.
Insecurebank에서는 Webview를 사용하는 viewstatement가 취약점을 발생시키는 존재이다.
mWebView 사용을 확인한다.
위의 코드에서는 .setJavaScriptEnabled(true) 로 설정되어 있으므로, 어플리케이션에서도 스크립트가 실행된다는 것을 알 수 있다.
스크립트를 삽입하고 난 이 후, Transfer를 진행하면 실패했다는 alert 창이 발생한다.
이 후, ViewStatement에 접근하면, 방금 필자가 작성한 스크립트가 실행되는 것을 확인할 수 있다.
3.8 취약한 인증
어플리케이션 사용 시, 취약한 인증 관리로 위변조를 통해 사용자에게 피해를 입히는 취약점
현재 필자는 jack 으로 로그인을 한 상태에서 진행한다.
jack의 계좌가 아닌 dinesh의 계좌인 888888888에서 jack의 계좌인 555555555로 금액이 전송되도록 시도한다. ( 2회 시도 )
전송 후, SQLite Browser를 확인하면, 금액이 변동되어 있는 것을 확인할 수 있다.
3.9 취약한 암호화 구현
이전의 SharedPreferences의 암호화되어있는 Password를 확인한다.
여기에서 이전부터 암호화를 진행한 CryptoClass를 확인한다.
- 사용하는 대칭 키는 32자리로 32 * 8 = 256 으로 256bit를 사용하고 있다.
- 초기화 벡터 값은 ivBtyes 로 설정되어 있다.
- 암호화 방식은 AES / 암호화 모드는 CBC 로 사용하는 것도 확인할 수 있다.
마지막으로 [그림 3.9-3]에 메서드의 마지막 부분을 확인하면 cipherText에 base64로 넣는 로직을 확인할 수 있다.
또한 암호화는 문자열이 아닌 파일로 저장하여 디코딩을 시작해야한다.
로직에 역순으로 base64 디코딩 이 후, 다시 디코딩을 실행할 예정이다.
여기에서는 문자열로 결과 값을 받는 것이 아닌 파일로 받아 다시 디코딩 작업을 실행할 예정이다.
이전 내용에서 확인한 정보들을 넣어 디코딩을 실행하면, Jack@123$ 이라는 패스워드 값을 얻어낼 수 있다.
대칭키는 노출이 될 수 밖에 없다. 하지만 모든 단말기에 설치되는 대칭 키가 같을 경우 큰 문제가 발생한다.
단말기마다 고유의 대칭키를 갖을 수 있도록 설정해야 한다.
핸드폰 번호 또는 IMEI 값 등을 기준으로 대칭 키를 생성하면 더욱 안전한 방식으로 사용할 수 있다.
3.10 취약한 로깅
LogFilter를 사용해서 로그에 대한 취약점을 확인한다.
자신이 사용하는 에뮬레이터를 누르고 Run 실행을 하면 로그를 전체 확인할 수 있다.
그중에서 우리는 Insecurebank에 관해서만 찾을 예정이다.
# 인시큐어 뱅크 pid 확인
adb shell ps
PID인 5213을 확인하고 LogFilter로 검색한다.
필자는 종료 후, 재 검색을 진행했으므로, PID가 변경된 상태이다.
현재 위의 로그를 확인하면 ID와 PW가 log에 노출되는 것을 확인할 수 있다.
3.11 취약한 페이스트 보드
사용자의 중요한 데이터 ( 암호 , 계좌번호 등 )이 메모리에 노출되어 있는 취약점
취약점 진단 순서는 아래와 같다.
- 진단 대상 안드로이드 앱에서 취약하거나 중요한 항목을 복사한다.
- adb shell su <user> service call clipboard 2 s16 com.android.insecurebankv2 명령을 이용하여 페이스트보드 검사
이제 <user> 값을 알아내기 위해 명령어를 입력한다.
#user 값 확인
adb shell ps
이제 명령어를 사용해서 Clipboard 를 확인한다.
# 클립보드 확인
adb shell su <user> service call clipboard 2 s16 com.android.insecurebankv2
위의 명령어에서 s16 은 문자열로 출력한다. 를 의미한다.
3.12 어플리케이션 패칭 취약점
클라이언트 어플리케이션 보안에서 요구되는 현 시점에서 가장 문제가 많은 취약점
안드로이드 클라이언트 코드를 변경하여 비정상적 작동을 유도하도록 APK 파일을 변조 및 수정한다.
(리패키징을 시도한다.)
클라이언트 단의 인증을 우회하므로써, 인증 절차를 무력화 시킬 수 있다.
여기서는 APK Easy Tool 을 사용하여 디컴파일 컴파일을 진행할 예정이다.
APK Easy Tool 에서 컴파일을 할 시, APK 서명도 같이 진행되므로, 참고한다.
InsecureBank를 경로로 설정하여 디컴파일을 진행한다.
디컴파일 진행 시, Smali 코드로 변환된 것을 확인할 수 있다.
필자는 InsecureBank 앱의 접속 시, Device not root 라는 구문을 바꿀 예정이다.
우선 자바코드와 Smali코드를 번갈아 확인하며, 진행할 예정으로 root 와 isroot 같은 추측가능한 문자열을 jadx에서 검색한다.
위의 구문을 확인하여 PostLogin에서 동작하는 문자열인 것을 확인할 수 있다.
이제 디컴파일한 Smali 코드 중 PostLogin을 찾아 내부 코드를 분석한다.
필자는 위의 그림과 같이 앞에 (hack)이라는 문자열을 추가했다.
이제 컴파일을 진행하고 Nox 플레이어에서 정상적으로 작동이 되는지 확인한다.
3.13 개발 백도어 취약점
개발 백도어는 개발 단계시 개발자가 자신만이 들어갈 수 있는 계정이나 인증 우회를 하여 접속하는 것을 의미한다.
개발 단계 시, 사용하지만 배포용 어플리케이션에 개발 백도어 코드가 사용되면 보안에 영향을 미친다.
jadx에서 dev를 검색하면, 아래와 같은 코드가 나타난다.
위 코드에서는 username이 "devadmin" 이라면 httppost2로 보내며 이는 /devlogin으로 패킷을 보내는 것을 의미한다.
이제 서버의 소스코드를 확인한다.
마찬가지로 '/devlogin'을 Post 방식으로 받을 때에, 구현이 존재한다.
또한 여기에서는 username 의 값만 확인하는 것으로 유추가 되므로, 로그인을 시도해보면 정상적으로 접속이 가능한 것을 확인할 수 있다.
3.14 루트 우회 취약점
안드로이드에서는 루트 권한을 사용자가 획득할 수 없도록 설정되어 있다.
안드로이드에 루트 권한을 사용자가 획득하는 것을 루팅이라고 하며, 이러한 단말기를 루팅 단말기 라고 한다.
"su" , "superuser" 로 설정되어 있는 메서드를 발견하여 내부의 소스코드를 분석한다.
하단의 Superuser.apk도 동작할 수 있는 것을 확인한다.
이제 로그인 로직을 확인하며 위 그림의 두 메소드가 어떻게 실행이 되는 지 확인한다.
위 메서드들은 로그인 시, 사용하는 Oncreate 메서드 내부에서 선언되는 함수들이다.
doesSuperuserApkExist는 단말기에 저 앱이 설치되어 있는지 확인하며, or 조건으로 doesSUexist()로 선언되어있으므로, doesSUexist에서 명령어 상에 su 가 존재하면 true 로 반환한다.
/system/xbin/ 위치에 su 가 존재하는지 확인해야한다. 이를 확인시켜주는 프로그램이 which 이다.
하지만 이 안드로이드 리눅스에서는 which 명령어가 존재하지 않아 못찾기 때문에 not rooted로 출력이 되는 것이다.
'앱 모의해킹 > 안드로이드' 카테고리의 다른 글
Frida(2) - 후킹, 쉘 다루기 (0) | 2024.06.14 |
---|---|
Frida(1) - 문법, 개념 이해 (0) | 2024.06.13 |
Drozer 프레임워크 (0) | 2024.05.30 |
안드로이드 기본개념(3) (0) | 2024.05.29 |
안드로이드 기본개념(2) (0) | 2024.05.28 |