So if you ask the average person to create a secure passphrase, they're very likely to create something that a "determined attacker" with a lot of computing power can crack.
A brain wallet is a standard wallet that generates its address by hashing a passphrase to create a private key and therefore a public key and resultant address. Seeing as a Bitcoin address is usually a 256 bit string.
private key = SHA256(passphrase)
Brain Wallets have a significant disadvantage that means they have a higher probability of being hacked. That is that us humans are pretty predictable in what we use as a passphrase and password, and hacking technology has got a lot better through the use of rainbow tables and dictionary attacks. Also a few large databases of passwords have been leaked meaning so it is quite easy to hash all these passwords and then see if their corresponding address exists as an active address on the blockchain – if so you have the private key and therefore access to the funds.
A simple technique is using a hashing functions number of times over so that the hacker will have to guess both the hashing function and the number of times it was applied to a particular password. This is called key stretching.
You can use Python scripts and install local Bitcoin node to bruteforce dictionary attack on brainwallets.
Typically, key strengthening is used to increase the time necessary for trying a single seed. This does however require either fixing the number of iterations (which should increase over time as hardware gets faster), or forcing the user to remember the number of iterations. It also lacks a way to verify a seed was correct, as every seed results in a valid key.
An alternative is using a checksumming system. For example, requiring that SHA256("BLAH" + seed) starts with a given number of zero bits, and using SHA256(seed) as key. With N required zero bits, this also slows down testing of seeds by 2N per valid seed. It does provide a way to verify a seed was correct, is very fast to do the actual derivation, but also introduces some variation in the seed generation.
Neither solution however addresses the fact that it requires the derivation count or checksum strength to be known in advance (either as part of the specification, or by making the user remember). However, by combining both strengthening and checksumming, we can have seeds that encode their own strength, without compromising security.