XML/Xpath Injection

반응형

XML

- W3C에서 개발한 특수한 마크업 언어를 만드는데 사용하도록 권장되는 다목적 마크업 언어

 ※ 마크업 언어

   - 태그등을 이용하여 문서나 데이터의 구조를 기록할 수 있는 언어

   - 주로 다른 종류의 시스템, 특히 인터넷에 연결된 시스템 끼리 데이터를 쉽게 주고 받을 수 있게 하여 HTML의 한계를 극복할

     목적으로 만들어진 언어

 

- XML을 사용하면 메타에디어를 기술할 수 있다.

 XML 사용하지 않는 경우

web hacking site

 - 데이터 표기시 HTML에서 어느부분이 데이터명이고 어디까지 데이터 값인지 알수 없음

XML을 사용한 경우

<dataname>web hacking</dataname>
<datavalue>site</datavalue>

 - 데이터명과 데이터 값처럼 데이터에 의미를 부여할 수 있다.

 - 이와같이 데이터에 의미를 부여하는 것을 메타데이터라고 한다.

 - XML은 수많은 종류의 데이터를 유연하고 자유롭게 기술하는데 적용이 가능하다.

 - XML 사용시 인터넷으로 연결된 시스템끼리 식별 가능한 데이터를 주고 받을 수 있다.

 - XML은 TCP / IP 네트워크 동신 할 때도 많이 사용하고 있다.

 

XPath Injection

- 웹 사이트가 사용자에게 제공한 정보를 사용하여 XPath 쿼리를 보낼 때 발생되는 취약점 공격

- 공격자는 의도적으로 잘못된 형식의 정보를 웹 사이트로 전송하여 XML 구조를 알아낸다.

- 공격자는 XPath Injection 공격을 통해 평소에 접근할 수 없는 데이터에 접근할 수 있게 됨

- XML 데이터가 인증에 사용되는 경우, 공격자는 XPath Injection을 통해 공격자의 권한 상승을 할 수 있음

 

XPath Injection(Login Form)- low

XML / XPath Injection에 들어가면 다음과 같은 로그인 창이 나온다.

etc-image-0

1. SQL 공격이 먹히는지 확인하기 - '

이 창에 인젝션 공격이 먹히는지 확인하기 위해 '(작은따옴표)를  입력한다.

'를 입력하면

etc-image-1

다음과 같은 경고창이 있는데 XPath와 관련된 오류이다.

이제 XPath Injection을 해야하는데 하기 전에 알아야 하는 명령어가 있다.

명령어 설명
/ 최상위 노드
// 현재 노드로부터 모든 노드 조회
* 모든 노드 조회
. 현재 노드
.. 

현재 노드의 상위 노드 접근

parent 현재 노드의 부모 노드
child 현재 노드의 자식 노드
[] 조건문
node() 현재 노드로부터 모든 노드 조회

로그인 페이지가 XML 데이터 베이스로 전송될 때

2. XML Injection 수행 - ' or 1=1 or '

login = '[login 입력값]' and password= ' [password 입력값]'

이제 login에다가 ' or 1=1 or ' 입력하고 비밀번호에는 아무값이나 입력한다.

 

etc-image-2

입력을 하면 다음과 같은 방식으로 DB에 들어가게 된다.

-> login = ' ' or 1=1 or ' ' and password = '123' 

and 연산자보다 or 연산자의 연산 순위가 높기 때문에 or문이 참이 되는 쿼리를 입력하게 되면 and 연산 결과에 상관없이 참이된다.

다음과 같이 입력하면

etc-image-3

이러한 결과가 나오게 된다.

XML Injection으로 neo를 제외한 나머지 사용자에 접속할 때는 or 연산자에 1=1 대신에 사용자 이름을 넣어주면 된다.

ex) alice 정보를 알고 싶을때

alice ' or 'alice'='alice

alice ' or 'alice'='alice

다음과 같이 입력하면 alice의 정보가 나온다.

etc-image-4

현재 페이지는 blind sql injection 처럼 참일경우와 거짓일 경우 때의 응답만 제공하고 있다.

이제 XML의 DB 구조를 알아내보자

3. 노드의 갯수 구하기 - count()

여기서 count 함수를 사용할건데 count() 함수는 인자로 받은 노드의 개수를 반환해주는 함수이다.

etc-image-5
출처 : http://tcpschool.com/xml/xml_xpath_filterExpression

count를 이용해서 현재 노드의 부모 노드부터 자식노드가 몇개인지 파악한다.

neo' and count(../child::*)=1 or 'a'='b

다음과 같은 코드는 ..(현재 노드의 상위 노드)/child(자식노드)::*(전체 노드 조회) = 1(노드의 갯수) or 'a'='b

다음과 같이 뒤에 false인 값을 집어 넣어 (true / false) or false를 맞춰준다.

만약 뒤에 참값이 나오게 되면 앞에 있는 내용이 거짓이어도 항상 참값이 나오기 때문이다.

node == 1일경우

etc-image-6

다음과 같이 'Invalid credentials'라는 문구가 나온다.

이와 같은 방식을 계속 반복하다보면 노드가 6일 경우

etc-image-7

다음과 같은 결과가 나온다.

이로써 현재 노드의 부모노드의 자식의 노드 수는 6개인 것을 알 수있다.

노드의 개수를 알아냈으니 다음으로 부모 노드명을 확인해보자

4. 부모 노드명 길이 알아내기 - string-length(), name()

부모 노드명을 알아내기위해 먼저 부모노드의 길이부터 알아내자

길이를 알아내기 위해 string-length 함수와 name 함수를 사용하였다.

neo' and string-length(name(parent::*))=1 or 'a'='b

다음과 같이 입력하면

etc-image-8

일단 부모노드의 길이는 1은 아니라는 것이다. 이제 이와같은 방식으로 길이를 늘려가면

길이가 6일 때 

 

etc-image-9

다음과 같이 참인 결과가 나오게 된다.

이로써 부모 노드의 이름은 6글자라는 것을 알 수 있다.

5. 부모 노드 이름 알아내기 - name(), substring()

부모 노드의 길이가 6글자인것을 알아냈으니 다음으로는 부모 노드의 이름을 추측해 보도록 하겠다.

부모 노드의 이름을 알아내기 위해서 name함수와 substring 함수를 사용하겠다.

neo' and substring(name(parent::*),1,1)='a' or 'a'='b

substring 와 name 함수를 사용해 첫번째 글자의 이름을 알아내고 있다.

위의 코드를 해석하면 parent 노드의 첫번째 글자가 a인가?라는 뜻이다.

결과를 확인해보면

etc-image-10

거짓의 결과가 나온다

이 행위를 반복하다 보면 'h'에서 참인결과가 나오게 된다.

etc-image-11

이로써 부모노드의 이름은 'h○○'라는 것을 알 수 있다.

만약 두번 째 단어를 알고 싶으면substring(name(parent::*),1,1) -> substring(name(parent::*),2,1)로 바꿔주면 된다.

이 방식을 통해 전체 부모노드 이름을 알아내면 heroes라는 것을 알 수 있게 된다.

neo' and substring(name(parent::*),1,6)='heroes' or 'a'='b

5. 자식 노드의 글자수 알아내기 - position()

부모 노드를 알아냈으니 이제 자식 노드의 이름을 알아내자

자식 노드의 이름을 알아내기 전에 자식 노드의 글자 수 부터 알아 보자

neo' and string-length(name(../child::*[position()=1))=1 or 'a'='b

position함수는 MYSQL에서 limit 함수를 의미한다.

다음 코드의 뜻은 heroes(부모노드)의 자식노드 중 첫번째 노드(position()=1)의 길이가 1인가 이다.

당연히 결과는 false이다.

etc-image-12

이 과정을 계속 반복하다 보면 글자가 글자수가 4일 때 true의 결과가 나온다.

neo' and string-length(name(../child::*[position()=1))=4 or 'a'='b

이로써 첫번째 노드의 길이는 4글자라는 것을 알게 되었다.

※ 현재 노드의 길이 알아내기

우리는 현재 hero라는 자식 노드안에 있다. 만약 현재 노드의 길이를 알아내려면 다음과 같이 입력하면 된다.

neo' and string-length(name(.))=4 or 'a'='b

6. 자식 노드의 이름 알아내기 - substring(), position()

첫번째 자식 노드의 길이가 4글자인것 까지 알아냈으니 다음으로 첫번째 자식노드의 이름을 알아보자

neo' and substring(name(../child::*[position()=1]),1,1)='a' or 'a'='b

다음 코드를 해석하면 첫번째 자식 노드의 첫번째 글자가 a인가?이다.

당연히 결과는

etc-image-13

기대 안했다.

다음과 같은 방식을 계속 반복하다보면

'h'일때 true의 결과가 나온다.

etc-image-14

이로써 첫번째 자식 노드는 'h○'라는 것을 알 수 있다.

이 방식을 반복하다 보면 첫 번째 노드의 이름은 'hero'라는 것을 알 수 있다.

neo' and substring(name(../child::*[position()=1]),1,4)='hero' or 'a'='b

이제 6개의 노드 중 한개 찾았다 이제 5,6번을 반복해서 6개의 노드를 전부다 알아내면 노드 이름이 전부 'hero'라는 것을 알 수 있다.

대충 구도를 그려보면

etc-image-15

heroes라는 부모노드 밑에 6개의 hero라는 자식노드가 있는 구조이다.

 

※ 현재 노드의 이름 알아내기

우리는 현재 hero라는 자식 노드안에 있다. 만약 현재 노드의 이름을 알아내려면 다음과 같이 입력하면 된다.

neo' and substring(name(.),1,1)='a' or 'a'='b

7. 자식노드의 이름 알아내기 - [], string-length()

이제 hero의 자식 노드의 갯수를 알아보자

neo' and string-length(name(//hero[1]/child::*[position()]=1))=1 or 'a'='b

다음 코드를 해석하면 현재 노드서부터 모든 노드까지(//)에서 첫번째 hero 노드(hero[1]) 첫번째 자식 노드([position()]=1)이 한글자(=1)인가?이다.

당연히 결과는 false이다.

etc-image-16

계속 반복해보면 노드의 길이가 2일 경우 True 결과가 나온다.

etc-image-17

8. hero의 자식 노드 이름 알아내기

이제 2글자인 것 까지 알아냈으니까 이름을 알아내자

neo' and substring(name(//hero[1]/child::*[position()]=1),1,1)='a' or 'a'='b

코드를 해석하면 hero의 자식노드의 첫번째 글자가 a인가? 이다.

당연히 결과는 False이다.

etc-image-18

b부터 계속 대입 해보면 'i'에서 True 결과가 나온다.

neo' and substring(name(//hero[1]/child::*[position()]=1),2,1)='a' or 'a'='b

이로써 자식 노드의 첫번째는 'i○'라는 것을 알 수 있다.

두번째 단어를 알아보자

간단하다. ),1을 2로 바꿔준다.

당연히 'a'는 False이다.

계속 반복하다보면 'd'일 때  True의 결과가 나온다.

neo' and substring(name(//hero[1]/child::*[position()]=1),2,1)='d' or 'a'='b

이제 첫번째 자식 노드의 이름이 'id'가 맞는지 확인해 보자

neo' and substring(name(//hero[1]/child::*[position()]=1),1,2)='id' or 'a'='b

현재 노드들의 관계를 그려보면

etc-image-19

다음과 같이 나온다.

9. 자식 노드(id) 값의 길이 알아내기 - string-length(), string()

이제 자식 노드의 값을 알아보자

우선 자식 노드의 값의 길이 알아내기 위해 string을 사용한다.

string안에 input 값으로 길이를 알아낼 노드의 값을 적는다.

neo' and string-length(string(//hero[1]/id))=1 or 'a'='b

다음과 같이 입력하면

etc-image-20

다음과 같이 나온다 

10. 자식 노드(id) 알아내기 - substring(),string()

첫번째 노드의 길이가 한글자라는 것을 알아냈다. 

이제 단어를 알아내자

neo' and substring(string(//hero[1]/id),1,1)=1 or 'a'='b

다음과 같이 입력하면 True 값이 나온다.

etc-image-21

이로써 hero의 첫번째 값은 1이라는 것을 알 수 있다.

이제 9번과 10번을 반복하다 보면 노드들의 값을 알아낼 수 있다.

 

XPath Injection(Login Form)- medium, high

로그인 창에 '를 입력해보자

etc-image-22

low때와 다른 결과이다.

이유를 확인하기 위해 xmli_1.php 페이지 코드를 확인해보자

etc-image-23

난이도 (중)과 (상)은 xmli_check_1 함수가 적용되어 있다.

etc-image-24

functions_external.php 페이지에서 xmli_check_1 함수를 확인해보면

모든 특수문자를 빈 문자로 치환해준다.

그로인해 특수문자가 먹히지 않아 공격이 먹히지 않는다.

반응형

'웹해킹 > bee-box' 카테고리의 다른 글

Broken Auth - Insecure Login Form  (0) 2019.10.21
XML/XPATH Injection(Search)  (0) 2019.10.21
XML / XPATH 인젝션 - Login Form  (0) 2019.08.07
SQL Injection - Blind - Time Based  (0) 2019.08.06
Blind SQL Injection - Boolean Based  (0) 2019.08.05