Linux - SecurityThis forum is for all security related questions.
Questions, tips, system compromises, firewalls, etc. are all included here.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Using a Wordpress Theme called "Comfy" or "Comfy-Plus"
it performs the following: downloads and saves a file in /tmp/f from "control IP", kills all unresponsive perl processes, and then reloads the bot
The URL changes each time. It appears random. I checked and this particular domain has nothing in his crontab file.
Quote:
Originally Posted by ceyx
Possible scenario ?
Using a Wordpress Theme called "Comfy" or "Comfy-Plus"
it performs the following: downloads and saves a file in /tmp/f from "control IP", kills all unresponsive perl processes, and then reloads the bot
I'll list commands to use and explain. I'll assert inside the VE the web server runs as UID 48.
The first goal is to come up with a clean list of PIDs to feed into 'lsof'.
Run 'ps' for the web server UID and list processes (this should only show "httpd"):
Code:
\ps -U 48 -o ppid,pid,sid,comm,args
* Note the backslash should keep any aliases from kicking in, "comm" and "args" are not equal (see 'man ps': "setproctitle"), the SID should make it easier to match children with their session leader and the PPID shows the parent as well.
Or see if any UID runs processes with "perl" in the name (returns a clean list of PIDs if any):
Code:
\ps -C perl -o pid --no-headers
Or check if a network connection is made to known IRC ports 6660-6669 (uncommon ports are 7000,7070,8000-8002):
Having the PID you can list open files (example PID 9449):
Code:
lsof -Pwlnp 9449
and this will show the user the process runs as in the "USER" column, the current working directory ("cwd") and network connections (if any) along with the rest of the open files. As you can see from ktreese's example output the current working directory may hold clues.
Let's tie this together as a shell script you can run inside a VE (thanks to ktreese for explaining vz.* commands) as long as basic commands are available:
Code:
#!/bin/bash
_help() { echo "Script arg: OpenVZ VEID, exiting."; exit 1; }
[ $# -ne 1 ] && _help; case "$1" in [1-9]*) ;; *) _help;; esac
# PATH inside VE:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:$PATH
# Required binaries:
for BINARY in ls ps cat find awk file xargs lsof mkdir; do which "${BINARY}" 2>/dev/null|| \
echo "Missing "${BINARY}", exiting."; exit 1; done
# Temp dir for deleted files storage:
MYTEMPDIR="/var/tmp"; umask 027
# Commence. Build PID list:
PIDLIST=$(\ps --no-headers -C perl -o pid; \lsof -Pwlni|egrep "TCP.*->.*:(666[0-9])"|awk '{print $2}')
[ ${#PIDLIST} -eq 0 ] && { echo "PID list empty, exiting."; exit 0; }
for CHKPID in $PIDLIST; do echo "Process nfo for PID ${CHKPID}: "
\ps wwwe -p ${CHKPID} -o ppid,sid,pid,comm,args --no-headers; echo
echo "Open files for PID ${CHKPID}: "; \lsof -Pwlnp ${CHKPID}; echo
echo "Files in CWD of PID ${CHKPID}: "; \lsof -Pwlnp ${CHKPID} -a -d cwd|awk '/cwd/ {print $NF}'\
|while read CHKPIDDIR; do \ls --full-time --time-style=long-iso --quoting-style=c -altr "${CHKPIDDIR:=error}"
\find "${CHKPIDDIR:=error}" -print0|xargs -0 -iX file 'X'; done; echo "Deleted files for PID ${CHKPID}: "
mkdir "${MYTEMPDIR}/undel_${CHKPID}"|| { echo "Could not create "${MYTEMPDIR}/undel_${CHKPID}", exiting."; exit 1; }
\lsof -Pwlnp ${CHKPID}|awk '/\deleted\)/ {print $2, $4, $NF}'|while read FPID FFID FFILE; do FFID=${FFID//[rwu]/};
FFILE=${FFILE//*\//}; [ -e "${MYTEMPDIR}/undel_${CHKPID}/${FFILE}" ] \
|| { cat /proc/${FPID}/fd/${FFID} > "${MYTEMPDIR}/undel_${CHKPID}/${FFILE}";
file "${MYTEMPDIR}/undel_${CHKPID}/${FFILE}"; }; done; done; exit 0
If you save this script on the hardware node as "/usr/local/bin/veinspect.sh" and make it executable then once you select the VEID to inspect you should be able to run it as 'vzctl runscript /usr/local/bin/veinspect.sh VEID'. It's not tested well and doesn't do error handling so as always YMMV(VM) but at least it's a start for providing details usable for analysis.
In following the various PID's and knowing ahead of time that this issue is largely related to Plesk and their public admission of a hack existing since v8.2 I was only slightly amazed when I entered the IP of http://216.14.112.66/.
It goes directly to a Plesk test page that appears as a place hold page and shows the customer that Perl, ASP, etc. are working. Some of us have already experiment with deleting the /test DIR on all sites. This appears to be the ingress.
Be careful that the customer has not put any of their files in the /cgi-bin/test DIR but it isn't likely. There are two /cgi-binb's. One for the main site above the root and one in/httpsdocs.
Code:
ls -lah /var/www/vhosts/*/cgi-bin/test/*
rm -fr /var/www/vhosts/*/cgi-bin/test
ls -lah /var/www/vhosts/*/httpsdocs/test/*
rm -fr /var/www/vhosts/*/httpsdocs/test
Logwatch (see for instance this web log post for extending its search capabilities).
There are three missing commas from the patch which break the http config for logwatch - please don't think I'm being pedantic. It's a compliment because obviously if I've noticed it, it's because I've used it :-)
It goes directly to a Plesk test page that appears as a place hold page and shows the customer that Perl, ASP, etc. are working. Some of us have already experiment with deleting the /test DIR on all sites. This appears to be the ingress.
The existence of cgi-bin/test is not the means by which the attackers are exploiting the sites. The problem you are referencing is with a SQL injection vulnerability in admin/plib/api-rpc/Agent.php. Instead of explaining what happens to exposed servers, I'll link to this blog. Also note the comments section below pertaining to additional files under /tmp.
The hack we're discussing here, IMO, is not related to the documented Plesk API vulnerability.
Last edited by ktreese; 04-02-2012 at 11:20 AM.
Reason: updated grammar and misspelled words
#!/bin/bash
_help() { echo "Script arg: OpenVZ VEID, exiting."; exit 1; }
[ $# -ne 1 ] && _help; case "$1" in [1-9]*) ;; *) _help;; esac
# PATH inside VE:
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:$PATH
# Required binaries:
for BINARY in ls ps cat find awk file xargs lsof mkdir; do which "${BINARY}" 2>/dev/null|| \
echo "Missing "${BINARY}", exiting."; exit 1; done
# Temp dir for deleted files storage:
MYTEMPDIR="/var/tmp"; umask 027
# Commence. Build PID list:
PIDLIST=$(\ps --no-headers -C perl -o pid; \lsof -Pwlni|egrep "TCP.*->.*:(666[0-9])"|awk '{print $2}')
[ ${#PIDLIST} -eq 0 ] && { echo "PID list empty, exiting."; exit 0; }
for CHKPID in $PIDLIST; do echo "Process nfo for PID ${CHKPID}: "
\ps wwwe -p ${CHKPID} -o ppid,sid,pid,comm,args --no-headers; echo
echo "Open files for PID ${CHKPID}: "; \lsof -Pwlnp ${CHKPID}; echo
echo "Files in CWD of PID ${CHKPID}: "; \lsof -Pwlnp ${CHKPID} -a -d cwd|awk '/cwd/ {print $NF}'\
|while read CHKPIDDIR; do \ls --full-time --time-style=long-iso --quoting-style=c -altr "${CHKPIDDIR:=error}"
\find "${CHKPIDDIR:=error}" -print0|xargs -0 -iX file 'X'; done; echo "Deleted files for PID ${CHKPID}: "
mkdir "${MYTEMPDIR}/undel_${CHKPID}"|| { echo "Could not create "${MYTEMPDIR}/undel_${CHKPID}", exiting."; exit 1; }
\lsof -Pwlnp ${CHKPID}|awk '/\deleted\)/ {print $2, $4, $NF}'|while read FPID FFID FFILE; do FFID=${FFID//[rwu]/};
FFILE=${FFILE//*\//}; [ -e "${MYTEMPDIR}/undel_${CHKPID}/${FFILE}" ] \
|| { cat /proc/${FPID}/fd/${FFID} > "${MYTEMPDIR}/undel_${CHKPID}/${FFILE}";
file "${MYTEMPDIR}/undel_${CHKPID}/${FFILE}"; }; done; done; exit 0
I've run this script on one of the 'infected' containers. First, I made some adjustments by commenting out the 2nd and 3rd line of code to pass the VEID argument to the script as this is already handled by the vzctl command:
Code:
vzctl runscript <veid> veinspect.sh
If we ran this with passing an argument, it would fail since the container itself doesn't know that it's a container since all the runscript action is doing is executing whatever lines of code are inside the script we pass to it. As a matter of fact, vzctl may interpret it as another script to run following veinspect.sh. Anyway, continuing on.
I found that the script was exiting while checking for missing binaries, and would exit even if the binaries existed. It exits upon the first binary it checks for:
Code:
-bash-3.1# sh ./veinspect.sh
/bin/ls
I assume we want to continue if the binary is found, so instead of messing with exclusive ors, I checked whether or not the command was successful or not:
Code:
for BINARY in ls ps cat find awk file xargs lsof mkdir; do which "${BINARY}" 2>/dev/null
if [ $? -ne 0 ]; then echo "Missing "${BINARY}", exiting."; exit 1; fi; done
This allows the script to get through to build the PID list. The output is heavy though because the cwd is /
In my case, it will always be / since we don't partition out /usr, /var, or any other file system. I'm letting the script run through its course now and will reply once it's finished and we'll see what's in /var/tmp.
The script has concluded:
Code:
-bash-3.1# ls -al /var/tmp
total 6
drwxrwxrwt 4 root root 1024 Apr 3 18:16 .
drwxr-xr-x 21 root root 1024 Jul 14 2008 ..
drwxr-xr-x 2 apache apache 1024 Mar 26 13:58 a
-rw-r--r-- 1 apache apache 1082 Mar 26 13:42 a.tgz
drwxr-x--- 2 root root 1024 Apr 3 18:16 undel_31783
-bash-3.1#
-bash-3.1#
-bash-3.1# cd /var/tmp/undel_31783/
-bash-3.1# ls -al
total 2
drwxr-x--- 2 root root 1024 Apr 3 18:16 .
drwxrwxrwt 4 root root 1024 Apr 3 18:16 ..
-bash-3.1#
The a and a.tgz was from the intruder of course. I also see that the same PID is "responsible" for the perl script and the established connections to 6667, and therefore it runs the course twice:
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.