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, das liegt daran das du damit nicht das ganze Internet scannen sollt und es ein Prototyp ist bei dem du möglicherweise mit dem Request Timeout spielen musst. Vielleicht ist es mir auch den Aufwand nicht wert. Optimierungen nehme ich gerne entgegen.

