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 🧡

    • LainTrain@lemmy.dbzer0.comOP
      link
      fedilink
      arrow-up
      9
      ·
      2 months ago

      I just want to learn in more practical terms how exploits like this function in the wild haha, but eventually I do hope to become a C chad and even an assembly chad and understand how computers actually work and perhaps shake the impostor syndrome of being a skid neesus monkey when it comes to pentesting and do something worth doing :)

      • litchralee@sh.itjust.works
        link
        fedilink
        English
        arrow-up
        4
        ·
        edit-2
        2 months ago

        A commenter already provided a fairly comprehensive description of low-level computer security positions. But I also want to note that a firm foundation in low-level implementations is also useful for designing embedded software and firmware.

        As in, writing or deploying against custom BIOS/UEFI images, or for real-time devices where timing is of the essence. Most anyone dealing with an RTOS or kernel drivers or protocol buses will necessarily require an understanding of both the hardware architecture plus the programming language available to them. And if that appeals to you, you might consider looking into embedded software development.

        The field spans anything from writing the control loop for washing machines, to managing data exchange between multiple video co-processors onboard a flying drone to identify and avoid collisions, to negotiating the protocol to set up a 400 Gbps optical transceiver to shoot a laser down 40 km of fibre.

        If something “thinks” but doesn’t have a monitor and keyboard, it’s likely to have one or more processors running embedded software. Look around the room you’re in and see what this field has enabled.

      • astrsk@kbin.run
        link
        fedilink
        arrow-up
        4
        ·
        edit-2
        2 months ago

        Since you are interested in practical examples, I would recommend you watch and maybe even follow along with Ben Eater’s 6502 breadboard computer series on YouTube (piped link). The kit is cheap and works great but more importantly it introduces so many core concepts about how computers actually work from a raw metal and machine code standpoint while touching on so many different aspects about computers that still apply today.

        • LainTrain@lemmy.dbzer0.comOP
          link
          fedilink
          arrow-up
          2
          ·
          2 months ago

          Yeah I’m a big fan of this actually! I remember putting together a half adder with some breadboards, never got to the full computer because I didn’t have the drive to do so and felt like I understood the concepts well enough, but yes this is awesome!

    • LainTrain@lemmy.dbzer0.comOP
      link
      fedilink
      arrow-up
      3
      ·
      edit-2
      2 months ago

      This resource was 100% exactly what I was looking for. Now gonna setup an env and play with the examples! Thanks so much!

  • mox@lemmy.sdf.org
    link
    fedilink
    arrow-up
    4
    ·
    2 months ago

    I think you might find some illustrations & examples of what you want by searching for return-oriented programming, rather than just buffer overflows.

  • sharky5740@techhub.social
    link
    fedilink
    arrow-up
    2
    ·
    edit-2
    2 months ago

    @LainTrain There used to be approximately a million examples floating around in the web. You could just write a simple program with a fixed-size stack buffer at a repeatable address, overflow a return address with a crafted string, return to the overwritten stack buffer full of shellcode. All of the mitigations (stack canaries, W^X, ASLR, CFI, canonical addresses, …) mean that you have to either use much more elaborate techniques (ROP/return to libc, address leaks, …) or you have to disable the mitigations to see a working exploit example, which is pretty unimpressive.

    • LainTrain@lemmy.dbzer0.comOP
      link
      fedilink
      arrow-up
      3
      ·
      2 months ago

      Thanks! The reason I was looking for an example is because I understand:

      overflow a return address with a crafted string, return to the overwritten stack buffer full of shellcode

      In principle, but not in practice. Especially the last part.

      I have my char buf[16] and some char * ptr = buf; and then a gets() gets a 20 char string, causing a buffer overflow either then or when the buffer is read where it reads out of bounds.

      I’ve done this many times, sometimes intentionally, and if I visualize the memory as one continuous line where the ptr is stored at the precise address buf[20] is at, allowing me to write into that memory location a new address for the pointer by having part of the string given to gets() be a new memory address at the address of ptr, so that next time that pointer is accessed in a program, it leads to an arbitrary memory read, and the arbitrary pointer address can be to still further down in the initial string we gave to gets(), e.g. buf[40] where our shellcode is stored, but how to do this - implement it in practice (so - in code), I don’t really know.

      Specifically I don’t know how to make a pointer at a predictable constant address so it’s stored address can be overwritten, and how to make the reading of the resulting maliciously modified pointer also somehow execute code. I’m guessing it can’t just be a char pointer reading in data, right?

      • sharky5740@techhub.social
        link
        fedilink
        arrow-up
        0
        ·
        2 months ago

        @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).

        • LainTrain@lemmy.dbzer0.comOP
          link
          fedilink
          arrow-up
          1
          ·
          2 months ago

          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?

          • sharky5740@techhub.social
            link
            fedilink
            arrow-up
            1
            ·
            edit-2
            2 months ago

            @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.

            • LainTrain@lemmy.dbzer0.comOP
              link
              fedilink
              arrow-up
              1
              ·
              2 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.

  • j4k3@lemmy.world
    link
    fedilink
    English
    arrow-up
    1
    ·
    2 months ago

    IIRC, the Nintendo Game & Watch hack on YouTube covers this with a STM32H7 on the little Mario handheld game from a few years ago.