TL;DR; Anywhere you want.
You have to understand that you're taking the snapshot with the intent of restoring an aggregate's state at a later stage (without replaying the events obviously). The snapshot is therefor a contract the model has with any external consumer of that model (most commonly persistence, but you could e.g. envision pushing it to a hot-standby aggregate). In other words, you have to treat it like a message, a structure, that you may or may not want to version. To a certain extent you are leaking "internals" but you're doing it in a deliberate/explicit way. I would be weary of expressing a snapshot using "internal" constructs such as value objects and generally bias towards primitives. Otherwise you might be in for a surprise if those value objects change and break your snapshot-as-a-contract. You'd also be delegating a serialization concern onto your value objects - something that may not be desirable (but to some this will sound like splitting hairs).
As to the persistence of snapshots, you could persist them in a separate stream, the same stream (here be dragons in the form of concurrency issues), a key/value store, a document store, a database acting like a key value store, etc ...
HTH,
Yves.