Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for CVE-2015-3222 which allows for root escalation via syscheck #622

Merged
merged 2 commits into from
Jun 24, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -1212,10 +1212,10 @@ win32_ui_o := $(win32_ui_c:.c=.o)
win32/ui/%.o: win32/ui/%.c
${OSSEC_CC} ${OSSEC_CFLAGS} -UOSSECHIDS -DARGV0=\"ossec-win32ui\" -c $^ -o $@

win32/ossec-agent.exe: win32/icon.o win32/win_agent.o win32/win_service.o ${syscheck_o} ${rootcheck_o} $(filter-out client-agent/main.o, $(filter-out client-agent/agentd.o, $(filter-out client-agent/event-forward.o, ${client_agent_o}))) $(filter-out logcollector/main.o, ${os_logcollector_o}) ${os_execd_o} ${ossec_libs} ${ZLIB_LIB}
win32/ossec-agent.exe: win32/icon.o win32/win_agent.o win32/win_service.o $(filter-out syscheckd/seechanges.o, ${syscheck_o}) ${rootcheck_o} $(filter-out client-agent/main.o, $(filter-out client-agent/agentd.o, $(filter-out client-agent/event-forward.o, ${client_agent_o}))) $(filter-out logcollector/main.o, ${os_logcollector_o}) ${os_execd_o} ${ossec_libs} ${ZLIB_LIB}
${OSSEC_CCBIN} -DARGV0=\"ossec-agent\" -DOSSECHIDS ${OSSEC_CFLAGS} $^ ${OSSEC_LDFLAGS} -o $@

win32/ossec-agent-eventchannel.exe: win32/icon.o win32/win_agent.o win32/win_service.o ${syscheck_o} ${rootcheck_o} $(filter-out client-agent/main.o, $(filter-out client-agent/agentd.o, $(filter-out client-agent/event-forward.o, ${client_agent_o}))) $(filter-out logcollector/main-event.o, ${os_logcollector_eventchannel_o}) ${os_execd_o} ${ossec_libs} ${ZLIB_LIB}
win32/ossec-agent-eventchannel.exe: win32/icon.o win32/win_agent.o win32/win_service.o $(filter-out syscheckd/seechanges.o, ${syscheck_o}) ${rootcheck_o} $(filter-out client-agent/main.o, $(filter-out client-agent/agentd.o, $(filter-out client-agent/event-forward.o, ${client_agent_o}))) $(filter-out logcollector/main-event.o, ${os_logcollector_eventchannel_o}) ${os_execd_o} ${ossec_libs} ${ZLIB_LIB}
${OSSEC_CCBIN} -DARGV0=\"ossec-agent\" -DOSSECHIDS -DEVENTCHANNEL_SUPPORT ${OSSEC_CFLAGS} $^ ${OSSEC_LDFLAGS} -o $@

win32/ossec-rootcheck.exe: win32/icon.o win32/win_service_rk.o ${rootcheck_rk_o} ${ossec_libs}
Expand Down
8 changes: 7 additions & 1 deletion src/syscheckd/create_db.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,15 @@ static int read_file(const char *file_name, int opts, OSMatch *restriction)
char alert_msg[916 + 1]; /* to accommodate a long */
alert_msg[916] = '\0';

#ifndef WIN32
if (opts & CHECK_SEECHANGES) {
char *alertdump = seechanges_addfile(file_name);
if (alertdump) {
free(alertdump);
alertdump = NULL;
}
}
#endif

snprintf(alert_msg, 916, "%c%c%c%c%c%c%ld:%d:%d:%d:%s:%s",
opts & CHECK_SIZE ? '+' : '-',
Expand Down Expand Up @@ -206,8 +208,11 @@ static int read_file(const char *file_name, int opts, OSMatch *restriction)

if (strcmp(c_sum, buf + 6) != 0) {
/* Send the new checksum to the analysis server */
char *fullalert = NULL;
alert_msg[OS_MAXSTR] = '\0';
#ifdef WIN32
snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
#else
char *fullalert = NULL;
if (buf[5] == 's' || buf[5] == 'n') {
fullalert = seechanges_addfile(file_name);
if (fullalert) {
Expand All @@ -220,6 +225,7 @@ static int read_file(const char *file_name, int opts, OSMatch *restriction)
} else {
snprintf(alert_msg, 916, "%s %s", c_sum, file_name);
}
#endif
send_syscheck_msg(alert_msg);
}
}
Expand Down
7 changes: 6 additions & 1 deletion src/syscheckd/run_realtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,15 @@ int realtime_checksumfile(const char *file_name)
}

if (strcmp(c_sum, buf + 6) != 0) {
char *fullalert = NULL;
char alert_msg[OS_MAXSTR + 1];

alert_msg[OS_MAXSTR] = '\0';

#ifdef WIN32
snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
#else
char *fullalert = NULL;

if (buf[5] == 's' || buf[5] == 'n') {
fullalert = seechanges_addfile(file_name);
if (fullalert) {
Expand All @@ -72,6 +76,7 @@ int realtime_checksumfile(const char *file_name)
} else {
snprintf(alert_msg, 912, "%s %s", c_sum, file_name);
}
#endif
send_syscheck_msg(alert_msg);

return (1);
Expand Down
122 changes: 106 additions & 16 deletions src/syscheckd/seechanges.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,21 +199,33 @@ static int seechanges_createpath(const char *filename)
/* Check if the file has changed */
char *seechanges_addfile(const char *filename)
{
time_t date_of_change;
time_t old_date_of_change;
time_t new_date_of_change;
char old_location[OS_MAXSTR + 1];
char tmp_location[OS_MAXSTR + 1];
char diff_location[OS_MAXSTR + 1];
char old_tmp[OS_MAXSTR + 1];
char new_tmp[OS_MAXSTR + 1];
char diff_tmp[OS_MAXSTR + 1];
char diff_cmd[OS_MAXSTR + 1];
os_md5 md5sum_old;
os_md5 md5sum_new;
int status = -1;

old_location[OS_MAXSTR] = '\0';
tmp_location[OS_MAXSTR] = '\0';
diff_cmd[OS_MAXSTR] = '\0';
md5sum_new[0] = '\0';
md5sum_old[0] = '\0';

snprintf(old_location, OS_MAXSTR, "%s/local/%s/%s", DIFF_DIR_PATH, filename + 1,
DIFF_LAST_FILE);
snprintf(
old_location,
sizeof(old_location),
"%s/local/%s/%s",
DIFF_DIR_PATH,
filename + 1,
DIFF_LAST_FILE
);

/* If the file is not there, rename new location to last location */
if (OS_MD5_File(old_location, md5sum_old) != 0) {
Expand All @@ -235,9 +247,16 @@ char *seechanges_addfile(const char *filename)
}

/* Save the old file at timestamp and rename new to last */
date_of_change = File_DateofChange(old_location);
snprintf(tmp_location, OS_MAXSTR, "%s/local/%s/state.%d", DIFF_DIR_PATH, filename + 1,
(int)date_of_change);
old_date_of_change = File_DateofChange(old_location);

snprintf(
tmp_location,
sizeof(tmp_location),
"%s/local/%s/state.%d",
DIFF_DIR_PATH,
filename + 1,
(int)old_date_of_change
);

if (rename(old_location, tmp_location) == -1) {
merror(RENAME_ERROR, ARGV0, old_location, tmp_location, errno, strerror(errno));
Expand All @@ -249,19 +268,90 @@ char *seechanges_addfile(const char *filename)
return (NULL);
}

new_date_of_change = File_DateofChange(old_location);

/* Create file names */
snprintf(
old_tmp,
sizeof(old_tmp),
"%s/syscheck-changes-%s-%d",
TMP_DIR,
md5sum_old,
(int)old_date_of_change
);

snprintf(
new_tmp,
sizeof(new_tmp),
"%s/syscheck-changes-%s-%d",
TMP_DIR,
md5sum_new,
(int)new_date_of_change
);

snprintf(
diff_tmp,
sizeof(diff_tmp),
"%s/syscheck-changes-%s-%d-%s-%d",
TMP_DIR,
md5sum_old,
(int)old_date_of_change,
md5sum_new,
(int)new_date_of_change
);

/* Create diff location */
snprintf(
diff_location,
sizeof(diff_location),
"%s/local/%s/diff.%d",
DIFF_DIR_PATH,
filename + 1,
(int)new_date_of_change
);

/* Create symlinks */
if (symlink(old_location, old_tmp) == -1) {
merror(LINK_ERROR, ARGV0, old_location, old_tmp, errno, strerror(errno));
goto cleanup;
}

if (symlink(tmp_location, new_tmp) == -1) {
merror(LINK_ERROR, ARGV0, tmp_location, new_tmp, errno, strerror(errno));
goto cleanup;
}

if (symlink(diff_location, diff_tmp) == -1) {
merror(LINK_ERROR, ARGV0, diff_location, diff_tmp, errno, strerror(errno));
goto cleanup;
}

/* Run diff */
date_of_change = File_DateofChange(old_location);
snprintf(diff_cmd, 2048, "diff \"%s\" \"%s\" > \"%s/local/%s/diff.%d\" "
"2>/dev/null",
tmp_location, old_location,
DIFF_DIR_PATH, filename + 1, (int)date_of_change);
snprintf(
diff_cmd,
2048,
"diff \"%s\" \"%s\" > \"%s\" 2> /dev/null",
new_tmp,
old_tmp,
diff_tmp
);

if (system(diff_cmd) != 256) {
merror("%s: ERROR: Unable to run diff for %s",
ARGV0, filename);
return (NULL);
merror("%s: ERROR: Unable to run diff for %s", ARGV0, filename);
goto cleanup;
}

/* Success */
status = 0;

cleanup:
unlink(old_tmp);
unlink(new_tmp);
unlink(diff_tmp);

if (status == -1)
return (NULL);

/* Generate alert */
return (gen_diff_alert(filename, date_of_change));
return (gen_diff_alert(filename, new_date_of_change));
}