Vorgurakendused 2 prax 1 2015

Allikas: Lambda

Zombie robot attack

P2MD5 - P2P MD5 cracker

Ülesandeks on ehitada P2P rakendus MD5 hashi murdmise ülesande tükkide jagamiseks võõrastele masinatele ja rehkendustulemuste kättesaamiseks, mis teeb laviinitaolise otsingu mööda P2MD5 klient/servereid, isetehtud P2P mehhanismi abil.

Kasutajaliidese hea kvaliteet ei ole praksis oluline.

Huvi korral võid vaadata ka sarnaseid vanu ülesandeid 2013 aasta arhiivis, 2014 aasta arhiivis ning sealt edasi vanemaid.


Üldkirjeldus

P2MD5 võimaldab:

  • saata teistele P2P masinatele MD5 bruteforcemise ülesande juppe
  • saada tagasi rehkendatud tulemus.


Võõraste rehkendamiseks valmis masinate leidmiseks kasutab P2MD5 järgmist viisi:

  • Saadab tema oma masinas oleva faili machines.txt masinatele ressursipäringu. machines.txt sees on masinate ip ja pordid json listina kujul
[["11.22.33.44","2345"],...,["111.222.333.444","23456"]]
  • Samamoodi saadab ressursipäringu P2MD5 startlehele a la http://dijkstra.cs.ttu.ee/~priit/P2MD5.txt olevatele masinatele (startlehel on plaintekstina eelmises punktis näidatud formaadis json-fail). Konkreetselt ülaltoodud urlil midagi ei ole, sobiv startleht tee ise ja pane enda valitud urlile.


  • Ressursipäringu kättesaaja otsustab, kas tal on ressurssi rehkendada. Kui jah, saadab ta OK teate ressursipäringu algatajale. Igal juhul saadab ta ressursipäringu P2P võrku edasi, vähendades time-to-live numbrit. Ehk, masinad saadavad minu antud päringut rekursiivselt ise edasi.

N sekundit peale ressursipäringu tegemist (N sea algul näiteks paari sekundi peale) jaotab ressursipäringu tegija ülesande talle OK vastanud masinate vahel ära. Edaspidiseid OK teateid ta ignoreerib (elegantsem oleks vastata, et ei kasuta).

  • Seejärel saadab ta kõigile OK vastanud masinatele ülesandesõnumi, mis sisaldab md5 hash stringi ja vahemikku katsetatavast sõnalistist.
  • Kui mingi masin saab minu ülesandesõnumi kätte, siis ta hakkab seda tükki läbi analüüsima ja saadab tulemuse päringu algatanud masinasse: tulemus ütleb kas et ei leidnud või et leidsin konkreetse sobiva stringi, ja mis string see on.


Miks just selline päringu edasisaatmisviis?

Põhimõtteliselt saab päringut massidesse P2P meetoditega laiali saata kahel viisil:

  • Iteratiivne meetod (antud praksis seda ei kasuta): algne masin küsib tuttavatelt neile tuttavate masinate faile, ja suurendab seeläbi endale teadaolevate masinate hulka. Igalt uuelt teadasaadud masinalt küsib ta jälle selle masina tuttavate faile jne. Teised masinad algset päringut ise kuhugi edasi ei saada. Meetodi pluss on see, et algne masin saab lihtsalt tagada, et päringut ei saadetaks kaks korda samale masinale. Meetodi miinus on see, et kõik masinad võrgus saadavad lõpuks terve neile tuttavate masinate faili algsele masinale: see tähendab väga suurt hulka väga suurte failide saatmisi, mis hakkavad jõhkralt ummistama võrku, ja algse masina väike kanal tõenäoliselt ummistub varsti. Saadud failide ühisosad on väga suured. Halvemal juhul saab algne masin N identset sõnumit, kus igaühes on N ip-d, kus N on kõigi masinate arv, kus jookseb P2MD5.
  • Rekursiivne meetod (antud praksis nõutud): algne masin saadab oma päringu tuttavatele masinatele, kes selle omakorda enda tuttavatele edasi saadavad jne. Igüks, kes leiab enda failide hulgast vajaliku faili, saadab info algsele masinale (vastasel korral ei saada ta algsele masinale midagi). Algne masin ei suurenda endale teadaolevate masinate hulka. Meetodi pluss on see, et algsele masinale saadetakse tagasi infot ainult siis, kui vajalik info leitakse (väga väike protsent masinaid) ja see info on lühike. Koormus võrgule langeb tugevasti ja algse masina kanal tõenäoliselt ei ummistu. Meetodi miinus on asjaolu, et üks ja sama masin võib saada algse päringu mitu korda eri suundadest, mis jällegi kasvatab võrgu koormust. Seda viimast probleemi saab mitmel moel leevendada (kuigi mitte täielikult kaotada), eeskätt päringu ttl (time to live) parameetrit kasutades, päringu ahela masinate lisamises päringu parameetrite hulka jne.

Gnutella kasutab rekursiivset meetodit, nii ka meie P2MD5. Lihtsakoeline rekursiivne meetod ummistab suure klientide arvu korral võrgu ja sele asemel kasutavad suured P2P süsteemid kas:

  • struktureeritud nn superpeeride süsteemi a la Kazaa ja esialgne Skype, kus rekursiivne päring toimub ainult superpeeride vahel, ja neid on vähe, või
  • väga kavalat nn distributed hash tables (DHT) mehhanismi, a la freenet ja (osaliselt) bittorrent. DHT on üks mitmest bittorrenti poolt kasutatud meetodist, kuigi bittorrenti põhifookus on hoopis faili paralleelse allatõmbamise optimeerimisel mitme masina koostöös, mitte masinate/failide leidmisel. Või:
  • kasutavad masinate leidmiseks eeskätt tsentraalseid servereid, a la esialgne Napster või kaasaegne Skype

Tehnilised nõuded

Programmeerimiskeele ja muu tehnoloogia valik on vaba, kuid rakendus peab vastama neile tingimustele:

  • Kogu programm peab töötama kas ITC-maja klassi arvutis või sinu oma läptopis, mis ITC maja klassis kaasas. Mingit kaugel asuvat serverit põhirakenduse jaoks kasutada ei tohi. Arusaadavalt võib aga panna P2MD5 lisaks käima ka suvalistesse välistesse masinatesse.
  • Http protokolli jms realisatsioon peab olema teie oma programmi osa, mingit "suurt" http serverit a la apache kasutada ei või. Kõikvõimalike võrguteekide (versus eraldiseisvad veebiserverid) kasutamine on ok, mikroserverite koodi integreerimine oma programmi on ok.

Protokoll

Kõik sõnumid saadetakse http kaudu. Neid sõnumeid saab katsetada brauserist ja curliga jne.

Ressursipäringu saatmine ja edasisaatmine

Konkreetsele masinale 11.22.33.44 (kus P2MD5 jookseb pordis 2345) ressursipäringu saatmine http://11.22.33.44:2345/resource?sendip=55.66.77.88&sendport=6788&ttl=5&id=wqeqwe23&noask=11.22.33.44_345&noask=111.222.333.444_223

kus parameetritel on järgmine sisu:

  • resource: ütleb, et tegu ressursipäringuga
  • sendip: esialgse saatja ip
  • sendport: esialgse saatja port
  • ttl: kui mitu otsingu-hopi veel teha (iga edasiküsimine vähendab ühe võrra)
  • id: optsionaalne päringu identifikaator
  • noask: (optsionaalne ja võib korduda) list ip_port kombinatsioonidest, kellele pole mõtet edastada (eraldajaks alakriips)

Päringu identifikaator ei pea tingimata üle terve võrgu unikaalne olema - lihtsam on ja ajab asja ära, kui on saatva masina piires unikaalne.

GET-päringu vastuseks on õnnestunud päringu korral number 0, ebaõnnestunud päringu korral muu (vea)number. Vastuse mõte on eeskätt debugimise lihtsustamine ja vastust peaks pärija üldiselt ignoreerima. P2MD5 peaks töötama edukalt ka juhul, kui ta saatmise peale ühenduse lihtsalt kinni paneb ja vastust kuulama ei hakka.

P2MD5-le tulnud päringu edasisaatmine käib täpselt sama protokolliga, kuid edasi saadetakse veidi muudetud päring:

  • ttl vähendatakse ühe võrra
  • optionaalselt: lisatakse oma masina ip uue noask argumendina

Seejuures ei saadeta päringut edasi, kui sissetulnud ttl oli 1 või vähem (st ttl=0 päringuid enam kuhugi ei saadeta)

Seda päringut saab ka brauserist katsetada, kuigi brauser ei saa vastuseks midagi huvitavat peale debugimis-vastuse 0 või mingi veakoodi.

Klientide filtreerimine (juhul kui soovitakse juhtida mingit alamhulka masinatest) toimub programmi käsurea kaudu. See osa ei ole kohustuslik vaid tuleneb konkreetsest rakendusest; protokollis see funktsionaalsus ei sisaldu.

Ressursipäringu tulemuse tagastamine algsele pärijale

Vastus oleks http post meetodiga käivitatud programmi kogu väljundi saatmine algsele küsijale muutmata kujul koos lisainfoga

http://11.22.33.44:2345/resourcereply

POST-itatud data:

  {"ip": "55.66.77.88", 
   "port": "6788",
   "id": "asasasas",
   "resource": 100 }

id peaks vastama esialgse saatja antud id-le, juhul kui seda kasutatakse.

  • ip: tulemuse saatnud masina ip
  • port: tulemuse saatnud masina port
  • id: esialgse päringu id (kui oli algselt antud)
  • resource: minu rehkendusvõimsus (keskmine masin on 100) seda ei pea täpsemalt hindama, võib alati öelda 100

Programm võiks ka mitte crashida, kui id puudu on, kuna id on optional (aga praktiline ja mõtekas on lisada).

Postituse saaja vastab eduka kättesaamise korral arvu 0, arusaamatuste korral mõne muu (vea) numbri. Jällegi, vastuse mõte on eeskätt debugimise lihtsustamine ja vastust peaks pärija üldiselt ignoreerima. Süsteem peaks töötama edukalt ka juhul, kui ta saatmise peale ühenduse lihtsalt kinni paneb ja vastust kuulama ei hakka.


Rehkenduspäringu saatmine

Konkreetsele masinale - rehkendajale - 11.22.33.44 (kus proge jookseb pordis 2345) rehkenduspäringu (md5 bruteforce mingi vahemiku jaoks) saatmine http://11.22.33.44:2345/checkmd5

POST-itatud data:

  {"ip": "55.66.77.88", 
   "port": "6788",
   "id": "siinonid",
   "md5": "siinonmd5string",
   "ranges": ["ax?o?ssss","aa","ab","ac","ad"],
   "wildcard": "?",
   "symbolrange": [[3,10],[100,150]]
  }

kus parameetritel on järgmine sisu:

  • ip: rehkenduspäringu saatja ip
  • port: rehkenduspäringu saatja port
  • id: rehkenduspäringu id
  • md5: hash stringina
  • ranges: list stringidest, kus võivad olla wildcardid ?
  • wildcard: optsionaalne: kui olemas, siis sümbol, mida wildcardina ? asemel kasutatakse
  • symbolrange: optsionaalne: list baidivahemike paaridest, mida wildcardi asemel katsetada.


Rehkenduse tulemuse tagastamine algsele päringu saatjale

Peale rehkenduse läbitegemist saadetakse vastus niimoodi:

http://11.22.33.44:2345/answermd5

POST-itatud data:

  {"ip": "55.66.77.88", 
   "port": "6788",
   "id": "asasasas",
   "md5": "siinonmd5string",
   "result": 0,
   "resultstring": "sssasasc"
    }

id peaks vastama esialgse saatja antud id-le, juhul kui seda kasutatakse.

  • ip: tulemuse saatnud masina ip
  • port: tulemuse saatnud masina port
  • id: esialgse rehkenduspäringu id
  • md5: bruteforcetav hash stringina
  • result: mis sai (leidsin stringi: 0, ei leidnud stringi: 1, ei jõudnud rehkendada: 2)
  • resultstring: leitud string (kui on), mille md5 hash ongi bruteforcetav hash

Ülesande andmine inimese poolt

Üks võimalik lihtne variant oleks selline: võtad lihtsalt http ühenduse (näiteks lihtsalt brauseri abil) mõne sinu progega a la

http://11.22.33.44:2345/crack?md5=45f0909...ff 

ja siis see proge jagab ülesande laiali ja jupp aega hiljem vastab. Ehk aeglane sünkroonne päring.

Selleks pead oma proges muidugi realiseerima eraldi osa, mis reageerib crack?... stringile, võtab sealt välja md5=... järel oleva tekstijupi, seejärel jaotab ülesande teistele laiali ja lõpuks saadab neilt kättesaadud info põhjal vastuse.

Praksi kaks osa

Väga soovitav on teha praks kahes osas ja esitada kaks korda ülevaatamiseks:

  • Teha http protokolli järgida suutev esmane rakendus.
  • Lisada sinna kogu vajalik funktsionaalsus:
    • Ressursipärinngu protokolli implementatsioon
    • Ülesande splittimine ja laialisaatmine
    • Saadud MD5 bruteforcemise ülesande lahendamine ja vastamine
    • Vastuste kokkukogumine ja puuduolevate vastuste ülesandejuppide uuesti laialijagamine

Http protokolli järgimise võimet kontrollitakse praksi eduka läbimise tingimusena.

Soovitusi ja ideid

Arendamiseks ja testimiseks pead saama jooksutada oma masinas mitut erinevat koopiat omaenda P2MD5-st, igaüks oma pordil, igaühel oma konfifail tuttavate masinatega.

Hea mõte on teha P2MD5 käsurealt käivitavaks nii, et ta võtab kohe käsurealt pordinumbri parameetriks ning loeb siis oma konfifaili vastavast pordinumbrist tuletatud failipathist.

P2MD5 peab päris kindlasti sisaldama või kasutama http serverit, muidu ei ole temaga võimalik väljast ühendust võtta. NB! See ei tähenda mingit nö suurt veebiserverit a la apache, vaid pigem ise kirjutatud väikest minimaalset serverit, mis pealegi ei pea veebilehti serveerima ja cgi-sid käivitama, vaid ainult teatud käskudele/parameetritele reageerima.

Server tuleb realiseerida ise, kasutades võrgust leitavaid näiteid mikro-http-serveri jaoks (tüüpiliselt paar lehekülge koodi). Selliseid näitekoode võib täiesti otse kasutada.

C jaoks on sobiv mikroserver näiteks tiny, java jaoks on see server väga hea väike näide, aga selgitava tekstita, ning selgitavate tekstidega servereid leiad mh siit ja siit.Loe java socketitest põhjalikumalt siit. Pythoni serverinäite saad siit. Http kohta võib lugeda näiteks siit.

Kasutajaliides võib olla tehtud aknaga, aga see ei ole kohustuslik: võib teha ka puhtalt käsurea rakenduse.

Rakendus on mõistlik teha nii, et annad käivitamisel ette pordi, millel ta räägib, ning kui seda porti ei ole antud, siis kasutad vaikimisi porti 1215 (1214 on Kazaa port).

Häid selgeid näiteid ja õpetusi socketite ja serveri tegemise kohta leiad veel siit:

MD5 rehkendus, template ja näitelahendus

See on väike näitelahendus template instantsieerimise ja kräkkimise jaoks Pythonis ühe programmiga, ilma sisendparameetrite, ülesande splittimise, P2P jms vajalike osadeta.

import hashlib

wildcard="?"

def main():
  print("md5 cracker here")
  tocrack="0d61f8370cad1d412f80b84d143e1257" # hash of C
  tocrack="5332ba558c6706d24ae90e9ffdbdac1f" # hash of aebgc
  tocrack="68e1c85222192b83c04c0bae564b493d" # hash of koer 
  res=md5_crack(tocrack,"k??r") 
  if res:
    print("cracking "+tocrack+" gave "+res)
  else:
    print("failed to crack "+tocrack)    
    
def md5_crack(hexhash,template): 
  "instantiate template and crack all instatiations"
  # first block recursively instantiates template
  i=0
  found=False
  while i<len(template):
    if template[i]==wildcard:  
      found=True
      char=32 # start with this char ascii
      while char<126:
        c=chr(char)
        if c!=wildcard: # cannot check wildcard!        
          ntemplate=template[:i]+c+template[i+1:]
          #print("i: "+str(i)+" ntemplate: "+ntemplate)
          res=md5_crack(hexhash,ntemplate)
          if res: # stop immediately if cracked
            return res
        char+=1
    i+=1    
  # instantiation loop done  
  if not found:
    # no wildcards found in template: crack
    m=hashlib.md5()
    m.update(template)
    hash=m.hexdigest()
    #print("template: "+template+" hash: "+hash) 
    if hash==hexhash: 
      return template # cracked!
  # template contains wildcards     
  return None    
 
main()
  

Ülesannete genereerimine rehkendajatele

Nö server ehk ülesannete laialijagaja peaks tagama, et kõik stringivahemikud rehkendakse läbi. Iga üksik saadetud rehkendusülesanne võiks olla mõistliku mahuga, a la temas võiks olla kaks wildcardi ?, mis teeb ca 10.000 katset.

Näitena võimalik ülesannete jagamine rehkendajatele: ülesanded oleks (lihtsustusena on meil siin tähevahemik a-z) sellised:

"?"
"??"
"a??"
"b??"
...
"z??"
"aa??"
"ab??"
...
"az??"
"ba??"
"bb??"
..
"zz??"
"aaa??"
...

Sul ei ole reaalselt ilmselt mõtet katsetada stringidega kogupikkusega üle nelja sümboli: nende kräkkimine võtaks juba päris pikalt aega.

Suhteliselt lihtne on oma proges esialgu tähevahemikuks valida #...~ ja kasutada wildcardina !, vaata ascii tabelit: lihtsalt, et oleks kergem neid stringe oma proges trükkida ja vaadata. Ka hea variant on võtta vahemikuks !...~ ja wildcardiks tühik.

Sellised vahemikud ei kata aga UTF-8 või ISO-8859-1 vms sümboleid piirkonnas 127-255: nende jaoks oleks vaja vastavalt baidivahemik võtta kuni 255. Aga, ära hakka esialgu oma elu keerulisemaks tegema: nende vahemike väljatrükk tekitab kindlasti ebamugavusi. Jända nendega ainult juhul, kui sul tekib ekstrahuvi :)

Firewall ja NAT

Firewallist läbi murdmise ja kinniste portidega ühendamise probleemiga ei pea selles praksis tegelema. Samas tähendab see, et ei ole kuigi lihtne teise masinaga tegelikult ühendust saada (ühes masinas debugimise võimaldamine ongi seepärast kriitiline).

NB! Arvutiklassi arvutid suudavad üksteisega edukalt suhelda ilma erihäkke ette võtmata: saab panna oma proged mitmel masinal reaalselt P2P tegema. Samas, läptop wifi võrgus pigem ei suuda arvutiklassi masinaga otse suhelda, kui siin alltoodud eripingutusi mitte teha.

Kes P2MD5 käima saab, võib mõelda välja ja realiseerida probleemi lahendamiseks sobiva vaheserveri: selle eest saab ekstrapunkte.

Võrgust infot otsides leiad kahte liiki teemasid, meie jaoks oluline on siit listist teine:

NB! Seda kõike ei ole väga lihtne teha ja sinu P2MD5 (ja ka selle inimese P2MD5, kellega suhtled) peab ka oskama seda vaheserverit kasutada. Ära hakka seda ehitama, kui nö lihtne P2MD5 veel ei tööta!

Ekstra-lisapunktide saamise variant: realiseeri ja pane kõigile kasutatavaks firewalliprobleemi lahendamiseks sobiv vaheserver. Kirjuta kasutamise juhend ja näited, mida teised saaks soovi korral oma P2MD5 jaoks tarvitada (st panna nad sinu vaheserverit kasutama, nii et seda saaks ka arvutiklassist kasutada). Esimesed kaks gruppi, kes sellega hakkama saavad, saavad lisaks pooled praksipunktid!

Paroolihashide salvestamise hea tava

Raskendamaks paroolihashide bruteforce crackkimist, kasutatakse paroolide salvestamisel tüüpiliselt nn salt-i.

Mis on selle idee?

Ütleme, et kasutaja sisestab algelt oma parooliks "koer". Kaks varianti paroolihashi salvestamisel ja kasutamisel on siis:

  • lihtvariant: baasi salvestatakse parooliväljale hash("koer") ehk "68e1c85222192b83c04c0bae564b493d" ja hiljem parooli kontrollimisel võetakse uuesti kasutaja poolt nüüd sisestatud "koer" ja kontrollitakse, kas "68e1c85222192b83c04c0bae564b493d"==hash("koer") ?
  • parem, nn salted variant: baasi parooliväljale salvestamise eel tehakse pikem string s="miskipikkalgustekst"+"koer" ("miski..." on nn salt) ja baasi salvestatakse parooliväljale hash(s) ehk mingi "d78a....". Hiljem parooli kontrollimisel võetakse uuesti "koer" ja kontrollitakse, kas "d78a...."==hash("miskipikkalgustekst"+"koer") ?

Punktiarvestusest

Kui P2MD5 protokoll töötab vastu mõne teise grupi P2MD5-i, sellele on realiseeritud mingi rakendus ja koodi suudetakse seletada, saab täispunktid.

Kui teiste P2MD5-programmidega ei suuda suhelda, aga iseenda koopiatega siiski, siis päris täispunkte ei saa.