Exploiting SUID files with LD_PRELOAD and IFS - c

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

Related

Why is this C program doing nothing in Ubuntu?

My very simple C program just hangs and I don’t know why.
I am trying to make a simple executable to handle multiple monotonous actions for me every time I start a new programming session.
So I decided with something simple (below) yet every time I run it, the app just hangs, never returns. So I have to Ctrl-C out of it. I have added printf commands to see if it goes anywhere, but those never appear.
My build command returns no error messages:
gcc -o tail tail.c
Just curious what I am missing.
#include <stdio.h>
#include <unistd.h>
int main() {
chdir("\\var\\www");
return 0;
}
There are at least two problems with the source code:
It is unlikely that you have a sub-directory called \var\www in your current directory — Ubuntu uses / and not \ for path separators.
Even if there was a sub-directory with the right name, your program would change directory to it but that wouldn't affect the calling program.
You should check the return value from chdir() — at minimum:
if (chdir("/var/www") != 0)
{
perror("chdir");
exit(EXIT_FAILURE);
}
And, as Max pointed out, calling your program by the name of a well-known utility such as tail is likely to lead to confusion. Use a different name.
Incidentally, don't use test as a program name either. That, too, will lead to confusion as it is a shell built-in as well as an executable in either /bin or /usr/bin. There is also a program /bin/cd or /usr/bin/cd on your machine — it will check that it can change directory, but won't affect the current directory of your shell. You have to invoke it explicitly by the full pathname to get it to run at all because cd is another shell built-in.
Two things:
First, that's not what Linux paths look like
Second, check the return value from chdir()
ie
if (chdir("/var/www") != 0)
printf("failed to change directory");
Finally, the effect of chdir() lasts for the duration of the program. It will not change the current directory of your shell once this program finishes.
The other answers adequately cover the issues in your C code. However, the reason you are seeing it hang is because you chose the name tail for your program.
In Linux, tail is a command in /usr/bin in most setups, and if you just type tail at the command line, the shell searches the $PATH first, and runs this. Without any parameters, it waits for input on its stdin. You can end it by pressing control-d to mark the end of file.
You can bypass the $PATH lookup by typing ./tail instead.
$ tail
[system tail]
$ ./tail
[tail in your current directory]
It is a good idea to use ./ as a habit, but you can also avoid confusion by not naming your program the same as common commands. Another name to avoid is test which is a shell built-in for testing various aspects of files, but appears to do nothing as it reports results in its system return code.

How do I trace coreutils down to a syscall?

I am trying to navigate and understand whoami (and other coreutils) all the way down to the lowest level source code, just as an exercise.
My dive so far:
Where is the actual binary?
which whoami
/usr/bin/whoami
Where is it maintained?
http://www.gnu.org/software/coreutils/coreutils.html
How do I get source?
git clone git://git.sv.gnu.org/coreutils
Where is whoami source code within the repository?
# find . | grep whoami
./man/whoami.x
./man/whoami.1
./src/whoami.c
./src/whoami
./src/whoami.o
./src/.deps/src_libsinglebin_whoami_a-whoami.Po
./src/.deps/whoami.Po
relevant line (84):
uid = geteuid ();
This is approximately where my rabbit hole stops. geteuid() is mentioned in gnulib/lib/euidaccess.c, but not explicitly defined AFAICT. It's also referenced in /usr/local/unistd.h as extern but there's no heavy lifting related to grabbing a uid that I can see.
I got here by mostly grepping for geteuid within known system headers and includes as I'm having trouble backtracing its definition.
Question: How can I dive down further and explore the source code of geteuid()? What is the most efficient way to explore this codebase quickly without grepping around?
I'm on Ubuntu server 15.04 using Vim and some ctags (which hasn't been very helpful for navigating existing system headers). I'm a terrible developer and this is my method of learning, though I can't get through this roadblock.
Normally you should read the documentation for geteuid. You can either read GNU documentation, the specification from the Open Group or consult the man page.
If that doesn't help you could install the debug symbols for the c-library (it's called libc6-dbg or something similar) and download the source code for libc6) then you point out the path to the source file when you step into the library.
In this case I don't think this would take you much further, what probably happens in geteuid is that it simply issues an actual syscall and then it's into kernel space. You cannot debug that (kernel) code in the same way as you would debug a normal program.
So in your case you should better consult the documentation and read it carefully and try to figure out why geteuid doesn't return what you expect. Probably this will lead to you changing your expectation of what geteuid should return to match what's actually returned.

nsinstall: Bad file number error on Vista

I'm attempting to build Firefox on my Windows Vista Ultimate machine. I keep getting the following error:
nsinstall: Bad file number
I've read that this error is caused because of UAC in Vista. Here are the two articles that lead me to this conclusion. https://wiki.mozilla.org/Penelope_Developer_Page#Windows_Vista and http://www.kevinbrosnan.net/mozilla-build-error-nsinstall-bad-file-number
Using the standard "Run as Administrator", I've attempted to redo my build but I get the exact same error. I also started a normal command prompt as admin and then went to the batch file in mozilla-build (start-msvc8.bat) and ran it. Still, same error at the same point.
Any other insights on how I might either get around this error or perhaps something else is causing the error?
Note: I also posted something here in the hopes to get topic-specific help but I've not heard a peep... After I posted that I found the info on nsinstall. Anyway, I prefer SO so I thought I'd try here...
Update: I've attempted to completly disable UAC to correct the problem as is suggested by cnemelkasr. I've received the exact same error. This new knowledge is making me think that a file or folder is missing... Does anyone who has experience with NSInstall know what the given error -- Bad file number -- might mean? I figure it might be referring to a file handle...
If it really is a UAC error, you can try turning off UAC altogether. I've had to do this for several packages. There are numerous places on the web to get the instructions for doing that.
http://www.petri.co.il/disable_uac_in_windows_vista.htm is one of them.
I found the answer to my question. I'm posting the answer here to share the answer with others and to close this question.
After disabling the UAC, it was suggested that the directory depth was interfering with NSInstall. I moved the folder from c:/Users/Frank/Documents/hg-repos/firefox-src-hgRepo/mozilla-fv-expirement/ to C:/mozilla-fv-expirement/. Cleaned all previous build attempts and finally redid my build (with UAC off) and I received a working debug binary.
The suggestion was posted at: mozilla.dev.builds
The "Bad file number" message in the cases I have seen, is caused by too many arguments passed to execvp (command, argv) (or similar) function. But only from some programs. An old bash, sh or a Borland/Watcom program in your PATH is an likely candidate.
So when you shorten the name of the build directory, the total size of the command line (that eventually gets passed to CreateProcess()) gets shorter. I don't think UAC has anything to do with this since I've seen this on Win-XP too. But it's a bit strange Mozilla would not use relative paths while building. I guess it uses some directory prefix value in it's makefiles (I've never tried building it).
If you look at the documentation for _execvp():
http://msdn.microsoft.com/en-us/library/3xw6zy53.aspx
E2BIG is one of the possible errno values:
The space required for the arguments and environment settings exceeds 32 KB.
Now, here is the strange part.
Fact 1:
On Visual-C/MingW (any version), strerror(EBADF) doesn't return "Bad file number" .
(it return "Bad file descriptor").
Fact 2:
On Borland's CBuilder 5.6 and Watcom 1.9 (these do not use the MSVC runtime), strerror(EBADF) does indeed return "Bad file number".
Theory:
Is possible that Borland, Watcom (and other CRTs too?) mixes up the meaning of E2BIG and EBADF. Did that make any sense? Someone please correct me if you have a better theory.
I'm a bit confused myself...
Conclusion: Either shorten the size of your environment (easiest) or shorten the command-line (not always easy).
--gv

Beginner Doing K&R

I'm just starting programming and going through K&R to try and learn C. I've gotten to the section on command line arguments (5.10) but now I'm stumped. Every time I try and open a program I've written with command line arguments I'm told that file X, X being the argument, doesn't exist.
`gcc -o find find.c
open find test
The file /Documents/Learning_C/test does not exist.`
Any suggestions? Thanks
What system are you on? In Unix/Linux you compile & run your executable via:
gcc -o find find.c
./find test
As others have noted, when you prefix your binary with "./", there wont be any naming conflicts. However, if you made find accessible in your $PATH, you might have some conflicts with find and test--standard programs with most *nix distributions... Maybe you could choose more specific names (i.e. ./myFind testArg)
Try giving your output executable a different name.
I suspect your executing the system find command which is looking for a directory called 'test'.
Or try forcing it by executing
./find toto
Edit: Prepending the ./ to the command is important because it tells the shell to execute the find in the current directory as opposed to the first 'find' that exists in your PATH. It is normally recommended that you don't have . (the current directory) in your PATH for security reasons.
HTH
P.S. Forgot to say good one for working through K&R. I just finished doing the same after working in C for thirty years and it was good to get back and refresh the mind!
Instead of making us all individually guess what exactly you're doing wrong, perhaps you should paste the program you're using for the illustration mentioned ?

Determine UID that last modified a file in Linux?

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;
}

Resources