Hey enthusiasts ✋✋,
I’m back again with my 4th part of the adventure Binary-Exploitation series. First of all, I wanna apologize for the crevices. The work was boisterous, & a few health issues were there. Presently, I’m fine after the surgery. Let’s keep that all apart, and now it’s time to begin.
Already we examined what’s a buffer overflow & how it resists shellcode execution by utilizing NX. If you’re new to this topic, a few terms may be uncommon. So it would be ideal if you check out the past parts for a better understanding. In case you’re stuck or gone completely, it’s okay. It needs a bit of practice.
Before plunging into our main theme, I wanna instruct you on a little tactic that’s commonly used for bypassing the NX.
So before getting into the assault stage, I’ll clarify a brief around libc. Libc is commonly used as a shorthand for the “Standard C library”. It’s a library of standard functions that can be utilized by all C programs. You can check out the Linux Manual for better ideas :)
Every time you engage in C programming, you’re sure to utilize one or the other inbuilt capabilities like printf, scanf, puts etc. All the standard C capacities have been compiled into a single file, named the “Standard C library” or the libc. The C standard library provides data definitions and functions for tasks, I/O handling, memory management, Mathematical computations, macros(“macro instruction”)- it’s a rule or pattern that indicates how certain inputs ought to be mapped to the replacement outputs. Macros are utilized for making the programming task less tedious and less error-prone by arranging computing instructions accessible by the programmer as a single program explanation. Several other OS services are also provided by libc. Some languages include the functionality of the standard C library in their possess libraries. The library may be adapted to superior suit the language’s structure, but the operational semantics are kept comparable. The C++ language, for case, incorporates the functionality of the C standard library within the namespacestd. In Python 2, for illustration, the built-in record objects are defined as “implemented utilizing C’s stdio package. Rust has a crate called libc which allows several C functions. Likewise, many… many… things to talk about.
The libc contains all the standard capacities that can be utilized by any C program. It’s ‘linked’ to the binary at execution time. Understanding the libc is pretty important from an exploitation point of view as we can divert the control stream to libc functions. Now we gonna focus on the system function.
Within the regular stack overflow attack, as we know there’s no stack protection. So we’re overwriting the return address with the address of the shellcode that we injected on the stack and it gets executed. However, if the vulnerable program’s stack is protected (NX bit is set), we can no longer execute our shellcode. These all we covered previously, and that’s how we started ROP or Return oriented programming.
In return-to-libc (ret2libc) technique, the return address will overwrite with a memory address that points to the system() function present in the libc library.
The C library function int system(const char *command) passes the command name or program name specified by command to the host environment to be executed by the command processor and returns after the command has been completed.
When we overwrite the return pointer to the address of the system() function, the program will jump to the system() function. And command that we passed as the command argument gets executed. We want the vulnerable program to spawn the shell, so we’ll make the vulnerable program to call system(“/bin/sh”).
So let’s do with an example. It would be ideal if you note that the code is made by myself to make my pursuers understand the circumstance. Don’t anticipate such scenarios within the genuine environment until “we reach our core topics.” (These are fair essentials)
The function overflow is vulnerable. So performing no mistakes, let’s dive in.
In case you’re lost or don’t get something, which means either you don’t cover the basics otherwise, you don’t contribute time within the previous parts.
Segmentation fault !! & the offset is determined via python. Now it’s time for debugging.
python2 -c 'print("A"*72)' > expgdb -q ./ret2libcr < exp
So it’s clear that we will take control of the instruction pointer rip to execute the instruction that we want. I precisely embellished the idea of exploitation above. I’m gonna make it happen. 1st of all, let’s discover the base address of libc by using ldd.
Cmd: ldd Ldd is a Linux command-line utility that’s utilized in case a user needs to know the shared library conditions of an executable or indeed that of a shared library. It prints the shared objects (shared libraries) required by each program or shared object specified on the command line.
So here we got the base address of libc. Now let’s figure out the address of “system function” & argument “/bin/sh” for popping the shell.
Cmd: readelfreadelf is a program for displaying various information about object files on Unix-like systems such as objdump.
Cmd: stringsIt could be a complex task for a human to discover out content from an executable file. The binary files, such as program records, contain human-readable content. It basically focuses on determining the contents of and extricating content from the binary files.
We’re utilizing these commands for finding the address of the “system function” & the argument “/bin/sh” & In case you’ve any apprehension about the corresponding flags check out the Linux manual.
Cmd: readelf -s /usr/lib/libc.so.6 | grep systemCmd: strings -a -t x /usr/lib/libc.so.6 | grep /bin/sh
We’ll utilize little snippets of assembly within the binary, called “gadgets.” These gadgets ordinarily pop one or more registers off of the stack and then call ret. We can set up a fake call stack with these gadgets to consecutively execute them, poping values we control into registers, and then conclude with a jump to the system (As expounded in part — > 0x000002).
We’ve comprehended everything that necessitates exploitation. By using python2 let’s develop our exploit & pop up the shell :)
Ideally, I completed writing a slick exploitation script via python. Now let’s run it.
Yeah! We bypassed the NX without shell-code.
The strategy succeeds. The steady shell is pop-upped. We effectively bypassed the security implementation of NX bit.
Are you missing the shell-code injection on the stack?
Probably you’ll think that even if we inject, we can’t pop up the shell because of the NX bit.
As I always say, Hackers never quit!
'm' for memory & 'protect' for protection
The mapped memory regions, also called shared memory areas, can serve as a large pool for exchanging data among processes. In Unix-like operating systems, mprotect() is a POSIX system call for controlling memory protections. The mprotect() is a protecting kind of a function. It sets protection for memory mapping.
#include <sys/mman.h> int mprotect(void *addr, size_t len, int prot);
addr: Is the starting address of the region for which the protection has to be changed.len: Is the length of the region, in bytes, whose protection has to be changed.prot: Is the desired protection of the memory mapped region.
As it’s clear about addr & len, now let’s talk about prot.
The mprotect() function changes the access protections to be that specified by prot for those whole pages containing any part of the address space of the process starting at address addr and continuing for len bytes. The parameter prot specifies whether read, write, execute, or some combination of accesses are permitted to the data being mapped.
PROT_NONE: The memory cannot be accessed at all.PROT_READ: The memory can be read.
PROT_WRITE: The memory can be modified.
PROT_EXEC: The memory can be executed.
There’re many techniques to bypass an NX stack by entreating the mprotect() function. Let’s go through a suitable one by injecting the shellcode on the stack & making that region executable.
function: mprotect(void *addr, size_t len, int prot);1. Pass the stack address on *addr2. The desirable size as len (here we choose stack length in hex)3. Finally, PROT_EXEC has to be set in prot for making the selected area executable.PROT_EXEC: The memory can be used to store instructions which can then be executed.
“- - -”
“r- -“
“-w-”;
“rw-”;
“--x”;
“r-x”;
“-wx”;
“rwx”;
So we need to set the stack address in the RDI register, the length in the RSI register and the value 0x7 (rwx) in the RDX register. (The calling convention for 64 bit is arguments in RDI, RSI, and so on…)
In case it appears like you’re totally lost, that’s okay! It takes time to understand. Attempt to overview at a technical level instead of memorizing.
I’m utilizing the same binary that we handled to elaborate the ret2libc. So it’s time to establish our exploit.
By debugging, it’s able to discover the address of mprotect.
The stack address must be passed in addr. We’ve to examine the stack by debugging. All these concepts were previously discussed. So I’m gonna rush the topic. We need to put the stack address within RDI register
The next step is to set the length (len) in the RSI register and the value 0x7 (rwx) in the RDX register.
Before the ret, the pop rsi gadget is followed by pop r15 instruction.
pop rsi
pop r15
retNote: Therefor we’ve to construct an exploit that nourishes garbage to r15.
Utilizing ldd we can determine the libc address (already examined). Utilizing ROPgadget, able to discover the gadget RDX. (RDX will not be found on our binary, we’ve to look into libc).
ROPgadget.py --binary <path-to-libc> | grep "pop rdx ; ret"
By invoking the mprotect() function we made the stack zone executable & hence, we were able to infuse our shellcode. The rip pointed zone (shellcode) was then executed, and we got the shell.
Similarly, we can pop up the shell by other techniques. NX gives a few levels of assurance, but not tons. It somewhat limits the flexibility of what an attacker can do with the initial issue, but given he can use that exploit to execute a shell, there’s not a lot of safety there.
The lesson to learn:
NX can’t “single handly” protect a program from exploitation.
There is no such thing as “secured compilation” there are some security mitigations, but depending on the kind of vulnerability, you often can bypass them.
Is that all accomplished? Did we circumvent every security technique?
The simplest answer is: NO
Address space layout randomization (ASLR) is a computer security technique included to defend the exploitation of memory-corruption vulnerabilities. ASLR randomly orchestrates the address space positions of key data ranges of a process, including the base of the executable and the stack positions, load and libraries to block an aggressor from dependably jumping. Attackers trying to perform return-to-libc attacks on NX enabled binary must locate the code to be executed (just like we bypassed NX before). Attacker needed locations are randomly placed and security is increased. If the attacker does not know the addresses used by the target process, then the ROP, ret-to-libc and other exploit mechanisms will be insane.
ASLR works considerably better on 64-bit systems, as these systems provide much greater entropy (randomization potential). ASLR enhances the control-flow integrity of a system by making it more challenging for an attacker to execute a successful buffer-overflow attack by randomizing the offsets it uses in-memory layouts. Note that “checksec” will not implicate you about ASLR, because protection is the property of the machine and not the binary. Command shown below will tell you whether ASLR is enabled on your system.
cat /proc/sys/kernel/randomize_va_spaceOutput0 = Disabled
1 = Conservative Randomization
2 = Full Randomization
“ So our next ensuing duty is to bypass NX + ASLR ”
The romance of NX & ASLR creates an influential debenture built-in protection. We need to work on it. Once if ASLR is bypassed, it is typically straightforward to exploit NX using the Return Oriented programming.
Can we do that…? How can we break it…?
It necessitates a practical necromancy
I don’t wanna make it long, spending time by surging stuff on your head, so for a time being, I’m concluding this right now. You need to take a few exertion to get it how the things works. I personally abhor spoon feeding as well. In the coming write-up, I’ll demonstrate how to do this. Till then, stay curious. And don’t forget to connect with me.
My twitter id: @7h3h4ckv157