-
03-02. Server Side Attack - Non-Relational DBMS해킹/웹해킹 이론 2023. 11. 21. 02:51
Non-Relational DBMS
관계형 DBMS와 달리 SQL를 사용하지 않고 복잡하지 않은 데이터를 저장해 단순 검색 및 추가 검색 작업을 위해 매우 최적화된 저장 공간인 것이 큰 특징이자 RDBMS와의 차이점이다. RDBMS는 SQL이라는 정해진 문법을 통해 데이터를 저장하기 때문에 한 가지의 언어로 다양한 DBMS을 사용할 수 있다. 반면에 NoSQL은 Redis, Dynamo, CouchDB, MongoDB 등 다양한 DBMS가 존재하기 때문에 각각의 구조와 사용 문법을 익혀야한다는 단점이 있다.
MongoDB, Redis, CouchDB에 대해서 알아보자.
MongoDB(https://docs.mongodb.com/manual/reference/operator/query/)
MongoDB는 JSON 형태인 도큐먼트(Document)를 저장하며, 다음과 같은 특징을 가진다.
- 스키마를 따로 정의하지 않아 각 컬렉션(Collection)에 대한 정의가 필요하지 않습니다. (컬렉션은 RDBMS의 테이블과 비슷한 개념)
- JSON 형식으로 쿼리를 작성할 수 있습니다.
- _id 필드가 Primary Key 역할을 합니다.
연산자
Name Description $eq equal $in 배열 안의 값들과 일치하는 값을 찾는다 $ne not equal $nin $in의 반대 $and 논리적 AND $not 논리적 NOT $nor 논리적 NOR (둘 다 아니어야 함) $or 논리적 OR $exists 지정된 필드가 있는 문서를 찾는다 $type 지정된 필드가 지정된 유형인 문서를 찾는다 $expr 쿼리 언어 내에 집계식 사용 $regex 지정된 정규식과 일치하는 문서 선택 $text 지정된 텍스트 검색 $where JavaScript 표현식을 만족하는 문서와 일치합니다. SQL과 문법 비교
SQL MongoDB SELECT * FROM account; db.account.find() SELECT * FROM account WHERE user_id="admin"; db.account.find({user_id:"admin"}) SELECT user_idx FROM account WHERE user_id="admin"; db.account.find( { user_id: "admin" }, { user_idx:1, _id:0 }) INSERT INTO account(user_id,user_pw,) VALUES ("guest", "guest"); db.account.insertOne( { user_id: "guest",user_pw: "guest" })
DELETE FROM account; db.account.remove() DELETE FROM account WHERE user_id="guest"; db.account.remove( {user_id: "guest"}) UPDATE account SET user_id="guest2" WHERE user_idx=2; db.account.updateOne( { user_idx: 2 }, { $set: { user_id: "guest2" } }) Redis(https://redis.io/commands)
- 키-값 쌍을 가진 데이터를 저장
- 메모리기반의 DBMS로 메모리를 사용해 다른 DBMS보다 훨씬 빨리 읽고 쓸 수 있어 임시 데이터를 캐싱하는 용도로 주로 사용된다.
명령어 구조 설명 GET GET key 단일 데이터 조회 MGET MGET key [key ...] 여러 데이터 조회 SET SET key value 단일 데이터 추가 MSET MSET key value [key value ...] 여러 데이터 추가 DEL DEL key [key ...] 데이터 삭제 EXISTS EXISTS key [key ...] 데이터 유무 확인 INCR INCR key 데이터 값 ++1 DECR DECR key 데이터 값 --1 INFO INFO [section] DBMS 정보 조회 CONFIG GET CONFIG GET parameter 설정 조회 CONFIG SET CONFIG SET parameter value 새로운 설정을 입력 CouchDB(https://docs.couchdb.org/en/latest/api/index.html)
- JSON 형태인 도큐먼트를 저장
- 웹 기반의 DBMS / REST API 형식으로 요청 처리
코드 예시
$ curl -X PUT http://{username}:{password}@localhost:5984/users/guest -d '{"upw":"guest"}' {"ok":true,"id":"guest","rev":"1-22a458e50cf189b17d50eeb295231896"} $ curl http://{username}:{password}@localhost:5984/users/guest {"_id":"guest","_rev":"1-22a458e50cf189b17d50eeb295231896","upw":"guest"}
요소 설명 POST 새로운 레코드를 추가합니다. GET 레코드를 조회합니다. PUT 레코드를 업데이트합니다. DELETE 레코드를 삭제합니다. / 인스턴스에 대한 메타 정보를 반환합니다. /_all_dbs 인스턴스의 데이터베이스 목록을 반환합니다. /_utils 관리자페이지로 이동합니다. /db 지정된 데이터베이스에 대한 정보를 반환합니다. /{db}/_all_docs 지정된 데이터베이스에 포함된 모든 도큐먼트를 반환합니다. /{db}/_find 지정된 데이터베이스에서 JSON 쿼리에 해당하는 모든 도큐먼트를 반환합니다. NoSQL Injection(Mongo DB)
Mongo DB는 데이터의 자료형으로 Object형도 사용하기 때문에 query에 다양한 값을 넣을 수 있다. data라는 파라미터로 들어오는 값을 저장하는 코드가 있다고 하자. 이런식으로 다양하게 넣을 수 있다.
http://localhost:3000/?data=1234 data: 1234 type: string http://localhost:3000/?data[]=1234 data: [ '1234' ] type: object http://localhost:3000/?data[]=1234&data[]=5678 data: [ '1234', '5678' ] type: object http://localhost:3000/?data[5678]=1234 data: { '5678': '1234' } type: object http://localhost:3000/?data[5678]=1234&data=0000 data: { '5678': '1234', '0000': true } type: object http://localhost:3000/?data[5678]=1234&data[]=0000 data: { '0': '0000', '5678': '1234' } type: object http://localhost:3000/?data[5678]=1234&data[1111]=0000 data: { '1111': '0000', '5678': '1234' } type: object
따라서 우리는 이 값들에 연산자를 넣어 공격을 할 수 있다.
http://localhost:3000/query?uid[$ne]=a&upw[$ne]=a
이렇게 실행할 경우 데이터는 find($and{{"uid": {"$ne":"a"}},{"upw":{"$ne":"a"}}}) 로 들어가 uid가 a가 아니면서 upw도 a가아닌 유저의 정보를 리턴할 것이다.
따라서 uid 에 admin / upw에 {"$ne":""}를 입력하는 형식으로 정보를 탈취할 수 있다.
Blind NoSQL Injection
$regex와 $where을 사용해 Blind NoSQL Injection을 시도할 수 있다.
- regex
- upw: {$regex:"표현식"}을 넣어주면 일치할 때 return을 받을 수 있다.따라서 ^a, ^aa, ^ab, ^aba 이런식으로 늘려가며 blind injection을 수행 할 수 있다. 혹은 이런식으로 ^(.{n-1}a.{0,})$ regex를 작성해 원하는 위치에 a가 있는지 검사하는 식으로도 작성할 수 있다.
- where
- 표현식
- 인자로 전달한 js 표현식을 만족하는 데이터를 조회한다. (사실 이해 못했음)
- {$where : "return 1==1"}
- substring
- regex와 같이 한글자씩 비교할 수 있다.
- {$where: "this.upw.substring(0,1)=='a'"}
- sleep 함수를 통한 time based injection
- 표현식과 함께 sleep함수를 사용해 지연 시간을 통해 참/거짓 결과를 확인한다. 하단 쿼리를 던져주면 substring이 일치할 경우 sleep이 발생하고 시간지연이 일어나므로 정보를 탈취 할 수 있다.
- /?uid=guest'&&this.upw.substring(0,1)=='a'&&sleep(5000)&&'1
- Error based Injection
- 에러가 나는 코드를 비교구문 뒤에 배치해 에러가 날 경우 해당 비교가 옳다는 것을 알아내는 방식
- db.user.find({$where: "this.uid=='guest'&&this.upw.substring(0,1)=='g'&&asdf&&'1'&&this.upw=='${upw}'"});
- 표현식
'해킹 > 웹해킹 이론' 카테고리의 다른 글
03-04. Server Side Attack - File Vulnerability (1) 2023.11.21 03-03. Server Side Attack - Command Injection (0) 2023.11.21 03-01. Server Side Attack - Relational DBMS (0) 2023.11.21 02. SOP 원칙 및 Client Side Attack (0) 2023.11.18 01. Introduction (0) 2023.11.15