Impact

The vulnerability, a PHP object injection, was fixed in the latest security release of Pydio. Affected are all installations below version 8.2.2 with default settings. The vulnerability allowed remote attackers to perform a full takeover of the filesharing system, leading to remote access to all internal files of the enterprise deploying Pydio. The vulnerability does not require any default settings to be changed or any user privileges. The vulnerability was found with RIPS Code Analysis in 200.000 LOC within 2 minutes.



Technical Details

The object injection occured due to the way Pydio stored user preferences, such as GUI settings, in the database. Sometimes the preference values were intended to be arrays. Since MySQL databases can’t store PHP types, such as arrays and objects, Pydio would create a serialized string of the array and then store it in the database.

/plugins/conf.sql/SqlUser.php

165
166
167
168
169
170
171
172
173
174
175
176
public function setPref($prefName, $prefValue)
    {
        // If the preference value (the user input) is not a string, serialize it
        if (!is_string($prefValue)) {
            $prefValue = '$phpserial$'.serialize($prefValue);
        }
        
        
        // Insert the preference into the database.
       dibi::query('INSERT INTO [ajxp_user_prefs] ([login],[name],[val]) VALUES (%s, %s, %bin)', $this->getId(),$prefName,$prefValue);
        
}

Since Pydio needs to know which preference values require deserialization later, the string $phpserial$ is prepended to a serialized string.

When the preference is then received by getPref(), it will check if the preference value starts with $phpserial$ and if so it returns the unserialized string.

/plugins/conf.sql/SqlUser.php

208
209
210
211
212
213
214
215
216
217
    public function getPref($prefName)
    {
        $p = parent::getPref($prefName);
            if (strpos($p, '$phpserial$') === 0) {
                $p = substr($p, strlen('$phpserial$'));
                return unserialize($p);
            }
            
        return $p;
    }

The security issue is that Pydio did not check if a preference value that is a string starts with $phpserial$. This means a user could simply enter a preference value of $phpserial$a:0:{} which Pydio would recognize as a serialized string then unserialize it.

Exploitation

At this point, an attacker can inject arbitrary serialized strings into the Pydio database that would then be deserialized. This allows to inject POP gadget chains. Pydio contained classes that allowed building a POP chain that lead to the attacker’s control of a call to call_user_func(), which allows arbitrary code execution on the remote system. Unauthenticated attackers were able to set their preferred language via the GET parameter $_GET[‘lang’], which would be passed to setPref() unsanitized.

plugins/action.share/src/Http/MinisiteAuthMiddleware.php

110
111
112
113
114
        if (isSet($_GET["lang"])) {
            if ($ctx->hasUser()) {
                $ctx->getUser()->setPref("lang", $_GET["lang"]);
            }
        }

The only requirement is that the attacker is in posession of a public link. A public link is created when any user of the target filesharing system, for example an employee or student, shares a file to another user. Such links could be obtained via social engineering or bruteforcing. We have also reported a reflected XSS vulnerability in the same version of Pydio that can be used to hijack an employees session and create such a link. The vulnerability can be exploited without a public link by any authenticated user of any privilege level, even regular employees or students.

Time Line

Date What
2018/09/21 Vulnerability reported to the Pydio email address for Security Issues.
2018/09/21 The vulnerability was acknowledged by the lead developer on the same day.
2018/10/11 A fix was released with version 8.2.2

Summary

We detected a critical PHP object injection vulnerability in Pydio with the help of static code analysis. The vulnerability was exploitable with a POP chain that allowed remote attackers to execute arbitrary system commands. The issue was patched in the latest Pydio release 8.2.2 and all users are urged to update. We would like to thank the Pydio security team for their professional communication and very fast addressing of this issue.