Skip Ribbon Commands
Skip to main content

Ondrej Sevecek's Blog

:

Engineering and troubleshooting by Directory Master!
Ondrej Sevecek's Blog > Posts > Správné použití Get-Random a Random třídy nebo raději něco lepšího
únor 01
Správné použití Get-Random a Random třídy nebo raději něco lepšího

X krát jsem se setkal s tím, že skriptaři, ale ani programátoři nesprávně používají generátor náhodných čísel, který mají k dispozici v NET framework a tedy i v PowerShellu. Dokonce jsme v jednom pentestu po restartu dostával stejné SMS jako OTP (one time password), což asi nebude to pravé ořechové.

Pokud skriptujete, tak nejspíš používáte Get-Random. Tak ho prostě používejte. A hlavně tam nedávejte parametr -SetSeed. Zkuste si to. Normálně pusťte několik oken PowerShellu a dejte si Get-Random 100 například. Dostanete pokaždé jiné náhodné číslo. Tak jste to asi chtěli :-)

Parametr -SetSeed vám naopak zajistí, že dostanete pokaždé úplně stejnou sérii náhodných čísel. Zkuste si to. Do každého okna PowerShellu na každém počítači na světě kdykoliv zadáte například Get-Random 100 -SetSeed 999 tak dostanete 62. Proč a na co to je?

No někdy potřebujete testovat skripty pokaždé se stejnou sadou náhodných čísel. Jednou to otestujete na nějakém vzorku a když to předěláte, tak by možná bylo dobré to zkusit na stejném. K tomu je SetSeed. Prostě nějak inicializuje ten pseudonáhodný generátor. On má v sobě nějakou náhodnou řadu, pokaždé stejnou. A pokud se inicializuje stejným číslem, tak to bude všude stejná řada.

Jestli chcete náhodnost, tak ho nechte, ať se inicializuje sám podle "hodin".

Pokud vyvíjete pomocí netfx třídy (class) System.Random, tak to máte to stejné. Cmdlet Get-Random používá tu stejnou třídu. Takže constructor Random(999) vám nastaví stejné semeno a volání Next(100) vám dá to stejné, tedy číslo 62. Můžete to zkusit rovnou z PowerShellu:

$rnd = New-Object Random 999
$rnd.Next(100)

Opakuji. Seed je tam na testy. Nikoliv na provoz.

Jak ten Get-Random a Random vlastně generují?

Podíval jsem na zdroják (http://referencesource.microsoft.com) a zjistil jsem, že pokud nepoužijete seed ručně, tak to tam použije samo aktuální Environment.TickCount.

Na základě Seed hodnoty (buď vámi zadané, nebo získané z TickCount) si vygeneruje padesátipětiprvkovou řadu, kterou potom používá. No fuj. Takže to moc bezpečné náhodné číslo není.

Uvědomte si, že jakmile budou mít dva počítače stejný TickCount, tak to bude dávat stejné výsledky. TickCount je počet 100ns intervalů od startu počítače, takže trefit se je asi poněkud nemožné, ale přece. Navíc ta hodnota jenom stabilně a pořád stejně rychle roste. Takže pokud to v nějakém okamžiku zachytíme, můžeme predikovat do budoucna. Počítač startuje také obvykle poměrně stejně rychle. Nahození služby tedy bude někde v nějakém intervalu.

Samozřejmě pro skriptování nejspíš v pohodě. Ale pro slušný vývoj?

Skutečný kryptograficky slušný (pseudo)náhodný generátor

Musíte na to používat systémovou knihovnu (crypto service provider), který je obalený třídou RNGCryptoServiceProvider. Ta obaluje cryptoAPI CSP knihovnu Microsoft Enhanced Cryptographic Provider v1.0. Tenhle poskytovatel používá standardní SP800-90 AES-256 counter mode (CTR_DRBG). Do náhodného čísla míchá (detaily zde, kapitola 5.3.2 SystemPrng) nejenom počet tiků, míchá tam i aktuální systémový čas, který bude různý po každém restartu. Míchá tam dále například čítač hardware přerušení, který neroste rovnoměrně. Přimíchává do toho i čítače spotřeby paměti a místa na disku, které občas také klesají apod. Pokud máte TPM, tak to cucá hardware entropii z TPM. Celkově je potřeba do náhody dát co nejvíc věcí, které jsou mimo schopnosti člověka to ovlivnit.

$cryptoRnd = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
[byte[]] $numbers = New-Object byte[] 1
$cryptoRnd.GetBytes($numbers)
$cryptoRnd.Dispose()

Takhle je to správně, pokud už vyvíjíte něco opravdu cíleného na bezpečnost.

Comments

There are no comments for this post.

Add Comment

Sorry comments are disable due to the constant load of spam *


Omlouvám se, ale příval spamu nelze kontrolovat, takže mi prosím pošlete email, pokud máte nějaký dotaz, nebo připomínku.

Title


Pole Title nemusíte vyplňovat, doplní se to samo na stejnou hodnotu jako je nadpis článku.

Author *


Pole Author nesmí být stejné jako pole Title! Mám to tu jako ochranu proti spamu. Roboti to nevyplní dobře :-)

Body *


Email


Emailová adresa, pokud na ni chcete ode mě dostat odpověď. Nikdo jiný než já vaši emailovou adresu neuvidí.

Attachments