前言:
本文只分析发生漏洞得原因,具体pop链简略分析。
joomla中得session会被存入数据库中,这是以前版本得RCE就可以得知得事情。
/libraries/joomla/session/storage.php:
public function register()
{
// Use this object as the session handler
session_set_save_handler(
array($this, 'open'), array($this, 'close'), array($this, 'read'), array($this, 'write'),
array($this, 'destroy'), array($this, 'gc')
);
}
通过这里得到目标注册得几个函数,但是此方法为抽象类,也就是说不能实例化的,所以我们需要寻找继承了此类的类进行分析,在JSessionStorageDatabase对象中,均重写了上面的几个函数。
0x01 入口:
根据github给出的payload得出路由为:/index.php/component/users
根据路由找到目标文件的真实文件为:/components/com_users/users.php
此文件获取了一个task参数,这个参数不做具体分析,我们只需要得知目标会根据此参数来找到最终提交的函数
payload中有如下:
'task': 'user.login',
也就是说会提交到 user控制器下面的login方法,直接追过去就好了,具体路径为:components/com_users/controllers/user.php
代码:
public function login()
{
JSession::checkToken('post') or jexit(JText::_('JINVALID_TOKEN'));
$app = JFactory::getApplication();
$input = $app->input;
$method = $input->getMethod();
// Populate the data array:
$data = array();
$data['return'] = base64_decode($app->input->post->get('return', '', 'BASE64'));
$data['username'] = $input->$method->get('username', '', 'USERNAME');
$data['password'] = $input->$method->get('password', '', 'RAW');
$data['secretkey'] = $input->$method->get('secretkey', '', 'RAW');
// Don't redirect to an external URL.
if (!JUri::isInternal($data['return']))
{
$data['return'] = '';
}
// Set the return URL if empty.
if (empty($data['return']))
{
$data['return'] = 'index.php?option=com_users&view=profile';
}
// Set the return URL in the user state to allow modification by plugins
$app->setUserState('users.login.form.return', $data['return']);
// Get the log in options.
$options = array();
$options['remember'] = $this->input->getBool('remember', false);
$options['return'] = $data['return'];
// Get the log in credentials.
$credentials = array();
$credentials['username'] = $data['username'];
$credentials['password'] = $data['password'];
$credentials['secretkey'] = $data['secretkey'];
// Perform the log in.
if (true === $app->login($credentials, $options))
{
// Success
if ($options['remember'] == true)
{
$app->setUserState('rememberLogin', true);
}
$app->setUserState('users.login.form.data', array());
$app->redirect(JRoute::_($app->getUserState('users.login.form.return'), false));
}
else
{
// Login failed !
$data['remember'] = (int) $options['remember'];
$app->setUserState('users.login.form.data', $data);
$app->redirect(JRoute::_('index.php?option=com_users&view=login', false));
}
}
0x02 进入login中:
这里我们可以看下重点代码:
JSession::checkToken('post') or jexit(JText::_('JINVALID_TOKEN'));
进入checkToken函数中,具体看下
$session = JFactory::getSession();
if ($session->isNew())
跟进后发现这句代码获取了现在的session对象:
public static function getSession(array $options = array())
{
if (!self::$session)
{
self::$session = self::createSession($options);
}
return self::$session;
}
这里获取到的对象其实就是当前对象,因为我在下面发现了isNew函数:
public function isNew()
{
$counter = $this->get('session.counter');
return (bool) ($counter === 1);
}
然后在跟进get函数:
public function get($name, $default = null, $namespace = 'default')
点击收藏 | 0
关注 | 1