0

I am absolutely new to C programming. Currently I am preparing for my new course of studies IT Security. In a slightly older exam I found a task where I have no approach how to solve it. The task is in German. In principle it is about finding critical errors.

It is not written how the passed parameters look like.

1) I have come to the point that you should not use strcpy because it has no bounds checking.

2) Also char[10] should not be used if you want to store 10 characters (\0). It should be char[11].

Is it possible to read Adresses or write sth due the printf(argv[1]) command ?

I would like to mention again that you help me here personally and do not help to collect bonus points in the university.

#include <stdio.h>

int main(int argc, char *argv[])
{
    char code[10];

    if(argc != 2) return 1;
    printf(argv[1]);

    strcpy(code, "9999999999");
    for(int i = 0; i < 10; ++i){
        code[i] -= argv[1][i] % 10;
    }

    printf(", %s\n", code);

    return 0;
}
SeRo
  • 85
  • 7
  • Copy code into question. – Fiddling Bits May 01 '20 at 14:49
  • 1
    Compile it with `clang -Weverything` for example. – Fiddling Bits May 01 '20 at 14:52
  • You're using `code` before it's initialized here: `code[i] -= ...`. You're assuming length of `argv[1]` is `10` or greater. – Fiddling Bits May 01 '20 at 14:53
  • 2
    For future questions you might post here: Please don't post pictures of text, post text as text. If you need to retype it, then do it. – Jabberwocky May 01 '20 at 15:04
  • Also `code` is ten chars long, but you need 11 chars for `"9999999999"` because of the NUL terminator or strings (read more about this in your C text book). So `strcpy` copies one byte beyond the end of the `code` array. – Jabberwocky May 01 '20 at 15:10
  • 1
    @FiddlingBits `code` is (wrongly) initialized with the `strcpy`. – Jabberwocky May 01 '20 at 15:11
  • @Jabberwocky True. Missed that. – Fiddling Bits May 01 '20 at 15:11
  • 1
    And there is nothing wrong with using `strcpy` as long as you make sure that the destination buffer is large enough. – Jabberwocky May 01 '20 at 15:14
  • Okay, thanks a lot! Sorry for the wrong formatting. Next time I'll type in the code. I don't have a compiler yet. I was just watching a lecture and wanted to solve tasks from the last years to write a good summary. I have one last question. In line 4 argv[1] is printed, is it possible to write something into the stack or read addresses ? – SeRo May 01 '20 at 15:24
  • You *do* have a compiler: https://godbolt.org/ – mlp May 01 '20 at 15:38
  • I tried it. Different Compilers give me different feedback even with -Weverything or Wall or Wextra. Clang gives me a warning about the print(argv[1]) command. GCC warns me the strcpy(). Thank you :). – SeRo May 01 '20 at 16:00
  • `printf(argv[1])` is a [format string vulnerability](https://en.wikipedia.org/wiki/Uncontrolled_format_string). The attacker can get the program to output various parts of its memory, and possibly also write them using `%n`. – Nate Eldredge May 01 '20 at 18:29

1 Answers1

0

See related.

you should not use strcpy() because it has no bounds checking

Nothing in C has bounds checking unless either

  • the compiler writer put it there, or

  • you put it there.

Few compiler writers incorporate bounds checking into their products, because it usually causes the resulting code to be bigger and slower. Some tools exist (e.g. Valgrind, Electric Fence) to provide bounds-checking-related debugging assistance, but they are not commonly incorporated into delivered software because of limitations they impose.

You absolutely should use strcpy() if

  • you know your source is a NUL-terminated array of characters, a.k.a. "a string", and

  • you know your destination is large enough to hold all of the source array including the terminating NUL

because the compiler writer is permitted to use behind-the-scenes tricks unavailable to compiler users to ensure strcpy() has the best possible performance while still providing the behaviour guaranteed by the standard.

char[10] should not be used if you want to store 10 characters (\0)

Correct.
To store 10 characters and the terminating NUL ('\0'), you must have at least 11 characters of space available.

Is it possible to read Adresses or write sth due the printf(argv[1]) command ?

In principle: maybe.

The first argument to printf() is a format string which is interpreted by printf() to determine what further arguments have been provided. If the format string contains any format specifications (e.g. "%d" or "%n") then printf() will try to retrieve corresponding arguments. If they were not in fact passed to it, then it invokes Undefined Behaviour which is Bad. An attacker could run your program giving it a command-line argument containing format specifiers, which would lead to such UB.

The right way to print an arbitrary string like this with printf() is printf("%s", argv[1]);

mlp
  • 809
  • 7
  • 21