Joomla 3.4.6 RCE复现及分析

本文详细介绍了Joomla 3.4.6版本的远程代码执行(RCE)漏洞,包括环境搭建、漏洞原理、利用过程和复现步骤。作者通过分析代码和反序列化过程,揭示了如何通过字符串长度替换和数组构造来实现文件读取和命令执行,最后探讨了漏洞的修复和防范措施。
摘要由CSDN通过智能技术生成

作者:whojoe(MS08067安全实验室SRST TEAM成员)

# 前言

前几天看了下PHP 反序列化字符逃逸学习,有大佬简化了一下joomla3.4.6rce的代码,今天来自己分析学习一下。

# 环境搭建

Joomla 3.4.6 : [https://downloads.joomla.org/it/cms/joomla3/3-4-6](https://downloads.joomla.org/it/cms/joomla3/3-4-6)

php :5.4.45nts(不支持php7)

影响版本: 3.0.0 --- 3.4.6

漏洞利用: https://github.com/SecurityCN/Vulnerability-analysis/tree/master/Joomla

(https://github.com/SecurityCN/Vulnerability-analysis/tree/master/Joomla)

要求PHP Version >= 5.3.10

# 反序列化长度扩展分析

## 0CTF-2016-piapiapia中的利用代码

这里就直接从大佬那里把代码拿来了

index.php

<?php
  require_once('class.php');
  if(isset($_SESSION['username'])) {
    header('Location: profile.php');
    exit;
  }
  if(isset($_POST["username"]) && isset($_POST["password"])) {
    $username = $_POST['username'];
    $password = $_POST['password'];




    if(strlen($username) < 3 or strlen($username) > 16) 
      die('Invalid user name');




    if(strlen($password) < 3 or strlen($password) > 16) 
      die('Invalid password');




    if($user->login($username, $password)) {
      $_SESSION['username'] = $username;
      header('Location: profile.php');
      exit;  
    }
    else {
      die('Invalid user name or password');
    }
  }
  else {
echo '
<!DOCTYPE html>
<html>
<head>
   <title>Login</title>
   <link href="static/bootstrap.min.css" rel="stylesheet">
   <script src="static/jquery.min.js"></script>
   <script src="static/bootstrap.min.js"></script>
</head>
<body>
  <div class="container" style="margin-top:100px">  
    <form action="index.php" method="post" class="well" style="width:220px;margin:0px auto;"> 
      <img src="static/piapiapia.gif" class="img-memeda " style="width:180px;margin:0px auto;">
      <h3>Login</h3>
      <label>Username:</label>
      <input type="text" name="username" style="height:30px"class="span3"/>
      <label>Password:</label>
      <input type="password" name="password" style="height:30px" class="span3">




      <button type="submit" class="btn btn-primary">LOGIN</button>
    </form>
  </div>
</body>
</html>';




  }
?>


profile.php

<?php
  require_once('class.php');
  if($_SESSION['username'] == null) {
    die('Login First');  
  }
  $username = $_SESSION['username'];
  $profile=$user->show_profile($username);
  if($profile  == null) {
    header('Location: update.php');
  }
  else {
    $profile = unserialize($profile);
    $phone = $profile['phone'];
    $email = $profile['email'];
    $nickname = $profile['nickname'];
    $photo = base64_encode(file_get_contents($profile['photo']));
?>
<!DOCTYPE html>
<html>
<head>
   <title>Profile</title>
   <link href="static/bootstrap.min.css" rel="stylesheet">
   <script src="static/jquery.min.js"></script>
   <script src="static/bootstrap.min.js"></script>
</head>
<body>
  <div class="container" style="margin-top:100px">  
    <img src="data:image/gif;base64,<?php echo $photo; ?>" class="img-memeda " style="width:180px;margin:0px auto;">
    <h3>Hi <?php echo $nickname;?></h3>
    <label>Phone: <?php echo $phone;?></label>
    <label>Email: <?php echo $email;?></label>
  </div>
</body>
</html>
<?php
  }
?>


register.php

<?php
  require_once('class.php');
  if(isset($_POST['username']) && isset($_POST['password'])) {
    $username = $_POST['username'];
    $password = $_POST['password'];




    if(strlen($username) < 3 or strlen($username) > 16) 
      die('Invalid user name');




    if(strlen($password) < 3 or strlen($password) > 16) 
      die('Invalid password');
    if(!$user->is_exists($username)) {
      $user->register($username, $password);
      echo 'Register OK!<a href="index.php">Please Login</a>';    
    }
    else {
      die('User name Already Exists');
    }
  }
  else {
?>
<!DOCTYPE html>
<html>
<head>
   <title>Login</title>
   <link href="static/bootstrap.min.css" rel="stylesheet">
   <script src="static/jquery.min.js"></script>
   <script src="static/bootstrap.min.js"></script>
</head>
<body>
  <div class="container" style="margin-top:100px">  
    <form action="register.php" method="post" class="well" style="width:220px;margin:0px auto;"> 
      <img src="static/piapiapia.gif" class="img-memeda " style="width:180px;margin:0px auto;">
      <h3>Register</h3>
      <label>Username:</label>
      <input type="text" name="username" style="height:30px"class="span3"/>
      <label>Password:</label>
      <input type="password" name="password" style="height:30px" class="span3">




      <button type="submit" class="btn btn-primary">REGISTER</button>
    </form>
  </div>
</body>
</html>
<?php
  }
?>


update.php

<?php
  require_once('class.php');
  if($_SESSION['username'] == null) {
    die('Login First');  
  }
  if($_POST['phone'] && $_POST['email'] && $_POST['nickname'] && $_FILES['photo']) {




    $username = $_SESSION['username'];
    if(!preg_match('/^\d{11}$/', $_POST['phone']))
      die('Invalid phone');




    if(!preg_match('/^[_a-zA-Z0-9]{1,10}@[_a-zA-Z0-9]{1,10}\.[_a-zA-Z0-9]{1,10}$/', $_POST['email']))
      die('Invalid email');
    
    if(preg_match('/[^a-zA-Z0-9_]/', $_POST['nickname']) || strlen($_POST['nickname']) > 10)
      die('Invalid nickname');




    $file = $_FILES['photo'];
    if($file['size'] < 5 or $file['size'] > 1000000)
      die('Photo size error');




    move_uploaded_file($file['tmp_name'], 'upload/' . md5($file['name']));
    $profile['phone'] = $_POST['phone'];
    $profile['email'] = $_POST['email'];
    $profile['nickname'] = $_POST['nickname'];
    $profile['photo'] = 'upload/' . md5($file['name']);




    $user->update_profile($username, serialize($profile));
    echo 'Update Profile Success!<a href="profile.php">Your Profile</a>';
  }
  else {
?>
<!DOCTYPE html>
<html>
<head>
   <title>UPDATE</title>
   <link href="static/bootstrap.min.css" rel="stylesheet">
   <script src="static/jquery.min.js"></script>
   <script src="static/bootstrap.min.js"></script>
</head>
<body>
  <div class="container" style="margin-top:100px">  
    <form action="update.php" method="post" enctype="multipart/form-data" class="well" style="width:220px;margin:0px auto;"> 
      <img src="static/piapiapia.gif" class="img-memeda " style="width:180px;margin:0px auto;">
      <h3>Please Update Your Profile</h3>
      <label>Phone:</label>
      <input type="text" name="phone" style="height:30px"class="span3"/>
      <label>Email:</label>
      <input type="text" name="email" style="height:30px"class="span3"/>
      <label>Nickname:</label>
      <input type="text" name="nickname" style="height:30px" class="span3">
      <label for="file">Photo:</label>
      <input type="file" name="photo" style="height:30px"class="span3"/>
      <button type="submit" class="btn btn-primary">UPDATE</button>
    </form>
  </div>
</body>
</html>
<?php
  }
?>


class.php

<?php
require('config.php');




class user extends mysql{
  private $table = 'users';




  public function is_exists($username) {
    $username = parent::filter($username);




    $where = "username = '$username'";
    return parent::select
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值