Security
Headlines
HeadlinesLatestCVEs

Headline

CVE-2023-3132: Changeset 2923512 for mainwp-child – WordPress Plugin Repository

The MainWP Child plugin for WordPress is vulnerable to Sensitive Information Exposure in versions up to, and including, 4.4.1.1 due to insufficient controls on the storage of back-up files. This makes it possible for unauthenticated attackers to extract sensitive data including the entire installations database if a backup occurs and the deletion of the back-up files fail.

CVE
#sql#js#git#wordpress#php#auth

mainwp-child/trunk/class/class-mainwp-backup.php

r2868300

r2923512

284

284

    } else {

285

285

        // When not an archive.

286

        $backupFile = 'dbBackup-' . $fileNameUID . '-\*.sql';

286

        $backupFile = 'dbBackup-' . $fileNameUID . '-\*.sql.php';

287

287

        $dirs       = MainWP\_Helper::get\_mainwp\_dir( 'backup' );

288

288

        $backupdir  = $dirs\[0\];

582

582

        while ( ( $file = readdir( $dh ) ) !== false ) {

583

583

            if ( '.' !== $file && '..' !== $file && ( preg\_match( '/dbBackup-(.\*).sql(\\.zip|\\.tar|\\.tar\\.gz|\\.tar\\.bz2|\\.tmp)?$/', $file ) ) ) {

584

                unlink( $dir . $file );

585

            }

586

            if ( '.' !== $file && '..' !== $file && ( preg\_match( '/dbBackup-(.\*).sql.php(\\.zip|\\.tar|\\.tar\\.gz|\\.tar\\.bz2|\\.tmp)?$/', $file ) ) ) {

584

587

                unlink( $dir . $file );

585

588

            }

1263

1266

        $table = $curr\_table\[0\];

1264

1267

1265

        $currentfile = $filepath\_prefix . '-' . MainWP\_Helper::sanitize\_filename( $table ) . '.sql';

1268

        $currentfile = $filepath\_prefix . '-' . MainWP\_Helper::sanitize\_filename( $table ) . '.sql.php';

1266

1269

        $db\_files\[\]  = $currentfile;

1267

1270

        if ( file\_exists( $currentfile ) ) {

1270

1273

        $fh = fopen( $currentfile . '.tmp', 'w' );

1271

1274

1275

        $protect\_content\_string = '<?php exit(); ?>';

1276

1277

        fwrite( $fh, $protect\_content\_string );

1272

1278

        fwrite( $fh, "\\n\\n" . 'DROP TABLE IF EXISTS ' . $table . ';' );

1273

1279

        $table\_create = $wpdb->get\_row( 'SHOW CREATE TABLE ' . $table, ARRAY\_N ); // phpcs:ignore -- required to achieve desired results. Pull requests appreciated.

mainwp-child/trunk/class/class-mainwp-child-actions.php

r2890510

r2923512

608

608

 \*/

609

609

public function callback\_upgrader\_pre\_install() {

610

    $this->current\_plugins\_info = $this->get\_plugins();

610

    if ( empty( $this->current\_plugins\_info ) ) {

611

        $this->current\_plugins\_info = $this->get\_plugins();

612

    }

611

613

}

612

614

mainwp-child/trunk/class/class-mainwp-child-cache-purge.php

r2890510

r2923512

148

148

        'flying-press/flying-press.php'              => 'FlyingPress',

149

149

        'wp-super-cache/wp-cache.php'                => 'WP Super Cache',

150

        'comet-cache/comet-cache.php'                => 'Comet Cache',

150

151

        'wp-optimize/wp-optimize.php'                => 'WP Optimize',

151

        'comet-cache/comet-cache.php'                => 'Comet Cache',

152

        'seraphinite-accelerator/plugin\_root.php'    => 'Seraphinite Accelerator',

152

153

    );

153

154

155

156

    foreach ( $supported\_cache\_plugins as $plugin => $name ) {

156

157

        if ( is\_plugin\_active( $plugin ) ) {

157

            $cache\_plugin\_solution     = $name;

158

            $this->is\_plugin\_installed = true;

158

159

            // Check if WP Optimize is active and page cache is enabled or disabled. If disabled, continue to next plugin as if it is not installed.

160

            if ( 'wp-optimize/wp-optimize.php' == $plugin ) {

161

                if ( class\_exists( '\\WP\_Optimize' ) ) {

162

                    $cache = WP\_Optimize()->get\_page\_cache();

163

                    if ( $cache->is\_enabled() === false ) {

164

                        continue;

165

                    } elseif ( $cache->is\_enabled() === true ) {

166

                        {

167

                            $cache\_plugin\_solution = 'WP Optimize';

168

                        }

169

                    }

170

                }

171

            } else {

172

                $cache\_plugin\_solution = $name;

173

            }

159

174

        }

160

175

    }

238

253

                case 'CDN Cache Plugin':

239

254

                    $information = $this->cdn\_cache\_plugin\_auto\_purge\_cache();

255

                    break;

256

                case 'Seraphinite Accelerator':

257

                    $information = $this->seraphinite\_auto\_purge\_cache();

240

258

                    break;

241

259

                default:

301

319

302

320

/\*\*

321

 \* Purge Seraphinite Accelerator plugin cache.

322

 \*

323

 \* @return array Purge results array.

324

 \*/

325

public function seraphinite\_auto\_purge\_cache() {

326

327

    $success\_message = 'Seraphinite Accelerator => Cache auto cleared on: (' . current\_time( 'mysql' ) . ')';

328

    $error\_message   = 'Seraphinite Accelerator => There was an issue purging your cache.';

329

330

    if ( class\_exists( '\\seraph\_accel\\API' ) ) {

331

332

        \\seraph\_accel\\API::OperateCache( \\seraph\_accel\\API::CACHE\_OP\_DEL );

333

334

        // record results.

335

        update\_option( 'mainwp\_cache\_control\_last\_purged', time() );

336

337

        return $this->purge\_result( $success\_message, 'SUCCESS' );

338

339

    } else {

340

        return $this->purge\_result( $error\_message, 'ERROR' );

341

    }

342

}

343

344

/\*\*

303

345

 \* Purge CDN Cache Plugin cache.

304

346

 \*

393

435

394

436

/\*\*

437

 \* Check if WP Optimize is installed and cache is enabled.

438

 \*/

439

public function wp\_optimize\_activated\_check() {

440

    if ( class\_exists( '\\WP\_Optimize' ) ) {

441

        $cache = WP\_Optimize()->get\_page\_cache();

442

        if ( ! $cache->is\_enabled() ) {

443

            return false;

444

        }

445

    }

446

}

447

448

/\*\*

395

449

 \* Preload WP Optimize cache after purge.

396

450

 \*

734

788

    $cust\_domain = trim( str\_replace( array( 'http://', 'https://', 'www.' ), '', get\_option( 'siteurl' ) ), '/' );

735

789

790

    // Check if we have all the required data.

736

791

    if ( '' == $cust\_email || '' == $cust\_xauth || '' == $cust\_domain ) {

737

792

        return;

738

793

    }

794

795

    // Strip subdomains. Cloudflare doesn't like them.

796

    $cust\_domain = $this->strip\_subdomains( $cust\_domain );

739

797

740

798

    // Get the Zone-ID from Cloudflare since they don't provide that in the Backend.

751

809

    if ( 'resource' === gettype( $ch\_query ) ) {

752

810

        curl\_close( $ch\_query ); // phpcs:ignore -- use core function.

753

    }

754

755

    // If the Zone-ID is not found, return status no-id but still return "SUCCESS" action because it did not fail.

756

    // Explanation: When no Child Site is found on CF account, this will stop execution of this function and return

757

    // back to auto\_purge\_cache() function for further processing.

758

    if ( ! isset( $qresult\['result'\]\[0\]\['id'\] ) ) {

759

        return array(

760

            'status' => 'no-id',

761

            'action' => 'SUCCESS',

762

        );

763

811

    }

764

812

784

832

        curl\_close( $ch\_purge ); // phpcs:ignore -- use core function.

785

833

    }

786

787

    $success\_message = 'Cloudflair => Cache auto cleared on: (' . current\_time( 'mysql' ) . ')';

788

    $error\_message   = 'Cloudflare => There was an issue purging your cache.' . json\_encode( $result ); // phpcs:ignore -- ok.

834

    $success\_message = 'Cloudflare => Cache auto cleared on: (' . current\_time( 'mysql' ) . ')';

835

    $error\_message   = 'Cloudflare => There was an issue purging the cache. ' . json\_encode( $qresult\['errors'\]\[0\], JSON\_UNESCAPED\_SLASHES ) . "-" . json\_encode( $result\['errors'\]\[0\], JSON\_UNESCAPED\_SLASHES ); // phpcs:ignore -- ok.

789

836

790

837

    // Save last purge time to database on success.

791

838

    if ( 1 == $result\['success'\] ) {

839

792

840

        // record results.

793

841

        update\_option( 'mainwp\_cache\_control\_last\_purged', time() );

795

843

        // Return success message.

796

844

        return $this->purge\_result( $success\_message, 'SUCCESS' );

797

    } else {

845

    } elseif ( ( 1 != $qresult\['success'\] ) || ( 1 != $result\['success'\] ) ) {

798

846

        // Return error message.

799

847

        return $this->purge\_result( $error\_message, 'ERROR' );

918

966

    update\_option( 'mainwp\_cache\_control\_log', wp\_json\_encode( $information ) );

919

967

}

968

969

/\*\*

970

 \* Strip subdomains from a url.

971

 \*

972

 \* @param string $url string The url to strip subdomains from.

973

 \*

974

 \* @return string The url without subdomains (if any).

975

 \*/

976

public function strip\_subdomains( $url ) {

977

978

    // credits to gavingmiller for maintaining this list.

979

    $second\_level\_domains = file\_get\_contents( 'https://raw.githubusercontent.com/gavingmiller/second-level-domains/master/SLDs.csv' ); //phpcs:ignore -- to do.

980

981

    // presume sld first ...

982

    $possible\_sld = implode( '.', array\_slice( explode( '.', $url ), -2 ) );

983

984

    // and then verify it.

985

    if ( strpos( $second\_level\_domains, $possible\_sld ) ) {

986

        return implode( '.', array\_slice( explode( '.', $url ), -3 ) );

987

    } else {

988

        return implode( '.', array\_slice( explode( '.', $url ), -2 ) );

989

    }

990

}

920

991

}

mainwp-child/trunk/class/class-mainwp-child-callable.php

r2881395

r2923512

1061

1061

    MainWP\_Helper::write( $information );

1062

1062

}

1063

1064

1063

}

mainwp-child/trunk/class/class-mainwp-child.php

r2910248

r2923512

34

34

 \* @var string MainWP Child plugin version.

35

35

 \*/

36

public static $version = '4.4.1.1';

36

public static $version = '4.4.1.2';

37

37

38

38

/\*\*

mainwp-child/trunk/class/class-mainwp-client-report-base.php

r2877395

r2923512

763

763

            $tok\_value = MainWP\_Helper::format\_time( MainWP\_Helper::get\_timestamp( strtotime( $record->created ) ) );

764

764

            break;

765

        case 'utime':

766

            $tok\_value = $record->created;

767

            break;

768

        case 'slug':

769

            $tok\_value = $this->get\_stream\_meta\_data( $record, $data );

770

            break;

765

771

        case 'area':

766

772

            $data      = 'sidebar\_name';

mainwp-child/trunk/class/class-mainwp-clone-install.php

r2900843

r2923512

9

9

10

10

namespace MainWP\Child;

11

12

use Stringable;

11

13

12

14

// phpcs:disable WordPress.WP.AlternativeFunctions, Generic.Metrics.CyclomaticComplexity – Required to achieve desired results, pull request solutions appreciated.

238

240

 \*/

239

241

public function clean() {

240

    $files = glob( WP\_CONTENT\_DIR . '/dbBackup\*.sql' );

242

    $files = glob( WP\_CONTENT\_DIR . '/dbBackup\*.sql.php' );

241

243

    foreach ( $files as $file ) {

242

244

        unlink( $file );

245

    }

246

    if ( file\_exists( WP\_CONTENT\_DIR . '/dbBackup.sql' ) ) {

247

        unlink( WP\_CONTENT\_DIR . '/dbBackup.sql' );

243

248

    }

244

249

    if ( file\_exists( ABSPATH . 'clone/config.txt' ) ) {

341

346

    $wpdb->query( 'SET foreign\_key\_checks = 0' );

342

347

343

    $files = glob( WP\_CONTENT\_DIR . '/dbBackup\*.sql' );

348

    $protect\_content\_string = '<?php exit(); ?>';

349

350

    $files = glob( WP\_CONTENT\_DIR . '/dbBackup\*.sql.php' );

344

351

    foreach ( $files as $file ) {

345

352

        $handle = fopen( $file, 'r' );

347

354

        $lastRun = 0;

348

355

        if ( $handle ) {

349

            $readline = '';

356

            $readline       = '';

357

            $remove\_protect = true;

350

358

            while ( ( $line = fgets( $handle, 81920 ) ) !== false ) {

351

359

                if ( time() - $lastRun > 20 ) {

352

360

                    set\_time\_limit( 0 ); // reset timer..

353

361

                    $lastRun = time();

362

                }

363

364

                if ( $remove\_protect ) {

365

                    if ( false !== stristr( $line, $protect\_content\_string ) ) {

366

                        $line           = str\_replace( $protect\_content\_string, '', $line );

367

                        $remove\_protect = false;

368

                    }

354

369

                }

355

370

mainwp-child/trunk/class/class-mainwp-clone.php

r2868300

r2923512

290

290

private function create\_clone\_backup() { // phpcs:ignore -- Current complexity is the only way to achieve desired results, pull request solutions appreciated.

291

291

    MainWP\_Helper::end\_session();

292

    $files = glob( WP\_CONTENT\_DIR . '/dbBackup\*.sql' );

292

    $files = glob( WP\_CONTENT\_DIR . '/dbBackup\*.sql.php' );

293

293

    foreach ( $files as $file ) {

294

294

        unlink( $file );

295

    }

296

    if ( file\_exists( WP\_CONTENT\_DIR . '/dbBackup.sql' ) ) {

297

        unlink( WP\_CONTENT\_DIR . '/dbBackup.sql' );

295

298

    }

296

299

    if ( file\_exists( ABSPATH . 'clone/config.txt' ) ) {

mainwp-child/trunk/class/class-mainwp-helper.php

r2900843

r2923512

106

106

 \*

107

107

 \* @return array Return directory and directory URL.

108

 \* @throws Exception Error Message.

108

109

 \*/

109

110

public static function get\_mainwp\_dir( $what = null, $die\_on\_error = true ) {

111

112

    if ( ! self::fs\_is\_connected() ) {

113

        throw new \\Exception( esc\_html\_\_( 'Unable to connect to the filesystem.', 'mainwp-child' ) );

114

    }

110

115

111

116

    /\*\*

116

121

    global $wp\_filesystem;

117

122

118

    self::get\_wp\_filesystem();

119

120

123

    $upload\_dir = wp\_upload\_dir();

121

124

    $dir        = $upload\_dir\['basedir'\] . DIRECTORY\_SEPARATOR . 'mainwp' . DIRECTORY\_SEPARATOR;

144

147

    return array( $dir, $url );

145

148

}

149

150

151

/\*\*

152

 \* Method fs\_is\_connected()

153

 \*

154

 \* Check if WP FileSystem is connected.

155

 \*/

156

public static function fs\_is\_connected() {

157

    self::get\_wp\_filesystem();

158

    global $wp\_filesystem;

159

    if ( ! empty( $wp\_filesystem ) && $wp\_filesystem->connect() ) {

160

        return true;

161

    }

162

    return false;

163

}

164

146

165

147

166

/\*\*

mainwp-child/trunk/mainwp-child.php

r2910248

r2923512

13

13

* Author URI: https://mainwp.com

14

14

* Text Domain: mainwp-child

15

* Version: 4.4.1.1

15

* Version: 4.4.1.2

16

16

* Requires at least: 5.4

17

17

* Requires PHP: 7.4

mainwp-child/trunk/readme.txt

r2910248

r2923512

8

8

Tested up to: 6.2

9

9

Requires PHP: 7.0

10

Stable tag: 4.4.1.1

10

Stable tag: 4.4.1.2

11

11

License: GPLv3 or later

12

12

License URI: https://www.gnu.org/licenses/gpl-3.0.html

148

148

== Changelog ==

149

149

150

= 4.4.1.2 - 6-8-2023 =

151

* Fixed: Potential issues caused by incorrect FileSystem settings

152

* Updated: Logging system related to the Cache Control extension

153

* Updated: Database export process related to the Cloning feature

154

150

155

= 4.4.1.1 - 5-9-2023 =

151

156

* Fixed: Potential conflict with the Oxygen Builder 4.6

CVE: Latest News

CVE-2023-50976: Transactions API Authorization by oleiman · Pull Request #14969 · redpanda-data/redpanda
CVE-2023-6905
CVE-2023-6903
CVE-2023-6904
CVE-2023-3907