Looking for external program invocations

M

Mark Hobley

I have some open source software packages that were written in C by a third
party, they make use of external programs. For the purposes of security
auditing, and for making appropriate fixes, I need to locate all instances
within the code, where an external program is being called.

What keywords or functions would I need to locate?

I am thinking of using grep to simply search for the function names. Would
that be sufficient, or is it possible that function names are split across
several lines, making it possible for some instances to be missed during the
audit?

Mark.
 
F

Flash Gordon

Mark said:
I have some open source software packages that were written in C by a third
party, they make use of external programs. For the purposes of security
auditing, and for making appropriate fixes, I need to locate all instances
within the code, where an external program is being called.

What keywords or functions would I need to locate?

The standard one is system, but pretty much all systems where this is
possible have other functions as well.
I am thinking of using grep to simply search for the function names. Would
that be sufficient, or is it possible that function names are split across
several lines, making it possible for some instances to be missed during the
audit?

Well, if you are considering possibly malicious source code then they
could play games with #define to build the token 'system' from
components, or they could use inline assembler, or all sorts of other
things.
 
M

Mark Hobley

Flash Gordon said:
The standard one is system, but pretty much all systems where this is
possible have other functions as well.

This is Linux.
Well, if you are considering possibly malicious source code then they
could play games with #define to build the token 'system' from
components, or they could use inline assembler, or all sorts of other
things.

Thanks for that.

In these cases, the code is not malicious in this case, it is just badly
written open source code, that I need to track down the external software
calls, for the purpose of making changes.

So far ... I need to look for system, asm, and exec. Is there anything else?
(I know that I have to audit the libraries too).

Can the commands ever cross line boundaries causing failure of detection by
grep, such as in the example below? Or is this not possible?

syst
em("causedamage.sh");

In future instances, I may need to be able to track down tokenized system
call. Presumably, I could achieve detection of this via buildwrappers
on the preprocessor.

I may also need to look for utilization of specific library calls that cause
invocation of external commands. What strategy would be best for this (again
for future reference, of course).

Mark.
 
I

Ike Naar

In these cases, the code is not malicious in this case, it is just badly
written open source code, that I need to track down the external software
calls, for the purpose of making changes.

So far ... I need to look for system, asm, and exec. Is there anything else?
(I know that I have to audit the libraries too).

popen() / pclose()
 
F

Flash Gordon

Mark said:
This is Linux.

In that case you really need to ask in a Linux group...
Thanks for that.

In these cases, the code is not malicious in this case, it is just badly
written open source code, that I need to track down the external software
calls, for the purpose of making changes.

So far ... I need to look for system, asm, and exec. Is there anything else?
(I know that I have to audit the libraries too).

Well, they could use #define to make wrappers around any of the calls
which can invoke external programs... e.g.

#define SYSTEM(cmd) system(cmd)
Or something more complex.

Also, if it is badly written there are loads of other ways nasty things
could happen.
Can the commands ever cross line boundaries causing failure of detection by
grep, such as in the example below? Or is this not possible?

syst
em("causedamage.sh");

No, that cannot be done.

To be honest, if you don't know C well enough to know that then you are
not really in a position to do any form of audit on C code, especially
not a security or safety audit.
In future instances, I may need to be able to track down tokenized system
call. Presumably, I could achieve detection of this via buildwrappers
on the preprocessor.

That may assist.
I may also need to look for utilization of specific library calls that cause
invocation of external commands. What strategy would be best for this (again
for future reference, of course).

You really need to ask in a Linux group, since there may be all sorts of
Linux specific things which could do that.
 
M

Mark Hobley

Ben Bacarisse said:
but this can:

syst\
em("causedamage.sh");

So ideally we need a way of causing the preprocessor to warn that the code
causes invocation of external programs and to identify the lines of source code
where this takes place. I wonder if the GNU C preprocessor has that
capability...

Mark.
 
R

Richard Tobin

syst\
em("causedamage.sh");
[/QUOTE]
So ideally we need a way of causing the preprocessor to warn that the code
causes invocation of external programs and to identify the lines of source code
where this takes place. I wonder if the GNU C preprocessor has that
capability...

You can compile each file and then run something on the object code
(nm for unix-like systems) that will show you the names of external
functions referred to. You may also be able to determine the line
numbers, but even without that it will help you identify which files
contain calls to the functions you are concerned about.

-- Richard
 
M

Moi

I have some open source software packages that were written in C by a
third party, they make use of external programs. For the purposes of
security auditing, and for making appropriate fixes, I need to locate
all instances within the code, where an external program is being
called.

What keywords or functions would I need to locate?

I am thinking of using grep to simply search for the function names.
Would that be sufficient, or is it possible that function names are
split across several lines, making it possible for some instances to be
missed during the audit?

Mark.

Preprocessor to the rescue!!!!

I would create a header file which "overloads" system(), exec*() popen(), etc by
crowbar-macros ala:

#define system(a) do { \
(void) fprintf(stderr, "System(%s) called in %s:%d\n", (a), __FILE__, __LINE ); \
some_undefined_function(); \
} while(0)

And similar lines for exec*(), etc. (you could also choose to add a abort() )

The reference to some_undefined_function() would cause the linker to fail.
gcc has an option -include <somename>, which allows you to include such a header,
before doing anything else.

If you want protect yourself against
sys\
tem(...);
, you'll probably have to use inline functions instead.

HTH,
AvK
 
E

Eric Sosman

Preprocessor to the rescue!!!!

I would create a header file which "overloads" system(), exec*() popen(), etc by
crowbar-macros ala:

#define system(a) do { \
(void) fprintf(stderr, "System(%s) called in %s:%d\n", (a), __FILE__, __LINE ); \
some_undefined_function(); \
} while(0)

Forbidden in any module that includes <stdlib.h> -- that is,
forbidden in exactly those modules that are of concern. Also, not
entirely effective:

int (*fptr)(const char*) = system;
fptr ("evildeeds.sh");

or simply

(system) ("evildeeds.sh");

.... will evade this preprocessor trick.

You could try something along the lines of

#define system {] :-( [}

.... but even that could be defeated by

#include "moi.h"
#undef system
#include <stdlib.h>

And similar lines for exec*(), etc. (you could also choose to add a abort() )

The reference to some_undefined_function() would cause the linker to fail.
gcc has an option -include<somename>, which allows you to include such a header,
before doing anything else.

If you want protect yourself against
sys\
tem(...);
, you'll probably have to use inline functions instead.

I don't see what that has to do with it. Your preprocessor
magic would be no more or less effective because of the broken
line; line-splicing occurs before macro processing (which is why
macro definitions can be written with spliced lines).

Best bet for the O.P., I think, is to tackle the problem
with platform-specific tools like <ot> "nm" and "truss" </ot>,
and to seek advice in platform-specific groups. The C-based
advice he's getting addresses only part of his total problem.
 
B

Ben Bacarisse

So ideally we need a way of causing the preprocessor to warn that the code
causes invocation of external programs and to identify the lines of
source code

I would take Eric's advice. I'd do this after the compile not
before. Using system tools you can see what functions are linked to
the interpose your own wrappers wound the ones you care about.

<snip>
 
M

Mark Hobley

Moi said:
Preprocessor to the rescue!!!!

I would create a header file which "overloads" system(), exec*() popen(), etc by
crowbar-macros ala:

#define system(a) do { \
(void) fprintf(stderr, "System(%s) called in %s:%d\n", (a), __FILE__, __LINE ); \
some_undefined_function(); \
} while(0)

And similar lines for exec*(), etc. (you could also choose to add a abort() )

The reference to some_undefined_function() would cause the linker to fail.
gcc has an option -include <somename>, which allows you to include such a header,
before doing anything else.

Right, so I could incorporate this facility into a buildwrapper.
If you want protect yourself against
sys\
tem(...);
, you'll probably have to use inline functions instead.

So the preprocessor would not strip the continuation character to straighten
this out into system(...); then?

Ok, I need to look at that inline function thingy. I suppose an easier way is
to grep the code for any lines that utilize a continuation character before
starting the audit.

Mark.
 
S

santosh

Mark said:
Right, so I could incorporate this facility into a buildwrapper.


So the preprocessor would not strip the continuation character to straighten
this out into system(...); then?

AFAIK, it'll still do so. Inline functions won't help with your
specific problem.

<snip>
 
F

Flash Gordon

Mark Hobley wrote:

Ok, I need to look at that inline function thingy. I suppose an easier way is
to grep the code for any lines that utilize a continuation character before
starting the audit.

No, what you really need is to look for system specific tools and a
system specific list of functions to look for in a Linux group.

grep is a poor tool for this job.
 
M

Moi

Forbidden in any module that includes <stdlib.h> -- that is,
forbidden in exactly those modules that are of concern. Also, not
entirely effective:


Well, my idea was not intended as a cure, but more as a way to
detect or diagnose.
int (*fptr)(const char*) = system;
fptr ("evildeeds.sh");

In the case of a locally defined function (static, or even inline) "system()",
this would at least involve a name clash, and a diagnostic.

Maybe the safest way to detect the calls would be to use a stripped form of the
system libraries (but syscalls may be implemented via strange methods)


BTW/offtopic: for unix-programs, a way to avoid execution of external programs
would be to put the program in a chroot cage.

AvK
 
K

Kaz Kylheku

I have some open source software packages that were written in C by a third
party, they make use of external programs. For the purposes of security
auditing, and for making appropriate fixes, I need to locate all instances
within the code, where an external program is being called.

Whatever harm the program can do by launching an external program, it
can also do by replicating the actions of that program in its own code.

Suppose that it's ``evil'' to overwrite a file called /path/to/foo.
So of course you don't want the program running an external
command like "echo junk > /path/to/foo", right? But the program
can easily just open the file and overwrite it directly,
resulting in the same evil.

If you do not trust a program, you cannot simply concentrate your
mistrust only on those parts where it runs another program. You have
to mistrust every place where the program has any kind of interaction
with the environment; and moreover, any place where the program may
subvert the programming language, thereby gaining covert access to the
environment.

If your security model for the execution of this program is that it can
do something bad, but you are trusting it not to do that, then to be
sure it does not do anything bad, you must perform a line-by-line audit
by a team of people who have a clue about secure programming.

There is no short-cut, like looking only for places where it calls
one of the exec functions, etc.

Well, not quite. The short cut to running untrusted programs without
carefully validating everything they do is to run them in a sandboxed
environment established by fine-grained security policies. I.e. rather
than predict and prevent the program from doing something ``bad'', you
detect it and stop it.

You might want to learn about the security enhancements to the Linux
kernel known as SELinux. With SELinux, you can implement sandboxing
rules, so that you can run programs you don't entirely trust.

You can impose rules such as ``this executable can only launch one of
these other executables, and not any others'', or ``this executable can
only modify files under this directory''.
 
R

Richard Tobin

Kaz Kylheku said:
Whatever harm the program can do by launching an external program, it
can also do by replicating the actions of that program in its own code.

Not at all. There may be external programs that have more privileges.
If you do not trust a program, you cannot simply concentrate your
mistrust only on those parts where it runs another program.

That depends on the nature of the mistrust. You may have reason to
believe that the program is not malicious, but fear that it places
undue trust in the environment used to run other programs.

Of course, the general thrust of your article is correct, but you
overstate the case.

-- Richard
 
M

Mark Hobley

Moi said:
BTW/offtopic: for unix-programs, a way to avoid execution of external programs
would be to put the program in a chroot cage.

Yeah this is a workaround (and in fact what the developer of the program
suggests). I think it would be better to locate and comment out the external
calls, so that the programs no longer require a chroot cage.

Mark.
 
M

Mark Hobley

Kaz Kylheku said:
Whatever harm the program can do by launching an external program, it
can also do by replicating the actions of that program in its own code.

Right in this case, the program is an issue tracking system (cvstrac), that
allows arbitrary commands to be run by using data from a database that is made
accessible via the public interface.

The program is not malicious, but I do not want to provide the facility to
run such commands on my system using the public interface, so I need to
comment out those code sections.

I am planning to simply grep the code and comment out the external calls.

However, I do have other software that I wish to audit, so I would like the
facility to be able to do this.
If you do not trust a program, you cannot simply concentrate your
mistrust only on those parts where it runs another program.
If your security model for the execution of this program is that it can
do something bad, but you are trusting it not to do that, then to be
sure it does not do anything bad, you must perform a line-by-line audit
by a team of people who have a clue about secure programming.

I don't have a team of people, so I need to achieve this on my own.

If I know what to scan for, I should be able to find it :)
With SELinux, you can implement sandboxing
rules, so that you can run programs you don't entirely trust.
You can impose rules such as ``this executable can only launch one of
these other executables, and not any others'', or ``this executable can
only modify files under this directory''.

Right. That sounds good. I will have a look at that. I still would like to
be able to patch programs to a trustworth state though. and I have got a few
packages that need an audit.

Mark.
 
S

Seebs

So ideally we need a way of causing the preprocessor to warn that the code
causes invocation of external programs

It can't tell.

There is no way to do this short of running the executable through all
possible code paths and instrumenting the system calls it makes.

Basically, you have two options:

1. Assume it'll all be really obvious. Check for the top few things
(popen, system, exec) and hope for the best.
2. Assume there might be something hidden. You have no options short
of completely instrumenting the entire run through all possible code
paths (including all possible inputs, in case of a back door triggered
by an input), or analyzing every single line of the code by hand until
you know what it does.

On modern Unix-like systems, there are dozens of ways to bypass the stuff
you've suggested so far. Someone trying to sneak something past you will
likely have used them.

-s
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top