런타임 보호 기능 RASP의 우회 원리와 보안 취약점 이해하기

모바일 RASP는 애플리케이션 내부에서 보호 로직을 실행시켜 주변 환경의 보안 경계에 의존하지 않는 보안 방식이다. 다만 공격자가 런타임 시스템 인터페이스(특히 libc 함수 경로)를 소유하면 보호 체크도 공격자 디바이스의 공격자 CPU에서 실행되고 판정되어 무력화된다. 이 글은 2026년 8월 기준 공개된 기술 검증 사례를 중심으로, RASP의 내부 구조와 우회 기법의 원리, 검증 시 반드시 구분해야 할 해석 범위를 기술적으로 정리한다.

모바일 RASP란 무엇인가: 앱 내부에서 동작하는 런타임 보호의 원리

RASP(Runtime Application Self-Protection)의 핵심 설계 철학은 보호 로직을 앱 자체 안에 내장하는 것이다. 네트워크 방화벽이나 외부 WAF와 달리, RASP는 실행 환경 주변에 보안 장비를 두지 않고 프로세스 내부에서 직접 이상 행위를 감지한다. 침해된 디바이스에서 앱이 실행 중일 때 재인증 시도, 앱 자체 변경 시도 등 런타임에 발생하는 이상 패턴을 실시간으로 탐지하고, 적대적 환경에서도 앱이 의도된 동작을 유지하거나 추가 공격을 방지하기 위해 프로세스를 종료시킨다.

이 설계의 함의는 명확하다. 보호 로직이 “주변 환경”이 아니라 “프로세스 내부”에 존재하므로, 그 내부의 함수 호출 경로가 공격자의 제어권 안에 들어오면 보호 자체가 무의미해진다. 이 점이 후술할 우회 원리의 출발점이다.

RASP의 내부 구조: 역할이 분리된 독립 보호 라이브러리와 구조 매핑의 중요성

공개된 분석 사례에 따르면, 특정 Android RASP는 단일 모놀리식 모듈이 아니라 역할이 분리된 독립적인 보호 라이브러리의 집합으로 구성된다. 각 라이브러리가 담당하는 검사 항목을 정리하면 다음과 같다.

라이브러리 담당 검사 항목 /proc 읽기 경로
libsafe-lib Frida / Xposed 스캐너 (t=0 킬) libc fopen
libantitrace TracerPid 기반 안티디버그 libc fopen
libtoolChecker 루트 탐지 libc fopen
libDexHelper 패커, raw syscall 기반 DEX 보호 raw syscall

이 표에서 드러나는 핵심 차이는 마지막 행이다. 거의 모든 검사 라이브러리가 /proc를 libc의 fopen으로 읽는 반면, libDexHelper(패커)만 raw syscall로 직접 커널을 호출한다. 이 한 줄의 차이가 “두 가지 완전히 다른 공격 전략”을 만들어 낸다.

구조 매핑이 선행되어야 개별 보호 요소를 평가할 수 있으며, RASP 보호 기능 평가는 구조 매핑과 런타임 조작 검증이라는 두 축으로 이뤄진다. 분석가는 “무언가를 깨뜨리는 첫 번째 규칙은 먼저 매핑하는 것”이라 표현하며, 라이브러리별 역할을 파악한 뒤에야 인터포즈 지점을 설계할 수 있다고 강조한다.

우회의 핵심 원리: 공격자가 libc를 소유하면 fopen의 반환값도 공격자가 결정한다

우회가 성립하는 근본 전제는 다음과 같다. “검사가 공격자 디바이스의 공격자 CPU에서 실행되고, 판정도 공격자 디바에서 내려진다”. 스캐너는 fopen(“/proc/self/maps”) 호출이 실제 메모리 매핑을 반환한다고 신뢰한다. 그러나 LD_PRELOAD 등으로 libc를 소유한 공격자는 그 fopen의 반환값을 직접 결정한다.

/proc는 편집 불가능한 합성 파일이다. 커널이 읽는 시점마다 새로 생성하므로 원문을 직접 수정할 수 없다. 그래서 우회 전략은 파일을 고치는 것이 아니라 스트림 자체를 교체하는 것이다. filtered_stream이라는 중개 계층이 실제 fopen으로 원 파일을 읽고, 힙 버퍼에 검열된 사본(censored copy)을 구축한 뒤, fmemopen으로 그 버퍼를 가리키는 FILE를 반환한다. 호출자인 스캐너는 이 FILE를 “정상적인 fopen 결과”로 받아들이지만, 실제로는 공격자가 필터링한 내용을 읽게 된다.

원문 분석에서 확인된 로그는 “raspbypass: libbypass loaded (maps/status filter + prop spoof active)”와 “filter maps /proc/self/maps”인데, 우회 라이브러리의 로딩과 필터 활성화 사실을 보여준다. 단, 이 로그가 우회 성공 자체를 명시적으로 입증하는 것은 아니다. 확인되는 범위는 기법 원리의 작동 확인 수준이다.

실제 우회 기법: LD_PRELOAD 주입과 프로퍼티 스푸핑의 구현 조건

우회 라이브러리를 프로세스에 주입하는 Android 경로는 링커의 wrap.<pkg> 속성을 활용한다. adb shell setprop wrap.<app> ‘/data/local/tmp/wrap.sh’ 형태로 실행 프로세스를 wrapper 아래에서 띄우고, 그 wrapper가 LD_PRELOAD를 설정한다. 이 기법은 에뮬레이터 또는 루팅 디바이스에서 가능하며, /data/local/tmp 경로를 거치므로 SELinux 정책 대응이 필요하다. 스톡 SELinux 규칙은 이 경로의 접근을 debuggable 앱이나 root 권한에 한정한다.

프로퍼티 스푸핑을 구현할 때는 두 가지 조건이 동시에 충족되어야 한다.

  1. Android는 _systemproperty_get과 _systempropertyreadcallback 두 경로를 모두 사용하므로 둘 다 인터포즈해야 한다. 첫 번째만 스푸핑하면 검출기가 두 번째 경로로 실제 에뮬레이터 프로퍼티를 읽어 버린다.
  2. 호출자가 libc에 넘기는 버퍼는 PROPVALUEMAX, 즉 92바이트 고정 스택 버퍼다. 인터포즈 함수가 이 계약을 정확히 지키지 않으면 앱 자체가 크래시한다.

Build.MODEL만 스푸핑하는 접근은 탐지 순서상 실패한다. 실제 탐지 코드는 ro.build.flavor와 gsm.version.baseband를 먼저 읽으며, 표준 에뮬레이터에서 이 둘 중 하나만 참이어도 즉시 참으로 판정한다. Build.MODEL 검사는 세 번째 순서에 도달하기 전에 이미 판정이 끝나 있다.

왜 스캐너는 속는가: 훅 가능한 libc 호출과 raw syscall의 트레이드오프

전체 RASP 체계를 관통하는 구조적 취약점은 “훅 가능한 호출이든 grep 가능한 명령어든, 어느 쪽이든 노출 경로는 남는다”는 점이다. libc로 데이터를 읽는 모든 검사는 공격자가 인터포즈할 수 있는 검사이며, 이를 raw syscall로 대체하면 인터포즈는 무효가 되지만 다른 형태의 노출(예: grep 가능한 패턴)이 발생한다.

libDexHelper가 raw syscall을 사용하는 것은 이 트레이드오프의 한쪽을 채운 사례다. raw syscall은 libc를 경유하지 않으므로 LD_PRELOAD 기반 인터포즈가 적용되지 않는다. 반면 libc 경유 라이브러리는 fopen, fgets 등 표준 함수 호출로 /proc을 읽기 때문에 “libc 호출은 내가 교체 가능한 함수”라는 전제 하에 우회가 성립한다.

“완벽한 RASP는 존재하지 않으며 트레이드오프만 존재한다”는 게 이 분석이 도달한 결론이다. 각 보호 체크는 훅 가능한 함수 호출에 의존하는가, 아니면 원시 커널 인터페이스에 직접 접근하는가에 따라 공격 표면이 달라지고, 어느 한쪽을 선택하든 다른 형태의 노출이 잔존한다.

프로세스 외부에서 보호된 DEX를 읽을 때: processvmreadv의 의미

안티디버그 우회 시 ptrace를 사용하면 /proc/<pid>/status의 TracerPid 필드가 설정되어 libantitrace의 루프 감지에 즉시 걸린다. processvmreadv는 권한 요건이 ptrace와 같지만, 프로세스에 attach하지 않으므로 TracerPid가 0으로 유지된다. 안티디버그 스레드는 TracerPid를 영구히 0으로 읽어 탐지 조건이 충족되지 않는다.

RASP 우회 검증 시 주의사항: 기술 검증 사례와 제품 취약점 확정의 구분

2026년 8월 22일 Security Desk에서 발행된 검증 가이드는 해당 분석 사례를 특정 제품 취약점 확정이나 공식 보안 고지가 아닌 기술 검증 사례로 규정한다. 제공된 로그에서 확인되는 범위는 maps/status 필터와 프로퍼티 스푸핑이 활성화된 우회 라이브러리의 로딩 기록이며, 이 기록이 우회 성공 자체를 명시적으로 입증하지는 않는다.

보안 엔지니어가 이 자료를 활용할 때는 “라이브러리가 로드되고 필터가 활성화된 상태”와 “보호가 실질적으로 무력화된 상태”를 구분해야 한다. 원저자의 결론 “완벽한 RASP는 존재하지 않으며, 트레이드오프만 있다”는 기술적 한계에 대한 일반론적 진술이지, 특정 버전에 대한 CVE 수준의 확정 판단이 아니다.

OWASP MASVS·MASWE·MASTG와 RASP 검증 프레임워크 연계

모바일 RASP의 보호 기능을 체계적으로 검증하려면 OWASP 모바일 앱 보안 프레임워크 체계를 참조하는 것이 적절하다. OWASP MASVS는 모바일 앱의 보안과 개인정보 보호 요구사항을 정의하고, MASWE는 이를 약점 항목으로 세분화하며, MASTG는 MASWE 약점에 정렬된 검증 테스트를 제공한다. MASTG는 MASVS 컨트롤을 MASWE 약점에 맞춰 검증하는 기술 프로세스를 설명하는 종합 매뉴얼로, 리버스 엔지니어링을 포함한 보안 테스트 방법론을 다룬다.

RASP 우회 검증을 MASTG 체계에 매핑하면 구조 매핑 단계는 MASVS의 런타임 보안 컨트롤 확인에, 런타임 조작 검증(인터포즈, 프로퍼티 스푸핑) 단계는 MASWE의 해당 약점에 대한 PoC 검증에 대응한다. 이 프레임워크를 적용하면 평가 기준이 개별 RASP 제품 벤더가 아닌 “런타임 보호 설계 자체의 구조적 한계”를 평가하는 쪽으로 바뀐다.

정리: 검증 엔지니어를 위한 체크포인트

  1. RASP 라이브러리 구성을 구조 매핑으로 먼저 파악하고, 각 라이브러리의 /proc 읽기 경로(libc vs. raw syscall)를 확인한다.
  2. libc 경유 라이브러리는 fopen 인터포즈와 fmemopen 기반 스트림 교체 기법의 원리 이해를 검증 기준으로 삼는다.
  3. 프로퍼티 스푸핑 시 PROPVALUEMAX 92바이트 계약과 _systemproperty_get / _systempropertyreadcallback 이중 경로를 모두 처리하는지 확인한다.
  4. raw syscall 경유 컴포넌트(libDexHelper 등)에는 별도의 우회 전략이 필요하다는 점을 인지하고, 해당 영역의 공격 표면을 따로 매핑한다.
  5. 검증 결과 해석 시 “라이브러리 로딩 및 필터 활성화 확인”과 “보호 무력화 확정”을 분리 기록하며, OWASP MASTG 프레임워크에 정렬된 테스트 항목으로 문서화한다.

모바일 RASP 우회는 단일 기법이 아니다. 보호 체인의 가장 약한 함수 호출 경로를 찾아 그 반환값을 재작성하는 일련의 설계 작업이다. 그 약한 경로는 설계 단계에서 이미 결정되어 있다. 훅 가능한 함수를 선택했는가, 원시 syscall을 선택했는가. 그 선택이 곧 공격 표면이다.

댓글 남기기