mitigating wordpress xmlrpc attack using ossec

I’ve created some local rules for ossec to mitigate some of the effects of the wordpress xmlrpc attack presented here: WordPress Pingback Portscanner – Metasploit Module.

They seem to work for me, use at your own risk of getting flooded with tons of alerts. Obviously you need to set the alert level of the second rule to something that will trigger your active-response. Feel free to tweak the alert level, frequency and timeframe. Before you change frequency to something else please read the following thread though: setting ossec frequency level


   <rule id="100167" level="1">
    <if_sid>31108</if_sid>
    <url>xmlrpc.php</url>
    <match>POST</match>
    <description>WordPress xmlrpc attempt.</description>
  </rule>

  <rule id="100168" level="10" frequency="2" timeframe="600">
    <if_matched_sid>100167</if_matched_sid>
    <same_source_ip />
    <description>WordPress xmlrpc attack.</description>
    <group>attack,</group>
   </rule>

btw, if you don’t want xmlrpc.php accessible at all, you can block it through a simple mod_rewrite rule:


<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/PATH/TO/xmlrpc.php [NC]
RewriteRule ^(.*)$ - [F,L]

or you can try any of the other numerous ways to accomplish the same thing as presented here.

You’ll lose pingback functionality though…oh well.

Resolving OSSEC active response iptables issues

The past few days some of my servers are having difficult times due to the increase of spam by some botnet(s). From around 600-700 emails per day for unknown addresses/recipients on local domains, this number reached a peak of 8.000 emails 2 days ago. In order to reduce further botnet attempts I’m having ossec to engage, which in turn tries to firewall hosts.

That worked quite ok for a while but then I’ve started seeing errors in the active-response.log like the ones below:

Unable to run (iptables returning != 3): 1 – /var/ossec/active-response/bin/firewall-drop.sh delete – 91.121.21.8 1310919172.51029 31106
Unable to run (iptables returning != 1): 1 – /var/ossec/active-response/bin/firewall-drop.sh delete – 79.149.198.149 1310919524.52191 3302
Unable to run (iptables returning != 1): 2 – /var/ossec/active-response/bin/firewall-drop.sh delete – 79.149.198.149 1310919524.52191 3302
Unable to run (iptables returning != 1): 3 – /var/ossec/active-response/bin/firewall-drop.sh delete – 79.149.198.149 1310919524.52191 3302
Unable to run (iptables returning != 1): 4 – /var/ossec/active-response/bin/firewall-drop.sh delete – 79.149.198.149 1310919524.52191 3302
Unable to run (iptables returning != 1): 5 – /var/ossec/active-response/bin/firewall-drop.sh delete – 79.149.198.149 1310919524.52191 3302
Unable to run (iptables returning != 4): 1 – /var/ossec/active-response/bin/firewall-drop.sh add – 115.242.188.157 1310969220.1045522 3302

Obviously iptables is busy doing something else at the time, adding or deleting some other rule, so the loop inside firewall-drop.sh sometimes fails. That was a bit worrying, I had to fix ossec so one way or another so that iptables rules would eventually be applied. I’ve faced the same issue with iptables in the past, trying to simultaneously add multiple (>5) iptables rules at exactly the same time is very error prone, there’s no way to tell which of those rules will be applied. In order to circumvent the issue, I added locking to the active response script.

Whenever it comes to locking with shell scripts I am using a set of four functions inside a file that I source when I need to. I place this file usually inside /usr/local/bin/ under the lock.sh filename.

lockme () {
    if [ -z "$1" ];then
        echo " o Use an argument to lock"
        return 1
    fi
    if [ -z "$2" ];then
        PID=$$
    else
        PID=$2
    fi
    LOCK_PID_FILE=/var/lock/$1
    if [ -f $LOCK_PID_FILE ];then
        sleep 1
        echo " o Lock file found"
        if [ ! -d /proc/`cat $LOCK_PID_FILE 2>/dev/null` ];then
            echo " o Stale lock file ignoring..."
            rm -f $LOCK_PID_FILE
        else
            return 1
        fi  
    fi  
    #temp file
    echo -n $PID > $LOCK_PID_FILE.$PID
    ln -s $LOCK_PID_FILE.$PID $LOCK_PID_FILE && return 0
    rm -f $LOCK_PID_FILE.$PID
    return 1
}

lockme_wait () {
    if [ -z "$1" ];then
        echo " o Use an argument to lock"
        return 1
    fi  
    if [ -z "$2" ];then
        PID=$$
    else
        PID=$2
    fi  
    while [ 1 ];do
        lockme $1 $PID && break
        sleep 4
    done
    return 0
}

unlockme () {
    if [ -z "$1" ];then
        echo " o Use an argument to unlock"
        return 1
    fi
    #remove pid file
    rm -f /var/lock/$1.`cat /var/lock/$1 2>/dev/null`
    rm -f /var/lock/$1
    return 0
}   

kill_locked () {
    if [ -z "$1" ];then
        echo " o Use an argument to kill_locked"
        return 1
    fi
    if [ -e /var/lock/$1 ]; then
        kill `cat /var/lock/$1 2>/dev/null`
    fi
    rm -f /var/lock/$1.`cat /var/lock/$1 2>/dev/null`
    rm -f /var/lock/$1
}

You can also use %s/var\/lock/tmp/g if you prefer having the locks on the /tmp which is usually ramfs, partition.

Afterwards I edited /var/ossec/active-response/bin/firewall-drop.sh to just add 3 lines. (I only edited the relevant Linux section of the script, since I haven’t tested, or don’t even know if it’s needed on the BSD, SunOS sections, I left those unedited):

  • Add . /usr/bin/lock.sh right after the “# Checking for an IP” section (around line 45)
  • Right after “# Executing and exiting” add lockme_wait active-response (around line 75)
  • Right after the second while loop finishes, after “done” and before “exit 0″ add unlockme active-response (around line 110)
  • That’s it…just 3 lines added and the errors have completely stopped since then.

    P.S. Yes, I could have used lockfile-progs to achieve the same result, but I (also) use lock.sh file in embedded systems when needed, and it’s far more portable and easy.

    Stopping Plesk Panel attacks with OSSEC

    During the past few weeks I’ve noticed increased brute forcing activity on various servers that I manage and run Plesk Panel. Most of the entries look like this:

    189.205.227.115 - - [30/Jan/2011:07:14:19 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [30/Jan/2011:07:14:19 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [30/Jan/2011:07:14:19 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [30/Jan/2011:07:14:21 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [30/Jan/2011:07:14:21 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [30/Jan/2011:07:14:23 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [30/Jan/2011:07:14:23 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    

    The side effect of all these attacks is increased server load.

    Since I already have ossec monitoring these servers the solution was quite simple. I just added a couple more rules to ossec in order to stop these attacks.

    Two steps are necessary to stop these attacks:
    1) Add plesk panel https log to monitor list in /var/ossec/etc/ossec.conf

      <localfile>
        <log_format>apache</log_format>
        <location>/opt/psa/admin/logs/httpsd_access_log</location>
      </localfile> 
    
      <localfile>
        <log_format>apache</log_format>
        <location>/opt/psa/admin/logs/httpsd_error_log</location>
      </localfile>
    

    2) Create some custom rules to block (and notify me) of these attacks.

    <rule id="100144" level="1">
        <if_sid>31100</if_sid>
        <id>200</id>
        <url>/login_up.php3</url>
        <description>Plesk Login.</description>
      </rule>
    
    <rule id="100145" level="12" frequency="3" timeframe="60">
        <if_matched_sid>100144</if_matched_sid>
        <same_source_ip />
        <description>Attack on plesk panel.</description>
        <group>attack,</group>
      </rule>
    

    That’s it. Ossec now monitors these files and blocks through iptables any attacks with active-response.

    Example notification mail:

    Received From: foo->/opt/psa/admin/logs/httpsd_access_log
    Rule: 100146 fired (level 12) -> "Attack on plesk."
    Portion of the log(s):
    
    189.205.227.115 - - [02/Feb/2011:20:19:56 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [02/Feb/2011:20:19:55 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    189.205.227.115 - - [02/Feb/2011:20:19:54 +0100] "GET /login_up.php3?passwd=setup&login_locale=default&login_name=admin HTTP/1.1" 200 5852
    

    ossec to the rescue

    That’s why I love ossec:

    OSSEC HIDS Notification.
    2009 Oct 06 17:45:17
    
    Received From: XXXX->rootcheck
    Rule: 510 fired (level 7) -> "Host-based anomaly detection event (rootcheck)."
    Portion of the log(s):
    
    Rootkit 'Suspicious' detected by the presence of file '/var/www/vhosts/YYYY.com/httpdocs/album_mod/..  /.../.log'.
    
     --END OF NOTIFICATION
    
    OSSEC HIDS Notification.
    2009 Oct 06 17:45:17
    
    Received From: XXXX->rootcheck
    Rule: 510 fired (level 7) -> "Host-based anomaly detection event (rootcheck)."
    Portion of the log(s):
    
    Rootkit 'Suspicious' detected by the presence of file '/var/www/vhosts/YYYY.com/httpdocs/language/lang_english/     /... /.log'.
    
     --END OF NOTIFICATION
    
    OSSEC HIDS Notification.
    2009 Oct 06 17:45:17
    
    Received From: XXXX->rootcheck
    Rule: 510 fired (level 7) -> "Host-based anomaly detection event (rootcheck)."
    Portion of the log(s):
    
    Rootkit 'Suspicious' detected by the presence of file '/var/www/vhosts/YYYY.com/httpdocs/language/     /... /.log'.
    
     --END OF NOTIFICATION

    Just found this by copying some files for a client from his previous hosting company to one of the hosting servers of a company I work for.

    There were actually 2 different sets of files.
    The first one contained a tool that “hides” a process, called: “XH (XHide) process faker”, and the second one contained an iroffer executable.

    Files:
    i)xh-files.tar.gz
    Listing:
    .log/
    .log/.crond/
    .log/.crond/xh
    .log/week~
    .log/week

    ii)iroffer-files.tar.gz
    Listing:
    .--/
    .--/imd.pid
    .--/imd.state.tmp
    .--/imd.state
    .--/linux

    Mind the . (dot) of the directories containing the files.