This will be a relatively quick article because it's a simple issue. The system function gets a lot of flak for being slow because it calls the shell runtime to execute a command, but I rarely see the more devastating issue of security brought up.

system is insecure in many cases. Let's use a simple example of opening Notepad on Windows:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    system("notepad.exe");
    getchar();
    return 0;
}

This works like a champ, so what's the problem? What if I told you that subverting this program is as simple as copying a malicious program into the same directory and calling it notepad.exe?

#include <stdio.h>

int main(void)
{
    puts("Malicious code! Arrrgh...");
    return 0;
}

Now instead of that lovely Notepad interface, you're met with a dastardly console message that your code has been hacked! Worse, the malicious code could do its evil and then open Notepad, with you none the wiser that bad stuff went down in between. If your program is run with superuser privileges, then the malicious program also has those privileges and can do a lot of damage.

Exercises

  1. Try it for yourself and see what happens.
  2. Does this work for built in commands like "cls"?
  3. Can you find a safe way to execute an external program?
  1. No need.
  2. Probably not, unless the function call was system(cmd.exe cls); - unfortunately since most of my programming is Unix/Linux I can't say. The Linux command to clear the screen is "clear" which is actually "/usr/bin/clear", so it should work, assuming the call was made in a program running in a console shell.
  3. This is why it is much more preferable to use full paths, and also the exec...() functions instead of system(...);

Final note - in your example, if the current working directory (.) is not before the directory holding "notepad.exe" in your PATH environment, then it will not work as you specify. I think this holds for both Linux and Windows systems; however, that is a MAJOR caveat! As in "caveat programmer"... :-)

if the current working directory (.) is not before the directory holding "notepad.exe" in your PATH environment, then it will not work as you specify

True, but it's merely one example. As long as the attacker can figure out where to place the malicious program, the hole exists.

This is why it is much more preferable to use full paths

Even if you use a full path, the problem still remains unless you can guarantee that the executable cannot be compromised.

Can you find a safe way to execute an external program?

No. It doesn't matter how you do it someone can always replace the intended program with his/her own malicious one. If you are that parinoid about it, the best way to prevent it is to not execute external programs at all.

i think that using system in our program reduce/destroy/neglect the most important feature and that is portability(moving program from one system to another) of the program.

let's imaging that if we are developing an application on Window OS. Upto Window Editions system will work but when we install our application on other OS(like linux etc.) then will through an error.

that's my opinion however right now , i don't have much knowledge in c++ , i am learning it.

Can you find a safe way to execute an external program?

What about checking a checksum on the executable before executing it? Something like this:

int secure_system_call(char* app_name, char* app_md5, char* app_args) {
  char* test_md5 = compute_md5(app_name);
  int cmp_result = strcmp(test_md5, app_md5);
  free(test_md5);

  if( cmp_result == 0 ) {
    char* full_name = malloc( strlen(app_name) + strlen(app_args) + 1);
    strcpy(full_name, app_name);
    strcat(full_name, app_args);
    system(full_name);
    free(full_name);
    return 0;
  } else {
    return ERROR_MD5_CHECKSUM_MISMATCH;
  };
};

where the compute_md5 would be some function that computes the MD5 checksum for the given file. And, of course, this assumes that you have some mechanism to securely acquire the expected checksum value for the application, which can be compromised too and is also a portability nightmare (unless you package the executable along with your own).

I'm sure there are also other ways to "verify" the authenticity of the executable. Doesn't Windows have some sort of way to do this? I'm pretty sure that signed packages in Linux environments provide this through MD5 or SHA-1 checksums.

Let's take AD's point to the extreme:

someone can always replace the intended program with his/her own malicious one

Okay, what if someone replaces libc with their own malicious one, with all of the original code in there, such that programs will still run, but there will be malicious code sprinkled through it? Of course, I'm intentionally taking things to extremes here.

Also, deceptikon's example doesn't work in Linux (well, not my installation...) To execute something in the working directory, it needs to be prefixed with a ./. I did a system("ls") successfully even when I wrote a program named ls and put it in the current directory. Sure, a hacker could replace /usr/bin/ls with a bad one, but they'd need to have root access. But if they had root access, they'd might as well do something worse to the system.

I'm not promoting the use of system(), just playing devil's advocate.

Edited 3 Years Ago by Assembly Guy

Also, just to add (apologies, I would've edited and tacked this onto my post above, but 30 minutes has passed) I've found the following to be fairly reliable at ensuring integrety of a program as long as you run a tight ship:

[asmguy@asmguybox ~]$ gpg -o test -d test.gpg && chmod +x test

You need a passphrase to unlock the secret key for
user: "Assembly Guy <asmguy@example.com>"
4096-bit RSA key, ID ########, created ####-##-## (main key ID ########)

gpg: encrypted with 4096-bit RSA key, ID ########, created ####-##-##
      "Assembly Guy <asmguy@example.com>"
gpg: Signature made Sat 30 Nov 2013 15:25:49 NZDT using RSA key ID ########
gpg: Good signature from "Assembly Guy <asmguy@example.com>"
[asmguy@asmguybox ~]$ ./test
Hooray!
[asmguy@asmguybox ~]$ 
This article has been dead for over six months. Start a new discussion instead.