반응형

Xpath injection 문제를 풀어보았습니다.

관리자 패스워드를 획득하는 것이 목적입니다.

아직 Xpath Injection에 대한 개념이 없어서 사전 검색을 먼저 해보았습니다.

 

Xpath Injection 이란?
  • XML 구조에 악의적인 쿼리/구문을 삽입하여 정보를 탈취하는 공격
  • XML DB 내용을 선택 및 조작
  • XML : 데이터를 트리 구조의 노드로 표현하며, 사용자 정의로 데이터 분류가 가능함(=구조화된 데이터베이스 조작)
  • 즉, XML이 DB, Xpath를 SQL 이라고 생각하면 된다.
Xpath 명령어
/ 최상위 노드
// 현재 노드로부터 모든 노드 조회
* 모든 노드 조회
. 현재 노드
.. 현재 상위 노드 접근
parent 현재 노드의 부모 노드
child 현재 노드의 자식 노드
[] 조건문 
node() 현재 노드로부터 모든 노드 조회

 

Xpath 함수
count() 노드들의 개수를 반환하는 함수
string-length() 문자열의 길이를 반환하는 함수
::* 지정 노드의 모든 내용
name() 노드의 이름을 반환하는 함수
substring() 지정한 문자열을 반환하는 함수
position() 노드의 위치를 반환하는 함수
string() 인자로 받은 값을 문자열로 반환하는 함수

 

문제 풀이

문제에 들어가면, 메뉴가 3개가 보입니다.

 

Members 메뉴를 클릭하면 계정 리스트가 보입니다. 그 중에서 두 번째 열의 John이 관리자군요.

John의 패스워드를 획득해야 합니다.

 

Login 메뉴를 클릭하였더니, Username과 Password를 입력하는 창이 보입니다.

Xpath injection이 가능한지 여부를 판단하기 위해 특수문자를 입력해 보았습니다.

 

[Step1. 취약 여부 판단1]

특수문자를 입력해보았더니 XML 문법 관련 Error가 뜹니다. 여기가 구멍일 것 같다는 느낌이 듭니다.

 

[Step2. 취약 여부 판단2]

이번에는 username : admin / password : 'or '1'='1 값을 입력해보았더니, Steve 계정으로 로그인이 되었습니다.

응답 값에서 해당 계정의 username과 password 값이 확인됩니다.

 

username : admin / password : 'or '1'='2즉 쿼리 구문이 거짓인 경우에는 "Wrong credentials" 로그인 실패 구문이 출력되는 것을 확인 할 수 있습니다.

확실하게 Xpath Injection이 가능하다는 판단을 할 수 있습니다.

 

[Step3. 자신과 동일한 위치의 자식노드 개수 파악] 

본격적으로 관리자의 패스워드를 알아내기 위해 인젝션을 시도해봐야겠죠.

우선, 동일한 위치의 자식노드 개수를 파악해보았습니다.

'and count(../chile::*)=3 or '1'='2

위의 결과(로그인 성공)로 인해 자식 노드가 3개 인것을 확인 할 수 있습니다.

(사실 members 메뉴에서 3개의 계정이 있다는 것을 미리 알고 있기 때문에 이 Step은 생략해도 무방합니다.)

 

[Step4. 부모 노드의 이름 길이가 몇 자인지 파악]

XML 데이터를 파악하려면 부모 노드의 이름을 알아야 합니다. 우선 길이부터 파악하는 것이 빠르겠죠.

'and string-length(name(parent::*))=8

string-length 함수를 사용하여 부모 노드의 이름 길이가 8자임을 알아냈습니다.

 

[Step5. 부모 노드의 이름 파악]

Blind Injection 공격을 이용하여 한 글자씩 파악해보았습니다.

'and substring(name(parent::*), 1, 1)='d' or '1'='2

부모 노드의 첫 글자가 d라는 것을 알 수 있습니다.

위와 같은 방법으로 두번째, 세번째, 8번째 길이까지 알아낸다면, 이름이 "database" 임을 알 수 있죠.

 

[Step6. 첫번째 자식 노드의 이름 파악]

부모 노드의 이름이 database 인 것을 알아냈으니 첫번째 자식 노드의 이름을 알아낼 차례입니다.

이 또한 substring 함수를 이용해 한 글자씩 알아낼 수 있습니다.

'and substring(name(../child::*[position()=1]), 1, 1)='u' or '1'='2

위의 결과로 첫번째 자식 노드의 이름인 "user" 를 획득하였습니다.

 

[Step7. 첫번째 자식 노드(user)의 자식 노드 개수 파악]

부모 노드(database) 밑에 자식노드(user)가 존재함을 알아냈고, 이번엔 user의 자식노드 개수를 알아 봅시다.

앞에서와 마찬가지로 count 함수를 이용해 쉽게 파악할 수 있습니다.

'and count(/database/user[1]/child::*)=5 or '1'='2

user의 자식 노드 개수는 5개네요.

 

[Step8. 첫번째 user 노드의 첫번째 자식노드 정보 파악]

user 노드에 5개의 자식노드가 존재함을 알아 내었으니, 해당 자식 노드들의 이름을 파악해야겠죠.

string-length, substring 함수들을 적절히 사용하여 첫 번째 자식노드가 "userid" 라는 것을 알아내었습니다.

 

[Step9. 첫번째 user 노드의 두번째 자식노드 정보 파악]

이번에는 position 값을 2로 설정하여 user의 두번째 자식 노드 이름이 "username" 임을 확인합니다.

 

[Step10. 첫번째 user 노드의 세번째 자식노드 정보 파악]

user의 세번째 자식 노드의 이름이 "password" 입니다!

이 노드를 이용하여 관리자의 패스워드를 파악할 수 있겠다는 생각이 듭니다.

 

[Step11. 첫번째 user 노드의 두번째 자식노드 username의 값 획득]

이제 전반적인 노드 구조를 파악했으니, 해당 노드에 매칭되는 값을 획득해야겠죠.

해당 노드에 들어있는 값을 가져오는 string 함수를 이용합니다.

'and string(/database/user[1]/username)='Steve' or '1'='2

위의 결과로 인해 첫번째 user 노드의 username 값이 Steve 임을 알아낼 수 있죠.

 

[Step12. 두번째 user 노드의 두번째 자식노드 username의 값 획득]

하지만 저희는 관리자의 패스워드가 필요합니다.(Steve의 패스워드는 이미 testing123임을 알 수 있음)

그래서 부모 노드(database)의 두번째 user 노드의 username 값을 확인하였더니 John, 즉 관리자가 들어 있는 것을 확인할 수 있습니다. 두번째 노드의 패스워드 값만 알면 되겠네요.

 

[Step13. 두번째 user 노드의 세번째 자식노드 password의 값 파악]

무턱대고 Blind Injection을 수행하기 전, 사전 정보인 길이를 확인했더니 23자임을 알 수 있네요.

 

substring 함수를 이용해 23자까지 값을 알아내보겠습니다. 우선 첫번째 값은 6이군요.

 

쉽게 인젝션을 하기 위해 저는 Burp Suite의 Intruder 기능을 이용하였습니다.

이로 인해 관리자의 패스워드를 획득할 수 있고, 이것이 Flag 값입니다^^

 

[ETC. 트리구조]

 

[ETC. XML 구조]

반응형

'Study > Wargame' 카테고리의 다른 글

[root-me] PHP - assert()  (0) 2020.01.02
[root-me] JSON Web Token (JWT) - Introduction  (0) 2019.12.20
[root-me] SQL Truncation  (0) 2019.07.18
[root-me] CRLF  (0) 2019.07.18
[root-me] Javascript - Obfuscation1  (0) 2019.04.15

+ Recent posts