Try   HackMD

SQL injection with Nodejs+MongoDB

tags: 工具

安裝Nodejs

https://nodejs.org/en

安裝Mongodb

下載

  1. 下載Enterprise Server,輸入信箱、姓名等資料,公司名稱隨便填。
    安裝在D槽,之後在mongodb資料夾內建立data資料夾,並在data底下建立db資料夾(D:/mongodb/data/db)

  2. 開啟CMD

D:
cd mongodb\bin
mongod -dbpath D:\mongodb\data\db  //指定資料儲存位置並啟動
  1. 再開啟一個CMD
D:
cd mongodb\bin
mongo   //開始mongodb操作介面
use blog   //創建一個叫做blog的資料庫並切換至該資料庫;已經存在資料庫便直接切換
db.createCollection(“users”)   //在資料庫內建立一個users的集合
db.users.insert({"name":"admin","password":"admin"})
                  //在users內加入物件 name為admin,password為admin
db.users.find()   //查詢在users內的物件

HTML、登入系統

建立專案

mkdir name
cd name
npm init
npm install -g express-generator   //安裝Express套件
express -e project_name   //建立express專案資料夾,-e表示使用ejs模板
cd projet_name
npm install
npm start   //啟動server,預設路徑為localhost:3000

開啟專案內的app.js,修改ejs模板引擎成html(原網頁為ejs檔,修改後為html)

修改 app.set('view engine', 'ejs'); 成 app.set('view engine', 'html');
app.engine('.html',require('ejs').__express);

首頁 index.html(刪除原本的index.ejs)

<!DOCTYPE html> <html> <head> <title>my index</title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <h1>Hello ~~</h1> <p><a href="login">登入</a></p> </body> </html>

登入頁面 login.html

<!DOCTYPE html> <html> <head> <title>my login</title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <p id="fail_login">Fail to login QQ</p> <form action="ucenter" method="post"> <p> <span>name:</span> <br> <input id="name" name="name" type="text" pattern="[^$()/><\][\\\x22,;|]+"> </p> <p> <span>password:</span> <br> <input id="password" name="password" type="password" pattern="[^$()/><\][\\\x22,;|]+"> </p> <p><input type="submit" value="submit"></p> </form> </body> </html>

登入失敗頁面 fail.html

<!DOCTYPE html> <html> <head> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <p>login fail</p> <p><a href="login">重新登入</a></p> </body> </html>

登入成功頁面 ucenter.html

<!DOCTYPE html> <html> <head> <title>Login successfully</title> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <p>登入成功!!!!</p> </body> </html>

修改router/index.js

var express = require('express'); var router = express.Router(); var user = require('../database/db').user; /* GET home page. */ router.get('/', function(req, res) { res.render('index', { title: 'index' }); }); /* login */ router.get('/login', function(req, res) { res.render('login', { title: 'login' }); }); /* login fall */ router.get('/fail', function(req, res) { res.render('fail', { title: 'login falled' }); }); /* 使用find比對資料庫內資料,若是找不到資料doc.length=0則登入失敗; 反之登入成功 */ router.post('/ucenter', function(req, res) { var query = {name: req.body.name, password: req.body.password}; (function(){ user.find(query, function(err,doc){ if(doc.length==0){ console.log(query); console.log(query.name + " : 登入失敗QQ " + new Date()); res.redirect('fail'); } else{ console.log(query); console.log(query.name + " : 登入成功~~ " + new Date()); console.log(doc.length); res.render('ucenter', { title:'ucenter' }); } }); })(query); module.exports = router;

建立module、連結資料庫

在專案內建立 database資料夾,並在底下建立db.js
/database/db.js

var mongoose = require('mongoose'); var db = mongoose.connect('mongodb://localhost/blog');//連結database var Schema = mongoose.Schema; //建立schema var userScheMa = new Schema({ name: String, password: String }); // module.exports.user = db.model('users', userScheMa);

安裝mongodb相關package,修改package.json,存檔後執行npm install

{
  "name": "project-1",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "cookie-parser": "~1.4.3",
    "debug": "~2.6.9",
    "ejs": "~2.5.7",
    "express": "~4.16.0",
    "http-errors": "~1.6.2",
    "morgan": "~1.9.0",
    "mongoose": "^4.13.12",
    "mongoose-auto-increment": "^5.0.1"
  }
}

npm start 啟動伺服器,進到localhost:3000檢查網頁

登入測試

在localhost:3000/login進行登入測試;
使用Postman直接對 http://localhost:3000/ucenter 發送post請求,選擇body

{
    "name":"admin",
    "password":"admin"
}

Injection測試

使用 {"$gt":""} 進行測試,該指令意思為:長度大於""內字串的資料,由於""沒有字串,故長度大於0的字串都符合。
name:{"$gt":""} , password:{"$gt":""} 進行登入,資料庫會回傳name長度大於0且password長度大於0的資料,這時候doc.length不等於0,會判定可登入。

自行修改登入成功判斷條件預防注入

  1. 使用HTML5 pattern 限制使用者輸入的內容(直接對server發送post無法限制)
  2. 修改index.js內的登入條件判斷
  3. 在index.js檢查輸入字串,檢查後才與資料庫比對

Brute Force

使用Hydra破解工具進行破解,下載不到Hydra可使用Kali Linux,Kali有內建Hydra及字典檔

破解步驟

  1. 開啟CMD
  2. cd 至 Hydra所在資料夾
  3. 輸入指令
Hydra -L dict.txt -P password.txt -s 3000 127.0.0.1 http-post-form "/ucenter:name=^USER^&password=^PASS^:login fail" /* -L dict.txt : 使用帳號字典檔dict.txt ;-l admin: 直接指定帳號為admin -P password.txt: 使用密碼字典檔password.txt;-p admin :直接指定密碼admin -s 3000 :指定port 3000 127.0.0.1 : 要攻擊的IP http-post-form : 服務的形式為對發送http post /ucenter:name=^USER^&password=^PASS^ 處理post的API(form action位置) ^USER^為帳號的變數,會自動取得字典檔內的帳號,name為form傳送的帳號參數 ^PASS^為密碼的變數,會自動取得字典檔內的密碼,password為form傳送密碼參數 :login fail 登入失敗的頁面會有這些提示字,Hydra藉由比對是否出現提示字判斷是否登入成功 */