this post was submitted on 27 Jul 2024
68 points (95.9% liked)

Programming

17512 readers
208 users here now

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you're posting long videos try to add in some form of tldr for those who don't want to watch videos

Wormhole

Follow the wormhole through a path of communities [email protected]



founded 1 year ago
MODERATORS
 

I've found lots of examples in C of programs illustrating buffer Overflows, including those of pointer rewrites which has been of great help in understanding how a buffer overflow works and memory safety etc. but I've yet to be able to find an example illustrating how such a buffer overflow can rewrite a pointer in such a way that it actually results in code execution?

Is this just not a thing, or is my google-fu rust y? Tried ChatGPT and my local Mistral and they both seem unable to spit out precisely what I'm asking, so maybe I'm wording this question wrong.

If anyone in here knows, could point me in the right direction? Thanks y'all btw love this community ๐Ÿงก

you are viewing a single comment's thread
view the rest of the comments
[โ€“] [email protected] 0 points 4 months ago (1 children)

@LainTrain The simplest case is overwriting the return address on the stack. If your stack layout looks like this (B for buffer, R for return address, A for function arguments):
BBBBBBBBRRRRAAAA
and you give a pointer to the first B byte to gets(), the input can overwrite the bytes of R.
You can try this with a 32-bit program complied with disabled mitigations. Run the program in a debugger, break in the function, inspect the stack pointer value. With ASLR disabled the addresses will remain the same for every program execution assuming the call graph at this point doesn't change. You can then overwrite the bytes of R with the buffer address (assuming no stack canary), and overwrite the buffer bytes with machine code instructions. When the function attempts to return, it instead jumps to the instructions you left in the buffer, and executes them (assuming no W^X).

[โ€“] [email protected] 1 points 4 months ago (1 children)

Thank you! This is incredibly helpful and insightful.

I now understand how one would do this with manually writing in a debugger, am I correct in thinking that if I constructed the input to gets() in such a manner that BBBBBBB contains shellcode, and RRRR is a return address pointing to the beginning of BBBBB then that is how arbitrary code execution can be achieved with this in practice?

[โ€“] [email protected] 1 points 4 months ago* (last edited 4 months ago) (1 children)

@LainTrain Yes, but "in practice" this simple approach worked 20 years ago. Modern processors, compilers and operating systems make exploitation of stack buffer overflows a lot more difficult.

[โ€“] [email protected] 1 points 4 months ago

That's fine, I think for my purposes it's better to start simple with the basic concept of it first, then add complexity by learning about the protections and how they have/could be circumvented.