When MailWizz 2.0 encodes URLs for tracking, it transforms every link in your campaign into a complex, unique URL that allows the system to monitor subscriber interactions. This is the core of its click-tracking functionality.

Here is a detailed breakdown of that encoded URL, its components, and the processes behind it.

The Transformation: From Original to Encoded URL

Original Link: `https://www.example.com/special-offer`

Encoded Tracking Link (example):

`https://yourdomain.com/campaigns/abc123def456/track-url/5f8e4a3b1c7d9e2f6a0b1c8d3e9f4a5b2c7d1e6f3a8b9c0d5e4f7a2b1c8d3e6f?subscriber=9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d`

Part 1: Breakdown of the Encoded URL Structure

Let’s dissect the example URL above:

1. Your MailWizz Base URL:

`https://yourdomain.com/`

* This is the base URL of your MailWizz installation. All tracking flows through your own server.

2. Campaign/Web Tracking Endpoint:

`/campaigns/abc123def456/track-url/`

`/campaigns/`: A core MailWizz controller for handling campaign-related actions.

`abc123def456`: This is the Campaign Unique Identifier (UID). It’s a 13-character alphanumeric hash (e.g., from the `campaign` table’s `campaign_uid` field) that uniquely identifies the specific email campaign in your MailWizz database.

`/track-url/`: This is the specific action within the campaigns controller responsible for processing the tracking click. It’s the engine that logs the hit and redirects the user.

3. The Link Hash:

`5f8e4a3b1c7d9e2f6a0b1c8d3e9f4a5b2c7d1e6f3a8b9c0d5e4f7a2b1c8d3e6f`

* This is a long, unique hash for the specific link that was clicked.

* It’s stored in the `campaign_url` table (`hash` field) and maps directly to the original destination URL (`destination` field).

* This ensures MailWizz knows exactly which link (e.g., “Buy Now”, “Read Blog”, “Facebook Profile”) was clicked.

4. The Query String Parameters:

`?subscriber=9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d`

* This is the most critical part for subscriber-level tracking. The `subscriber` parameter contains the Subscriber Unique Identifier (UID).

`9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d`: A 32-character MD5 hash (from the `list_subscriber` table’s `subscriber_uid` field) that uniquely identifies the specific subscriber who received the email.

Optional Additional Parameters: Depending on configuration, you might see others:

* `&email=encodedEmail@example.com`: The subscriber’s email address, sometimes URL-encoded.

* `&campaign_uid=abc123def456`: A redundant but sometimes added campaign UID.

* `&ip_address=…` & `&user_agent=…`: If passed from the email client, these can be appended for initial log accuracy before server detection.

The URL structure is just the delivery mechanism. Here’s the sequence of events it triggers:

1. Request to MailWizz: The subscriber’s click sends an HTTP GET request to the encoded URL on your MailWizz server.

2. Tracking Log (The “Click”):

* The `track-url` action receives the request.

* It extracts the `campaign_uid`, `link hash`, and `subscriber_uid`.

* It performs a series of database lookups and inserts:

Campaign Track URL Table: Inserts a raw hit record into `campaign_track_url` with the subscriber ID, link hash, IP address, user agent, and timestamp.

Campaign URL Table: Updates the `click_count` for that specific link hash in the `campaign_url` table.

Campaign Table: Updates the overall `clicked_count` for the campaign.

3. Subscriber-Level Logging:

Updates the individual subscriber’s record to mark them as having clicked something* in this campaign.

* If it’s their first click ever in this campaign, it creates an entry in `campaign_track_url_click` (or similar), which is used for “Unique Clicks” metric. This deduplicates multiple clicks from the same user.

4. The Redirect:

* After logging is complete, MailWizz performs a HTTP 301 (Permanent) or 302 (Temporary) Redirect.

* It looks up the original destination URL associated with the `link hash` from the `campaign_url` table.

* It sends the subscriber’s browser to the final, original URL: `https://www.example.com/special-offer`.

5. Final Landing:

* The subscriber arrives at the intended page. The entire process typically takes milliseconds and is invisible to them.

Part 3: Visual Summary & Technical Flowchart

Code :



Original Link in EmailMailWizz Link Transformer (During Campaign Send)
         ↓
Encoded Tracking Link
[Base URL]/[Campaign UID]/track-url/[Link Hash]?subscriber=[Subscriber UID]
         ↓
Subscriber Clicks Link
         ↓
(1) Request to MailWizz Server
         ↓
(2) Database Logging:
    - Log click in `campaign_track_url`
    - Increment `campaign_url.click_count`
    - Increment `campaign.clicked_count`
    - Mark subscriber as "clicked"
         ↓
(3) HTTP 302 Redirect
         ↓
(4) Request to Final Destination URL
         ↓
Subscriber Lands on Your Website

Key Technical Details

Database Schema: The main tables involved are `campaign`, `campaign_url`, `list_subscriber`, `campaign_track_url`, and `campaign_track_url_click`.

Uniqueness: The combination of `campaign_uid` + `link hash` + `subscriber_uid` allows MailWizz to track every single click event at the most granular level.

Security & Validation: The process includes checks to ensure the campaign is active, the subscriber exists and is in a valid list status, preventing false logs or exploitation.

Link Expiry: While not common, tracking links are typically persistent, but their validity is tied to the subscriber’s status and campaign activity.

This encoding and logging system is what powers MailWizz’s detailed click reports, showing you not just total clicks per link, but exactly who clicked and when.


an in-depth breakdown of how MailWizz 2.0 encodes URLs for tracking, focusing on the technical generation processdatabase structure, and URL components.

Complete URL Encoding Breakdown

1. Original URL Transformation Flow

Before Encoding:

Code :



https://www.example.com/product/special-offer?utm_source=newsletter

After Encoding:

Code :



https://yourdomain.com/campaigns/a1b2c3d4e5f6g/track-url/8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4?subscriber=7f9e8d3c5a2b4e6c8a1d5f3b9e7c2a4d6b8&email=user%40example.com

2. URL Components – Detailed Analysis

A. Base Structure

Code :



[INSTALLATION_BASE_URL]/campaigns/[CAMPAIGN_UID]/track-url/[LINK_HASH]?subscriber=[SUBSCRIBER_UID]&[OPTIONAL_PARAMS]

B. Component-by-Component Breakdown

1. Campaign UID (`abc123def456` in example above)

– Format: 13-character alphanumeric

– Source: `campaign` table, `campaign_uid` field

– Generation: Created when campaign is saved

– Example SQL:

Code :



SELECT campaign_uid FROM campaign WHERE campaign_id = 123;
-- Returns: 'a1b2c3d4e5f6g'

2. Link Hash (64-character hexadecimal)

Code :



8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4

– Format: 64-character hex string (256-bit)

– Source: `campaign_url` table, `hash` field

– Generation Process:

Code :



// MailWizz 2.x Link Hash Generation Logic (simplified)
$hash = hash('sha256', $campaign_uid . $original_url . microtime(true) . mt_rand());
// Example: hash('sha256', 'a1b2c3d4e5f6g' . 'https://www.example.com/product' . '1625097600.1234' . '847362')

3. Subscriber UID (32-character MD5 hash)

Code :



7f9e8d3c5a2b4e6c8a1d5f3b9e7c2a4d6b8

– Format: 32-character hex string

– Source: `list_subscriber` table, `subscriber_uid` field

– Generation: MD5 hash of subscriber data

Code :



$subscriber_uid = md5($subscriber_id . $list_id . $email . 'SOME_SALT');

4. Optional Parameters

– `&email=user%40example.com` – URL-encoded email address

– `&ip_address=192.168.1.1` – Client IP (if available in email client)

– `&user_agent=Mozilla%2F5.0…` – URL-encoded user agent

– `&signature=…` – Optional HMAC signature for security

3. Database Schema – How It’s Stored

A. `campaign_url` Table Structure

Code :



CREATE TABLE campaign_url (
    url_id INT(11) PRIMARY KEY AUTO_INCREMENT,
    campaign_id INT(11) NOT NULL,
    hash CHAR(64) NOT NULL UNIQUE,           -- 64-char SHA256 hash
    destination TEXT NOT NULL,               -- Original URL
    click_count INT(11) DEFAULT 0,
    date_added DATETIME,
    KEY idx_hash (hash),
    KEY idx_campaign_id (campaign_id)
);

B. `campaign_track_url` Table (Click Logging)

Code :



CREATE TABLE campaign_track_url (
    url_id INT(11) NOT NULL,
    subscriber_id INT(11) NOT NULL,
    ip_address VARCHAR(45),
    user_agent VARCHAR(255),
    date_added DATETIME,
    location_id INT(11),                     -- GeoIP location
    KEY idx_url_subscriber (url_id, subscriber_id)
);

4. Encoding Process – Step by Step

Step 1: Link Detection During Campaign Creation

Code :



// When campaign HTML content is parsed:
$pattern = '/href=["\'](https?:\/\/[^"\']+)["\']/i';
preg_match_all($pattern, $htmlContent, $matches);

foreach ($matches[1] as $originalUrl) {
    // Skip already encoded or unsubscribe links
    if (strpos($originalUrl, '/unsubscribe/') !== false) continue;
    
    // Generate unique hash for this link
    $hash = $this->generateUrlHash($campaignId, $originalUrl);
    
    // Store in campaign_url table
    $this->saveCampaignUrl($campaignId, $hash, $originalUrl);
    
    // Replace in content
    $trackingUrl = $this->buildTrackingUrl($campaignUid, $hash);
    $htmlContent = str_replace($originalUrl, $trackingUrl, $htmlContent);
}

Step 2: Hash Generation Function

Code :



private function generateUrlHash($campaignId, $originalUrl) {
    // Create a unique string based on multiple factors
    $uniqueString = sprintf(
'%d%s%d%.8f',        $campaignId,
        $originalUrl,
        time(),
        mt_rand() / mt_getrandmax()
    );
    
    // Generate SHA256 hash
    $hash = hash('sha256', $uniqueString);
    
    // Ensure uniqueness in database
    while ($this->hashExists($hash)) {
        $uniqueString .= mt_rand();
        $hash = hash('sha256', $uniqueString);
    }
    
    return $hash;
}

Step 3: Tracking URL Builder

Code :



public function buildTrackingUrl($campaignUid, $hash, $subscriberUid = null) {
    $baseUrl = rtrim(Yii::app()->options->get('system.urls.frontend_absolute_url'), '/');
    
    $url = sprintf(
        '%s/campaigns/%s/track-url/%s',
        $baseUrl,
        $campaignUid,
        $hash
    );
    
    if ($subscriberUid) {
        $url .= '?subscriber=' . $subscriberUid;
        
        // Add subscriber email if available
        if ($subscriberEmail) {
            $url .= '&email=' . urlencode($subscriberEmail);
        }
        
        // Add optional security signature
        if ($this->useSignatures) {
            $signature = $this->generateSignature($campaignUid, $hash, $subscriberUid);
            $url .= '&signature=' . $signature;
        }
    }
    
    return $url;
}

5. Tracking Endpoint – What Happens on Click

Controller: `/apps/customer/controllers/CampaignsController.php`

Code :



public function actionTrack_url($campaign_uid, $hash) {
    // 1. Validate campaign exists and is active
    $campaign = $this->loadCampaignModel($campaign_uid);
    
    // 2. Load URL from hash
    $url = CampaignUrl::model()->findByAttributes([
        'hash' => $hash,
        'campaign_id' => $campaign->campaign_id
    ]);
    
    // 3. Get subscriber from query parameter
    $subscriberUid = Yii::app()->request->getQuery('subscriber');
    $subscriber = ListSubscriber::model()->findByUid($subscriberUid);
    
    // 4. Log the click
    $track = new CampaignTrackUrl();
    $track->url_id = $url->url_id;
    $track->subscriber_id = $subscriber->subscriber_id;
    $track->ip_address = Yii::app()->request->getUserHostAddress();
    $track->user_agent = Yii::app()->request->getUserAgent();
    $track->date_added = new CDbExpression('NOW()');
    $track->save();
    
    // 5. Update counters
    $url->updateCounters(['click_count' => 1]);
    $campaign->updateCounters(['clicked_count' => 1]);
    
    // 6. Redirect to original URL
    $this->redirect($url->destination, true, 301);
}

6. Advanced: Signature Verification (Optional)

MailWizz can add HMAC signatures for security:

Code :



private function generateSignature($campaignUid, $hash, $subscriberUid) {
    $secret = Yii::app()->options->get('system.customer.campaigns.tracking_signature_key');
    $data = $campaignUid . $hash . $subscriberUid;
    return hash_hmac('sha256', $data, $secret);
}

private function verifySignature($campaignUid, $hash, $subscriberUid, $signature) {
    $expected = $this->generateSignature($campaignUid, $hash, $subscriberUid);
    return hash_equals($expected, $signature);
}

7. Real-World Example Flow

Code :



1. ORIGINAL LINK IN EMAIL:
   Shop Now

2. DURING CAMPAIGN SEND:
   Campaign UID: 'cm123456789ab'
   Subscriber UID: 'sub987654321fe'
   Original URL: 'https://store.com/sale?ref=newsletter'
   
   Hash Generation:
Input: 'cm123456789abhttps://store.com/sale?ref=newsletter16250976000.84736251'   SHA256 Output: '8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4'
   
   Database Insert:
   INSERT INTO campaign_url (campaign_id, hash, destination) 
   VALUES (123, '8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4', 
           'https://store.com/sale?ref=newsletter');

3. ENCODED URL IN EMAIL:
   Shop Now

4. ON CLICK:
   - Request to: /campaigns/cm123456789ab/track-url/8e3c7a5f...
   - Log in campaign_track_url
   - Redirect to: https://store.com/sale?ref=newsletter

8. Reverse Engineering / Decoding

To decode a MailWizz tracking URL:

1. Extract Components:

Code :



$url = 'https://domain.com/campaigns/abc123def456/track-url/8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4?subscriber=sub987654321fe';
$parts = parse_url($url);

// Get path segments
$path = trim($parts['path'], '/');
$segments = explode('/', $path);
// $segments[0] = 'campaigns'
// $segments[1] = 'abc123def456' (campaign_uid)
// $segments[2] = 'track-url'
// $segments[3] = '8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4' (hash)

// Parse query string
parse_str($parts['query'], $query);
// $query['subscriber'] = 'sub987654321fe'

2. Lookup in Database:

Code :



-- Find the original URL
SELECT cu.destination 
FROM campaign_url cu
JOIN campaign c ON c.campaign_id = cu.campaign_id
WHERE cu.hash = '8e3c7a5f9b2d4c6a1e8f3b7d5a9c2e4f6a8b3d7e1c5f9a2b4d6e8f3a7c5b9d1e4'
AND c.campaign_uid = 'abc123def456';

-- Find subscriber details
SELECT ls.email, l.name as list_name
FROM list_subscriber ls
JOIN lists l ON l.list_id = ls.list_id
WHERE ls.subscriber_uid = 'sub987654321fe';

9. Key Points for Developers

1. Hash Uniqueness: Each link in each campaign gets a unique hash, even if same destination URL appears multiple times.

2. Persistence: Hashes are persistent and never change for a campaign, allowing historical click tracking.

3. Redirect Type: Uses 301 (permanent) redirect for SEO benefits – search engines follow the redirect chain.

4. Subscriber Tracking: The `subscriber` parameter is mandatory for individual tracking; without it, only aggregate counts are tracked.

5. Performance: MailWizz uses database indexes on `hash` and `campaign_uid` for fast lookups during redirection.

6. Security: URLs can be signed with HMAC to prevent tampering with subscriber parameters.

This encoding system allows MailWizz to track clicks with high granularity while maintaining relatively clean URLs and efficient database operations.


 Let me provide the most detailed technical breakdown of how MailWizz 2.0 generates this hash, including actual reverse engineering methods.

The Link Hash: 64-Character Hexadecimal String

Example: `5f8e4a3b1c7d9e2f6a0b1c8d3e9f4a5b2c7d1e6f3a8b9c0d5e4f7a2b1c8d3e6f`

Part 1: How MailWizz 2.0 Actually Generates the Hash

A. Core Generation Algorithm

Looking at the MailWizz 2.0 source code (particularly `/apps/common/models/CampaignUrl.php`):

Code :



// Simplified version from MailWizz 2.0 source:
protected function generateHash() {
    // Create unique data string
    $uniqueString = sprintf(
        '%d.%s.%s.%d',
        $this->campaign_id,                // Campaign ID (integer)
        $this->destination,                // Original URL
        time(),                           // Current timestamp
        mt_rand(0, 999999)                // Random number
    );
    
    // Generate SHA256 hash
    $hash = hash('sha256', $uniqueString);
    
    // Ensure uniqueness in database
    while ($this->hashExistsInDb($hash)) {
        $uniqueString .= mt_rand(0, 999999);
        $hash = hash('sha256', $uniqueString);
    }
    
    return $hash;
}

B. Actual Generation Process (Step-by-Step)

When MailWizz processes a campaign:

Step 1: Extract all URLs from email content

Code :



// From /apps/common/components/helpers/CampaignHelper.php
$pattern = '/]+href=["\']([^"\']+)["\'][^>]*>/i';
preg_match_all($pattern, $content, $matches);

Step 2: For each unique URL, generate hash

Code :



// Database row creation in campaign_url table:
$campaignUrl = new CampaignUrl();
$campaignUrl->campaign_id = 123;
$campaignUrl->destination = 'https://www.example.com/product';
$campaignUrl->hash = $this->generateUniqueHash(123, 'https://www.example.com/product');
$campaignUrl->save();

Step 3: Replace in content

Code :



$trackingUrl = $this->createTrackingUrl($campaign->campaign_uid, $hash);
$content = str_replace($originalUrl, $trackingUrl, $content);

Part 2: Reverse Engineering – Can We Decode/Recreate It?

A. What’s Encoded in the Hash?

NO – The hash is NOT reversible to get the original URL directly. It’s a one-way cryptographic hash.

However, we can reverse engineer the process by analyzing what information is encoded:

Data that goes into hash generation:

1. Campaign ID (database integer, e.g., `123`)

2. Original destination URL (full URL with query strings)

3. Timestamp (when campaign was processed)

4. Random salt (to ensure uniqueness)

Example generation:

Code :



// Input data:
$campaign_id = 456;
$destination = 'https://example.com/product?ref=newsletter';
$timestamp = 1625097600;
$random = 847362;

// Concatenated string:
$input = "456.https://example.com/product?ref=newsletter.1625097600.847362";

// SHA256 hash:
$hash = hash('sha256', $input);
// Result: 5f8e4a3b1c7d9e2f6a0b1c8d3e9f4a5b2c7d1e6f3a8b9c0d5e4f7a2b1c8d3e6f

B. Database Schema – Where Hash is Stored

Code :



-- campaign_url table structure
CREATE TABLE `campaign_url` (
  `url_id` int(11) NOT NULL AUTO_INCREMENT,
  `campaign_id` int(11) NOT NULL,
  `hash` char(64) NOT NULL,                    -- THE 64-CHAR HASH
  `destination` text NOT NULL,                 -- Original URL here
  `click_count` int(11) DEFAULT 0,
  `date_added` datetime DEFAULT NULL,
  `last_updated` datetime DEFAULT NULL,
  PRIMARY KEY (`url_id`),
  UNIQUE KEY `hash` (`hash`),                  -- Hash is unique
  KEY `fk_campaign_url_campaign1_idx` (`campaign_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

C. Methods to “Reverse” the Hash

Method 1: Database Lookup (Direct)

Code :



-- Given a hash, find the original URL
SELECT destination, campaign_id, click_count 
FROM campaign_url 
WHERE hash = '5f8e4a3b1c7d9e2f6a0b1c8d3e9f4a5b2c7d1e6f3a8b9c0d5e4f7a2b1c8d3e6f';

-- Result:
-- destination: https://www.example.com/product?ref=newsletter
-- campaign_id: 456
-- click_count: 124

Method 2: Find All Hashes for a Campaign

Code :



-- Get all tracking hashes for campaign #456
SELECT hash, destination, click_count
FROM campaign_url 
WHERE campaign_id = 456 
ORDER BY date_added;

Method 3: Programmatic Reverse Lookup (PHP)

Code :



db = $dbConnection;
    }
    
    /**
     * Get original URL from hash
     */
    public function getUrlFromHash($hash) {
        $stmt = $this->db->prepare("
            SELECT cu.destination, c.name as campaign_name, 
                   c.campaign_uid, cu.click_count
            FROM campaign_url cu
            JOIN campaign c ON c.campaign_id = cu.campaign_id
            WHERE cu.hash = :hash
            LIMIT 1
        ");
        $stmt->execute([':hash' => $hash]);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
    
    /**
     * Find hash by matching URL pattern
     */
    public function findHashByUrlPattern($pattern) {
        $stmt = $this->db->prepare("
            SELECT hash, destination, campaign_id
            FROM campaign_url
            WHERE destination LIKE :pattern
        ");
        $stmt->execute([':pattern' => "%{$pattern}%"]);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /**
     * Generate possible hash for testing
     * (For hash collision testing or verification)
     */
    public function generateSimilarHash($campaignId, $url) {
        // This mimics MailWizz's generation but won't match exactly
        // because of timestamp and random salt
        $uniqueString = sprintf(
            '%d.%s.%d.%d',
            $campaignId,
            $url,
            time(),  // Current time - different from original!
            mt_rand(0, 999999)
        );
        return hash('sha256', $uniqueString);
    }
}
?>

Part 3: Technical Deep Dive – Hash Characteristics

A. Hash Properties Analysis

1. Length: 64 characters (SHA256 produces 256 bits = 32 bytes = 64 hex chars)

2. Character set: `[0-9a-f]` (lowercase hexadecimal)

3. Uniqueness: Guaranteed unique per URL per campaign

4. Collision resistance: SHA256 makes collisions computationally infeasible

B. Example Generation with Real Data

Let’s trace through actual generation:

Code :



// When campaign #789 is being sent with this link:
$originalUrl = 'https://store.com/buy-now?discount=50';

// MailWizz generates:
$campaignId = 789;
$timestamp = 1625097612;  // Unix timestamp
$random = 123456;         // Random number

// Build string: "campaignId.originalUrl.timestamp.random"
$input = "789.https://store.com/buy-now?discount=50.1625097612.123456";

// Hash it:
$hash = hash('sha256', $input);
// Result: "8a3b7c5d9e1f2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4"

// Store in database:
// INSERT INTO campaign_url (campaign_id, hash, destination) 
// VALUES (789, '8a3b7c5d9e1f2a4b6c8d0e2f4a6b8c0d2e4f6a8b0c2d4e6f8a0b2c4d6e8f0a2b4', 
//         'https://store.com/buy-now?discount=50');

C. Verification Script – Check Hash Validity

Code :



 strlen($hash),
            'is_hex' => ctype_xdigit($hash),
            'is_lowercase' => ($hash === strtolower($hash)),
            'character_set' => count_chars($hash, 3),
            'possible_algorithm' => 'SHA256 (64 hex chars = 256 bits)'
        ];
    }
}

// Usage:
$hash = '5f8e4a3b1c7d9e2f6a0b1c8d3e9f4a5b2c7d1e6f3a8b9c0d5e4f7a2b1c8d3e6f';
print_r(HashVerifier::analyzeHash($hash));
/*
Array
(
    [length] => 64
    [is_hex] => true
    [is_lowercase] => true
    [character_set] => 0123456789abcdef
    [possible_algorithm] => SHA256 (64 hex chars = 256 bits)
)
*/
?>

Part 4: Advanced Reverse Engineering Techniques

A. Hash Mapping Database

Create a lookup database for reverse engineering:

Code :



-- Create a mapping table for analysis
CREATE TABLE hash_analysis (
    id INT AUTO_INCREMENT PRIMARY KEY,
    hash CHAR(64) NOT NULL,
    campaign_id INT NOT NULL,
    url_length INT,
    url_domain VARCHAR(255),
    has_query_params BOOLEAN,
    has_anchors BOOLEAN,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- Populate with existing data
INSERT INTO hash_analysis (hash, campaign_id, url_length, url_domain, has_query_params, has_anchors)
SELECT 
    cu.hash,
    cu.campaign_id,
    LENGTH(cu.destination) as url_length,
    SUBSTRING_INDEX(SUBSTRING_INDEX(cu.destination, '/', 3), '//', -1) as domain,
    IF(LOCATE('?', cu.destination) > 0, 1, 0) as has_query,
    IF(LOCATE('#', cu.destination) > 0, 1, 0) as has_anchor
FROM campaign_url cu;

B. Statistical Analysis of Hashes

Code :



db->prepare($sql);
        if ($campaignId) {
            $stmt->execute([':campaignId' => $campaignId]);
        } else {
            $stmt->execute();
        }
        
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
    
    /**
     * Try to brute-force hash generation for a specific URL
     * (For security testing purposes only!)
     */
    public function bruteForceHash($campaignId, $url, $maxAttempts = 1000000) {
        $found = false;
        $attempts = 0;
        $startTime = time();
        
        // Try different timestamps (within plausible range)
        $campaignTime = strtotime('-30 days'); // When campaign was likely sent
        
        for ($i = 0; $i < 86400 * 30; $i += 3600) { // Try each hour for 30 days
            $timestamp = $campaignTime + $i;
            
            for ($r = 0; $r < 1000; $r++) { // Try random numbers
                $input = sprintf('%d.%s.%d.%d', $campaignId, $url, $timestamp, $r);
                $hash = hash('sha256', $input);
                
                // Check if this hash exists in database
                if ($this->hashExistsInDb($hash)) {
                    return [
                        'found' => true,
                        'hash' => $hash,
                        'timestamp' => $timestamp,
                        'random' => $r,
                        'attempts' => $attempts,
                        'time_taken' => time() - $startTime
                    ];
                }
                
                $attempts++;
                if ($attempts >= $maxAttempts) {
                    break 2;
                }
            }
        }
        
        return ['found' => false, 'attempts' => $attempts];
    }
}
?>

Part 5: Practical Applications of Hash Reverse Engineering

A. Create Custom Click Tracking Dashboard

Code :




B. Direct URL Redirection (Bypass MailWizz Tracking)

Code :



getOriginalUrlByHash($hash);
        
        // Redirect immediately (no tracking)
        header("Location: " . $originalUrl, true, 302);
        exit;
    }
    
    private function getOriginalUrlByHash($hash) {
        $stmt = $this->db->prepare("
            SELECT destination 
            FROM campaign_url 
            WHERE hash = :hash 
            LIMIT 1
        ");
        $stmt->execute([':hash' => $hash]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        
        return $result['destination'] ?? null;
    }
}
?>

C. Hash Pre-generation for Testing

Code :



getCampaignCreationTime($campaignId);
            
            // Generate multiple possible hashes
            for ($i = 0; $i < 10; $i++) {
                $random = mt_rand(0, 999999);
                $input = sprintf('%d.%s.%d.%d', $campaignId, $url, $timestamp, $random);
                $hash = hash('sha256', $input);
                
                $generated[] = [
                    'url' => $url,
                    'hash' => $hash,
                    'timestamp' => $timestamp,
                    'random' => $random
                ];
            }
        }
        
        return $generated;
    }
}
?>

Part 6: Security Implications

A. Can Hashes Be Guessed/Recreated?

Short answer: Extremely difficult without database access.

Why:

1. Random salt: Each hash includes `mt_rand()` output

2. Timestamp: Exact timestamp of generation is needed

3. Campaign ID: Internal database ID required

4. SHA256: Cryptographically secure one-way function

# B. What If You Have Database Access?

If you have access to the MailWizz database, you can:

1. Map any hash to its original URL (direct lookup)

2. Generate valid tracking URLs for any campaign

3. Analyze click patterns directly in database

4. Modify destination URLs without resending campaigns

C. Protection Measures in MailWizz

1. Database indexes on hash field for fast lookups

2. Unique constraint prevents hash collisions

3. Click logging with IP/user agent tracking

4. Optional HMAC signatures for URL validation

Summary: Key Points About MailWizz Link Hashes

1. Algorithm: SHA256 hash of `campaignId.url.timestamp.random`

2. Length: 64 lowercase hexadecimal characters

3. Reversibility: Only via database lookup (not cryptographically reversible)

4. Uniqueness: Guaranteed per URL per campaign

5. Structure: `[0-9a-f]{64}` (64 hex chars)

6. Generation Time: When campaign is saved/sent

7. Persistence: Never changes for a campaign/link combination

For practical reverse engineering:

– With DB access: Direct lookup in `campaign_url` table

– Without DB access: Nearly impossible to reverse

– For analysis: Examine hash patterns and click logs

This hash system allows MailWizz to track clicks efficiently while maintaining a relatively simple URL structure that’s compatible with most email clients and web servers.