Root권한이 허용된 단말기에 앱 설치 후 실행할 경우 루팅이 탐지되며 강제종료 되는 것을 확인

 

이번에 루팅을 해제한 상태에서 실행할 경우

비밀키를 입력하라는 메시지가 출력된다. 틀린 비밀키 입력 시 다시 시도하라는 문구가 출력

 

2. 목표

1. 비밀키 검증 우회

2. 비밀키를 찾아서 입력

두 가지 방법으로 좁힐 수 있다.

 

3. 풀이

1) JEB3 Decompiler를 사용하여 Manifest부터 확인

Manifest 확인 시, 패키지명은 owasp.mstg.uncrackable1, 메인 액티비티 이름은 sg.vantagepoint.uncrackable1.MainActivity이다.

 

2) 메인 액티비티 sg.vantagepoint.uncrackable1.MainActivity 확인

루팅 탐지로직과 비밀키 입력 시 성공여부를 판단하는 로직이 보이며 각각 onCreate, verify 메서드라는 이름을 가지고 있다.

 

3) 루팅탐지 로직 분석

이 루팅을 탐지하는 로직이며, sg.vantagepoint.a 패키지 안의 c 클래스a, b, c 메서드를 모두 false를 만족하여야 루팅 탐지가 안되는 것을 확인할 수 있다.

c 클래스의 내부를 확인한 결과 a, b, c 메서드가 각각 무슨 일을 하는지 확인 할 수 있다.

a 메서드는 su의 PATH를 탐지하여 단말기에 su 경로가 존재하는지 확인

b 메서드는 test-keys라는 문자열이 있는지 확인

c 메서드는 su 바이너리들이 있는지 탐지

 

4) 루팅탐지 우회를 위한 Frida 코드 작성 후 실행

Java.perform(function(){
	// 콘솔로그로 정상 동작하는지 테스트 수행
	console.log("[*] passed!");
	
	// Rooting 우회
	var ByPassRooting=Java.use("sg.vantagepoint.a.c");
	console.log("[*] Rooting Detect_hook!!");
	ByPassRooting.a.implementation = function(param){return false;}
	ByPassRooting.b.implementation = function(param){return false;}
	ByPassRooting.c.implementation = function(param){return false;}
	console.log("[*] Rooting Bypass!!");
});

 

 

5) 루팅 우회 후, 비밀키 입력할 경우 다시 입력하라는 문구 출력

 

6) 비밀키를 알아내어 검증 우회 시도

UnCrackable에서 사용하는 모든 String 문자열을 모두 Console.log로 출력하는 후킹 코드 작성

Java.perform(function(){
	// 콘솔로그로 정상 동작하는지 테스트 수행
	console.log("[*] passed!");
	
	// Rooting 우회
	var ByPassRooting=Java.use("sg.vantagepoint.a.c");
	console.log("[*] Rooting Detect_hook!!");
	ByPassRooting.a.implementation = function(param){return false;}
	ByPassRooting.b.implementation = function(param){return false;}
	ByPassRooting.c.implementation = function(param){return false;}
	console.log("[*] Rooting Bypass!!");

	// 사용하고 있는 텍스트 출력하기
	var HookString = Java.use("java.lang.String");
	HookString.equals.implementation = function(param){
		console.log(param);
		return true;
	}
});

실행 결과, 사용하고 있는 모든 문자열이 출력되고 있어서 비밀키로 의심되는 문자열만 필터링한다.

이를 위한, 후킹코드를 재작성한다.

Java.perform(function(){
	// 콘솔로그로 정상 동작하는지 테스트 수행
	console.log("[*] passed!");
	
	// Rooting 우회
	var ByPassRooting=Java.use("sg.vantagepoint.a.c");
	console.log("[*] Rooting Detect_hook!!");
	ByPassRooting.a.implementation = function(param){return false;}
	ByPassRooting.b.implementation = function(param){return false;}
	ByPassRooting.c.implementation = function(param){return false;}
	console.log("[*] Rooting Bypass!!");

	// 사용하고 있는 텍스트 출력하기
	var HookString = Java.use("java.lang.String");
	HookString.equals.implementation = function(param){
		// 키 값이 아닌 항목 추가
		if (param == "ko-KR" | param == "owasp.mstg.uncrackable1" | param == "android.view.Display$HdrCapabilities" |  param == "SEC_FLOATING_FEATURE_MESSAGE_CONFIG_PACKAGE_NAME" | param == "sg.vantagepoint.uncrackable1.MainActivity" | param == "value" | param == "_track_generation" | param == "android.content.res.Configuration" | param == "0x4f4c" | param == "user" | param == "android.graphics.Rect" | param == "SEC_FLOATING_FEATURE_COMMON_SUPPORT_ULTRA_POWER_SAVING" | param == "SEC_FLOATING_FEATURE_COMMON_SUPPORT_SAFETYCARE" | param == "time_12_24" | param == "java.io.tmpdir" | param == "package" | param == "/data/app/owasp.mstg.uncrackable1-Qm86DR0g7jzG1URJA_qGOA==/base.apk" | param == "_generation" | param == "android.util.MemoryIntArray" | param == "sans-serif" | param == "sans-serif-medium" | param == "v30" | param == "android.os.ParcelFileDescriptor" | param == "settings" | param == "_generation_index" | param == "_generation_index" | param == "window" | param == "KRW" | param == "0"){
		}
		else{
			console.log(param);
		}
		return true;
	}
});

비밀키 값으로 의심되는 문자열 중 “I want to believe”가 보이며, 루팅 해제 후, 키 값 확인

 

7) 비밀키 값 확인

1. 분석 과정

1. APK 파일 구조체 파악
2. 구조체를 보기 위해 APK 파일 디컴파일
   - smali 코드로 변환
   - smali 코드를 java로 변경
   - APK > smali > java 이 과정을 알아야함
   - 원하는 smali 코드로 분석할지, java 코드로 변환해서 분석할지 선택
   - smali 코드는 난독화가 되어있으면 분석에 힘듬, java 코드로 분석 추천
3. 앱 동작과정 분석 (동적분석, 정적분석)
   - 참고로 사람마다 분석 스타일이 다름
4. 디컴파일이 완료되었으면, java 코드를 볼 수 있고, 소스코드 분석 포인트를 잡아야함
   - 이것도 분석 스타일이 다름
5. frida를 셋팅하여 후킹 준비
    - frida의 기능을 파악
    - 사용할 기능은 frida docs를 검색해서 기능을 직접 찾아야함
6. 후킹 환경 세팅
7. 실제 후킹 시도

 

2. APK 파일 구조체 파악

JEB Decompiler for Android를 다운로드 받아 실행하고, APK 파일을 업로드 후,
Manifest에서 Package 이름 확인, MAIN 액티비티의 이름 확인
 
Bytecode/계층구조 탭에서 해당 액티비티의 이름을 찾아가서 키보드의 Tab 버튼을 눌러 구조체 파악
 

3. frida 셋팅

pip install frida
pip install frida-tools
# frida 실행
frida -h
 
frida 서버 파일 다운로드
 
루팅 적용된 진단 폰 연결 후, 아래와 같이 입력 (루팅 과정 생략)
adb push frida-server-16.0.19 /data/local/tmp
 
ls -l 명령어 사용 시 권한이 666으로 되어 있는 것을 확인 (실행 권한이 없다는 뜻)
 
실행 권한 부여 후, frida-server 실행
chmod 777 frida-server-16.0.19
./frida-server-16.0.19 &
 
frida-server 작동 여부 확인
 
진단 폰 연결 후, adb shell을 실행하여 frida-server 실행
adb shell 'su -c /data/local/tmp/frida-server-16.0.19 &'
 
 

1. 보안 방안

정말 간단하다. 모든 Nginx의 alias 설정되어 있는 디렉터리들의 끝을 /로 마무리지어 정확하게 설정하면 된다.

 

2. 시연

1) 도커 컨테이너 내리기

# 컨테이너 ID 확인
docker ps

# 컨테이너 내림
docker kill [컨테이너 ID]

 

2) 도커 이미지 삭제

# 도커 이미지 확인
docker images

# 도커 이미지 삭제
docker rmi [이미지 ID] -f
 

3) 도커 파일 삭제

vulnerable.conf 파일 내부에 nginx 설정이 들어있으므로 이 부분을 수정한다.

 

기존대로 /static 뒤에 슬래쉬(/)가 빠져 있다.

 

위와 같이 /static을 /static/으로 바꾸고 저장한다.

 

4) 도커 컨테이너 다시 생성

docker build -t nginx-traversal .
docker run -d -p 127.0.0.1:3000:80 nginx-traversal:latest

 

5) 브라우저 테스트

이전과 동일하게 주소창에 입력한 결과 flag.txt가 읽혀지지 않는 것을 확인

 

1. 구성 환경

- VMware Player

- CentOS 7.8

- Docker

 

2. 구축

1) VMware에 CentOS를 설치 후 yum update까지 완료한다. (과정 생략)
2) 터미널에서 yum update까지 완료 후 아래와 같이 Docker 설치 수행

yum install docker
systemctl start docker
systemctl status docker

3) Github 샘플 가져오기

yum install git

# 취약점 샘플 GitHub 사이트
git clone https://github.com/tkmru/nginx-alias-traversal-sample

4) 기져온 Dockerfile 실행

cd nginx-alias-traversal-sample/
docker build -t nginx-traversal .
docker run -d -p 127.0.0.1:3000:80 nginx-traversal:latest

 

3. 시연

3000번 포트를 80번 포트로 연결하였으므로 localhost:3000으로 연결할 경우 위와 같은 페이지가 나타난다.

 

먼저 localhost:3000/static/welcome.txt에 접속할 경우, 환영한다는 텍스트 파일이 출력된다.
참고로 해당 샘플 테스트 사이트는 flag.txt를 여는 것이 목적이다.

 

물론, 바로 주소창에 입력해서 해당 경로로 접근하면 404 Not Found 에러가 출력된다.
존재하지 않는 파일이라는 것을 추측할 수 있다.

 

그렇다면 localhost:3000/static/welcome.txt에 다시 돌아간 뒤, localhost:3000/static../를 입력할 경우
403 Forbidden 에러가 출력된다.
여기서 우리는 폴더는 존재하나 직접적인 접근 권한이 나한테 없는 것 추측할 수 있다.

 

그렇다면 아래와 같이 주소창에 입력 해본다.

flag 값이 떨어지는 것을 볼 수 있고, localhost:3000/static../flag.txt 요청 시 
localhost:3000/static/../flag.txt이 요청된 셈이고, 

 

잘못된 별칭(alias) 설정이 공격자가 Nginx가 지정한 대상 폴더 외부의 파일을 읽을 수 있게 할 수 있다는 것을 알 수 있다.

 
 

 

1. 발생한 배경

웹 서버 운영 시, 다수의 클라이언트들이 다양한 브라우저를 통해 접속을 하게 되는데 만약 큰 포털 사이트라면 엄청난 부하를 감당해야 한다. 이를 위해 등장한 것이 경량화 웹 서버라는 개념이며 Nginx는 그 중에 하나이다.

그럼 왜 앞에서 부하가 왜 많이 일어날까?

 

우선 Apache와 같은 웹 서버는 클라이언트로부터 받은 요청을 처리할 때 새로운 프로세스나 쓰레드를 생성하여 처리하는데, 사용자가 많아질수록 그만큼 대응하는 프로세스와 쓰레드도 많아지므로 CPU와 자원이 증가하게되기 때문이다.

 

2. Nginx 란?

(간략하게) 경량 웹 서버 중 하나이며, 클라이언트로부터 요청을 받으면 요청에 맞는 정적 파일(예를 들면, 이미지 파일)을 응답 해주거나, WAS의 부하를 줄이는 로드 밸런서 역할Reverse Proxy Server로 사용하기도 한다.

3. Reverse Proxy Server ?

우선 포워드 프록시(Forward Proxy)와 리버스 프록시(Reverse Proxy) 차이부터 알면 이해가 쉽다.
또한, 우리가 흔히 말하는 프록시 서버는 포워드 프록시(Forward Proxy) 서버를 가르킨다.

지금까지 배워온 프록시 서버 즉, 클라이언트가 인터넷 웹 서버에 요청을 보내면 중간에서 포워드 프록시 서버가 요청을 가로채고 프록시 서버가 해당 요청을 웹 서버에 보내고, 응답을 받아와 다시 클라이언트에게 전달하는 방식이다.


아래 구성도를 보면 프록시 서버(포워드 프록시 서버)보통 클라이언트 앞쪽에 놓여져 있다.

Forward Proxy 구성도 (출처 :  https://losskatsu.github.io/it-infra/reverse-proxy)

이제 리버스 프록시 서버를 보면 포워드 프록시 서버와 반대로 웹 서버 앞에 위치하고 있다. 

Reverse Proxy 구성도 (출처 :  https://losskatsu.github.io/it-infra/reverse-proxy)

 

4. Reverse Proxy Server를 사용하는 이유

1) 로드 밸런싱에 유리하다.

앞서 말했듯이 유명하거나 큰 포털 사이트는 수백 수천이 방문하는데 대량의 트래픽 부하를 감당해야하는데, 이를 하나의 서버가 감당하기란 어렵다. 리버스 프록시 서버를 여러대를 웹 서버 앞에 두면 특정 서버가 과부화 되는 것을 방지 할 수 있다.

 

2) 보안성 측면에서 좋다.

리버스 프록시 방식을 사용하면 웹 서버 자체의 IP를 노출 시킬 필요가 없으며, DDoS 공격과 같은 공격을 어느정도 방어할 수 있다.

 

3) 캐시 데이터 저장 기능으로 인한 성능 향상

자주 방문하는 사이트나 해외 사이트 등 매번 반복적으로 동일한 데이터를 요청할 필요 없이 캐싱된 데이터를 사용하면 되므로 성능적인 측면에서 좋다.

 

4) SSL 암호화에 용이하다.

원래 서버가 클라이언트들과 통신을 할 때 암호화 통신을 하는것을 당연하고, 이 과정에서 소모되는 비용은 상당하다. 그러나 리버스 프록시에는 이 과정이 모두 포함되어 있어 안전한 통신이 가능하다.

 

5. Forward Proxy 와 Reverse Proxy 차이

솔직히 위 도식도만 보면 크게 차이가 없어 보인다.

포워드 프록시(Forward Proxy)클라이언트의 입장에서 본인이 누구인지 웹 서버한테 숨기는 것에 중점을 두고 있고, 리버스 프록시(Reverse Proxy)는 다수의 클라이언트가 정체를 숨길 필요 없이 웹 서버를 방문할 경우 정확한 웹 서버의 위치나 정보를 숨기고, 성능 향상 등을 통해 부하를 줄여 웹 서버를 보호하는 것에 중점을 두고 있는 것 같다.

+ Recent posts