I worked at a few places like that, and here's my take on what to do:
Remain productive: take each task as it comes, don't build more than what you absolutely need in order to complete the task, and try not to add more dung to the pile of dung that is already there. If your code is good, then at least there will be some good code instead of "none". Don't waste a minute worrying about how dumb the what they're asking for is, just build it the best way you know how, and move on to the next task. If you build up enough steam, you may get extra time at the end that you can use to pitch the idea of refactoring over and over until someone lets you do at least a little refactoring.
Avoid getting depressed: consider how many jobs are so much worse than programming. If you can get a job somewhere better, I'd go for it, but remember that a gross codebase is just one of many things that can make a job annoying. If it were all sunshine and roses, they wouldn't need to pay someone to do it. Again, take lots of notes to help yourself decide if the pros/cons are really as bad as they seem. On a good day, the notes may look different to you than on a bad day, that's why it's useful to realize what frame-of-mind can do to warp the perception of how bad things are.
Write decent code when the rest of the code is crappy/terrible architecture: One thing that makes crappy code look that way is the scattering of related functions. Try to keep everything together, so at least no one is hunting for needles in your code "haystack".
Just don't introduce more problems in your own code, and keep a log of when the existing codebase causes problems and how long they took to fix. That can be used to help promote the case for refactoring.
Note: sometimes code looks bad because it really is bad, and other times there are mitigating factors in why the code looks bad.
The other programmers might not have been that stupid; instead they may have been forced to build something a certain way to achieve a certain effect.
The code probably works, so in a sense it's "good enough" for the company.
When new developments come along, use the opportunity to fix anything from the old system that has to interface with the new component using the following reason: "the new version has features that just aren't 100% compatible, we just need to 'change a few things' in the old version to make it work right.' That should allow you a bit of wiggle room to at least refactor the output and input to the big ball of mud.
The more code you see in your life, the less any of it looks "all that bad", so hang in there.