Show Notes

131 - GitLab Arbitrary File Read and Bypassing PHP's filter_var

A directory traversal issue, the root of it is a flawed regex and replace: #(/)[^\/]+/\.\./#. This regex will match on directory/../ and once matched its replaced with the first match group (/). So basically it performs the traversal itself and normalizes the path, always a red-flag to do this adhoc. The bypass was pretty simple, it is specifically looking for one or more non / characters, followed by a /../. So by providing //../ it won’t match because the parent directory has no non / characters.

Unfortunately for the Synactiv team, the most straight-forward case was mitigated in the most recent versions of elFinder. As using a relative file path would pass through the _joinPath function which resolved the file using realpath. So even though this later check might not catch the //../ such things would get resolved before reaching there. That said, absolute paths were still an option, but this required the start of the path begin with the sandboxed directory for the application. This might be guessable in some situations like /var/www or it might need to be disclosed with another vulnerability. Regardless, providing a path that matches the expected root, followed by standard traversal would work.

I’m not even too sure why this one works, but basically by changing the JSON object sent in results in being able to login in as (presumably) arbitrary accounts.

Basically the normal login request would look like:

{
  "email":"test@example.com",
  "password":"example"
}

Changing this to

{
  "root": {
    "email":"test@example.com",
    "password":"example"
  }
}

Would login as an administrative account. My best guess is that this might have been closer to a SQL Injection style issue. On the server end some code may have been processing this to turn it into a sane query using the keys from the JSON dictionary. Perhaps similar in nature to the MySQLjs issue we covered a few weeks ago.

It is definitely an interesting test case to keep in mind though, some application try to be too smart for their own good.

The bulk import API when importing a group would, if the group had any uploads, download the uploads.tar.gz and extract it including any symlinks. When the extracted files are later listed, viewing any of the symlinked files will result in the symlink being followed and arbitrary files being read from outside the upload directory.

Cool trick impacting php’s filter_var which is actually a bit of a binary-level issue, if you provide a long enough string as the argument to filter_vareventually some code for (FILTER_VALIDATE_DOMAIN and FILTER_FLAG_HOSTNAME) will mistakenly believe the size is much smaller than it actually is (negative).

This can be exploited by providing a long string that still contains some of the things it checks for such as . for the tld. Ultimately leading to a filter bypass looking something like:

// filter bypass  
var_dump(filter_var("5;id;" . str_repeat("a", 4294967286) . "a.com", FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME));