Android Ptrace Bypass 전략
※ Magisk 사용시 문제가 되던 사항으로 Zygisk 가 범용적으로 사용되는 현재에는 본 글이 별 의미가 없음
◼︎Story
금융권 안드로이드 앱에 대해 보안 검수를 한다고 가정해봅시다.
해당 안드로이드 앱에는 비싼 보안솔루션이 올라가 있다고 합니다.
개발자는 보안솔루션을 내려줄수가 없다고 합니다.
검수기간은 보고서 포함 단3일이 주어졌습니다.
시간관계상 수동으로 루팅탐지 우회가 어렵다고 판단하였습니다. 운좋게(?) MagiskHide로 우회가 되었습니다. 너무 기쁜 나머지 프록시를 잡아서 우선 하루동안 네트워크 단을 점검하였습니다.
이제 한시름 놓고, 클라이언트단을 점검하려고 frida를 붙이려고 했더니 다음과 같은 에러가 뜹니다.
"Failed to attach: unable to access process with pid 9060 due to system restrictions; try `sudo sysctl kernel.yama.ptrace_scope=0`, or run Frida as root"
심장이 쿵쾅거리기 시작했지만, 간신히 부여잡고 대책을 생각해봅니다.
예전에 선배가 "앱 프로세스를 선점하면 ptrace를 우회할 수 있고, frida spawning으로 앱 프로세스를 선점할 수 있다" 고 말한 것을 생각해냅니다.
회심의 미소를 지으면서 frida spawn을 시전했는데, 다음과 같은 에러가 뜹니다.
"Failed to spawn: unable to access PID 4388 (zygote64) while preparing for app launch; try disabling Magisk Hide in case it is active"
아드레날린 수치가 솟구치면서 동공이 흔들리고, 등에서 식은땀이 흐르기 시작합니다.
에러 메세지가 말하길 frida spawn하고 싶으면 MagiskHide를 끄라고 합니다.
그런데 MagiskHide를 끄면 루팅탐지 우회가 안됩니다.
이미 시간은 오후2시를 넘어가고 있었고, 클라이언트쪽은 손도 되지 못한 상태이며, 늦더라도 내일 오후부터는 보고서 작성을 시작해서 고객사 보안담당자가 퇴근하기 전까지 보고서를 넘겨야 합니다.
어쩔 수 없습니다. MagiskHide를 끈 상태에서 frida spawn으로 루팅탐지 우회를 하기로 판단합니다. 그러면 ptrace는 신경쓰지 않아도 되니까요.
점점 인생이 꼬이는 느낌이 들었지만 속으로 "할수 있다"를 외치며 IDA로 so파일을 정적 분석한결과 크리티컬한 루팅탐지 로직을 찾아내는데 성공하였습니다.
이를 바탕으로 루팅탐지우회 frida script를 작성하고, 다시 한번 회심의 미소를 지으면서 frida spawn을 시전하였습니다.
그런데...싸늘하게 비수가 날아와 꽂힙니다...보안솔루션이 frida를 탐지하고 있습니다.
심지어 frida spawn으로 앱 프로세스에 붙이자마자 바로 떨궈버립니다.
이것은 듣도 보도 못한 기술입니다. frida가 붙자마자 떨궈버리다니...so 파일을 분석해봐도 어디에서 이런 극악무도한 짓을 하는지 감조차 잡기 어렵습니다.
그래도 포기할 수는 없으니 난독화로 인해 스파게티같은 소스코드를 보면서 원인을 알아내려고 노력합니다.
어느덧 시간은 오후 11시가 가까워지고 있으며, 이상하게도 마음이 편안합니다. 체념을 했더니 그런가 봅니다.
결국 원인은 알아내지 못해서, 내일 오전에 프리다가 필요없는 클라이언트 항목만 점검하고 끝내기로 마음먹고 퇴근을 합니다.
◼︎ptrace bypass 전략
위 이야기는 제가 모의해킹을 시작한지 한달정도 되었을때의 경험을 약간 각색한 것인데요.
나에게는 이런 일이 생기지 않을꺼야라고 확신할 수 있으신가요? 모의해커는 나의 실력에 상관없이 사이트에 투입됩니다.(대부분의 중소 컨설팅업체들이 컨설턴트들의 역량, 의견 물어보지 않고 투입시키며, 심지어 진단대상이 대략적으로 뭔지도 모르는 상태에서 투입되는 경우도 있습니다;;;)
투입된 사이트에 어마무시한 보안솔루션이 올라가 있을 수 있습니다. 그래도 우리는 잘하든 못하든 최선을 다해서 기간안에 결과를 내어놓는게 중요합니다. 하지만 하필 빡센 보안담당자(모의해커 출신)를 만나게 되었고, 최선을 다했지만 잘 못했다면(보안담당자의 실력이 출중하여 결과물의 퀄리티를 간파한 경우) 인생이 피곤해질수 있습니다.
따라서, 모의해커라면 이런 난감한 상황에 부딪힐 경우에 대한 대비가 필요하겠지요.
위의 사례의 경우 ptrace만 우회하면 인생이 smooth 해지는 상황인데요.
첫번째 방법은 so 파일에서 ptrace를 호출하는 부분을 찾아내어 이를 NOP 지시어로 바꿔주면 됩니다. 즉, so 파일 패치를 하는 것인데요. 문제는 비싼 보안솔루션은 당연히 so파일의 무결성 검증을 하고 있다는 것입니다. 따라서, 무결성 검증 로직을 우회해야 하는데, 이게 쉽지가 않습니다. 혹 떼려다 혹 붙이는 꼴이 되는 경우가 많습니다.
두번째 방법은 프로세스 선점, 즉 frida spawn을 통해서 ptrace보다 먼저 앱 process에 attach해서 우회하는 방법인데요. 대부분의 보안솔루션의 ptrace 로직은 이를 통해 우회가 가능합니다. frida를 탐지하더라도 탐지했다고 알림창을 띄우며, frida를 떨궈버리는 경우는 많이 없습니다. 따라서, frida 탐지로직만 우회해주면 ptrace는 신경 쓸 필요 없이 해피 모의해킹을 진행하면 됩니다. 단, MagiskHide를 쓰지 못하기 때문에 루팅탐지도 수동으로 우회해줘야 합니다.
세번째 방법은 frida spawn만 하면 이를 떨궈버리는 극악무도한 경우에 대한 것입니다.(실제 그런 솔루션이 있습니다)
Zygote Injection 이 필요합니다. 안드로이드에서 자이곳은 모든 앱 프로세스의 부모입니다. 그냥 빵빵한 사업체를 운영하는 부모라고 생각하시면 됩니다. 빵빵한 부모 밑에서 태어난 금수저 자식(앱 프로세스)은 부모의 사업체(라이브러리 및 리소스 등)를 물려받아 사회에 빨리 자리잡을 수 있습니다(앱이 빨리 실행).
따라서 부모 사업체에 물려줄 자산을 심어놓으면 금수저 자식은 넙죽 받아들이겠지요. 그런데 그 물려줄 자산이 ptrace를 후킹하는 코드라면? 네. 부모 사업체에 상주해있는 보안업체(보안솔루션)는 외부 침입만 막고 있었는데, 내부에서 세콤(ptrace)을 꺼버리니 "음 금수저 사장님께서 뭔가 생각이 있으시니 끄셨겠지..."라고 생각만 하고 넘어가겠지요.
이미 Zygote Injection 프레임워크는 나와있습니다. 최근에 Magisk에서 버전업된 Zygisk역시 Zygote Injection을 수행합니다.
즉, Zygisk Module을 만들어서 설치하면 Zygote에 해당 모듈이 injection되어 모든 앱 프로세스에서 해당 모듈이 돌아가게 됩니다. 돌아가는 모듈은 후킹코드가 될 수 있습니다.
다음은 Zygisk 모듈인 LSPosed 모듈의 한 예시 코드입니다. 해당 모듈은 ptrace를 후킹하여 앱 프로세스가 아닌 1번 프로세스에 attach하도록 합니다.
...
long (*orig_ptrace)(int request, pid_t pid, void *addr, void *data);
long hook_ptrace(int request, pid_t pid, void *addr, void *data){
LOGD("ptrace got hooked! request: %d, pid: %d", request, pid);
return orig_ptrace(request, 1, addr, data);
}
...
extern "C" __attribute__((visibility("default"))) NativeOnModuleLoaded
native_init(const NativeAPIEntries *entries) {
hook_func = entries->hookFunc;
DobbyHook((void*)ptrace, (void*) hook_ptrace, (void**)&orig_ptrace);
return on_library_loaded;
}
ptrace가 우회된 결과 frida도 spawn할 필요 없이 앱 프로세스에 붙일 수 있습니다.
사실 실제 앱 모의해킹을 하면서 만나본 앱들은 두번째 방법으로 해결이 가능하였습니다.
그러나 개인적으로 앱을 만지작거리다가 세번째 경우를 만났고 다시는 심장이 쿵쾅거리는 경험을 하고 싶지 않은 저로서는 이에 대한 대비책을 생각하여야 했습니다.
저와 비슷하게 심장이 약한 분들에게 본글이 도움이 되었으면 합니다.
다만, 얕은 지식으로 인해 정확하지 않은 정보가 섞여있을 수 있으니 감안하고 읽어주시길 바랍니다.