About Format String Attack for D's *writef*()

is91042 xrwang at cs.NCTU.edu.tw
Thu Oct 5 00:01:30 PDT 2006


Format string attacks are a problem of C's printf().

Consider the following C code:

	char name[100];
	printf("Please input your name: ");
	scanf("%s", name);
	printf(name);

If a user type "John", he will get:

	Please Input your name: John
	John

However, he may type "John%sWang" and get:

	Please Input your name: John%sWang
	JohnJohn%sWangWang (This may depend on the runtime environment.)

These bugs may be prevented by saying to the programmers:
"Don't let the input of a user be the first argument of printf()"
because printf() only interprets the first parameter as a format string.
But we can't just do the same thing to prevent the bugs for *writef*()
because of the power of *writef*().

The problem is *writef*() can interpret not only the first but also many
parameters as format strings.
Consider the following code.

	int x=123, y=321;
	writefln("This is a test: %s. ", x,
		"And this is another test: %s.", y);
	writefln("This is a test: %s.",
			"And this is another test: %s.", x, y);

And the output will be:

	This is a test: 123. And this is another test: 321.
	This is a test: And this is another test: %s..123321

It shows that *writef*() interpret any string as a format string if it way
not assigned by any other format strings.

Consider the following code.

	char[] user_name;
	writefln("Please Input your name: ");
	din.readf("%s", &user_name);
	writefln("Your name is ", user_name, ". And my name is Peter.");

If a user type "John", he will get:

	Please Input your name:
	John
	Your name is John. And my name is Peter.

However, he may type "John%sWang":

	Please Input your name:
	John%sWang
	Your name is John. And my name is Peter.Wang

Its behavior is so strange and is not what we expected.

Although we can use the same approach that we requires the programmers
put an argument "%s" before every string affected by users, I think it
is not a good privacy because it requires an extra heavy load for
programmers and loses the convenience of that *writef* can treat many
arguments as format strings.

So, I suggest a solution: Add a new type 'fstring' as the meaning
"format string" and *writef*() will do different thing for fstrings
and strings. If a string is encountered, they dump the string.  If a
fstring is encountered, they do the same thing as before.

Moreover, for easily creating a fstring, we can use f" and ".
For example:

	writefln(f"Your name is %s", user_name, ". And my name is Peter.");



More information about the Digitalmars-d-bugs mailing list