보안개구리

4. Input Validation Issues(입력 검증 이슈) 본문

앱 진단(Android)/Diva 실습

4. Input Validation Issues(입력 검증 이슈)

보안개구리 2024. 7. 25. 09:26

[Part 1]

1) 7.Input Validation Issues - Part1에 접속합니다. 

목표: 세 명의 사용자가 존재. 검색을 통해 세명의 모든 사용자 데이터를 출력하기

힌트: 입력값을 필터링하거나 검증하지 않을 경우 문제가 발생할 수 있음. 테스트의 편의를 위해 DB에 세명의 사용자가 이미 존재하는데 그중 한 사용자는 'admin' 

 요약하자면 현재 DB에 3명의 사용자가 있고 그중 하나가 'admin'입니다. 해당 액티비티에는 입력값 검증이 없기 때문에 그 부분을 이용하여 나머지 두 명의 사용자도 찾으라는 문제인 것 같습니다. 먼저 'admin'을 입력해 보겠습니다.

 

2) 'admin' 입력 시 화면 하단에 메시지가 출력되는데 id값(admin)과 admin계정의 패스워드로 추측되는 패스워드 값(passwd123) 그리고 해당 계정의 신용카드번호(123457812345678)가 노출됩니다. 없는 사용자의 경우도 확인해 보기 위해 임의의 문자열(test0915)을 입력해 보겠습니다.

 

3) 임의의 문자열 즉 등록되는 않은 사용자 계정 입력 시 찾을 수 없다는 메시지가 출력됩니다. 

 

4) 이번 실습은 입력값 검증 미흡에 대한 실습이니까 소스코드를 보기 앞서 먼저 앞서 입력한 두 개의 문자열을 비교해 보도록 하겠습니다.

 admin 문자열 입력 시 User: (admin) pass: (passwd123) Credit card: (1234567812345678)이 출력되었으며

 test0915 입력 시 User: (test0915) not found 가 출력되었습니다.

 이 두 가지로 유추할 수 있는 점은 

 1) 입력한 문자열은 반드시 출력값에 포함된다

 2) 입력한 문자열이 실제 아이디일시(참일 시) 패스워드정보가 출력, 그렇지 않을 시(거짓일시) not found 출력된다

 참 거짓에 따라 값이 변환되며 입력한 문자열이 쿼리에 직접 들어갈 수 있다는 점을 생각해 보면 SQL Injection 공격을 시도해 볼 가치가 있습니다.

 

5) 먼저 쿼리문을 추측해 보면 SELECT * FROM test WHERE user = '[유저명]'; 으로 예상해 보겠습니다. 그렇다면 해당 쿼리문을 반드시 참값을 만들기 위해서는 입력값에 [' or '1'='1]을 입력하게 되면 전체적인 쿼리문은 SELECT * FROM test WHERE user = '' or '1'='1'로 완성되며 이때 앞에 값이 참 뒤에 값도 참이기 때문에 해당 쿼리문은 반드시 참이 됩니다.

 해당 구문( ' or '1'='1)을 입력해 보도록 하겠습니다.

 

6) 쿼리 구문 입력 시 화면 아래에 사용자 정보들이 정보 노출되는 것을 볼 수 있습니다. 그렇다면 해당 소스코드를 확인해 보도록 하겠습니다.

 

7) 소스코드 확인 시 search 메서드를 보면 사용자 입력값을 쿼리에 직접 넣게 되어 위 사례처럼 SQL Injection 공격이 발생하게 되었습니다. SQL Injection 공격을 예방하기 위해 preparedstatement를 사용해 사용자 입력값과 쿼리를 분리시켜야 합니다.

 

 

[Part 2]

1) 8.Input Validation Issues - Part2에 접속합니다. 

목표: 웹 URL 외 민감한 정보에 접근

힌트: 입력값이 필터링되거나 검증되지 않으면 문제가 발생할 수 있음. 외부에서 입력값을 받을 시 반드시 검증을 해야 함 

 먼저 임의의 문자값(1)을 먼저 입력해 보겠습니다.

 

2) '1'이라는 값을 입력 시 해당 웹페이지를 로드할 수 없다고 나옵니다. 그럼 제 블로그 주소를 검색해 보도록 하겠습니다.

 

3) 블로그 주소 검색 시 해당 블로그로 이동하는 것을 확인하였습니다. 아마 해당 액티비티는 사용자가 입력한 URL이 직접 웹뷰에 로드되는 방식인 것 같은데 여기서 목표는 URL 이외의 접근이었고 힌트는 입력값 검증 불충분입니다. 그렇게 생각하면 할 수 있는 방식은 로컬파일 시스템 접속입니다.

 

4) URL 입력 창에 URL 대신 file:///data/data/jakhar.aseem.diva/shared_prefs/jakhar.aseem.diva_preferences.xml 구문을 입력해 보겠습니다. 해당 파일은 3. Insecure Data Storage - Part1 실습 때 로그인 과정에서 생성된 파일로 아이디와 패스워드 정보를 담고 있습니다. 이렇듯 URL 입력 시 별도의 검증을 하지 않아 로컬 파일에 접근이 가능함을 확인하였습니다.

 

 

[Part 3]

1) 13.Input Validation Issues - Part3에 접속합니다. 먼저 목표 해당 앱에 DOS 공격을 하라는 것 같긴 한데 정확히 무엇을 원하는지는 잘 모르겠습니다. 힌트 확인 시 기존과 비슷하게 입력값 검증이 미흡하다고 하며 특히 해당 취약점은 메모리 손상 취약점이라고 합니다. 입력창에는 어떤 값을 입력해도 "Access denied"라는 값이 출력됩니다. 우선 jadx를 통해 코드를 확인해 보도록 하겠습니다.

 

2) push 메서드 확인 시 조건문이 참인 경우 "Launching in~"라는 메시지가 거짓일 경우 "Access denied!"라는 메시지가 출력됩니다. 조건문의 조건을 확인하기 위해 'djni.initiateLaunchSequence' 메서드를 확인해보겠습니다.

 

3) DivaJni 클래스는 네이티브 메서드를 호출하기 위해 정의된 클래스로 https://gaeguloo.tistory.com/110 12. Hardcoding Issues - Part2에서도 다뤘습니다. 기존과 동일하게 Ghidra를 통해 확인해 보겠습니다.

 

4) 코드를 우리가 입력했던 문자열을 처리하고 결과에 따라 0 또는 1을 반환하는데 이때 조건을 보면 문자열이 ".dotdot"가 일치할 경우 1을 반환합니다. 해당 문자열을 입력해 보도록 하겠습니다.

 

5) 해당 문자열 입력 시 10초 뒤 발사라는 메시지가 출력됩니다. 기존 목표가 미사일을 막는 거고 힌트에 메모리 손상 취약점이라는 키워드가 있었으므로 해당 방법은 정답이 아닌 것 같습니다. 메모리 관련 취약점과 위 코드 내 strcpy() 함수를 사용한 것을 생각하면 버퍼오버플로우 취약점이 존재함을 의심할 수 있습니다. 다시 한번 코드를 살펴보겠습니다.

 

6) strcpy(local_1c, pcVar1); 는 pcVar1이 가리키는 문자열을 local_1c에 복사하는 데 이때 local_1c는 28바이트의 고정 크기를 가지며 여기 사용된 strcpy() 함수는 입력 문자열의 길이를 확인하지 않고 복사하기 때문에 pcVar1이 가리키는 문자열의 크기가 local_1c의 크기 보다 보다 클 경우 버퍼 오버플로우가 발생할 수 있습니다. 문자열을 입력하는 공간에 많은 양의 문자열을 입력해 보겠습니다.

 

7) 아래와 같이 무수히 많은 양의 데이터를 입력할 경우 앱이 중지된 것을 확인하였습니다. 해당 방법이 아마 본래의 실습에서 원하던 방식이 아닐까 싶습니다.