I'm writing a program that will be monitoring select files and directories for changes. Some of the files are world writeable, some owner, some group.
What I need to do is be able to figure out the last person to modify (not just access) a file. Somehow I thought this would be simple, given that we know the inode of the file .. however I can not seem to find any way of obtaining this. I thought there was a practical way of correlating any given inode to the uid last accessing it.
I think I've squeezed google for all its going to give me on the topic.
Any help is appreciated. I'm writing the program in C.
Edit:
I need to be able to do this after the PID of whatever program modified the file is long gone.
If you are on a 2.6 kernel, you can take advantage of kernel's auditd daemon. Check this URL out. It might give you some hint on how to accomplish what you are trying to. I'm sure there is an API you could use in C.
To my knowledge, this information is not stored by any of the common filesystems, but you should by able to hook into inotify and keep an audit trail of which processes touch which files.
Okay, using straight old standard Linux with normal file systems, you're not going to be able to do it. That information isn't stored anywhere (see man lstat for what is stored.)
As #pablo suggests, you can do this with security auditing turned on. The link he notes is a good start, but the gist of it is this:
you turn on the audit daemon, which enables auditing form the kernel
you configure the rules file to capture what you want
you search the audit files for the events you want.
The difficulty here is that if you start auditing all file operations for all files, the audit is going to get big.
So what is the actual need you want to fil?
very basic , but it works:
you can easily write a little c-program that does what you want
this example retrieves the UID of file or directory or link,
just try to find the properties that you want.
compile with:
gcc -x c my-prog.c -o my-prog
then:
./my-prog /etc
a lot of other information can be obtained like this
it's not robust. but whatever, i know how to use it,
and do the checking in a bash shell :-)
[ -x /etc ] && my-prog /etc
source code:
# retrieve the uid of a file
# source code: my-prog.c
#
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(int argc, char **argv) {
struct stat buffer;
int status;
char *fname;
fname=argv[1];
status = stat(fname, &buffer);
printf("%i",buffer.st_uid);
return 0;
}
Related
I'm not sure how to ask this, but I'll do my best. Anyway, my situation is this: I have files that I want my app/executable to be able to access at all times that are relative to the executable's path or in the same directory as the program. Since I want my program to be able to run in any CWD and still get everything it needs. I want to know what's the best way or method to get a file that's relative to my executable, that won't mess up the user's CWD?
The approach I had in my head is this:
Get program's directory using OS dependent function.
Use some string manipulation to get the program's home directory.
Append to the string the file I require during run time without having to use any hat trick CWD commands.
Not sure if Windows/Linux already has something up it's sleeves to deal with this, but I thought I should know if there is a better alternative.
Thank you!
If the files, that you want to access from your C binary, are in the same directory or subdirectory, you can access directly by using ".", this is the current directory.
or you can simply use the getwd function.
char *getwd(char *buf);
Typically, you can use like this (this snippet will print you, the current directory of the C binary):
int main()
{
char buf[4096];
getwd(buf);
printf(but);
}
I was recently at a presentation where one of the speakers stated that he'd used a single CGI file, written in C, that is called by the webserver, but the webserver calls the file by using different names, the CGI file would run a different method.
How can I have a single C file execute different functions within when it is called by different names? Also how do I re-direct the calls for differently named files back to this single file?
Is this possible or was he just full of himself?
If you create the executable with different names but with the same code base, you can take a different branch of the code based the name of the executable used to invoke the program.
Simple example file:
#include <stdio.h>
#include <string.h>
int main1(int argc, char** argv)
{
printf("Came to main1.\n");
return 0;
}
int main2(int argc, char** argv)
{
printf("Came to main2.\n");
return 0;
}
int main(int argc, char** argv)
{
// If the program was invoked using main1, go to main1
if (strstr(argv[0], "main1") != NULL )
{
return main1(argc-1, argv+1);
}
// If the program was invoked using main2, go to main2
if (strstr(argv[0], "main2") != NULL )
{
return main2(argc-1, argv+1);
}
// Don't know what to do.
return -1;
}
Create two different executables from the file.
cc test-262.c -o main1
cc test-262.c -o main2
Then, invoke the program by using the two different executables:
./main1
Output:
Came to main1.
and...
./main2
Output:
Came to main2.
Unix filesystems support the concept of hard and soft links. To create them just type:
ln origfile newfile
to create a hard link, or:
ln -s origfile newfile
to create a soft link.
Soft links are just a special kind of file that contains the path of another file. Most operations in the link transparently result in operating on the target file.
Hard links are lower level. In effect, all files are a link from the pathname to the content. In Unix you can link more than one pathname to the same content. In effect, there's no "original" and "links", all are links. When you delete a file, you're just removing a link, and when the link count goes to zero, the content is removed.
Many unix utilities do this trick. Since the running shell includes the name used to invoque the executable, it's handled just like the 0'th argument of the command line.
When a CGI script is being called by a web server, it receives a considerable amount of information in its environment to let it know how it was called, including:
SCRIPT_NAME, the path to the script from the document root
SCRIPT_FILENAME, the filesystem path to the script (usually the same as argv[0])
REQUEST_URI, the path that was requested by the browser (usually similar to SCRIPT_NAME in the absence of URL rewriting)
QUERY_STRING and PATH_INFO, which contain URL parameters following the script's name
HTTP_*, which contain most of the HTTP headers that were passed in the request
Point is, the script gets a lot of information about how it was called. It could be using any of those to make its decision.
It's possible and actually pretty common.
The first element in the argv array passed to the main function is the "name" of the executable. This can be the full path, or it can be just the last component of the path, or -- if the executable is started with an exec* function call, it can be an arbitrary string. (And Posix allows it to be a null string, as well, but in practice that's pretty rare.)
So there is nothing stopping the executable from looking at argv[0] (having first checked to make sure that argc > 0) and parsing it.
The most typical way to introduce a different name for the executable is to insert a filesystem link with the alternate name (which could be either a hard or a soft-link, but for maintainability soft links are more useful.)
For CGIs, it is not even necessary to examine argv[0], since there are various useful environment variables, including (at least): SCRIPT_NAME.
I have a sandboxed Cocoa app that, during an export process, needs to run a third party command-line tool. This tool appears to be hardcoded to use /tmp for its temporary files; sandboxing doesn't permit access to this folder, so the export fails.
How can I get this tool to run? I don't have access to its source code, so I can't modify it to use NSTemporaryDirectory(), and it doesn't appear to respect the TMP or TEMPDIR environment variables. For reasons I don't understand, giving myself a com.apple.security.temporary-exception.files.absolute-path.read-write entitlement doesn't seem to work, either.
Is there some way to re-map folders within my sandbox? Is there some obscure trick I can use? Should I try to patch the tool's binary somehow? I'm at my wit's end here.
I was able to get user3159253's DYLD_INSERT_LIBRARIES approach to work. I'm hoping they will write an answer describing how that works, so I'll leave the details of that out and explain the parts that ended up being specific to this case.
Thanks to LLDB, elbow grease, and not a little help from Hopper, I was able to determine that the third-party tool used mkstemp() to generate its temporary file names, and some calls (not all) used a fixed template starting with /tmp. I then wrote a libtmphack.dylib that intercepted calls to mkstemp() and modified the parameters before calling the standard library version.
Since mkstemp() takes a pointer to a preallocated buffer, I didn't feel like I could rewrite a path starting with a short string like "/tmp" to the very long string needed to get to the Caches folder inside the sandbox. Instead, I opted to create a symlink to it called "$tmp" in the current working directory. This could break if the tool chdir()'d at an inopportune time, but fortunately it doesn't seem to do that.
Here's my code:
//
// libtmphack.c
// Typesetter
//
// Created by Brent Royal-Gordon on 8/27/14.
// Copyright (c) 2014 Groundbreaking Software. This file is MIT licensed.
//
#include "libtmphack.h"
#include <dlfcn.h>
#include <stdlib.h>
#include <unistd.h>
//#include <errno.h>
#include <string.h>
static int gbs_has_prefix(char * needle, char * haystack) {
return strncmp(needle, haystack, strlen(needle)) == 0;
}
int mkstemp(char *template) {
static int (*original_mkstemp)(char * template) = NULL;
if(!original_mkstemp) {
original_mkstemp = dlsym(RTLD_NEXT, "mkstemp");
}
if(gbs_has_prefix("/tmp", template)) {
printf("libtmphack: rewrote mkstemp(\"%s\") ", template);
template[0] = '$';
printf("to mkstemp(\"%s\")\n", template);
// If this isn't successful, we'll presume it's because it's already been made
symlink(getenv("TEMP"), "$tmp");
int ret = original_mkstemp(template);
// Can't do this, the caller needs to be able to open the file
// int retErrno = errno;
// unlink("$tmp");
// errno = retErrno;
return ret;
}
else {
printf("libtmphack: OK with mkstemp(\"%s\")\n", template);
return original_mkstemp(template);
}
}
Very quick and dirty, but it works like a charm.
Since #BrentRoyal-Gordon has already published a working solution I'm simply duplicating my comment which inspired him to produce the solution:
In order to fix a program behavior, I would intercept and override some system calls with the help of DYLD_INSERT_LIBRARIES and a custom shared library with a custom implementation of the given system calls.
The exact list of the syscalls which need to be overridden depends on nature of the application and can be studied with a number of tools built upon MacOS DTrace kernel facility. E.g. dtruss or Hopper. #BrentRoyal-Gordon has investigated that the app can be fixed solely with an /appropriate/ implementation of mkstemp.
That's it. I'm still not sure that I've deserved the bounty :)
Another solution would be to use chroot within the child process (or posix_spawn options) to change its root directory to a directory that is within your sandbox. Its “/tmp” will then be a “tmp” directory within that directory.
I've been reading about IFS exploitation and LD_PRELOAD Privilege escalation by overriding functions. Although these are two completely different questions, I've decided to post them together and hope that isn't a problem. Though both of these are very old, I've been told that they can both still be used for privilege escalation and I would love to look into that. However, I've ran into some problems.
So, let's begin by making the SUID file, /tmp/suid.
#include <unistd.h>
int main() {
system("/bin/date");
}
This calls /bin/date. The idea is that we can change the internal field separator and deceive the file into running something else with the privileges that it currently holds. This can be done (or can it?) by making a new file called bin contain the malicious code that the attacker put in a custom location. Then we change the $PATH variable and make it so that locations are first searched inside our custom path, where our malicious fake binary is located. Then by changing the internal field separator to '/', instead of running /bin/date the program will run /tmp/fakepath/bin with argument date, which can potentially trigger privilege escalation.
When I attempt the method described dankalia.com, it fails. /bin/date gets executed instead. If I just type bin date into the console the malicious binary does get started, but it doesn't when it's being invoked through /tmp/suid.
I thought that the vulnerability is patched and that it simply ignores the IFS variable, but then a post on stackoverflow got me interested. (C: IFS System() Vulnerability). Can anyone confirm to me if this works or not, and what I am doing wrong? Thanks.
As for the LD_PRELOAD, I'll keep it rather simple.
define _GNU_SOURCE
#include <stdio.h>
int puts(const char *str) {
printf("lel");
}
Use the following command line to compile:
gcc –Wall –fPIC –shared –o puts.so puts.c –ldl
Then, override the function puts with preload tricks:
LD_PRELOAD=./puts.so ./vuln_program_that_uses_puts
This works quite well. However, when dealing with a SUID file and when we're talking about privilege escalation, this ain't happening. LD_PRELOAD doesn't work well with SUID files and for a good reason. I've been told that "you can get it to work but that it's hard". Ideas?
Thanks in advance, and sorry for the long questions.
I've been told that "you can get it to work but that it's hard". Ideas?
The operating system is wise to these sorts of tricks, and most are remediated now. Te general idea is setuid, sudo and friends don't use an unprivileged user's environment.
The following offers more reading:
suid-binary vulnerabilities
Breaking the links: Exploiting the linker
If all you want is a setuid binary to break into the system:
shutdown the computer
mount the hard drive
rename ls (or other program like date)
copy sudo to ls (or other program like date)
unmount and reboot
How can one create a new file descriptor from an existing file descriptor such that the new descriptor does not share the same internal file structure/entry in the file table? Specifically attributes such as file offset (and preferably permissions, sharing and modes) should not be shared between the new and old file descriptors.
Under both Windows and Linux, dup() will duplicate the file descriptor, but both descriptors still point to the same file structure in the process' file table. Any seeking on either descriptor will adjust the position for the other descriptors as well.
Note
I've since received answers for both Windows and Linux and adjusted the question a little too often, which has made it difficult for people to answer. I'll adjust my votes and accept the cleanest answer which covers both Windows and Linux. Apologies to all, I'm still new to the SO paradigm. Thanks for the great answers!
So basically, what you really want is to be given a file descriptor, and basically open the same file over again, to get a separate position, sharing, mode, etc. And you want to do this on Windows (where the "file descriptor" is basically a foreign object, not something used directly by the OS or the run-time library at all.
Amazingly enough, there is a way to do that, at least with MS VC++. All but two steps of it use only the Win32 API so porting to other compilers/libraries should be fairly reasonable (I think most supply versions of those two functions). Those are for converting a Unix-style file descriptor to a native Win32 file handle, and converting a native Win32 file handle back to a Unix-style file descriptor.
Convert file-descriptor to native file handle with _get_osfhandle()
Get a name for the file with GetFileInformationByHandleEx(FILE_NAME_INFO)1
Use CreateFile to open a new handle to that file
Create a file descriptor for that handle with _open_osfhandle()
Et voilà, we have a new file descriptor referring to the same file, but with its own permissions, position, etc.
Toward the end of your question, you make it sound like you also want the "permissions", but that doesn't seem to make any real sense -- the permissions attach to the file itself, not to how the file is opened, so opening or reopening the file has no effect on the file's permissions. If you really want to know the, you can get it with GetFileInformationByHandle, but be aware that file permissions in Windows are quite a bit different from the (traditional) file permissions in Unix. Unix has owner/group/world permissions on all files, and most systems also have ACLs (though there's more variation in how they work). Windows either has no permissions at all (e.g., files on FAT or FAT32) or else uses ACLs (e.g., files on NTFS), but nothing that's really equivalent to the traditional owner/group/world permissions most people are accustomed to on Unix.
Perhaps you're using "permissions" to refer to whether the file was open for reading, writing, or both. Getting that is considerably uglier than any of the preceding. The problem is that most of it is in the library, not Win32, so there's probably no way to do it that will be even close to portable between compilers. With MS VC++ 9.0 SP1 (not guaranteed for any other compiler) you can do this:
#include <stdio.h>
int get_perms(int fd) {
int i;
FILE * base = __iob_func();
for (i=0; i<_IOB_ENTRIES; i++)
if (base[i]._file == fd)
return base[i]._flag; // we've found our file
return 0; // file wasn't found.
}
Since this involved some spelunking, I wrote a quick test to verify that it might actually work:
#ifdef TEST
#include <io.h>
void show_perms(int perms, char const *caption) {
printf("File opened for %s\n", caption);
printf("Read permission = %d\n", (perms & _IOREAD)!=0);
printf("Write permission = %d\n", (perms & _IOWRT)!=0);
}
int main(int argc, char **argv) {
FILE *file1, *file2;
int perms1, perms2;
file1=fopen(argv[1], "w");
perms1 = get_perms(_fileno(file1));
fclose(file1);
file2=fopen(argv[1], "r");
perms2 = get_perms(_fileno(file2));
fclose(file2);
show_perms(perms1, "writing");
show_perms(perms2, "reading");
return 0;
}
#endif
And the results seem to indicate success:
File opened for writing
Read permission = 0
Write permission = 1
File opened for reading
Read permission = 1
Write permission = 0
You can then test that returned flag against _IOREAD, _IOWRT, and _IORW, which are defined in stdio.h. Despite my previous warnings, I should probably point out that I suspect (though I certainly can't guarantee) that this part of the library is fairly stable, so the real chances of major changes are probably fairly minimal.
In the other direction, however, there's basically no chance at all that it'll work with any other library. It could (but certainly isn't guaranteed to) work with the other compilers that use the MS library, such as Intel, MinGW or Comeau using MS VC++ as its back-end. Of those, I'd say the most likely to work would be Comeau, and the least likely MinGW (but that's only a guess; there's a good chance it won't work with any of them).
Requires the redistributable Win32 FileID API Library
So, I recommend reading up on this a little more. The dup() and related functions serve to create a duplicate value in the file descriptor table pointing to the same entry in the open file table. This is intended to have the same offset. If you call open(), you will create a new entry the open file table.
It doesn't make any sense to create a duplicate of a file descriptor and that new file descriptor have a different offset in the open file table (this seems to contradict what the word "duplicate" means).
I'm not sure what your question is actually. I mean, it isn't the same thing as a duplicate. You could read:
/proc/self/fd/[descriptor]
and get the string that was used to open that file descriptor; bear in mind this may provide some pitfalls, some of which you actually noted in your observation of calling open() again.
Maybe you can explain a little more and I can try to update to help.
Why don't you just open the file a second time with open() or CreateFile() on windows? This gives you all freedom of different access rights and separate offset.
This of course has the drawback that you you can not open the file exclusively, but it solves your problem very simply.