본문 바로가기

보안지식/주통기반

[주통기반] 공격 시나리오 정리(LDAP 인젝션)

안녕하세요! 이번에는 주통기반에 있는 LDAP 인젝션을 설명해 드리겠습니다.

 

우선 LDAP 인젝션이 뭔지 알아야 되겠죠?

 

 

-LDAP?

 

LDAP

 

Lightweight Directory Access Protocol의 약자입니다.

그대로 해석을 하면 경량 디렉터리 접근 프로토콜을 뜻한다고 합니다.

 

가벼운 디렉터리이여서 데이터를 적은 양으로 전송이 가능하고 빠른 응답이 가능하다고 합니다!

이 말은 사용자들이 디렉터리 정보를 빠르게 조회할 수 있게 도와주는 겁니다.

 

.. 간단히 말씀드리자면 보통 서버보단 빠른 서버 시스템이라고 보시면 됩니다!

 

그래서 많은 사용자가 있는 곳은 종종 이용한다고 하네요.

 

클라이언트가 LDAP 어플 통해 요청을 하면 LDAP API에서 요청을 만들어 서버로 보냅니다.

근데 OSI 7 계층을 전부 안 쓰고 TCP/IP 계층에서 옮겨집니다.

그럼 LDAP 서버는 그 요청을 받고 백엔드 즉 데이터 베이스에 데이터를 가져오게 합니다.

그걸 반대로 응답을 하는 게 작동 원리입니다.

 

에스코어에 퍼온 사진입니다. LDAP 작동 원리를 간단하게 설명합니다.

 

이 OSI 7 계층을 전부 안 쓰고 통신한다는 게 네트워크 부담을 줄인다고 합니다.

 

 

 

-LDAP Injection

 

인젝션이라 하면 다들 아시다시피 SQL Injection을 떠올리실 거예요.

 

같은 원리입니다! 

 

LDAP 통신으로 데이터베이스에 접근을 합니다.

그럼 LDAP 통신 이용해 데이터베이스에 있는 내용을 받을 수 있는 쿼리문을 넣으면

 

SQL Injection 처럼 가로챌 수 있겠죠?

 

 

**LDAP 쿼리문

그럼 쿼리문을 알아야만 하겠죠?

 

간단합니다! 기본 문법은 (operator (attribute=value)) 입니다.

 

operator(연산자) : &(AND) , |(OR), !(NOT) 이런 논리 연산자가 오는 위치입니다.

attribute(속성) : 검색하고 싶은 위치의 속성을 작성합니다. 디렉터리 위치 이름을 적는 곳입니다.

value(값) : 속성에서 찾을 값을 작성합니다. 

 

간단하게 제가 사용자 명(username)은 john을 찾고 싶고 부서(department)는 IT인 사용자를 조회하는 LDAP 쿼리는

 

(&(objectClass=user)(username=john)(department=IT))

 

objectClass가 user인 객체 중에 username이 john이고 department이 IT인 사용자를 조회하는 겁니다.

 

 

 

맨 앞에 &가 있으니 전부 AND 구문입니다. 만약 | 을 중간에 넣고 싶다면

 

(&(objectClass=user)(username=john)) (|(department=IT)(title=Manager))

 

이렇게 쓰시면 됩니다.

user객체에 username이 john인 사람이고 department이 IT 또는 title이 Manager인 사용자를 조회합니다.

.

.

.

.

.

다시 돌아가 인젝션 이야기 하겠습니다.

 

여기서 인젝션에 쓰이는 구문은 * 입니다!

*은 SQL 구문에 LIKE 와 같은 역할을 합니다.

 

즉 (&(username=a*)) 이런 구문이면 a을 시작하는 모든 문자열을 검색합니다.

 

그럼 만약 LDAP을 이용해 로그인 서비스를 하는 곳이 있다고 가정하겠습니다.

 

https://www.root-me.org/en/Challenges/Web-Server/LDAP-injection-Authentication

 

Challenges/Web - Server : LDAP injection - Authentication [Root Me : Hacking and Information Security learning platform]

>comment jouer au ctf toute la journée ? en posant un jour de congés

www.root-me.org

실습은 여기 Root me에서 했습니다.

 

 

아하.. 로그인을 하네요.

일단 쿼리문 예측이 가능하죠.

(&(uid=[ID란 작성한 값])(upw=[password 작성한 값])) 이겠죠!

 

그럼 일부러 *)을 넣어서 에러 구문을 내보겠습니다.

 

root me

 

에러 구문이 나와주네요!

 

당연히 보통 로그인 화면에 저렇게 에러 구문 안 보여 줍니다!

그럼 정상적인 계정으로 로그인할 때

 

)(&)) 을 넣어서 로그인이 되는지 확인하면 됩니다.

저 쿼리문 뜻은 그냥 그리고을 넣은 쿼리입니다. 만약 정상 로그인 되면 LDAP 인젝션이 통하는 걸 알 수 있겠죠.

 

어쨌든 저 에러문은 문법 에러입니다. (&(uid=*))(userPassword=1234)) 괄호 문법 오류가 난 겁니다.

정상 문법은 (&(uid=*)(userPassword=1234)) 이겠죠! 

 

 

 

*은 문자 포함된 모든 문자열을 검색하는데 아무 문자 없이 *이 있으면 모든 문자열을 검색합니다.

 

그럼 *)(&을 id와 pass에 적으면 어떻게 될까요?

 

(&(uid=*)(&(userPassword=*)(&)  이렇게 쿼리문이 작성이 됩니다.

해석하면 uid는 모든 문자열 검색하고 userpassword도 모든 문자열 검색합니다.

 

그럼 무조건 참이 나오게 되겠죠.

 

*)(&

 

 

성공!

 

이렇게 LDAP 인젝션을 해보았습니다.

 

 

 

***대응방법

좋은 방법은 Prepared Statements을 이용하는 겁니다!

 

prepared statements는 미리 컴파일을 한 뒤에 입력한 데이터를 바인딩하는 함수입니다.

간단히 말해 미리 실행해두고 입력한 값을 넣어서 보는 겁니다. 이러면 입력한 모든 값은 문자로 취급하게 됩니다.

 

만약 저 함수 이용하기 힘들다면 whitelist을 이용해 특수문자들을 필터링하면 됩니다.

 

예시입니다.

 

감사합니다!