• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
  • Skip to secondary sidebar

Code

  • DevPage

command-line-tutorials

Parsing WP Engine Security Auditor Information from Your Error Logs

Reading Time: 3 minutes

WP Engine has a plugin called Security Auditor which logs certain activities to a site’s error logs. While it can muddy up your logs, it’s a great resource, but they only keep the logs for 5 days, so download them from within your WordPress site by looking for the WP Engine logo, and clicking “General Settings”.
The direct link is: wp-admin/admin.php?page=wpengine-common

Once on this page, look for “Web Server & PHP Error Log” (which is usually towards the bottom) and ensure you click the links that say “Live Site” to download your files. This is the last two days, but you can easily script if you know what you’re doing.
I’m not posting the link here since it has an API key, and I don’t recommend you publicly post the link either.
Alternatively, you can set up an Amazon S3 bucket to store your logs – read here for setting that up.

Okay, now that you have your logs in front of you, let’s get to the meat and potatoes. In the You also may not need zgrep if your logs are not compressed by the gzip program. If that’s the case, change zgrep to grep (ggrep if on Mac using Homebrew if you haven’t set your alias).

This script prints the user’s email, time and date as well as the plugin that was updated. In order for the user’s email to print, you must have wp-cli installed for this to work. If you don’t, the function will print out the user ID instead.
Usage: printupdates logfile
Replace “logfile” with the path to your log file
e.g. /var/log/apache2/site.error.log

function printupdates(){
    getlog=$(zgrep -vh 'scan' "${1}" | grep 'auditor.*upgrade.*plugin');
    if [[ -z "${getlog}" ]]; then 
        printf "%s\n" "No data found. Exiting."; 
        return 1;
    else
        if [[ $(which wp) ]]; then 
            printf "%s\n" "${getlog}" | awk 'BEGIN{a[$2];a[$3];a[$4]}{for (x in a)
            date=gensub(/.*([A-Z][a-z]{2}) ([0-9]{2}).([0-9]{2}):([0-9]{2}):([0-9]{2}).*$/, "\\1 \\2 \\3:\\4", "g", $x);
            plugin=gensub(/.*plugin\":\"(.*)\/.+\.php.*/, "\\1", "g", $12);
            cmd = "wp plugin get " plugin " --field=title 2>/dev/null"; 
            cmd | getline plugin
            getuser=gensub(/.*current_user_id\":([0-9]+).*/, "\\1", "g", $12);
            cmd = "wp user get " getuser " --field=user_email 2>/dev/null"
            cmd | getline getuser
                printf "\nDate/Time: %s\tUser: %s\nPlugin: %s\n\n",
                date, getuser, plugin
            close(cmd)
            }'
        else
            printf "wp-cli not found. Double check if wp-cli is installed. Printing user ID instead.\n" &&
            printf "%s\n" "${getlog}" | awk 'BEGIN{a[$2];a[$3];a[$4]}{for (x in a)
            date=gensub(/.*([A-Z][a-z]{2}) ([0-9]{2}).([0-9]{2}):([0-9]{2}):([0-9]{2}).*$/, "\\1 \\2 \\3:\\4", "g", $x);
            plugin=gensub(/.*plugin\":\"(.*)\/.+\.php.*/, "\\1", "g", $12);
            getuser=gensub(/.*current_user_id\":([0-9]+).*/, "\\1", "g", $12);
            printf "\nDate/Time: %s\tUser: %s\nPlugin: %s\n\n", date, getuser, plugin
            }'
        fi
   fi
}
User: myemail@gmail.com
Date/Time: Feb 05 20:32
Plugin: myplugin

User: myemail@gmail.com
Date/Time: Feb 05 20:32
Plugin: my-next-plugin

I went through a few iterations to get this working perfectly. It will also detect if you don’t have wp-cli installed.

Cut

Reading Time: 2 minutes

There’s no way to cut it when it comes to telling you how to use this great tool!

Whenever I’ve used it, I commonly use it in lieu of a user’s home directory:
$(pwd | cut -d\/ -f5). This helps me save time from copy and pasting the install name, however it doesn’t always work.
For example, if we’re not in /path/to/live/SITE or /path/to/log/SITE then cut can’t grab the appropriate path. Let me break it down by first running pwd.

spencer@local:/nas/content/live/dubtraxx/wp-content/themes/minimum-pro$ pwd
/nas/content/live/dubtraxx/wp-content/themes/minimum-pro

We see that it’s printing the working directory, all the way up to the directory we’re in. PWD is just printing the folder I’m currently in, including the server’s absolute path. Whenever you include the -d you’re telling pwd that you want to use / as your delimiter (separator).
However, since /is a special character in Linux’s bash shell, we need to escape it by adding a backslash \.

On this note, it’s also perfectly acceptable to use -d'/' instead of a \ to signal the delimiter of choice to cut.

Let’s take a look at what happens if we run the following:

spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f2
path
spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f3
to
spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f4
live
spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f5
dubtraxx

And for some testing…

spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d'/' -f4-
live/dubtraxx
spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f2-
path/to/live/dubtraxx
spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f1

spencer@local~ :/path/to/live/dubtraxx $ pwd | cut -d\/ -f1-
/path/to/live/dubtraxx

There are many more uses for cut, but we’ll go over those in another tutorial.
Ciao!

Awk

Reading Time: 2 minutes

Awk is a powerful tool that we’ll take a look at to parse our logs. It’s much more powerful than what we’re going to be using it for in these tutorials, but I encourage you to learn more about awk on your own if you like it.

Awk separates a file into columns (known as fields) and rows – whenever you think of a file and how awk parses it, think of columns and rows.

With this knowledge, we can now take a look at awk’s -F flag which allows us to specify how awk sees columns. By default, awk uses a space as its delimiter to read through text. In the following example, we can see that if we just print then awk is going to print the entire file:

awk '{ print }' /var/log/nginx/site.apachestyle.log| head -n3

100.43.90.123 supadupa.rocks - [27/Apr/2019:00:54:32 +0000] "GET /robots.txt HTTP/1.1" 200 106 "-" "Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)"
127.0.0.1 supadupa.rocks - [27/Apr/2019:00:59:52 +0000] "GET //?wp-cmd=ping HTTP/1.0" 200 5 "-" "curl/7.47.0"
127.0.0.1 supadupa.rocks - [27/Apr/2019:00:59:53 +0000] "GET //wp-admin/?wp-cmd=ensure HTTP/1.0" 200 305 "-" "curl/7.47.0"

Now if we go to print field $1 (the IP addresses) we simply need –
awk '{ print $1 }' /var/log/nginx/site.apachestyle.log

awk '{ print $1 }' /var/log/nginx/site.apachestyle.log |head -n3
100.43.90.123
127.0.0.1
127.0.0.1

If I wanted to search like grep, but using awk, there’s a solution for that. With awk, you have to put your regex nested between two / in order for it to be interpreted.
Additionally, if your regex has special characters inside of it (like ?!*& or other other special characters) you will need to escape them using a \. See awk’s man page for more information.

awk -F'"' '/104\.196\.177\.220/{ print $2 }' /var/log/nginx/site.apachestyle.log |head -n3
POST /wp-cron.php?doing_wp_cron=1556326791.3251020908355712890625 HTTP/1.0
POST /wp-cron.php?doing_wp_cron=1556334044.2906210422515869140625 HTTP/1.0
POST /wp-cron.php?doing_wp_cron=1556336718.0919361114501953125000 HTTP/1.0

That’s all for now. I hope you enjoyed reading this post!

Primary Sidebar

Categories

  • command-line-tutorials (3)
  • Uncategorized (1)

Secondary Sidebar

Copyright © 2022 · eleven40 Pro · spanish · devment