NoSQL Injection
이전의 SQL Injection과 공격 목적 및 방법이 매우 유사하다. 두 공격 모두 이용자의 입력값이 쿼리에 포함되면서 발생하는 문제점으로써, 이용자의 입력값에 대한 타입 검증이 불충분할 때 발생한다.
No SQL중 하나인 MongoDB는 정수, 날짜, 실수 이외에도 오브젝트, 배열 타입을 사용할 수 있는데 오브젝트 타입의 입력값을 처리할 때 쿼리 연산자를 사용할 때 다양한 행위를 할 수 있다.
실습
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 |