#!/bin/sh
# This script is supposed to test cacti a little bit. At least each page and
# each link is tried. I mean to add checks for new CVE's (at least those that I
# can trigger with wget) as well.

# Catch any error
set -e

save_log_files() {
    # add timestamp to log file name as subsequent runs share the same
    # artifacts directory
    echo "Copying /var/log/cacti/cacti.log to artifacts"
    cp /var/log/cacti/cacti.log cacti_$(date --iso-8601=minutes).log
    if [ -f /var/log/apache2/access.log ] ; then
        echo "Copying /var/log/apache2/access.log to artifacts"
        cp /var/log/apache2/access.log apache_access_$(date --iso-8601=minutes).log
    fi
    if [ -f /var/log/apache2/error.log ] ; then
        echo "Copying /var/log/apache2/error.log to artifacts"
        cp -f /var/log/apache2/error.log apache_error_$(date --iso-8601=minutes).log
    fi
    if [ -f /var/log/lighttpd/error.log ] ; then
        echo "Copying /var/log/lighttpd/error.log to artifacts"
        cp -f /var/log/lighttpd/error.log lighty_error_$(date --iso-8601=minutes).log
    fi
    chmod a+r *.log
}

# Remove the crontab line to prevent the cron from interfering
rm -f /etc/cron.d/cacti

# Get the current database password, which by default is also used for the
# admin.
database_pw=$(grep -m1 database_password /etc/cacti/debian.php | awk '{print $3}' | sed "s/';//" | sed "s/'//")
database_pw=${database_pw%%\";}
database_pw=${database_pw#\"}

# To make sure that the autopkgtest/CI sites store the information
if [ -n "${AUTOPKGTEST_ARTIFACTS}" ] ; then
    cd "${AUTOPKGTEST_ARTIFACTS}"
    trap save_log_files 0
fi

# Lighttpd is not the default httpd for cacti. If we are testing for it, we
# need to enable the conf first.
if [ -n "$(which lighttpd-enable-mod)" ] ; then
    lighttpd-enable-mod cacti
    /etc/init.d/lighttpd force-reload
fi

tmpFile1=$(mktemp)
tmpFile2=$(mktemp)
cookieFile=$(mktemp)
loadSaveCookie="--load-cookies $cookieFile --keep-session-cookies --save-cookies $cookieFile"

# Make sure we get the magic, this is stored in the cookies for future use.
wget --keep-session-cookies --save-cookies "$cookieFile" --output-document="$tmpFile1" http://localhost/cacti/index.php
magic=$(grep "name='__csrf_magic' value=" "$tmpFile1" | sed "s/.*__csrf_magic' value=\"//" | sed "s/\" \/>//")
postData="action=login&login_username=admin&login_password=${database_pw}&__csrf_magic=${magic}"
wget $loadSaveCookie --post-data="$postData" --output-document="$tmpFile2" http://localhost/cacti/index.php

# Now loop over all the available links (but don't log out and don't delete or
# remove stuff.
wget $loadSaveCookie --reject-regex="(logout\.php|remove|delete)" --recursive --level=0 --execute=robots=off http://localhost/cacti/index.php

# Check for the existance of at least one of the files, as unauthorized access
# still gets http OK back.
if [ ! -f localhost/cacti/graphs.php ] ; then
    echo "localhost/cacti/graphs.php not found"
    return 179
fi

# SQL injection CVE's
# Well, the idea is simple, try to trigger the CVE and inject a long
# sleep. Make sure the timeout is below the sleep. 

# CVE-2016-3172
postData="action=item_edit&tree_id=1&parent_id=7%20and%20sleep%28100%29&__csrf_magic=${magic}"
wget $loadSaveCookie --post-data="$postData" --timeout=10 --tries=1 "http://localhost/cacti/tree.php"

# CVE-2017-15194
wget  --output-document="$tmpFile1" $loadSaveCookie 'http://localhost/cacti/graph_view.php?action=tree&'\'';window.alert('\''bla'\'');'\'
echo -n "Checking $tmpFile1 for unescaped code (CVE-2017-15194)... "
grep -q ";window.alert('bla');" "$tmpFile1" && echo "failed" && false
echo "done"

# CVE-2017-16641
postData="tab=path&path_rrdtool=touch%20/tmp/CVE-2017-16641&action=save&path_snmpwalk=/usr/bin/snmpwalk&path_snmpget=/usr/bin/snmpget&path_snmpbulkwalk=/usr/bin/snmpbulkwalk&path_snmpgetnext=/usr/bin/snmpgetnext&path_snmptrap=/usr/bin/snmptrap&path_php_binary=/usr/bin/php&path_cactilog=/var/log/cacti/cacti.log&logrotate_retain=7&path_spine=/usr/sbin/spine&path_spine_config=/etc/cacti/spine.conf&rrd_autoclean_method=1&rrd_achive=/usr/share/cacti/site/rra/archive/&__csrf_magic=${magic}"
wget --output-document="$tmpFile1" $loadSaveCookie --post-data="$postData" http://localhost/cacti/settings.php
sleep 300
if [ -f /tmp/CVE-2017-16641 ] ; then
    echo "/tmp/CVE-2017-16641 found"
    return 179
fi

# CVE-2017-16660
echo "update cacti.settings set value='/var/lib/cacti/rra/shell.php' where name='path_cactilog' ;" | mysql -ucacti -p"$database_pw" cacti
wget --output-document="$tmpFile1" $loadSaveCookie --header 'Client-ip: <?php phpinfo();?>' http://localhost/cacti/remote_agent.php
echo -n "Checking for CVE-2017-16660 ... "
if [ -f /var/lib/cacti/rra/shell.php ] ; then
    grep -q '<?php phpinfo();?>' /var/lib/cacti/rra/shell.php && echo "failed" && false
fi
echo "done"

# CVE-2017-16661
echo "update cacti.settings set value='/etc/cacti.log' where name='path_cactilog' ;" | mysql -ucacti -p"$database_pw" cacti
wget --output-document="$tmpFile1" $loadSaveCookie 'http://localhost/cacti/clog.php?rfilter=&reverse=1&refresh=60&message_type=-1&tail_lines=500&filename=passwd'
echo -n "Checking $tmpFile1 for /etc/passwd content (CVE-2017-16661) ... "
grep -q "root:x:0:0" "$tmpFile1" && echo "failed" && false
echo "done"

# CVE-2017-16785
wget --output-document="$tmpFile1" $loadSaveCookie 'http://localhost/cacti/host.php/gahv8'\''-alert('\''this_is_bad'\'')-'\''w6vt7??host_status=-1&host_template_id=-1&site_id=-1&poller_id=-1&rows=-1&filter='
echo -n "Checking $tmpFile1 for XSS content (CVE-2017-16785) ... "
grep -q '-alert('\''this_is_bad'\'')-' "$tmpFile1" && echo "failed" && false
echo "done"

# For local use, fix all paths again
postData="tab=path&action=save&path_snmpwalk=/usr/bin/snmpwalk&path_snmpget=/usr/bin/snmpget&path_snmpbulkwalk=/usr/bin/snmpbulkwalk&path_snmpgetnext=/usr/bin/snmpgetnext&path_snmptrap=/usr/bin/snmptrap&path_rrdtool=/usr/bin/rrdtool&path_php_binary=/usr/bin/php&path_cactilog=/var/log/cacti/cacti.log&logrotate_retain=7&path_spine=/usr/sbin/spine&path_spine_config=/etc/cacti/spine.conf&rrd_autoclean_method=1&rrd_achive=/usr/share/cacti/site/rra/archive/&__csrf_magic=${magic}"
wget --output-document="$tmpFile1" $loadSaveCookie --post-data="$postData" http://localhost/cacti/settings.php

# Finally check the cacti log for unexpected items
FILTERED_LOG="$(grep -v \
     -e "AUTH LOGIN: User 'admin' Authenticated" \
     -e "AUTOM8 ERROR: The Network ID: 1 is disabled.  You must use the 'force' option to force it's execution." \
     -e "AUTOM8 \[PID: [0-9]\+\] Network Discover is now running" \
     -e "AUTOM8 \[PID: [0-9]\+\] Network Test Network Thread [0-9]\+ Finished" \
     -e "CMDPHP SQL Backtrace: " \
     -e "IMPORT Importing XML Data for " \
     -e "IMPORT NOTE: File is Signed Correctly" \
     -e "POLLER: Poller\[1\] Maximum runtime of 298 seconds exceeded. Exiting." \
     -e "SYSTEM STATS: Time:" \
     -e "WEBUI NOTE: Poller Resource Cache scheduled for rebuild by user admin" \
     /var/log/cacti/cacti.log)" || true

if [ -n "${FILTERED_LOG}" ] ; then
    echo "Unexpected output in /var/log/cacti/cacti.log:"
    echo "${FILTERED_LOG}"
    return 17976
else
    echo "No unexpected output in /var/log/cacti/cacti.log"
fi
