NoSQL Injection
이전의 SQL Injection과 공격 목적 및 방법이 매우 유사하다. 두 공격 모두 이용자의 입력값이 쿼리에 포함되면서 발생하는 문제점으로써, 이용자의 입력값에 대한 타입 검증이 불충분할 때 발생한다.
No SQL중 하나인 MongoDB는 정수, 날짜, 실수 이외에도 오브젝트, 배열 타입을 사용할 수 있는데 오브젝트 타입의 입력값을 처리할 때 쿼리 연산자를 사용할 때 다양한 행위를 할 수 있다.
$type — MongoDB Manual
Docs Home → MongoDB Manual $type$type selects documents where the value of the field is an instance of the specified BSON type(s). Querying by data type is useful when dealing with highly unstructured data where data types are not predictable.You can use
www.mongodb.com
실습
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded( {extended : false } ));
const mongoose = require('mongoose');
const db = mongoose.connection;
mongoose.connect('mongodb://localhost:27017/', { useNewUrlParser: true, useUnifiedTopology: true });
app.post('/query', function(req,res) {
db.collection('user').find({
'uid': req.body.uid,
'upw': req.body.upw
}).toArray(function(err, result) {
if (err) throw err;
res.send(result);
});
});
const server = app.listen(80, function(){
console.log('app.listen');
});
Node.js 로 작성한 글인데
이걸 또 알아야하나 싶다
대충 보니 const db랑 mongoose 랑 연결이 되고, 거기에 이제 이것저것 연결이 되는 것 같다.
uid랑 upw가 body에서 요청받아지는 구조이다.
MongoDB를 사용해서 uid 부분에는 admin, upw부분에는 $ne를 사용하여 공백이 아닌 것들을 불러오는 방식으로 데이터를 불러온다.
Blind NoSQL Injection
SQL처럼 참/거짓 결과를 통해 데이터베이스 정보를 알아낼 수 있음.
$expr | 쿼리 언어 내에서 집계 식을 사용 |
$regex | 지정된 정규식과 일치하는 문서를 선택 |
$text | 지정된 텍스트 검색 |
$where | JS 표현식을 만족하는 문서와 일치 |
> db.user.find({upw: {$regex: "^a"}})
> db.user.find({upw: {$regex: "^b"}})
> db.user.find({upw: {$regex: "^c"}})
...
> db.user.find({upw: {$regex: "^g"}})
{ "_id" : ObjectId("5ea0110b85d34e079adb3d19"), "uid" : "guest", "upw" : "guest" }
이런식으로 사용한다는 거 같은데, 비밀번호가 g로 시작하는 것을 불러온다는 의미인 것 같다.
> db.user.find({$where: "this.upw.substring(0,1)=='a'"})
> db.user.find({$where: "this.upw.substring(0,1)=='b'"})
> db.user.find({$where: "this.upw.substring(0,1)=='c'"})
...
> db.user.find({$where: "this.upw.substring(0,1)=='g'"})
{ "_id" : ObjectId("5ea0110b85d34e079adb3d19"), "uid" : "guest", "upw" : "guest" }
substring 를 이용하여 한 글자씩 비교해서 upw 의 첫 글자를 비교해 데이터를 알아내는 쿼리이다.
sleep 함수를 이용해 지연시간으로 참/거짓을 확인할 수도 있고, 첫 글자가 g문자인 경우 올바르지않는 문법인 asdf 를 활용하여 에러를 발생시켜 참.거짓을 확인할 수 있다.
실습
const express = require('express');
const app = express();
app.use(express.json());
app.use(express.urlencoded( {extended : false } ));
const mongoose = require('mongoose');
const db = mongoose.connection;
mongoose.connect('mongodb://localhost:27017/', { useNewUrlParser: true, useUnifiedTopology: true });
app.get('/query', function(req,res) {
db.collection('user').findOne({
'uid': req.body.uid,
'upw': req.body.upw
}, function(err, result){
if (err) throw err;
console.log(result);
if(result){
res.send(result['uid']);
}else{
res.send('undefined');
}
})
});
const server = app.listen(80, function(){
console.log('app.listen');
});
여기다가 admin계정으로 비밀번호 획득하는 문제이다.
{"uid": "admin", "upw": {"$regex" : ".{5}"}}
다음과 같이 입력해서 upw : {$regex : .{5} } 를 입력하면 길이가 5인 것을 알아낸다.
1 2 3 4 5 일경우에는 admin이라고 알 수 있지만, 6이상일 때는 undefined 라고 뜨며 비밀번호는 5라는 것을 알 수 있다.
그 다음
{"uid": "admin", "upw": {"$regex" : "^a"}}
이런식으로 각 알파벳이 존재하는지 확인한다.
이러면 첫 번째 글자가 a라는 것이다.
이렇게 노가다 해서 찾아내면 된다.
^의 이미는 입력의 시작부분을 나타낸다.
에필로그
개노잼.. SQL하고 싶다.
'보안 스터디 > 웹 해킹' 카테고리의 다른 글
[드림핵/웹해킹] ServerSide: Command Injection (1) | 2024.01.15 |
---|---|
[드림핵/워게임] Mango (웹 해킹) (0) | 2024.01.12 |
[드림핵/웹해킹] Background: Non-Relational DBMS (1) | 2024.01.11 |
[드림핵/워게임] simple_sqli -1(웹해킹) (1) | 2024.01.08 |
[드림핵/웹해킹] ServerSide: SQL Injection (0) | 2024.01.07 |