detect flashback mac

April 12, 2012

F-Secure  has created a free tool that automates the detection and removal of the widespread Flashback Mac OS X malware.

F-Secure Flashback removal tool

How to use the tools:

1) Download FlashbackRemoval.zip to the Mac machine you want to scan.
2) Double-click the zip package to unzip it in the current folder.
3) Double-click the FlashBack Removal app to run the tool.
4) Follow the instructions to check your system and clean any infections.

The tools creates a log file (RemoveFlashback.log) on current user’s Desktop. If any infections are found, they are quarantined into an encrypted ZIP file (flashback_quarantine.zip) to the current user’s Home folder. The ZIP is encrypted with the password “infected”.

Apple has announced that it’s working on a fix for the malware, but has given no schedule for it.

About Flashback malware, support.apple.com/kb/HT5244

Quite surprisingly, Apple hasn’t added detection for Flashback — by far the most widespread OS X malware ever — to the built-in XProtect OS X antivirus tool.

Also note that Apple has not provided a patch for the Java vulnerability used by Flashback for OS X v10.5 (or earlier). More than 16% of Macs still run OS X 10.5.

Chitika, March 2012, Mac OS X Verions

If you run an older version of Mac OS X, update to a current version. Or disable Java in your browser. Or uninstall Java. And run ourfree tool. And yes, we have a full-blown F-Secure Antivirus for Mac available as well.

Update: Small false positive fix. The tool linked above has been updated (April 12th).
What is this tool you say?  How does it work?

It is actually based on the open source flashback removal script by Yoshioka Tsuneo found at github

F-secure’s modified version, RemoveFlashback.sh, kicked off and controlled by the app they package inside the .zip:

#!/bin/sh
#
# RemoveFlashback.sh
#   -- Flashback removal tool --
#    Based on a script by Yoshioka Tsuneo:
#      https://github.com/yoshiokatsuneo/RemoveFlashback
#
# Ref:
#   F-Secure Weblog - Mac Flashback Infections
#   http://www.f-secure.com/weblog/archives/00002345.html
#

timestamp=`date '+%Y%m%d-%H%M%S'`
infected=0
tmpfilename_base=/tmp/RemoveFlashback.$$

quar_dir=${tmpfilename_base}.quarantine

string1="slfp"
string2="cfinh"

string3="ksyms"
string4="__ldpath__"

mkdir -p "$quar_dir"

# for the LaunchAgent:
#  * Check that binary start with "."
#
#    * (permission is 777)
#    * has StartInterval (4212)
#    * StandardOutput and Error is /dev/null
#
#

safari_plist_base="/Applications/Safari.app/Contents/Info"
firefox_plist_base="/Applications/Firefox.app/Contents/Info"
#safari_plist_base="`pwd`/test-Info"
macosx_environment_plist="${HOME}/.MacOSX/environment"
#macosx_environment_plist="${HOME}/work/RemoveFlashback/test-environment"

if [ "$1" = "scanonly" ]; then
    scanonly=true
    echo "------- Scanonly mode"
else
    scanonly=false
    echo "------- Quarantine mode"
fi

files_to_quarantine=/tmp/FS_to_quarantine
rm -f $files_to_quarantine

quarantine_later() {
    echo "$1" >> $files_to_quarantine
}

quarantine() {
    $scanonly && return
    if ! [ -e "$files_to_quarantine" ] ; then
        echo "Nothing to quarantine."
        return
    fi
    echo "Quarantining files:"
    sort $files_to_quarantine | uniq | \
    xargs -I % mv -v % "$quar_dir"
    rm -f $files_to_quarantine
}

zip_quarantine() {
    zipfile="${HOME}/flashback_quarantine.zip"
    zip -rq -e --password infected $zipfile ${quar_dir}
    rm -rf "${quar_dir}"
    chown $USER $zipfile
    echo "Quarantined files stored in password-protected zip file $zipfile"
}

is_malicious() {
    file="$1"
    echo "Checking file $file"
    if file_is_signed "$file" ; then
	echo " - File $file is signed"
	return 1
    fi
    # libraries whose name starts with . are bad
    filename=`basename "$file"`
    if echo $filename | grep -q '^\.' ; then
	echo " - File $file has a bad name"
	return 0
    fi
    if grep -q "${string1}" "$file" && grep -q "${string2}" "$file" ; then
	echo " - File $file matches patterns 1 & 2"
	return 0
    fi
    if grep -q "${string3}" "$file" && grep -q "${string4}" "$file" ; then
	echo " - File $file matches patterns 3 & 4"
	return 0
    fi
    return 1
}

check_launchagent()
{
    for plist in ~/Library/LaunchAgents/* ; do 
        prop=`echo $plist | sed -e 's/\.plist$//'`
        pathname=`defaults read $prop ProgramArguments 2> /dev/null | head -2 | tail -1 | sed -e 's/.*"\(.*\)".*/\1/'`
        if [ -z "$pathname" ] ; then
            continue
        fi
        filename=`basename "$pathname"`
        if echo $filename | grep -q '^\.' ; then
            infected=1
	    if $scanonly; then
                echo "File $pathname is most likely Flashback"
	    else
                echo "File $pathname is most likely Flashback -- removing"
           	quarantine_later "$pathname"
                quarantine_later "$plist"
	    fi
        fi
    done
}

file_is_signed() {
    codesign -R="anchor trusted" -v "$1" 2> /dev/null
}

check_libraries()
{
    plist_base="$1"
    libraries="$2"

    rm -f /tmp/infected
    grep -a -o '__ldpath__[ -~]*' "${libraries}" | while read line; do
        ldpath=${line/#__ldpath__/}
        if [ -f "$ldpath" ]; then
            if [ -x "$ldpath" ] && is_malicious "$ldpath" ; then
                echo "Infected file (check 1): ${ldpath}"
                $scanonly || quarantine_later "${ldpath}"
                touch /tmp/infected
            fi
        fi
    done
    if [ -f /tmp/infected ] ; then
        infected=1
        rm /tmp/infected
    fi

    if is_malicious "$libraries" ; then
        $scanonly || quarantine_later "$libraries"
        infected=1
    fi

}

check_browser_plist(){
    local plist_base=$1

    if ! [ -e "${plist_base}.plist" ]; then return 0; fi
    if ! defaults read "${plist_base}" LSEnvironment > "${tmpfilename_base}.plist" 2>/dev/null ]; then
        return 0
    fi
    libraries=$(defaults read "${tmpfilename_base}" "DYLD_INSERT_LIBRARIES")
    if [ $? -eq 0 ]; then
        check_libraries "${plist_base}" "$libraries"
    fi
    echo "Found DYLD_INSERT_LIBRARIES in ${plist_base}.plist LSEnvironment: $libraries"
    infected=1
    if ! $scanonly; then
        echo "Removing..."
        sudo cp -vp "${plist_base}.plist" "${quar_dir}"
        sudo defaults delete "${plist_base}" LSEnvironment
        sudo chmod 644 "${plist_base}.plist"
        if [ -f "$libraries" ] ; then
            quarantine_later "$libraries"
        fi
    fi
}

dont_do() {
    echo "NOT DOING: $@"
}

check_macosx_environment_plist()
{
    local plist_base=$1

    if ! [ -e "${plist_base}.plist" ]; then return 0; fi
    libraries=$(defaults read "${plist_base}" "DYLD_INSERT_LIBRARIES" 2>/dev/null)
    if [ "$?" -ne "0" ]; then
        return 0
    fi
    check_libraries "${plist_base}" "$libraries"
    echo "Found DYLD_INSERT_LIBRARIES in ${plist_base}.plist: $libraries"
    if ! $scanonly;then
        echo "Removing..."
        cp -vp "${plist_base}.plist" "${quar_dir}"
        defaults delete "${plist_base}" DYLD_INSERT_LIBRARIES
        [ -f ${plist_base}.plist ] && chown $USER ${plist_base}.plist
        if [ -f "$libraries" ] ; then
            quarantine_later "$libraries"
            infected=1
        fi
    fi
}

path_contains_malware() {
    path="$1"
    rm -f /tmp/bad_element
    echo "$path" | tr : "\n" | while read part ; do
	if is_malicious "$part" ; then
	    echo "$part" >> /tmp/bad_element
	fi
    done
    if [ -s /tmp/bad_element ] ; then
	return 0
    fi
    return 1
}

global_dyld=`launchctl getenv DYLD_INSERT_LIBRARIES`
if [ -n "$global_dyld" ] && path_contains_malware "$global_dyld" ; then
    infected=1
    echo "Found DYLD_INSERT_LIBRARIES in launchctl environment ($global_dyld)."
    if ! $scanonly; then
        echo "Removing..."
        launchctl unsetenv DYLD_INSERT_LIBRARIES
    fi
fi

check_launchagent
check_browser_plist "${safari_plist_base}"
if ! $scanonly; then
    touch /Applications/Safari.app
fi
check_browser_plist "${firefox_plist_base}"
if ! $scanonly; then
    [ -d /Applications/Firefox.app ] && touch /Applications/Firefox.app
fi
check_macosx_environment_plist "${macosx_environment_plist}"

quarantine

if [ -f "${tmpfilename_base}.plist" ]; then
    rm "${tmpfilename_base}.plist"
fi

if [ "$infected" -eq "0" ];then
    echo "No Flashback malware found."
else
    if ! $scanonly; then
    	zip_quarantine
    	if "$0" scanonly; then
    	    echo "Your system has been cleaned."
            infected=0
    	else
    	    echo "There has been a problem and your system is still infected."
            infected=2
    	fi
    fi
fi

exit $infected

For more details on how flashback works check out my other post brakertech.com/detect-mac-flashback/