CTF中常见的C语言输入函数截断属性总结

函数 截断字符 截断属性 截断字符是否保留 截断后加
read(0,a,0x100) EOF
*a = getchar() EOF
scanf("%c",a) EOF
scanf("%s",a) EOF 0x09 0x0A 0x0B 0x0C 0x0D 0x20 截断字符前有有效内容则截断,如无有效内容则跳过截断字符读后面 不保留 0x00
sscanf(a,"%s",b) 0x00 0x09 0x0A 0x0B 0x0C 0x0D 0x20 截断字符前有有效内容则截断,如无有效内容则跳过截断字符读后面 不保留 0x00
gets(a) EOF 0x0A 截断字符前无论有无有效内容均截断 不保留 0x00
fgets(a,256,stdin) EOF 0x0A 截断字符前无论有无有效内容均截断 保留 0x00
sscanf(a,"%[^;];",b) 0x00 0x3B 不保留 0x00
sprintf(b,"%s",a) 0x00 保留 无(相当于截断字符不保留,截断后加0x00)
strcpy(b,a) 0x00 保留 无(相当于截断字符不保留,截断后加0x00)
strcat(b,a) 0x00 保留 无(相当于截断字符不保留,截断后加0x00)
strncat(b,a,0x10) 0x00 保留 无(相当于截断字符不保留,截断后加0x00)
strncat(b,a,0x10) 到达拷贝长度 保留 如果到达拷贝长度,则自动补上0x00

当然EOF不是字符,是读取结束,linux在命令行里ctrl+D即可发送EOF给程序

测试代码如下:

# include <sys/types.h>
# include <sys/uio.h>
# include <unistd.h>
# include <stdio.h>

void debug(char * random){
    for(int i=0;i<0x120;i++){
        if((i%8==0)  && (i!=0)) printf("  ");
        if((i%16==0) && (i!=0)) printf("\n");
        printf("%02X ",random[i] & 0xff);
    }
    printf("\n");
}

int main(){
    char a[0x120]={0};
    char b[0x120]={0};
    memset(a,0xff,0x120);
    memset(b,0xff,0x120);
    read(0,a,0x120); // EOF ;结束不会加00
    //scanf("%s",a); // EOF 0x09 0x0A 0x0B 0x0C 0x0D 0x20 前面有截断后面,前面没有跳过读后面 ; 截断不保留;结束加00
    //gets(a); //EOF 0x0A 前面有没有都截断 ;截断不保留;结束加00
    //fgets(a, 0x101, stdin); //EOF 0x0A 前面有没有都截断 ;截断保留;结束加00 
    //for (int i=0;i<=0xff;i++){ * (a+i) = getchar(); }  //EOF
    //for (int i=0;i<=0xff;i++){ scanf("%c", a+i); } //EOF
    //sscanf(a,"%s",b);   // 0x00 0x09 0x0A 0x0B 0x0C 0x0D 0x20 0x00截断,其他的前面有截断后面,前面没有跳过读后面;截断不保留;结束加00
    //sscanf(a,"%[^;];",b); // 0x00 0x3b;结束加00;截断不保留;
    //sprintf(b,"%s",a); // 00 结束加00
    //strcpy(b,a); // 00 结束加00
    //debug(b);
    debug(a);
    return 0;
}

测试输入代码如下:

a = ""
for i in range(0,256,1):
    # if i == 0x00:continue
    # if i == 0x09:continue
    # if i == 0x0a:continue
    # if i == 0x0b:continue
    # if i == 0x0c:continue
    # if i == 0x0d:continue
    # if i == 0x20:continue
    # if i == 0x3B:continue
    a += chr(i)
print a