It does not matter what kernel you compile an exploit under.
The failures were because the kernel was providing protections from the exploit methods you used. These protections are done at runtime. The kernel does not somehow insert code to cripple exploits compiled under it. The solution would be to run the exploit on a kernel with these security features removed or disabled, not to compile it on such a kernel. You do not have to have ASLR running (or even supported by your kernel) to compile a position-independent executable, for example.
The running kernel does not change the output of the compiler in a way that would break an exploit. All that matters is that you are compiling it with the same (or at least compatible) compiler features, libraries (if statically linked), and optimizations. If this is the case, it can be compiled anywhere. You could even compile an exploit for a Linux application on Windows or OpenBSD, and vice versa.
Some things you may want to keep in mind regarding your toolchain's environment:
- Compiling on one system with
-march=native
may result in an executable that does not function properly or at all on another system. Avoid hardware-specific optimizations.
- Using features from, say, GCC 7.2.0 may cause breakage if compiled on a machine that only has 6.4.0. The same applies to regressions that may break an exploit on a newer compiler.
- If your target has header files which are incompatible with a working exploit for whatever reason, you will need to include the correct header files or compile it under a system which has them.
- Some libraries' build systems check the kernel version running, and use this to decide what features to include. Be aware of this if you are compiling libraries on this system as well.