Auf heise.de habe ich am Tag nach dem Bemerken des Einbruchs (Bemerkt am: 01.12.2010) gelesen, das die offiziellen ProFTPD FTP Quellen seit dem 28.11.2010 mit einem Backdoor verseucht seien. Laut heise online soll die Infektion des Quellcodes über eine ungepatchte Sicherheitslücke Lücke im SQL-Modul in ProFTPD selbst verseucht worden seien. Was für eine Ironie. 🙂

Ich wusste mein Server ist nicht infiziert da ich mein System aus den Debian Paketquellen pflege und in darin niemals derart aktuelle Pakete enthalten sind. Dennoch wollte ich mehr darüber wissen. Auf der ProFTPD Projektseite fand ich eine News Meldung.

The ProFTPD Project team is sorry to announce that the Project’s main FTP server, as well as all of the mirror servers, have carried compromised versions of the ProFTPD 1.3.3c source code, from the November 28 2010 to December 2 2010. All users who run versions of ProFTPD which have been downloaded and compiled in this time window are strongly advised to check their systems for security compromises and install unmodified versions of ProFTPD.

To verify the integrity of your source files, use the PGP signatures which can be found here as well as on the FTP servers.

The source code in CVS was not affected.

CVS Benutzer müssen sich laut ProFTPD Team eigenen Angaben keine Sorgen machen. Anwender die die FTP Quellen benutzt haben sollten prüfen ob deine heruntergeladene Versionen des ProFTPD Quellcodes gültige PGP Signaturen aufweisen. (ProFTPD PGP Signaturen)

ProFTPD sollte normalerweise nicht als Prozess des Benuters root laufen. In wie weit das für den root Zugang über den Backdoor eine Rolle spielt weiß ich nicht. In kombination mit einem verwundbaren Kernel durch das „privilege escalation“ Exploit der selben Gruppe wäre dies kein Hindernis. Mehr dazu hier.

Um das Aufspüren von infizierten Servern zu erleichtern habe ich ein Scanner Script „verfasst“. Wie du an der Shebang und der Syntax erkennst handelt es sich um ein Ruby Script.

#! /usr/bin/ruby -w
 
require 'net/ftp'
require 'timeout'
 
##
## Validate and split IP address 
##
def explodeip(ip)	
	if 5 == len = (ip = ip.match('^(d{1,3}).(d{1,3}).(d{1,3}).(d{1,3})$').to_a).length
		i = 1		
		4.times do
			ip[i] = ip[i].to_i()
			i = i + 1
		end
		return ip
	else
		return false
	end
end
 
##
## Check FTP host for infection
##
def checkinfect(ip)
	begin
		timeout(3) do
     		ftp = Net::FTP.new(ip)
			puts ip+': connected'
			begin
				ftp.sendcmd('help ACIDBITCHEZ')				
				puts ip+': infected'
			rescue Net::FTPPermError
				puts ip+': clean'
			ensure
				ftp.close()
			end
		end		
	rescue Timeout::Error
		puts ip+': timeout'
	rescue Errno::ECONNREFUSED
		puts ip+': connection refused'
	rescue Errno::EHOSTUNREACH
		## Maybe you wan't to google?
	end	
end
 
##
## Script info
##
if !ARGV[0].is_a?(String)
	puts '# ACIDBITCHEZ ProFTPD backdoor scanner'
	puts '# Usage: ./ACIDBITCHEZ_ftpscanner <ip adress> || <start ip> <end ip>'
	puts '# More: http://www.monkey-business.biz/1211/proftpd-acidbitchez-backdoor-scanner/'	
	Process.exit()
end
 
if ip1 = explodeip(ARGV[0])
	if ARGV[1].is_a?(String)
 
		##
		## Cycle trough IP's
		##
		if ip2 = explodeip(ARGV[1])
			while ip1[1] <= ip2[1]
				while ip1[2] <= ip2[2]								
					while ip1[3] <= ip2[3]					
						while ip1[4] <= ip2[4]							
							checkinfect(ip1[1].to_s()+'.'+ip1[2].to_s()+'.'+ip1[3].to_s()+'.'+ip1[4].to_s())
							ip1[4] = ip1[4] + 1
						end
						ip1[4] = 0
						ip1[3] = ip1[3] + 1							
					end
					ip1[3] = 0
					ip1[2] = ip1[2] + 1
				end
				ip1[2] = 0
				ip1[1] = ip1[1] + 1
			end
		else			
			puts '# Second IP adress not valid'
		end
 
	##
	## Check single IP
	##
	else
		checkinfect(ip1[0])	
	end
else
	puts '# IP adress not valid'
end

Das Script läuft nicht ansynchron / in Threads. Zusätzlich wird auch versucht IP Adressen zu scannen die nicht existieren können. Dadurch ist das Script sehr ineffizient. Das liegt daran das du damit nicht das ganze Internet scannen sollst. 😉

Mehr zum Thema:

Keine Kommentare »