Some security issues in Perl scripts

Source: Internet
Author: User
Tags perl script
In a programming language, security risks are generally not generated when designing this language. In fact, this risk is introduced by programmers. Almost every programming language has such a vulnerability, which may cause insecure software to some extent, however, the overall security of a software, for example, is still largely dependent on the knowledge, understanding, and security awareness of the software manufacturer. Perl also has a worrying security aspect, but most programmers are not fully aware of this aspect.
In this article, we will take a look at some of Perl's most commonly misused and ignored attributes. We will see how their misuse threatens the security of the systems running them and their users. We will demonstrate how to mine these vulnerabilities and how to modify and avoid them.
Weakness in user input
A major source of security issues in Perl scripts is the input of users who have not been properly validated (or are not confirmed at all. Every time your program gets input information from an untrusted user, you should be careful even if you adopt a non-direct method. For example, if you write CGI scripts in Perl, you should expect malicious users to send fake input to you. Incorrect user input is recognized and used without confirmation, which may lead to errors in many aspects. The most common and obvious error is that other programs with user-defined parameters are executed without confirmation.
Syetem () and exec () Functions
Perl is known for its ability to be used as a "cohesive" language-it can do a great job in the following ways: when calling other programs to work for it, collect the output of a program, reformat it into a specific way, and then pass the input to other programs to carefully coordinate their operation. In this way, each program can run well.
As Perl has advertised, there are more than one way to do the same thing. A Method to execute an external program and a system command by calling the exec () function. When Perl encounters an exec () statement, it examines the parameters at which exec () is called and starts a new process to execute this specific command. Perl will never return the original process that is controlled to call exec.
Another similar function is system (). The running mode of system () is very similar to Exec (). The only major difference between them is that Perl first splits a child process from the parent process, and the child process serves as a parameter provided to system. The parent process waits until the child process ends and then runs the rest of the program. We will discuss system () calls in more detail below, but most of these discussions also apply to Exec ().
The parameter passed to system () is a list. The first element in the list is the program name of the program to be executed. Other elements are the parameters passed to the program. However, if there is only one parameter, the execution method of system () varies. In that case, Perl will scan this parameter to see if it contains any shell Conversion characters. If any, it will use shell to explain these characters. Therefore, a shell command line is generated to work. Otherwise, Perl splits the string into words and calls the more efficient C-database function execvp (). This function cannot understand special shell characters.
Now let's assume that we have a cgi form that asks for the user name and then displays a file containing the user statistics. You can use system () to call 'cat' for the following requirements:
System ("cat/usr/stats/$ username ");
The user name comes from a form like this:
$ Username = param ("username ");
. For example, after the user adds username = jdimov to the form, the user submits the request. Perl does not find any conversion character in the ''cat/usr/stats/jdimov ''string, so it calls execvp () after the function runs "CAT", it is returned to our script. This script may seem harmless, but it is easily exploited by a malicious attacker.
The problem is that by using special characters in the form's "username" field, an attacker can execute any command through shell. For example, if an attacker passes the string "jdimov; CAT/etc/passwd", Perl treats the semicolon as a conversion character, then pass it to shell:
CAT/usr/stats/jdimov; CAT/etc/passwd
Attackers can obtain both sub-meta files and password files. If attackers want to destroy the data, they only need to send "; rm rf.
We mentioned earlier that system () has a parameter table, and regards the first element as a command for execution, while other elements are passed as parameters. So We Can slightly change our script so that only the program we want to execute can be executed:
System ("cat", "/usr/stats/$ username ");
Since we specify program parameters separately, shell will never be called. Therefore, sending "; RM-RF/*" will not work, because the Attack String will only be interpreted as a file name.
This method is much better than the version of a single parameter because it avoids using shell commands but still has potential defects. In particular, we need to consider whether the $ username value will be exploited to generate vulnerabilities that can be executed in the program. For example, an attacker can still use the code version we have rewritten to set $ username to a string ".../../etc/passwd" to obtain the system password file.
Errors may occur in many places when such a program is used. For example, some applications interpret special character sequences as requests for executing a shell command. A common problem is that some versions of UNIX mail tools See "~!…" in a certain context "~!..." A shell command will be executed during character sequences. Therefore, the blank line in a message body contains "~! Rm-RF * "user input may cause problems in some situations.
As long as it is about security, anything mentioned above about the system () function also applies to Exec ().
Open () function
In Perl, the open () function is used to open files. In the most common form, it is used as follows:
Open (filehandle, "FILENAME ");
In this way, 'filename' is opened in read-only mode. If "FILENAME" is the prefix containing ">", it is opened for the output and overwrites the original file when the file already exists; if the prefix ">" is included, it is opened for append; prefix "<" to open the file for input operations, but this is also the default method when the prefix is not included. Some problems arising from using unconfirmed user input as part of the file name should always be obvious. For example, you can still use this method by looking back at the directory. There are other issues worth worrying about. Now we use open () to replace "CAT" to modify our script file. We use a command like this:
Open (statfile, "/usr/stats/$ username ");
Then we read the code from the file and display it. The Perl document tells us that if the file name starts with "│", the file name will be interpreted as an output pipeline command. Otherwise, if the file name ends with "│, the file name will be interpreted as the pipeline for output.
Therefore, if you add a "│" prefix, you can run any command in the/usr/stats directory. The back-tracing directory operation allows users to execute any program in this system.
One way to solve this problem is to explicitly specify the file you want to open and input to it by adding "<.
Sometimes we do need to call an external program. For example, we want to modify the table's script file so that it can read the old plain text file/usr/stats/username, however, you must use an HTML filter before it is displayed to the user. We have a convenient method that we can use immediately to achieve this intention. One way is to do this:
Open (HTML, "/usr/bin/txt2html/usr/stats/$ username │ ");
Print while <HTML>;

Unfortunately, this still needs to pass through the shell layer. However, we can use another form of open () call to avoid shell involvement:
Open (HTML, "-│ ")
Or exec ("/usr/bin/txt2html", "/usr/stats/$ username ");
Print while <HTML>;
When we open a pipeline command, or to read ("-│") or to write ("│-"), Perl generates a branch in the current process, and return the child process PID to the parent process, and return 0 to the child process." Or statement is used to determine whether we are in the parent process or the child process. If we are in the parent process (the returned value is non-zero), we continue to execute the print () statement. Otherwise, execute the txt2html program in the sub-process and use the safe version of exec () with more than one parameter to avoid passing any command to the shell layer. What happens is that the sub-process promises the stdout output produced by txt2html, and then silently disappears (remember: exec () never returns), while the parent process reads the result from stdin. A technology like this can be used to output data to an external program through a pipeline:
Open (Program, "│ -")
Or exec ("/usr/bin/progname", "$ userinput ");
Print program, "this is piped to/usr/bin/progname ";
When we need pipelines, the above open () forms should always be preferred over the open () commands of the direct pipeline because they do not pass through the shell layer. Now let's assume that we want to convert static text into well-formatted HTML pages, and store them in the same directory as Perl scripts that display these pages for convenience. Then our open statement may look like the following form:
Open (statfile, "<your username.html ");
The script displays jdimov.html. It is still possible to be attacked. Unlike C ++ and C, Perl does not need to end the string with NULL bytes. In this case, the string jdimov/"jdimov/LO/BAH is interpreted as" jdimo "in calls to a vast number of C libraries ", but in Perl, it is "jdimov/0blah ". When Perl passes a string containing null characters to a program written in C, this problem is highlighted. The Unix kernel and the vast majority of UNIX and shell are pure C languages. Perl itself is mainly written in C. When the user calls our script as follows:
Statscrit. plusername = jdimov/% 00
What will happen? Our program passes the string "jdimov/%. Html "to the corresponding system call to open it, but because those system calls are written in C, accept the Null Byte string method. What are the results? If there is a file "jdimov", the file will be displayed, and this file may not exist, even if it is useful. However, if "statscript./pusername = statscript is used. P/% "to call the script. What will happen? If the script and our HTML file are in the same directory, we can use this input to cheat the script to display all the content to us. In this case, it may not be a major security risk, but it will certainly be used by other programs because it allows attackers to analyze the sources of other usable defects.
Single quotes
In Perl, another way to read the output of an external program is to put the command in single quotes. So if we want to save the content of our stats file in a hierarchical $ stats file, we can do this:
$ Stats = 'cat/user/stats/$ username ';
This is indeed implemented through the shell layer. Any script that contains user input in a pair of single quotes poses a risk to all the security issues discussed above. There are many ways to avoid misunderstanding of Possible Conversion characters in shell. But the safest thing is not to use quotation marks. Instead, open a pipe that passes to stdin and execute an external program in a fork, just as we did in the previous section open.
Eval () And/e Modifier
The function eval () can execute a Perl code block at run time and return the value of the last evaluated statement. This function is often used in configuration files. It can be written into Perl code. unless you absolutely believe that the source code is imported into eval (), do not do such things as eval/$ userinput, this also applies to the/e modifier in a general expression that enables Perl to explain the expression before execution.
Filter user input
A common method (Fu in OCA) used to filter user input for all the issues discussed in this section is to filter any unnecessary Conversion characters and problematic data. For example, we can filter the directories at any time to avoid viewing them backwards. Similarly, once we see illegal characters, the program fails. This policy is called "Blacklist". This philosophy is that if something is not explicitly prohibited, it must be good. A better policy is "whitelist", which means that if something is not explicitly recognized, it must be disabled. The most important problem with the blacklist ticket is that it is very difficult to maintain integrity and obtain more information. You may forget to filter a specific character, or your program may have to convert it to a different shell with different conversion character sets. However, the unnecessary Conversion characters are filtered out. On the contrary, only valid characters are filtered out. The following snippet is an example. It stops performing an operation with security issues. If a user input contains letters and numbers, anything except the dot and @ symbol (@ is often used for the user's email address)
Unless ($ useradress = ~ /^ [-@/W.] +) $ /)
{Print "secrity error. /N "exit (1 );
}
The basic idea is not to compile a list of specific values for protection, but to generate a security list to accept a list of acceptable input values. The choice of acceptable input values will certainly change with different applications. Acceptable values should be selected in a way that minimizes the possibility of destruction.
Avoid Shell
Of course, you must avoid shell as much as possible, but this technology can be widely used. If you call an editor with a specific sequence. You must confirm that these specific sequences are not allowed. Generally, by using the existing Perl module, you can avoid using external programs to execute an external function, CPAN is a module source of tested functions that can accomplish almost everything that can be done in almost all standard UNIX tool sets. However, it may involve effort to include a module and call it, instead of calling an external program, the module method is generally safer and more flexible. To clarify this, use net: SMTP instead of exec () 'ing sendmail/-- t will help you reduce the trouble of using shell and prevent your users from looking for known vulnerabilities in the sendmail proxy.
Other sources of security issues (uneasiness)
User input is actually the source of the main security issues of Perl programs, but there are other factors that must be filtered out when writing secure Perl source code, the vulnerable vulnerabilities of scripts that often run in shell, or insecure loop variables through network servers, usually path/variable. When you use an external application or function inside your code and only specify a relative path, you are at risk for this program and the system that runs it. If you call the following system:
System ("txt2html", "user/stats/jdiov ");
For this call, assume that the txt2htm file is contained in a directory where the PATH variable is located, but if this happens, if an attacker changes your path to another malicious program with the same name, the security of your system will not be guaranteed. To avoid similar incidents, every program that requires remote security awareness should start writing like this:
#! /Usr/bin/perl-WT
Require 5.001;
Use strict;
$ ENV {path} = join': '=> split ("", <' _ eopath __');
/Usr/bin
/Bin
/Maybe/something/else
_ Eopath __
If Programs depend on other environment variables, they must be clearly defined before they are used.
Another dangerous variable (this is especially for Perl) is the @ INC array variable, which is very similar to the path, but it specifies where Perl is going to find the module to be included in the program. The @ incr problem is very similar to the path. Someone may point your Perl to a module with the same name, and do the same thing as you expected, but it also secretly does some bad things, therefore, @ INC and path are not worthy of trust. All external modules must be completely redefined before they are included.
Setuid script
Generally, a Perl program runs with the permissions of the user who executes it. By generating a setuid script, the valid user ID can be set to a higher permission, which allows the user to access resources that he does not actually have access, for example, the passwd program uses setuid to obtain the write permission on the system password file, which allows users to change their own passwords, because the execution program is executed through the CGI interface, this interface is run under the user permission of the network server. cgi programmers often try to use the setuid technique to execute some pranks for their scripts. This may be used, but it may also be very dangerous. For one thing, if an attacker finds that each method can exploit the weakness of the script, they not only obtain the permission to access the system by mistake, however, they will use valid UID privileges to obtain other similar race conditions. In a program, such defects are relatively easy to monitor, especially for experienced programmers, the current work in related areas is actively exploring. There is no easy and effective solution to this problem. The best way to solve this problem is to use atomic operations when racial conditions exist, this means that only one system is used to check and store files simultaneously. You do not need to use a processor to switch between them. Of course, this is not always possible.
In addition, we use sysopen to determine a read-only mode, without having to set the delete flag.
In this way, even if our file name has been formed, when we open the file for write operations, we will not destroy the file. Note: fcnt1 modulo must be included quickly to enable the sysopen () function to take effect, because this module is the following constant, where o_rdonly, o_wronly, o_creat, and so on are defined.
Buffer overflow and Perl
Generally, Perl scripts are not prone to buffer overflow because Perl can dynamically expand its data structure as needed. Perl traces the size allocated to each string. Before a string is assigned a value, Perl ensures that there is sufficient space to use. If necessary, it can also allocate more space for that string.
However, there are several well-known buffer overflow conditions in some older Perl implementation methods. An obvious example is that version 5.003 crashes due to buffer overflow. All suidperl versions (one designed to work for certain kernels) are earlier than 5. It is based on the different types of Perl of version 004.
Conclusion:
In our future articles, we will take some time to familiarize ourselves with the security features provided to us by Perl, especially the Perl "Taint mode", and we will prove that, if we are not careful, there may still be some problems even under such a strong security mechanism. When learning these aspects of Perl and some typical examples. Our goal is to cultivate a kind of intuition that helps us to be aware of the security issues at the first glance of the Perl script, to avoid making similar mistakes in our program.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.