Hello I'm quite new to C and in a nutshell I was doing the following as part of my assignment in class:
foo (char *var) {
printf(var);
}
I was told that this is bad practice and insecure but did not get much detailed information on this by my tutor. I assume that if the string value of var is controllable by the user it may be used to perform a bufferoverflow? How would I properly harden this code? Do I have to limit the str length or something?
Cheers & Thanks!
You should use:
printf("%s", var);
instead. The way you have it, I could enter %s as my input, and printf would read a random piece of memory as it looked for a string to print. That can cause any amount of unexpected behaviour.
This is UNSAFE because it could lead to a Format String Attack
Well, the first argument of printf is a format string. So the caller of your function could pass:
foo("%d")
and then printf would look for an integer which isn't there, and cause undefined behaviour. One possible fix would be for your function to call:
printf("%s", var);
which would have printf interpret var as a regular string (rather than a format).
Printf has the following signature:
int printf(
const char *format [,
argument]...
);
If the user inputs format characters for example %s all kinds of bad things will happen.
Use puts if you just want to output the string.
Related
user_input = "%s%s%s%s%s%s%s%s";
printf("user input is: %s", user_input);
... crash!
The above lines cause an error. I want to write a function which can be used like printf but can sanitize all arguments after the first to make sure they do not contain the % symbol. The function should be used like 'printf' in that it can take any number of arguments and it print outs a string in the same manner. If the other arguments contain the % symbol, I just want that symbol taken out before it is put in the format string.
If this new function were called safe_printf, I would want the behavior to be like this:
user_input = "%s%s%s%s%s%s%s%s";
safe_printf("user input is: %s, user_input);
user input is: ssssssss
It seems like writing a function like this may not be possible, (I can't figure out how to preprocess the char *s in the va_list without knowing how many there are) if that's the case please let me know. Thanks!
The string formatting vulnerability exists if user provided input is passed to the printf(3) function. You can prevent this by not allowing that happen, ever. There is absolutely not reason to have a dynamic format string because you should know ahead of time the required format, and therefore you can put the format string in read only memory through the use of a const char *
Task: Write two possibilities printf commands to print the following char array.
char str[] = "Im a sentence";
I found out one:
printf("%s", str) // this prints: Im a sentence
But i need another one, can anyone help me?
It's a silly question, but they are probably looking for this:
printf(str); // 1
printf("%s", str); // 2
Note that (1) is not considered good practice, but it is valid and it works.
The other one would be passing the string directly to printf:
printf(str);
As long as str is free of format specifiers, this is going to work. However, you should avoid using this in production code, because the compiler would be unable to properly diagnose potential mismatches between parameter types and format specifiers, which could lead to undefined behavior.
int x;
for (x=0;x<strlen(str);++x)
printf("%c",str[x]);
i am learning now c and i come up with this example, where i can print a text using pointers.
#include <stdio.h>
main ()
{
char *quotes = "One good thing about music, when it hits you, you feel no pain. \"Bob Marley\"\n";
printf(quotes);
}
I get a warning from the compiler "format not a string literal and no format arguments" and when I execute the program it runs successfully.I read some other questions here that they had the same warning from the compiler but I didn't find an answer that fits me. I understood the reason why i get this message:
This warning is gcc's way of telling you that it cannot verify the format string argument to the printf style function (printf, fprintf... etc). This warning is generated when the compiler can't manually peek into the string and ensure that everything will go as you intend during runtime...
Case 3. Now this is somewhat your case. You are taking a string generated at runtime and trying to print it. The warning you are getting is the compiler warning you that there could be a format specifier in the string. Say for eg "bad%sdata". In this case, the runtime will try to access a non-existent argument to match the %s. Even worse, this could be a user trying to exploit your program (causing it to read data that is not safe to read).
(See the answer)
but what i have to add in my case to in order to have not warnings from the compiler?
Change it to printf("%s", quotes); which adds the specifier that quotes is a 'string', or array of char.
You need to tell printf what is it that you are printing. %s descriptor will tell printf that you are printing a string.
Format of printf = ("descriptor of what type of data you are printing",variable holding the data);
descriptor for strings is %s, for characters %c, for int %d
Change printf to:
printf("%s",quotes);
You have to specify format string - in simplest form:
char *quotes = "One good thing about music(...)\n";
printf("%s", quotes);
or, you can use format string to decorate output:
char *quotes = "One good thing about music(...)"; // no newline
printf("%s\n", quotes); // newline added here
or, if you don't want to mess with format strings:
char *quotes = "One good thing about music(...)"; // no newline
puts(quotes); // puts() adds newline
or
char *quotes = "One good thing about music(...)\n";
fputs(quotes,stdout);
This warning is gcc's way of telling you that it cannot verify the format string argument to the printf style function (printf, fprintf... etc). This warning is generated when the compiler can't manually peek into the string and ensure that everything will go as you intend during runtime. Lets look at a couple of examples.
So as other suggested explicitly use format specifier to tell the compiler...i.e.
printf("%s",quotes);
You are getting the warning because it is dangerous when the string you are printing contains '%'. In this line it makes no sense for percents but when you want to print this for instance:
int main ()
{
int percent = 10;
char *s = "%discount: %d\n";
printf(s, percent);
return 0;
}
your program will likely crash when printf encounters the second percent and it tries to pop a value from the stack from printf.
When you want to print a percent sign use: "%%discount:"
Try this:
#include <stdio.h>
main ()
{
char *quotes = "One good thing about music, when it hits you, you feel no pain. \"Bob Marley\"\n";
puts(quotes); //Either
printf("%s",quotes);//or
return 0;
}
Say we are working in C.
if I go ahead and do this:
char *word;
word = "Hello friends";
printf(word);
then XCode tells me that because I'm not using a string literal, that I might have something that is potentially insecure. Does that mean an opening for something to hack my program? If so, how could that happen?
Alternatively, if I do this:
char *word;
word = "Hello friends";
printf("%s", word);
Then XCode raises no flags and I'm fine. What exactly is the difference?
The first argument to printf is not the string you want to print. It's a format string. It can contain formatting instructions which results in the string that is printed once it is combined with further arguments.
Your first example is an uncontrolled format string vulnerability.
The issue is that in the first case if word contains formatting specs (%d, %f, %s, etc.) then printf() will assume those values are on the stack, but in fact they aren't, which could lead to a crash.
Use puts() or fputs() instead if you don't care about formatting.
I am writing a code like this using snprintf():
char myId[10] = "id123";
char duplicateId[10] = "";
snprintf(duplicateId, 10, myId);
As you can see, I am not specifying the format specifier %s explicitly.
Do I need to explicitly specify the format specifier in the above snprintf() statement like this snprintf(duplicateId, 10, "%s", myId);?
No, you don't have to, technically. But it's better practice to do so, because without a constant format string, your format string remains modifiable thus your code will be more prone to format string attacks.
Ah, and also use sizeof(duplicateId) instead of a constant 10 - also for security reasons (in order to avoid future buffer overflows when changing the size of the output buffer of sprintf).
No you dont, but it's generally considered a good idea especially if there's any chance of passing user-input text to snprintf(). If the user enters a string with % in it otherwise, there will be trouble:
const char *userString = "%";
snprintf(duplicateId, sizeof duplicateIt, userString); /* BAD */
const char *userString = "%s";
snprintf(duplicateId, sizeof duplicateIt, "%s", userString); /* GOOD. */
It will be better to use %s since it is more secured... Don't you get a warning for this?
try to compile in the highest warning level, as well.
read more here