Understanding Exploits – For Beginners (Part 1)

If you are here, you are most likely a beginner in the hacking community, so I'd like to give you a warm welcome 🙂

You decided to learn about exploits, and that is a good thing, so without further delays, I'd like to start making things clear about them. At first, being a beginner is very important to know there are multiple kinds of exploits for multiple scenarios. It really depends on what you want to achieve. You will see a lot of "beginner guides" on the internet explaining some crap like Buffer Overflows on 3 line of code apps – Yes, these are good guides if you are absolutely n00b as it sets the ground for the next things like ROP or even more advanced memory handling, but the problem is, they only provide *THAT* particular tutorial, which is useless.

Let's talk Exploits

See, exploits can be put in two main categories: LOCAL Exploits and Remote Access Exploits. There are, of course more types, but usually these 2 are the main ones. Local Exploits are running on the machine you want to exploit, but most of the times would requires physical access to the machine, unlike their counterpart, the Remote Access ones that can be triggered remotely.

To build an exploit, you need a vulnerability. I often hear "How can I find an exploit?". You don't really find and exploit, not literally, you find a vulnerability that you can exploit (unless you literally go searching for exploits on databases). One good place to analyze exploits would be https://www.exploit-db.com, it contains archives full of exploits (most of them patched in the last versions of the software they attack). So who is the main enemy of an exploit? Well, the patch. If we talk iOS Exploits, Apple can easily patch them (fix them) in the newest version rendering them useless: and that's taking us the next term used in the industry and that is: 0 day (or 0day, zero-day). 0 day term means an exploit that uses a vulnerability the company whose software is exploited isn't aware of, therefore they have 0 days left to patch it before the exploit can be used. Usually 0 days are exploits kept private, releasing them in the wild renders them patched sooner or later (sooner in case of Apple).

So to recap, exploits can either be local or remote, require a vulnerability and usually are created to change the flow of an application and to make it to do something it isn't programmed to do.

How can I write an exploit?

Exploits can be written in any programming language, with different difficulty levels. It is highly recommended to learn C, C++ and even Assembly (or ARM Assembly if your target is mobile) to be able to write your exploits. If that's too hard for you for the moment, Python is also very used for exploits, and is very friendly with the beginners. 

What is ShellCode?

If you dig a little bit into exploits you will find the magic term of "shellcode", shell code is usually written in assembly, but I've personally written shellcode in C and used a a script to automatically convert it. The shellcode is usually the payload you want executed on the compromised machine. A simple shell code is this:

"\xB8\xFF\xEF\xFF\xFF\xF7\xD0\x2B\xE0\x55\x8B\xEC"

"\x33\xFF\x57\x83\xEC\x04\xC6\x45\xF8\x63\xC6\x45"

"\xF9\x61\xC6\x45\xFA\x6C\xC6\x45\xFB\x63\x8D\x45"

"\xF8\x50\xBB\xC7\x93\xBF\x77\xFF\xD3

The above shell code is a Windows one for 32-Bit. It uses a buffer overflow to spawn a calculator instance (starts calc.exe). This is the standard form of a shellcode – of course, it can get very long depending on what you need, but pay attention to the actual space you have on the stack at your disposal.

Let's make things clear about Buffer Overflow Exploits:

A buffer overflow is a powerful exploit, thing is, it is harder to implement nowadays – MUCH HARDER than some people pretend in various tutorials on the web where they use totally unprotected apps – This scenario they're presenting is useless because nowadays most of the apps are NOT using gets(), which is the function they always use in their test dummies. gets() is actually so dangerous most of the compilers WILL REFUSE to compile an app containing it and will error out telling you your app is unsafe. To compile that you need to disable various protections and the app will still warn you about gets() at runtime. Anyways, nowadays applications use DEP (Data Execution Protection) which a very powerful mechanism that prevents executing payloads by exploiting buffer overflows.

The principle of a buffer overflow is simple: You find a vulnerable app (please no gets, pleaseee, the internet is full of it), and you start a process called fuzzing. Fuzzing involves stuffing the app with various inputs of variable lengths to trigger a Segmentation Fault 11 error. Basically, at that point your command gets past the Stack space in the memory and overwrites various registers (R15 being the target as it is the program counter PC). The program counter holds the address of the next instruction to be executed by CPU, so changing this will change the flow of the app. Now, don't take for granted the "secret" functions shown in all beginner tutorials across the internet – yes, they do show something correct, but nowadays no app developer is that stupid to create such vulnerable app, so you can't really make use of that technique. You will need to reverse engineer the application to find methods (functions) you may wanna call, but that already involves knowing Assembly, which no matter what others say, is a MUST in Security Research and Hacking. Once you've found the method you wanna return to, you just need the address of it and you're good to go right? NO. Nowadays apps use a technology called ASLR (Address Space Layout Randomization) that, in a nutshell changes the addresses of the methods in the memory at every runtime, and so you can't predict WHERE will the method you wanna return to, be at the time you run the sploit.

That not all, there are also buffer overflow protections (we call them Canaries) . Canaries are parts of the memory that usually prevent overflows by killing the app / erroring out when modified. Let me explain:

The canaries are small random integers positioned right before the stack return pointer for example: So if you use the classic and too popular buffer overflow thing by fuzzing with "AAAAAAAAABBBCCC" crap, you will get past the stack, write into the canaries and you will trigger the shutdown of the app before reaching the PC (program counter), so no, unless you patch / disable these security methods first, it won't be as easy as fuzzing the app with "AAAAAAAA".

But how the hell I bypass / disable ASLR?

Well, good question. ASLR usually is hard to bypass, either way it will be useless, so you need to leak a component, usually a pointer or anything that you can use to obtain its address, but for a beginner guide this is already too much, so if you wanna know in-depth, I invite you to read this whitepaper: https://www.exploit-db.com/docs/17914.pdf 

Why is it call stack btw?

Everything you application contains is being positioned in this "stack" in the memory that grows from the bottom and all the components get an address to be called by on the memory. In order for your program to work properly, it has to know where its components are loaded in the memory, for that we have various registers (usually general purpose registers, and special registers). R0 to R15 are the ones you'll encounter the most. As I said earlier, R15 is the PC (program counter) and it holds the address of the next instruction to be executed. There are also Stack Pointers, data registers (EAX, EBX, EDX, ECX), base pointer (BP), Instruction Pointer (IP) etc. Every app must contain these registers, more or less. For example, The SP (Stack Pointer) is a 16-bit register that works with SS register to provide the current layout or position of the data in the program stack. Don't worry if it seem hard, this is Assembly, you'll grow to love it as a hacker, it is hard only at the beginning. Just wanted to let you know about the existence of these registers because they're important and you will get to work with them a lot.

Let's take a real example:

We're going to analyze an exploit for OS X EL Capitan, written by Stefan Esser that is basically a Privilege Escalation.

What is Privilege Escalation? In a nutshell, if you are ~GeoSn0w, you probably are the admin of the Mac, but not the ROOT, so you are still limited in what you can execute – but if you are a limited user, like Guest, then you can't do too much. A Privilege Escalation Exploit is something definitely useful and usable in the real life (UNLIKE THE BLOODY GETS() APP), as it makes a totally limited user to have ROOT permissions and basically doom the computer if one will. 

If you've imagined an exploit as having thousands of lines of code, you were wrong.

echo 'echo "$(whoami) ALL=(ALL) NOPASSWD:ALL" >&3' | DYLD_PRINT_TO_FILE=/etc/sudoers newgrp; sudo -s 

Yes, that's the whole OS X 10.11.6. Two lines of code that gives you ROOT access over any OS X El Capitan machine. Cool ain't it? But how does it work?

Do you see the DYLD_PRINT_TO_FILE command in there? It gets as an argument the following file owned and only modifiable by ROOT: /etc/sudoers. This file on OS X contains the permissions of each user, so it is the main target if you want to obtain ROOT ACCESS but the file can only by written by ROOT. So, here we have DYLD_PRINT_TO_FILE, this is an environment variable of DYLD app (Dynamic Linker of the OS X). Due to a flaw on DYLD, the exploit is possible. 

Let me explain: DYLD_PRINT_TO_FILE takes the file you've set as a file in which the debugging data should be written. The little "&3" is the Descriptor 3. DYLD_PRINT_TO_FILE has 4 descriptors: 0 – stdin, 1 – stdout, 2 – errout and 3 – empty. Because 3 is empty we attach the file to it and so we're able to open the file in the memory. The next important piece is newgrp. Newgrp is a setuid app and is able to set different user permissions for different users. Powerful as this UNIX app is, it is still not enough to be able to write to a ROOT owned file unless called by ROOT, so? Where's the vulnerability? 

Once dyld opens the sudoers file owned by root, it will remain open in the memory and the next command calls newgrp with a root-owned file already open in the memory. Normally, before running setuid programs like newgrp, DYLD should sanitize / remove the  DYLD_PRINT_TO_FILE variables, but because the sanitization was done by Apple wrongly, the DYLD_PRINT_TO_FILE executes before pruneEnvironmentVariables and therefore, the file remains open.

The next thing that happens: DYLD_PRINT_TO_FILE dumps the result of $(whoami) ALL=(ALL) NOPASSWD:ALL to the sudoes. whoami will return the name of the user: in my case GeoSn0w, so "GeoSn0w ALL=(ALL) NOPASSWD:ALL", this makes GeoSn0w user to have SUDO permission and no password will be required.

From here, a new shell is spwned as ROOT and here you have it: You've got ROOT ACCESS! on OS X with 2 lines of code due to a simple vulnerability in DYLD. If you want to check out DYLD's source code, it is here.

See? This is a practical example where a small vulnerability turns into privilege escalation with a simple exploit.

And this is how an exploit tutorial for beginners should be written!

If you are more of a Visual Learner, here's a video I've made explaining this specific exploit. https://www.youtube.com/watch?v=KRi0iMWB6vQ

GeoSn0w

About GeoSn0w

C#, C, Objective-C Programmer | Beginner iOS Security Researcher | Content Creator | Web Developer I like to bring the latest news from the iOS / iDevice / Jailbreak battlefield to you in a beautiful manner :) I hope you like the site. If you do, don't forget to check out my channel :)

Leave a Reply