Upgrading to pro - hack issue?

Hi,

I’ve upgraded my site to pro, and now MalCare tells me my site is hacked: “Infected File (./wp-content/themes/pro/cornerstone/includes/classes/styling/class-font-manager.php)”

Is this a hack, or just part of the upgrade? MalCare gives me the option to mark it not malware.

Thank you in advance!

The full file reads as follows:

<?php class Cornerstone_Font_Manager extends Cornerstone_Plugin_Component { public $queue = array(); public $extend = array(); public $custom_css_output = ''; protected $font_items; protected $font_config; protected $loaded = array(); public function setup() { add_filter('cs_css_post_process_font-family', array( $this, 'css_post_process_font_family') ); add_filter('cs_css_post_process_font-weight', array( $this, 'css_post_process_font_weight') ); add_action( 'cornerstone_head_css', array( $this, 'output_typekit_loading_styles' ) ); add_action( 'x_head_css', array( $this, 'output_typekit_loading_styles' ) ); add_filter( 'wp_check_filetype_and_ext', array( $this, 'upload_check'), 10, 5 ); add_filter( 'upload_mimes', array( $this, 'upload_mimes' ), 999 ); add_action( 'wp_head', array( $this, 'load_initial_items'), 0 ); add_action( 'cs_head_late', array( $this, 'load_queued_fonts' ) ); add_action( 'wp_footer', array( $this, 'load_queued_fonts' ) ); } public function load_initial_items() { $items = $this->load_items(); $force = did_action('cs_before_preview_frame'); foreach ($items as $item) { if ($force || isset($item['force']) && $item['force']) { $this->queue_font( $item ); } } } public function get_extended() { return apply_filters('cs_fonts_extend', array() ); } public function default_font_items( $data = array() ) { return apply_filters('cornerstone_option_model_defaults_cornerstone_font_items', array( array( '_id' => bin2hex('Body Copy'), 'title' => csi18n( 'app.fonts.body-copy' ), 'family' => 'Helvetica', 'stack' => 'Helvetica, Arial, sans-serif', 'weights' => array( '300', '300i', '400', '400i', '700', '700i' ), 'source' => 'system' ), array( '_id' => bin2hex('Headings'), 'title' => csi18n( 'app.fonts.headings' ), 'family' => 'Helvetica', 'stack' => 'Helvetica, Arial, sans-serif', 'weights' => array( '300', '300i', '400', '400i', '700', '700i' ), 'source' => 'system' ), ) ); } public function get_fallback_font() { return array( 'family' => 'Helvetica', 'stack' => 'Helvetica, Arial, sans-serif', 'weights' => array( '400', '400i', '300', '300i', '700', '700i' ), // The first weight will be used when falling back 'source' => 'system' ); } public function get_font_items() { if ( ! $this->font_items ) { $this->font_items = $this->load_items(); } return $this->font_items; } public function get_font_config() { if ( ! $this->font_config ) { $this->font_config = $this->load_config(); } return $this->font_config; } protected function preload_config() { $preloaded = apply_filters('cs_preload_font_config', false ); if ($preloaded) { return $preloaded; } $saved = get_option( 'cornerstone_font_config' ); return ( is_null( $saved ) ) ? array() : json_decode( wp_unslash( $saved ), true ); } protected function load_config() { return wp_parse_args( $this->preload_config(), array( 'googleSubsets' => array(), 'typekitKitID' => '', 'customFontItems' => array(), 'customFontFaceCSS' => '', 'fontDisplay' => 'auto' ) ); } protected function load_items() { $preloaded = apply_filters('cs_preload_font_items', false ); if ($preloaded) { return $preloaded; } $stored = get_option( 'cornerstone_font_items' ); if ($stored === false ) { $stored = wp_slash( cs_json_encode( $this->default_font_items() ) ); update_option( 'cornerstone_font_items', $stored ); } return ( is_null( $stored ) ) ? array() : json_decode( wp_unslash( $stored ), true ); } protected function locate_font( $_id ) { $this->get_font_items(); foreach ($this->font_items as $font) { if ( isset( $font['_id'] ) && $_id === $font['_id'] ) { return $font; } } return array( 'family' => 'inherit', 'stack' => 'inherit', 'weights' => array( 'inherit' ), 'source' => 'system' ); } public function queue_font( $font ) { if ( 'system' === $font['source'] || 'extend' === $font['source'] ) { return; } if ( isset( $this->queue[$font['stack']] ) ) { $this->queue[$font['stack']]['weights'] = array_unique( array_merge( $this->queue[$font['stack']]['weights'], $font['weights'] ) ); } else { $this->queue[$font['stack']] = $font; } if ( ! isset( $this->queue[$font['stack']]['weights'] ) ) { $this->queue[$font['stack']]['weights'] = array(); } } protected function queue_font_weight( $font, $weight ) { $this->queue_font( $font ); if (isset($this->queue[$font['stack']]) && isset($this->queue[$font['stack']]['weights']) ) { if ( ! in_array($weight, $this->queue[$font['stack']]['weights'], true ) ) { $this->queue[$font['stack']]['weights'][] = $weight; $this->queue[$font['stack']]['weights'][] = $weight . 'i'; } } } public function css_post_process_font_family( $value ) { $font = $this->locate_font($value); $this->queue_font( $font ); return $font['stack']; } protected function normalize_weight( $value ) { return ( false === strpos($value, ':' ) ) ? 'inherit:' . $value : $value; } public function css_post_process_font_weight( $value ) { $value = $this->normalize_weight( $value ); $parts = explode(':', $value ); if ( 'inherit' === $parts[0] ) { return $parts[1]; } $font = $this->locate_font($parts[0]); $weight = ( in_array( $parts[1], $font['weights'], true ) ) ? $parts[1] : $font['weights'][0]; $this->queue_font_weight( $font, $weight ); return $weight; } public function load_queued_fonts() { if (count( array_keys( $this->queue ) ) <=0 ) { return; } $sources = array(); foreach ($this->queue as $font) { if ( ! isset( $font['source'] ) ) { continue; } if ( ! isset( $sources[$font['source'] ] ) ) { $sources[$font['source']] = array(); } $sources[$font['source']][] = array( 'family' => $font['family'], 'weights' => $font['weights'] ); } ksort($sources); do_action( 'cs_load_queued_fonts', $this->queue, $sources ); foreach ($sources as $source => $fonts) { $method = array( $this, "load_fonts_$source" ); if ( is_callable( $method ) ) { call_user_func_array( $method, array( $fonts ) ); } } $this->queue = array(); } public function load_fonts_google( $fonts ) { if ( ! apply_filters('cs_load_google_fonts', '__return_true' ) ) { return; } $in_footer = 'wp_footer' === current_action(); $config = apply_filters( 'cs_google_font_config', wp_parse_args($this->get_font_config(), array( 'googleSubsets' => array(), 'fontDisplay' => 'auto' ) ) ); $subsets = array_merge( array('latin', 'latin-ext'), $config['googleSubsets'] ); $subsets = array_unique($subsets); $family_strings = array(); foreach ($fonts as $font) { $weights = array_unique( $font['weights'] ); $to_load = str_replace(' ', '+', $font['family'] ) . ':' . implode(',', $weights ); if ( ! isset( $this->loaded[$to_load] ) ) { $family_strings[] = $to_load; $this->loaded[$to_load] = true; } } if ( count($family_strings) <=0 ) { return; } $request = esc_url( add_query_arg( array( 'family' => implode('%7C', $family_strings), //Was | (pipe), but %7C is required for W3C Markup validation, this is also more optimized than using urlencoder 'subset' => implode(',', $subsets ), 'display' => $config['fontDisplay'] ), apply_filters('cs_google_fonts_uri', '//fonts.googleapis.com/css' ) ) ); $atts = cs_atts( array( 'rel' => 'stylesheet', 'href' => apply_filters( 'cs_google_fonts_href', $request ), 'type' => 'text/css', 'media' => 'all', 'data-x-google-fonts' => null, ) ); $output = ""; if ( $in_footer ) { $output = $this->late_google_font_script( $output ); } echo $output; } public function late_google_font_script( $output ) { ob_start(); ?> <?php return ob_get_clean(); } public function load_fonts_typekit( $fonts ) { add_action( did_action('cs_head_late_after') ? 'wp_footer' : 'cs_head_late_after', array( $this, 'output_typekit_script') ); } public function load_fonts_custom( $fonts ) { $config = apply_filters( 'cs_custom_font_config', wp_parse_args($this->get_font_config(), array( 'customFontItems' => array(), 'fontDisplay' => 'auto' ) ) ); $load = array(); $buffer = ''; foreach ($fonts as $font) { $load[] = $font['family']; } foreach ($config['customFontItems'] as $item) { if (in_array($item['family'], $load)) { $buffer .= $this->make_custom_font_css( $item, $config ); } } if ( $buffer ) { CS()->component( 'Styling' )->add_styles( 'cs-custom-fonts', $buffer ); } } public function identify_custom_font_variants( $item ) { $variants = []; $variant_config = []; foreach ($item['files'] as $file) { $key = $file['weight'] . ':' . $file['style']; if ( ! isset( $variants[ $key ] ) ) { $variant_config[$key] = [ esc_attr($file['weight']), esc_attr($file['style']) ]; $variants[ $key ] = []; } $file_parts = explode( '.', $file['filename']); $format = array_pop( $file_parts ); if ($format) { $variants[ $key ][] = [esc_attr($file['url']), $this->normalize_format( $format)]; } } return [$variants, $variant_config]; } public function normalize_format( $format ) { switch ($format) { case 'ttf': return "format('truetype')"; case 'otf': return "format('opentype')"; case 'woff': return "format('woff')"; case 'woff2': return "format('woff2')"; } return ""; } public function make_custom_font_css( $item, $config ) { list( $variants, $variant_config ) = $this->identify_custom_font_variants( $item ); $family = isset($item['stack']) ? $item['stack'] : $item['family']; $display = esc_attr( $config['fontDisplay'] ); $buffer = ''; foreach ($variants as $key => $variant_files) { list($weight, $style) = $variant_config[$key]; $sources = []; foreach ($variant_files as $file) { list($url, $format) = $file; $sources[] = "url('$url') $format"; } $sources = implode(', ', $sources); $buffer .= "@font-face { font-family: $family; font-display: $display; src: $sources; font-weight: $weight; font-style: $style; }"; } return $buffer; } public function output_typekit_script() { $config = $this->get_font_config(); if ( ! $config['typekitKitID'] ) { return; } ?> <?php } public function output_typekit_loading_styles() { $config = $this->get_font_config(); if ( ! $config['typekitKitID'] ) { return; } echo '.wf-loading a, .wf-loading p, .wf-loading ul, .wf-loading ol, .wf-loading dl, .wf-loading h1, .wf-loading h2, .wf-loading h3, .wf-loading h4, .wf-loading h5, .wf-loading h6, .wf-loading em, .wf-loading pre, .wf-loading cite, .wf-loading span, .wf-loading table, .wf-loading strong, .wf-loading blockquote { visibility: hidden !important; }'; } public function item_permissions( $value, $operation ) { $permissions = $this->plugin->component('App_Permissions'); if ( 'update' === $operation ) { return $permissions->user_can('fonts.create') || $permissions->user_can('fonts.change') || $permissions->user_can('fonts.rename'); } if ( 'delete' === $operation ) { return $permissions->user_can('fonts.delete'); } return true; } public function config_permissions( $value, $operation ) { $permissions = $this->plugin->component('App_Permissions'); if ( 'update' === $operation ) { return $permissions->user_can('fonts.manage-google') || $permissions->user_can('fonts.manage-adobe-fonts'); } return 'delete' !== $operation; } public function upload_check( $result, $file, $filename, $mimes, $real_mime ) { $mime_types = $this->mime_types(); $parts = explode( '.', $filename); $ext = end($parts); if ( isset($mime_types[$ext]) && false !== strpos( $mime_types[$ext], $real_mime ) ) { $ext_mime_types = explode('|', $mime_types[$ext]); $result['ext'] = $ext; $result['type'] = array_shift( $ext_mime_types ); } return $result; } public function upload_mimes( $mime_types ) { $new_types = $this->mime_types(); foreach ($new_types as $ext => $type) { if (! isset($mime_types[$ext])) { $mime_types[$ext] = $type; } } return $mime_types; } public function mime_types() { return apply_filters( 'cs_font_manager_mime_types', array( 'woff2' => 'font/woff2|application/octet-stream', 'woff' => 'font/woff|application/font/woff|application/font-woff|application/octet-stream', 'ttf' => 'font/sfnt|application/x-font-ttf' ) ); } public function get_app_data() { return array( 'fontItems' => $this->get_font_items(), 'fontConfig' => $this->get_font_config(), 'customFontMimeTypes' => $this->mime_types(), 'fallbackFont' => $this->get_fallback_font(), 'extend' => $this->get_extended() ); } }

Hi @boera,

It’s difficult to tell since the formatting is lost. It could be a false positive. I was looking at the original code and we have this: var tk = doc.createElement("script") which could look suspicious since it’s a way to add third party javascript. We’re using it legitimately to load Adobe Fonts, but it’s a technique that could be used maliciously.

Here’s a way you can find out for sure if the file was altered somehow:

  • Download a new copy of Pro from your Themeco dashboard
  • Unzip and locate the file you’ve mentioned
  • Open https://www.diffchecker.com/
  • Copy the contents of class-font-manager.php in the original theme package into one side of the diff checker
  • Copy the contents of the file that is currently on your server to the other side
  • Run the diff checker

You should see no code insertions or removals if the file is untampered with. Hopefully this helps!

Hi Alexander,

Thanks for this. So, the hacked file is missing two sections, in addition to changes in spacing. In terms of resolving this, can I use FTP to replace the file with the correct version? Or is there something else I need to do?

Thank you for your help!
Beate

Hello Beate,

To make correction in the hack files you can use diff checker as mentioned by @alexander or you can simply download the new Pro theme file and replace the file at the same path or same location of the files. I would also suggest you change your WordPress Login credentials and add proper permission to the wp-content folder and files so that file can not be writable by any other users or script.

Thanks

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.