Reminds me of the time I realized that the indie multiplayer game I was playing would print jibberish whenever you typed a "%" in the chat and therefore it was probably just doing an unsanitized sprintf somewhere. Then I realized that putting a %n in there would mess things up and yup crash the server (not just the client). It would have taken a lot more skill than I had to actually exploit that to do more than just randomly crash servers.
Yeah, pulling off a successful format string attack generally requires knowledge of where the stack is or having a variable pre-initialized to the address of something on it; then you'll need the address of something useful to jump to. If you have a copy of the non-PIE/ASLR executable, this is easy, otherwise other methods are needed.
Actually, if you (the attacker) receive the printf output, then you can pretty trivially leak almost any memory you want with %N$x, allowing you to first leak the entire stack, then pivot to leak any referenced memory regions (which will almost certainly include the executable and many libraries due to return addresses on the stack). Worse, you can then use %N$n to write to any pointer in memory - if you can find your input string in memory (dereference stuff until you find the heap, for example), you can stuff pointers into it and get a write-what-where primitive (which is game over).
This is part of what makes format string vulnerabilities so nasty - they hand you a free leak in addition to %n being capable of very flexible overwrites.
> you can then use %N$n to write to any pointer in memory - if you can find your input string in memory (dereference stuff until you find the heap, for example), you can stuff pointers into it
You first have to get a valid pointer to something, which can be pretty hard when the addresses are randomized. Yes: if you can satisfy all the requirements for a printf attack, there's a whole lot you can do: overflow the stack and write to the return address, find the address of system, perform arbitrary reads or writes, etc. But as you've mentioned yourself, a successful format string exploit requires more than just "someone passed a user-controlled string to printf", at least as far as I'm aware.