Trotzdem ist es relativ einfach, den Seed des Zufallszahlengenerators herauszubekommen, siehe bspw. http://crypto.di.uoa.gr/CRYPTO.SEC/Randomness_Attacks_files/paper.pdf und http://blog.ptsecurity.com/2012/08/not-so-random-numbers-take-two.html. Von solchen Attacken habe ich immer wieder gehört.
Beide Beispiele beruhen aber darauf, dass der Angreifer wichtige Informationen über einen Bypass bekommt. So wird z.B. eine session_id mit md5 aus IP, dem Zeitpunkt und einem sehr eingeschränktem Zufallswert ermittelt. Das ist relativ einfach angreifbar.
Und wieder ist die Moral von der Geschicht’: Verwende (mt_)rand() für Krypto nicht.
Nochmal: Ich erzeuge den Salt mit einer Funktion, die rand() verwendet.
Den Salt speichere ich sogar, denn das geht auch gar nicht anders. Den Salt kann der Angreifer also immer dann haben, wenn er das gehaschte Passwort haben kann. Es ist also scheiß-egal ob rand ggf, erratbare Zufallswerte liefert, Hauptsache ist: Ich habe 10000 verschiedene Hashes! Er muss (im Beispiel) nur am ersten "~" trennen oder darauf vertrauen, dass der immer gleich lang ist (oder halt darauf, dass die hash-Funktion immer einen Hash gleicher Länge produziert).
Das Problem für den Angreifer ist bei meiner Funktion außerdem, dass die Hashes und ergo zuvor die Salts zu völlig unterschiedlichen Zeitpunkten berechnet werden - von denen der Angreifer eben nichts weiß. Er kennt auch die Reihenfolge nicht in der die Salts ermittelt wurden.
Anders als in den von Dir verlinkten Beispielen weiß er also gar nichts. Ich wüsste jetzt nichts, was seinen Aufwand so verringert, wenn er 10.000 solche Passwörter mit je einem bekanntem - aber unterschiedlichem - Salt bekommt und die knacken soll, dass er jenseits eines Wörterbuchangriffs, eines Angriffs auf schlechte hash-Methoden, eines Rainbow-Table-Angriffs oder gar eines brutalen, zeitfressenden brut-force-Angriffs auf jedes einzelne Passwort (das geht bei genug Zeit und Rechenpower theoretisch immer) eine reale Chance hat, alle 10.000 Passwörter innerhalb eines brauchbaren Zeitrahmens und mit (auch von der NSA) bezahlbarer Hardware zu knacken - was ja seine Aufgabe ist.
Rainbow-Tables sind bei hinreichend langen Salts kaum noch zu händeln.
"Die Größe einer Rainbow Table steigt mit der Länge der Kennwörter, für die sie generiert werden soll. Je nach Hashtyp ist ab einer gewissen Kennwortlänge die Berechnung einer Rainbow Table nicht mehr wirtschaftlich, sowohl was die Dauer der Generierung als auch den Platzbedarf der Tabellen angeht."
Im Fall von gehaschten Kennwörtern ist diese Länge: Länge des Passwortes + die Länge des Hashes.
Und weiter:
"Der Aufwand kann weiter erhöht werden, wenn ein Passwort nicht einfach, sondern mehrfach gehasht wird - üblich sind mehrere tausend Iterationen. Erst beide Methoden kombiniert ergeben ein Hashing-Verfahren, welches eine gewisse Resistenz gegen typische Angriffsmethoden aufweist. Das Salt macht das Erstellen von Tabellen unwirtschaftlich oder gar unmöglich, zusammen mit den Iterationen werden Brute-Force-Angriffe erheblich verlangsamt."