취약점 개요
바이너리 패칭 취약점은 애플리케이션이 관리자 상태, 기능 접근과 같은 권한 확인을 클라이언트 측 로직과 하드코딩된 검사에 의존하기 때문에 발생합니다. 이러한 검사는 서버 측 검증, 코드 무력성 확인과 같은 보호 메커니즘 없이 애플리케이션의 APK 내에 구현되어 있습니다.
그 결과, 공격자는 APK를 디컴파일하거나 디스어셈블하고, 명령어 및 변수를 수정한 뒤, 애플리케이션을 리패키징하여 보안 제한을 우회할 수 있습니다.
바이너리를 패치함으로써 공격자는 인증 확인 절차를 무력화하거나, 관리자 권한을 부여하고 남용할 수 있습니다.
취약점 분석

현재 앱에서는 ADMINISTRATION 버튼이 비활성화되어 있습니다.

PS C:\Users\WIN11> adb -s 2c838d0cfa0b7ece shell dumpsys window | findstr 'mCurrentFocus'
mCurrentFocus=Window{996e86f u0 owasp.sat.agoat/owasp.sat.agoat.BinaryPatchingActivity}
액티비티명을 확인한 뒤 디컴파일한 코드를 분석해보겠습니다.

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(C1278R.layout.activity_binary_patching);
TextView isAdminText = (TextView) findViewById(C1278R.id.isAdminText);
Button adminButton = (Button) findViewById(C1278R.id.adminButton);
if (this.isAdmin) {
isAdminText.setText("You are Admin Now");
adminButton.setBackgroundColor(Color.parseColor("#000000"));
adminButton.setTextColor(Color.parseColor("#FFFFFF"));
adminButton.setEnabled(true);
}
adminButton.setOnClickListener(new View.OnClickListener() { // from class: owasp.sat.agoat.BinaryPatchingActivity$$ExternalSyntheticLambda0
@Override // android.view.View.OnClickListener
public final void onClick(View view) {
BinaryPatchingActivity.onCreate$lambda$0(this.f$0, view);
}
});
}
public static final void onCreate$lambda$0(BinaryPatchingActivity this$0, View it) {
Intrinsics.checkNotNullParameter(this$0, "this$0");
Toast.makeText(this$0, "You clicked on Administration button", 1).show();
}
이 코드에서는 기능에 대한 권한을 확인하기 위해 클라이언트 측에서 제어할 수 있는 isAdmin 변수에 따라 할당합니다.
초기 변수 선언 시 isAdmin은 final로 선언되어, 별도의 보안 메커니즘이 존재하지 않고 onCreate()함수 내에서 사용됩니다.
이는 공격자가 디컴파일 후 바이너리 패칭이나 런타임 조작을 수행해 isAdmin 값을 true로 변경할 수 있습니다. 결과적으로 공격자가 권한이 없더라도 버튼을 활성화 시킬 수 있습니다.
바이너리 패칭 우회 실습
먼저, 명령어 또는 프로그램을 사용하여 APK 파일을 디컴파일해 Smali 코드를 획득합니다.
- Smali는 안드로이드 Dalvik 바이트코드의 사람이 읽을 수 있는 저수준 표현입니다. 이를 통해 Java나 Kotlin으로 컴파일된 앱의 내부 로직을 분석하고 수정할 수 있습니다.
그다음 smali_classes2/owasp/sat/agoat/ 경로로 이동하여 BinaryPatchingActivity.smali 파일을 수정합니다.

현재는 if-eqz로 설정되어 있습니다. 이는 "값이 0(거짓)과 같다면"을 의미하므로, 코드는 조건이 거짓일 때 관리자 버튼이 활성화됩니다.
그러므로 if-eqz로 설정된 코드를 if-nez로 변경하여 조건 검사의 논리를 반전시킬 수 있습니다. 이러한 코드 패칭을 통해 적절한 권한 부여 없이 Admin 기능을 활성화 시킬 수 있었습니다.
코드를 변경한 뒤 컴파일을 진행하고, 새롭게 컴파일한 앱을 기기 내 설치합니다. 설치 후, Binary Patching메뉴로 이동하면:

이전에 활성화되지 않았던 ADMINISTRATION 버튼이 활성화되어있고, 클릭 시 동작하는 것을 볼 수 있습니다.
취약점 발생 원인
바이너리 패칭은 안드로이드 애플리케이션 내 사용자가 APK 파일에 대한 완전한 접근 권한을 갖는 클라이언트 제어 환경에 배포되기 때문에 발생합니다. 앱이 설치되면 공격자는 APK를 추출하고 디컴파일하여 내부 로직을 분석할 수 있습니다.
컴파일된 코드는 본질적으로 수정으로부터 보호되지 않아, 클라이언트 측에만 구현된 보안 로직은 우회가 가능합니다.
또한, 안드로이드 앱은 인증 및 권한 부여 같은 제한을 강제하기 위해 종종 변수, 하드코딩된 값 또는 클라이언트 측 검사에 의존합니다. 서버 측 검증, 코드 무결성 확인 및 변조 방지 메커니즘과 같은 보호 조치 없이는 앱의 바이트 코드를 수정하고, 조건 검사를 변경하고, APK를 리패키징할 수 있습니다.
이는 특히 애플리케이션이 자신의 클라이언트 측 로직을 맹목적으로 신뢰할 때 바이너리 패칭을 가능하고 효과적으로 만듭니다.
Mitigation
안드로이드 애플리케이션에서 바이너리 패칭 취약점을 완화하기 위해 다음과 같은 보안 조치를 적용할 수 있습니다.
- 중요 로직은 서버 측 검증: 인증 및 권한 부여와 같은 부분은 클라이언트 측 검사에 의존하지 않고 신뢰할 수 있는 백엔드에서 진행해야 합니다.
- 무결성 및 변조 탐지: 앱의 서명이나 체크섬을 확인하는 등 APK가 수정되었는지 감지하기 위해 런타임 무결성 검사를 진행합니다.
- 코드 난독화: ProGuard나 R8과 같은 도구를 적용하여 클래스 이름, 메서드 및 로직 흐름을 명확하지 않게 만듦으로써 리버스 엔지니어링 및 Smali 코드 수정을 어렵게 만들 수 있습니다.
- 루팅 및 변조된 환경 탐지: 런타임 조작 위험을 줄이기 위해 루팅된 기기나 후킹 프레임워크를 탐지하는 검사를 추가합니다.
결론
결론적으로, 바이너리 패칭 취약점은 안드로이드 애플리케이션이 앱 코드가 수정될 수 없다고 가정하고 보안 결정을 강제하기 위해 클라이언트 측 로직에 의존할 때 발생합니다.
APK 파일은 추출, 디컴파일 및 변경이 가능하여 공격자는 조건부 검사, 하드코딩된 값 또는 권한 부여 로직을 조작해 제한을 우회하고 제한된 접근 권한을 획득할 수 있습니다.
이는 클라이언트 측의 신뢰만으로 보안에 불충분함을 보여줍니다. 이 문제를 해결하기 위해 중요 로직은 서버 측에서 검증되어야 하며, 바이너리 패칭 공격의 영향을 줄이기 위해 무결성 확인, 난독화 및 변조 탐지와 같은 추가적인 보호 조치가 필요합니다.
Comments
Sign in with GitHub to leave a comment.