TransWikia.com

Are call stack addresses predictable with all protections disabled?

Information Security Asked by Maikkeyy on October 28, 2021

I’m currently practicing buffer overflows, but there is one thing I don’t understand yet. I have read this similar question. I understand that if you don’t know the address of ESP you must look for an address that executes JMP ESP to jump to the injected shellcode.

But do you really don’t know the address of ESP? You do know the address of EIP, because you detected the point where EIP is overwritten or do you only know the offset of the EIP from your injected buffer? If so, then even no address is known to an attacker (ESP included ofcourse) and the attacker has to work with offsets only?

The picture below I’ve made shows the position right when the program has popped the return address.

Stack

Can’t you just do any of these actions:

  • Inject JMP ESP directly into the address of EIP, why do you need to find an address that performs this call?
  • Add +4 to the return address as the shellcode comes right after the return address

I’ve read that the return address must point to another address that does JMP ESP is necessary, because of ASLR and a possible different depth of the call stack. I don’t understand what is meant with the latter, does somebody have an example? Isn’t the shellcode always right after the overwritten EIP?

And if ASLR is not enabled, do you then still have to find an address with JMP ESP?

EDIT:

My main question is: Why does the state of the stack at a moment in time influence the stack pointer? I’ve read that this makes it hard for the attacker to predict the stack addresses. But if you have a program that you start up again and again, then the same amount of variables and procedures are executed, so the stack size always will be the same.

After some talking with a colleague, he thinks they mean with that the situation of a Apache Webserver that handles requests and responses and performs a lot of actions. When you fire your buffer overflow exploit you don’t know where in the execution the stack is. This opposed to having a program on your own pc that you can start over in the same manner again and again. Is this assumption correctly?

With all protections disabled; can you know the location of the stack in memory? Is the bottom of the stack a fixed address?

All the examples of exercises made me confusing, because that is not the real-world scenario. In the debugger you CAN see the stack addresses being modified, but you can’t when remotely exploiting a buffer overflow. That’s the reason why I thought you know the EIP and ESP address while exploiting, but that is only when you are using a debugger.

2 Answers

For myself and other people who want a brief overview of the things discussed I will answer my own question for the sake of clarity.

The confusion arose when I read that the address ESP points to (after overflowing EIP) can’t be used to effectively jump to the shellcode as the address changes dynamically. At the same time, I was working with the debugger to exploit a buffer overflow with all protections disabled, just seeing all the addresses and them not changing. So why is the ESP then a dynamic value?

Well, there are actually two (exploitable) situations:

  • Locally, where you always run and restart an application in the same way
  • Remotely, where the application is already running and you not knowing in what state it is

Think of a program that reads configuration files out of a directory and if you have that program locally you KNOW how much config files are stored in the local directory. But you don’t know how much config files are stored on the remote machine, thus putting the stack in a different state or call stack depth. You don’t know how far the application is in reading the files, so the top of the stack (ESP) could be different than what it is on your local computer. I think another example is an Apache webserver of which you don’t how far it is with handling requests.

So my question was: “But do you really don't know the address of ESP?” and yes you do if you test it locally, but it is not reliable remotely. All this goes for the situation where no protection is enabled. This brings me to another point, namely the situation where protections have been put in place.

ASLR

This protection also ensures that you cannot rely on the address you see in the debugger to return to after overflowing, because the addresses are frequently randomized. Gdb disables ASLR by default, so you could make your exploit work there, but it is not representative for real-world scenarios. Even running the vulnerable program out of the debugger results in your exploit not working, because the hardcoded address where the program must return to doesn't exist anymore as all the addresses are randomized upon each execution.

So this is even a problem locally and of course remotely.

So, to summarize: the following situations affect the stack layout in a target application:

  • State/call stack depth

  • Variable memory allocations within functions based on external parameters

  • Different code paths that make use of the vulnerable code

  • Protections based on memory-randomization

Conclusion

This all boils down to the reliability of your crafted exploit AFTER debugging. So utilizing a gadget like “jmp esp” is necessary, because you don’t have to jump to an absolute address which you can’t predict easily (call stack depth/state, aslr), but instead it jumps to the correct address on behalf of you.

Answered by Maikkeyy on October 28, 2021

[why can't you] inject JMP ESP directly into the address of EIP, why do you need to find an address that performs this call?

First of all, EIP is a register in x86. It itself does not have an address pointing to it. What you mean to say is more along the lines of "the value on the stack that will be popped into EIP at time of return". This is important, because you can't just "inject" or put instructions into EIP; it only holds a 4-byte address pointing to the memory address of the instruction to be executed. If you tried to put the opcodes directly in EIP, you'd get a segfault since invalid memory would be accessed.

You might need the jmp ESP or a similar gadget in this case in order to redirect execution to an address you cannot (easily) guess, assuming ASLR is enabled.

[why can't you] add +4 to the return address as the shellcode comes right after the return address

If PIE is disabled (which is a fair assumption for an old fashioned exploit like this), then you are able to know the addresses of all the program's instructions. So you know where the program normally returns, but you don't know the stack address where that value is stored. So no, you can't add 4 to an address you don't know unless you are able to leak it somehow.

Isn't the shellcode always right after the overwritten EIP?

Not necessarily, it depends what is on the stack, or the shellcode could end up in the heap depending how the program is written. Technically, it would be before since it would be lower addresses.

And if ASLR is not enabled, do you then still have to find an address with JMP ESP?

No, if there is no ASLR or you are able to leak/guess/bruteforce where the stack is, you can use that address directly such that it ends up in EIP.

As far as call stack depth goes, maybe I'm not understanding the question, but I can't think of any impacts from that.

Answered by multithr3at3d on October 28, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP