In my experience, the reason all companies have shitty codebases is because of risk-compensation. When a company does
not have a shitty code base, it quickly throws all of its resources into improving the product and user experience for its customers, which increases its market share, revenue, and moat against competitors. This continues until all the new complexity makes the code shitty again, where they stage a cleanup & architectural fixit to be able to make forward progress. If the codebase is
not shitty, it means that they're leaving money on the table, and will continue to get shittier until code quality starts costing them money again.
Companies like Google, Microsoft, and Facebook actually do adopt (and often discover) many of the industry best practices. Their codebase is still shitty; the reason is that any cleanliness and rationality in their architecture is quickly eaten up by new features and products that drive the industry forward. As consumers, we see the benefits; as employees, we just muddle along as best as we can.
The only way to break this cycle is for engineers to pay companies instead of getting paid by them. I don't think this is what you had in mind. (Although, some engineers do make this bargain. This is why Haskell/Erlang/Ocaml/Lisp salaries are often lower than they would be for equivalently-skilled Java and C++ engineers: you take a pay cut to work in a language that's actually enjoyable to program in.)
Barring that, the way out is to learn some negotiating skills and at least get paid for putting up with a sucky codebase. If you frame it as "employing my skills will let your other employees implement the features you've been asking for for a year, which will make you $XM in revenue", you can make quite a pretty penny. I know some senior engineers that regularly get paid a couple million in restricted stock for a couple years worth of work.