Data scrambling for the development data
If you produce the new SSNs with a function like newSSN = makeSSN(hash(realSSN+salt)), where hash() is a known good hash function[1], salt is a long randomly generated string, and makeSSN() takes some/all of the hash function's output to make a nine-digit number output[2]. This way you get the same new value where-ever you have the same input SSN without needing to produce a mapping table to keep values consistent. To make sure that a real SSN can't be mapped to one in the resulting test data by using the same function[3] don't store the salt value between invocations.

Of course the "there are going to be other ways to identify what real person maps to which person in your munged test data-set" issue is something you should be aware of. For truly sensitive data it is far easier to be secure if you generate test data procedurally instead of by trying to depersonalise real live data.



[1] SHA2, SHA3, ...

[2] for example you could take the first or lowest 29 bits, or use CRC32 with output to decimal and strip off one character as it can produce 10

[3] though there are going to be other ways to identify what real person maps to which person in your munged test data-set