NoSQL Injection

2024. 9. 7. 00:58·Web/Web Hacking

NoSQL Injection이란?

Not Only SQL의 약자인 NoSQL은 비관계형 DBMS를 뜻하며 이러한 비관계형 DBMS에서 사용되는 쿼리를 조작하여 인증을 우회하거나 데이터베이스의 내용을 유출시키는 공격이 NoSQL Injection입니다. 이전에 SQL Injection 포스팅에서 언급하였듯 DBMS에는 테이블 형식으로 데이터가 저장되는 관계형 DBMS와 키-값 형태로 데이터가 저장되는 비관계형 DBMS가 있습니다. 아래는 관계형 DBMS인 MySQL과 비관계형 DBMS인 MongoDB의 쿼리문을 비교한 것입니다.

두 쿼리 모두 userid가 admin이고, password가 keshu인 데이터를 불러오는 쿼리이지만, 구조가 다른 것을 알 수 있습니다. mysql에서는 sql문법으로 명령형 쿼리를 사용하지만, mongodb에서는 객체지향적인 접근 방식을 사용해 선언형 쿼리를 사용한다는 차이점이 있습니다. DBMS에 대한 자세한 설명은 다른 포스팅에서 확인하실 수 있습니다. (관계형 DBMS, 비관계형 DBMS)

실습을 위해 MongoDB와 Node.js를 활용해 간단한 로그인 페이지를 구현해 주었습니다. php를 사용할 수도 있지만, MongoDB의 쿼리는 Binary JSON 형식의 문서로 저장되기 때문에 JSON를 객체의 형태로 처리하는 Node.js와 자주 함께 사용된다고 하였기에 Node.js를 선택하였습니다.


MongoDB 연산자

MongoDB에서 사용하는 쿼리 연산자를 사용하여 NoSQL Injection 공격을 할 수 있는데 해당 연산자를 포함하여 쿼리를 보내면 쿼리의 결과에 조건이 적용되어 나오기 때문에 원하는 결과를 얻을 수 있습니다.


인증 우회

db.member.find({"userid":userid, "password":password});

 

위와 같은 쿼리로 로그인 폼에 입력을 가져올 때 $ne 연산자를 사용하여 인증을 우회할 수 있습니다. $ne 연산자는 조건에 입력한 값이 아닌 데이터를 반환하는 연산자로 아래와 같이 입력하게 될 경우

db.member.find({"userid":{"$ne":null}, "password":{"$ne":null}});

 

null 값이 아닌 값을 반환하기 때문에 인증을 우회할 수 있습니다. 실습 내용을 살펴보면

파라미터 값으로 userid와 password가 요청이 가면 그 내용을 데이터베이스에 조회하여 로그인 결과를 보여주는 로그인 환경입니다. 저는 실습을 할 때 guset와 admin 계정을 저장해두었습니다.

위에서 언급한 $ne 연산자를 파라미터에 추가하여 보내게 되면 userid가 guest가 아니고, password가 1234가 아닌 값을 반환하기 때문에 admin이라는 이름의 계정으로 로그인 성공이 뜨는 것을 알 수 있었습니다. 이때 해당 조건을 만족하는 데이터가 많을 경우 조건을 만족하는 모든 데이터를 반환하는데 검색어를 이용해 다량의 결과를 출력하는 경우이기에 모든 상품을 반환하면 되지만,

하지만 연산자를 사용할 경우 로그인 폼에 직접 입력하면 클라이언트와 서버가 이를 주고받을 때 문자열로 바꾸어서 보내기 때문에 로그인 폼에 직접 입력하는 방법은 사용할 수 없습니다.


데이터 추출

db.member.find({"userid":userid, "password":password});

 

위와 같은 쿼리로 로그인 폼에 입력을 가져올 때 $regex 연산자를 사용하여 데이터를 추출할 수 있습니다. $regex 연산자는 지정한 정규표현식을 만족하는 경우 값을 반환하는 연산자로 아래와 같이 입력하게 될 경우

db.member.find({"userid":admin, "password":{"$regex":^a}});

 

비밀번호의 첫 시작이 a로 시작한다면 로그인이 이루어지고, 아닐 경우 로그인이 안되기에 이를 통해 데이터를 추측할 수 있습니다.

일단 비밀번호의 길이를 알아내기 위해 임의의 문자를 통해 길이를 구할 수 있는 정규 표현식을 사용하여 5는 로그인이 되었지만

6으로 로그인 요청을 보낼 시 로그인 실패가 뜨는 것을 확인할 수 있었습니다. 따라서 비밀번호의 길이가 5라는 것을 알게 되었고, 효율적인 공격을 위해 파이썬으로 자동화 코드를 작성하여 실행시켜 비밀번호를 알아낼 수 있었습니다.

import requests, string

host = 'http://localhost:3000/'
payload='abcdefghizklmnopqrstuvwxyz1234567890'

pw = ''
print('\n')
for i in range(5):
    for ch in payload:
        response = requests.get(f'{host}login?userid=admin&password[$regex]=^{pw}{ch}')
        if response.status_code == 200:
            print(f'{i+1}번째 문자 : {ch}')
            pw += ch
            break
print(f'비밀번호 : {pw}')


JavaScript

MongoDB는 자바스크립트 기반의 쿼리 언어를 사용하기 때문에, $where를 사용하면 자바스크립트를 이용해 공격이 가능합니다.

db.member.find({$where: `this.userid == '${userid}' && this.password == '${password}`);

 

위와 같은 쿼리로 로그인을 진행할 때 userid와 password를 넣는 부분에 자바스크립트 수식을 사용하면 injection 공격이 가능합니다.

db.member.find({$where: `this.userid == ''; return true; // && this.password == '123`);

 

위와 같이 참의 값을 반환하고 password 부분을 주석처리 해주는 구문을 입력할 경우 참의 값이 반환되며 로그인이 가능해집니다. 이와 관련해 burp suite PortSwigger에서 제공되는 랩을 통해 실습해 보았습니다.(Lab: Detecting NoSQL injection)

해당 페이지는 아래 보시는 것과 같이 쇼핑몰에서 검색어를 선택하면 해당 검색어의 상품을 보여주는 기능을 하고 있는데요.

Burp sutie를 통해 요청과 응답을 확인해 보았습니다.

검색어를 클릭하게 되면 파라미터 값으로 해당 검색어가 입력되어 요청되는 것을 확인할 수 있었고 그에 맞는 응답이 오는 것을 확인하였습니다. 하지만 해당 구문이 where 연산자를 사용한다면 '와 같은 문자를 입력하였을 때 오류가 생기는데요. 해당 요청에 '를 입력해 보았더니

이렇게 구문 에러가 뜨는 것을 확인할 수 있었습니다. 따라서 NoSQL Injection이 가능하다는 것을 알게 되었고 공격 구문인 '||'1'=='1 이라는 구문을 입력하여 모든 값이 반환되도록 해주었습니다.

이렇게 상품을 검색하는 기능은 그나마 피해가 덜하지만, 만약 중요한 정보를 조회하거나, 데이터를 삭제하는 기능에 사용된다면 큰 피해가 될 수 있는 공격입니다.


대응 방안

입력 값 검증

MongoDB에서는 mongo-sanitize라는 라이브러리를 사용하여 입력값에 쿼리를 조작할만한 특수문자가 있을 경우 이를 제거해 주는 기능이 있습니다.

db.board.aggregate([
	{ $match: { status: "content" } },
    { $group: { _id: "$category", avgValue: { $avg: "$value" } } },
    { $sort: { avgValue: -1 } }
])

화이트 리스트 필터링

사용할 수 있는 검색어가 제한적이거나 정해져 있는 경우 화이트 리스트 필터링을 통해 미리 지정해 둔 값이 아니면 제한을 해주는 방법이 있습니다.

데이터베이스 권한 최소화

데이터베이스의 권한을 최소화하여 사용자가 필요한 행위만 할 수 있도록 설정해 주는 방법입니다.

'Web > Web Hacking' 카테고리의 다른 글

CSTI (Client Side Template Injection)  (0) 2024.10.24
GraphQL Injection  (2) 2024.09.25
XXE External Entities  (0) 2024.09.06
File Download Vulnerability  (0) 2024.09.06
File Upload Vulnerability  (0) 2024.09.06
'Web/Web Hacking' 카테고리의 다른 글
  • CSTI (Client Side Template Injection)
  • GraphQL Injection
  • XXE External Entities
  • File Download Vulnerability
Pandyo
Pandyo
판됴의 성장 스토리 'ㅅ'
  • Pandyo
    dyostory
    Pandyo
  • 전체
    오늘
    어제
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • Kategorie (35)
      • Web (19)
        • Web Hacking (10)
        • 언어 (2)
        • 개발 (5)
        • DataBase (2)
      • Cloud (1)
        • CloudGoat (1)
        • 개념 학습 (0)
      • Project (11)
        • Cloud (11)
      • Wargame (4)
        • Dreamhack (1)
        • CTF (1)
        • Wargame site (2)
  • 링크

  • 태그

    cloudgoat
    Cloud
    API
    buildspec.yml
    ecs
    배포 방식
    Token
    Rolling Update
    Injection
    Route Table
    Blue/Green
    template
    JWT
    graphql
    AWS
    Fargate
    target group
    무중단배포
    Internet GateWay
    file
    vulnerability
    jws
    Web
    CI/CD
    canary release
    XML
    WebHacking
    DBMS
    devops
    NoSQL
  • hELLO· Designed By정상우.v4.10.0
Pandyo
NoSQL Injection
상단으로

티스토리툴바