#!/bin/bash

##############################################################################
##############################################################################
## This script is intended locate potential compromise scripts by anylizing 
## the Apache domlogs.
## 
## This is done by searching for POST requests which have no referrer but
## which do receive a success response. Certain other scripts are filtered
## out, as they may not indicate an actual compromise. Once a URL is
## found, the script attempts to look for a corresponding file which still
## exists and reports that file.
##
## Daniel K
##

usage() {
    echo "Usage: $0 [ --help | DOMAIN [DOMAIN ...] ]"
    echo ""
    echo "Look for files which have had successful POSTs without a referrer in Apache domlogs."
    echo "Excludes some common files, such as crons, xmlrpc, WordPress logins, etc."
    echo ""
    echo -e "  DOMAIN\t\tDomain to check for POSTs. If none are given, check all domains."
    echo -e "  -i, --with-ips\t\tShow IP addresses which have connected to each script."
    echo -e "  -h, --help\t\tDisplay this message and exit."
    echo ""
    exit
}

# Parse options:
show_help=''
with_ips=''
all_domains=''
domain_array=()
for opt in "$@" ; do
    case $opt in
        -h | --help)       show_help=1 ; break ;;
        -a | --all)        all_domains=1; ;;
        -i | --with-ips)   with_ips=1; ;;
        [a-z0-9.-]*)       domain_array+=("$opt"); ;;
    esac
done

[[ -n "$show_help" ]] && usage

# Location of files containing VirtualHost entries
VHOST_LOCATION='/usr/local/apache/conf/httpd.conf'
# Location of Apache domlogs
DOMLOG_DIR='/usr/local/apache/domlogs'
# Number of lines to scan at the end of the log files
LOG_LINES=10000
LOCAL_IPS="$(ifconfig|awk 'match($0,/addr: *([a-f0-9.:]+)/,a){printf a[1]"|"}')LOCALIPS"

find_suspicious_posts() {
    name="${1?Must include host and document root to check}"
    document_root="${2?Missing either hostname or document root}"

    domlog="${DOMLOG_DIR}/${name}"

    [[ -f "$domlog" ]] || continue

    tail -n "$LOG_LINES" "$domlog" |
        awk -v local="$LOCAL_IPS" \
            '$6~/POST/&&
            $1!~local&&
            $11~"\"-\""&&
            $7!~/(cron|api)|(xmlrpc.php|wp-login.php|admin-ajax.php)$)/&&
            $9~/^2/{gsub("\\?.*$","", $7); if (!x[$7]++)
            {print $7}}' |
        (

                while read url; do
                    file="${document_root}${url}"
                    if [[ -f "$file" ]] ; then
                        echo "$file"
                        if [[ -n "$with_ips" ]] ; then
                            tail -n "$LOG_LINES" "$domlog" |
                                awk -v local="$LOCAL_IPS" \
                                    -v url="$url" \
                                    '$6~/POST/&&
                                    $1!~local&&
                                    $11~"\"-\""&&
                                    $7~url&&
                                    $9~/^2/{if (!x[$1]++)
                                    {print "\t"$1}}'
                        fi
                    fi
                done
        )

}

search_one_domain() {
    domain="${1}"
    awk -v domain="$domain" \
        '/ServerName/{name=$2}
        /Server(Name|Alias)/&&$0~"\\y"domain"\\y"{v=1}
        v&&$1~/DocumentRoot/{print name,$2;exit}' \
        "$VHOST_LOCATION" |
    (

        read name document_root

        [[ -z "$name" ]] && (>&2 echo "Cannot find domain '$domain'") && break

        find_suspicious_posts "$name" "$document_root"

    )
}

search_all_domains() {
    awk '$1~/ServerName/{printf $2" "}$1~/DocumentRoot/{print $2}' "$VHOST_LOCATION" | (
        while read name document_root; do
            find_suspicious_posts "$name" "$document_root"
        done
    )
}

if [[ -n "$all_domains" ]] ; then
    search_all_domains
    exit
fi

for domain in "${domain_array[@]}" ; do
    search_one_domain "$domain"
    shift
done
