All computer languages are essentially instructions to one (or more than one) CPU, in the form of "do this. Now do that". So you always "get down to assembly" sooner or later. High level languages are frameworks (scaffolds?) to avoid lenghty repetitions of assembly code, and allow programming in a way that's more intuitive; this gain in understandability, flexibility and maintainability comes at a price - in size, performance and requirements.
When you succeed in gaining control of the application process, whatever the means (buffer overflow, etc.), you basically have just an area of memory where you can place whatever you want, and this is mostly independent on how you got at this point.
Now, for one, assembly has the highest "density" of instructions over code size, at least for small code sizes, so it is naturally your first choice if you want to cram the most in the area you just 'conquered'.
Secondly, and probably more important, when you smash into a memory area, you know little or nothing about the "context" - you do not have a context setup. For example, in C language, your main()
function is indeed a function - it gets called by the C runtime, which has already prepared an environment for the program to run in, a sort of life support system for your code. With a shellcode, you have no such support, and you need either to be able to do without (i.e. assembly) or build your own (again in assembly, since the life-support building code can't be needing a life support itself).
So in theory, you could prepare a "shellcode runtime stub" initializing an environment and "linking" your C code into the system. Once you had this, you could simply attach a C shellcode to the runtime and be able to refer OS functions by name. Several shellcodes have a stub to do this, but it's usually written in Assembly because reason number one still holds: space is at a premium.
Those exploits which allow the execution of an independent binary (in the most basic and trivial form, an executable attachment to an email that the victim will click on) have little size restraints and (usually) no runtime requirements, so they need not, and for maintenance purposes they almost never are, written in low-level languages.