iOS DVIA-v2 | Side Channel Data Leakage (Screen Shot)
백그라운드 스냅샷 취약점
취약점 개요
부채널 데이터 유출은 사용되는 어플리케이션의 주 기능이 아닌 타 기능을 통해 데이터가 유출되는 취약점을 말한다. 의도하지 않은 데이터 유출은 개발자가 실수로 모바일 디바이스의 다른 앱이 쉽게 액세스할 수 있는 위치에 민감한 정보나 데이터를 저장할 때 발생한다.
개발자의 코드가 사용자 또는 백엔드에서 제공한 민감한 정보를 처리할 때 이 과정에서 개발자가 알지 못하는 부작용으로 인해 해당 정보가 모바일 디바이스의 안전하지 않은 위치에 배치되어 디바이스의 다른 앱이 공개적으로 액세스할 수 있게 된다. 일반적으로 이러한 부작용은 기본 모바일 디바이스의 운영 체제(OS)에서 발생하며 공격자는 간단한 코드를 작성하여 민감한 정보가 저장된 위치에 액세스할 수 있다.
취약점 실습
- 실습 환경 : iOS 14.6, iPhone 8
- 좌측 상단 메뉴 > Side Channel Data Leakage > App Screenshot
This Security Question에 중요정보라 가정한 임의의 문자를 입력하고 백그라운드로 돌릴 시 중요정보가 그대로 노출되고 있는 것을 알 수 있다.
iOS의 경우 백그라운드로 진입 시 해당 화면에 대한 스크린샷을 저장하여 해당 사진을 보여주게 된다. 즉 이 스냅샷 파일이 임시로 저장되고 해당 파일을 보여주게 되는데 저장 경로는 아래와 같다.
Snapshot Path
/var/mobile/Conatiners/Data/Application/[BundleID]/Library/SplashBoard/Snapshots/sceneID:[PackageName]-default/
[iOS 8 미만]
/var/mobile/Application/[BundleID]/Library/Caches/Snapshots/[PackageName]/
[iOS 8 이상 13 미만]
/var/mobile/Containers/Data/Application/[BundleID]/Library/Caches/Snapshots/[PackageName]/
[iOS 13 이상]
/var/mobile/Conatiners/Data/Application/[BundleID]/Library/SplashBoard/Snapshots/sceneID:[PackageName]-default/
Filza 어플리케이션을 이용하여 직접 해당 경로로 이동하여 파일을 확인해보면 백그라운드에 대한 이미지 파일이 저장되어 있는 것을 알 수 있다.
해당 단말기에 피해자 몰래 원격이 되어 있거나 파일 접근 권한이 있는 경우 백그라운드 이미지를 통해 중요정보를 탈취할 수 있기에 아래의 대응 방안으로 정보 노출을 못 하게 대응해야한다.
대응 방안
어플리케이션을 백그라운드로 넘길 때 해당 View에서 중요한 정보를 담고 있다면 다른 View로 중요 정보를 가려야한다.
-
sceneDidBecomeActive: 액티브 상태가 됐을 경우 -
sceneWillResignActive: App Switcher 모드(홈 바 쓸어 올렸을 경우 또는 홈 버튼 모델 홈 버튼 두번 눌렀을 경우) -
sceneWillEnterForeground: 백그라운드 상태였다가 돌아왔을 경우 -
sceneDidEnterBackground: 백그라운드 상태로 갔을 경우
※ iOS13 미만의 경우 AppDelegate.swift에서 작업
-
applicationDidBecomeActive -
applicationWillResignActive -
applicationWillEnterForeground -
applicationDidEnterBackground
func callBackgroundImage(_ bShow: Bool) {
let TAG_BG_IMG = -101
let backgroundView = window?.rootViewController?.view.window?.viewWithTag(TAG_BG_IMG)
if bShow {
if backgroundView == nil {
//Create View
let bgView = UIView()
bgView.frame = UIScreen.main.bounds
bgView.tag = TAG_BG_IMG
bgView.backgroundColor = .black
let lbl = UILabel()
lbl.frame = UIScreen.main.bounds
lbl.textAlignment = .center
lbl.font = UIFont.systemFont(ofSize: 30)
lbl.textColor = .white
lbl.numberOfLines = 0
lbl.text = "Hide Imformation"
bgView.addSubview(lbl)
window?.rootViewController?.view.window?.addSubview(bgView)
}
} else {
if let backgroundView = backgroundView {
backgroundView.removeFromSuperview()
}
}
}
func sceneDidBecomeActive(_ scene: UIScene) {
print("SceneDelegate - sceneDidBecomeActive 켜지기 전 2 (App Switcher 모드 였다가 돌아올 때)")
callBackgroundImage(false)
}
func sceneWillResignActive(_ scene: UIScene) {
print("SceneDelegate - sceneWillResignActive - 쓸어 올렸을 때, App Switcher 모드")
callBackgroundImage(true)
}
func sceneWillEnterForeground(_ scene: UIScene) {
print("SceneDelegate - sceneWillEnterForeground - 켜지기 전 1 (완전 백그라운드로 갔다 다시 돌아올 때) 백그라운드로 갔다가 바로 오면 여기 안탐. 백그라운드 1초 있다가 켜야 여기 탐")
callBackgroundImage(false)
}
func sceneDidEnterBackground(_ scene: UIScene) {
print("SceneDelegate - sceneDidEnterBackground - 백그라운드로 갔을 때, 홈 눌렀을 때")
callBackgroundImage(true)
}