cp src dst
reads the contents of the src
file and writes in into the new dst
file it has created.
So it needs read permission to the file.
On Linux at least and on some file systems such as btrfs
, it can replace the read()
s + write()
s with a ioctl (dest_fd, FICLONE, src_fd)
to do a so called reflink copy where the data is initially not duplicated on disk, but even then it still needs to open the source file for reading onto src_fd
.
If it was enough to copy a file to bypass read restrictions, then the permission system would be severely broken.
Now, instead of copying a file, you could make a new link to it with a different name:
After:
ln from/src to/dst
For which you only need search access to the from
directory and search+write access to the to
directory, with dst
on the same filesystem as src
. You end up with both src
and dst
, but note that they are the same file linked to two different directories (or the same directory with different names).
Now, if src
is executable, and is a native executable format (as opposed to a script for instance, though you can't run a script without read permission as the interpreter does need to be able to read it), that means the system is allowed to map the contents of the executable into the memory of one of your processes, which kind of amounts to reading it on your behalf.
The system does take care not to allow bypassing the read restriction. For instance, at least on Linux, the process won't generate a core dump when receiving signals such as SIGQUIT (as sent upon Ctrl+\ ). It won't let you read /proc/<pid>/maps
or /proc/<pid>/mem
for that process:
$ cp /usr/bin/sleep .
$ chmod 111 sleep
$ ./sleep inf &
[1] 86474
$ cat /proc/$!/maps
cat: /proc/86474/maps: Permission denied
$ cat /proc/$!/mem
cat: /proc/86474/mem: Permission denied
It will also not let you attach a debugger to it, even with kernel.yama.ptrace_scope = 0
.
But the process itself can obviously read its own memory, so if you can convince it to dump it somewhere, you could recover some of the data in the file.
If the file is a dynamically linked ELF executable and it's not setuid/setgid... (secure-execution-mode not enabled), on GNU/Linux systems at least, you can convince the dynamic linker to inject arbitrary code into the executable with the $LD_PRELOAD
mechanism, or tell it to use modified versions of the shared libraries it uses that have been hijacked to do that dumping by changing $LD_LIBRARY_PATH
.
For instance with:
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
static void init(void) attribute((constructor));
static void init(void)
{
FILE maps, dst;
char exe[4096], path[4096];
char start, end;
off_t offset;
int n;
n = readlink("/proc/self/exe", exe, sizeof(exe));
exe[n] = '\0';
dst = fopen(getenv("DST"), "w");
maps = fopen("/proc/self/maps", "r");
while((n = fscanf(maps, "%p-%p%s%lx%s%s%[ ]%[^\n ]\n", &start, &end, &offset, path)) != EOF) {
if (n == 4 && !strcmp(path, exe)) {
printf("Dumping [%p - %p] from %s at offset %#lx\n", start, end, path, offset);
fseek(dst, offset, SEEK_SET);
fwrite(start, end - start, 1, dst);
}
}
exit(0);
}
(error handling left as an exercise to the reader)
Compiled with:
gcc -fPIC -shared -o hack.so that-file.c
Running src
as:
DST=./dst LD_PRELOAD=./hack.so ./src
truncate -r src dst
Would have it dump the sections of the file that are mapped into memory into the ./dst
file.
If you have a readable copy of src
and use:
cmp -l src-copy dst | perl -pe 's/\d+/sprintf"%#x",$&-1/e'
And match the output against the output of objdump -h src-copy
on the offsets, you'll see it's not identical as some sections are missing or have been modified by the dynamic linker. In my tests, they were:
20 .init_array 00000008 0000000000009bb0 0000000000009bb0 00008bb0 2**3
CONTENTS, ALLOC, LOAD, DATA
21 .fini_array 00000008 0000000000009bb8 0000000000009bb8 00008bb8 2**3
CONTENTS, ALLOC, LOAD, DATA
22 .data.rel.ro 000000b8 0000000000009bc0 0000000000009bc0 00008bc0 2**5
CONTENTS, ALLOC, LOAD, DATA
23 .dynamic 000001f0 0000000000009c78 0000000000009c78 00008c78 2**3
CONTENTS, ALLOC, LOAD, DATA
24 .got 00000190 0000000000009e68 0000000000009e68 00008e68 2**3
CONTENTS, ALLOC, LOAD, DATA
26 .bss 000001b8 000000000000a080 000000000000a080 00009080 2**5
ALLOC
But the .text
and .rodata
sections at least are intact, which shows that it's futile to try to hide secrets in a non-readable dynamically linked ELF executable.
ls -l /etc/file
gives you-rws--x--x 1 root root
suid & user's executable bit enabled (lowercase s) - the bitsrwsr-x---x
are set. – Dipankar Nalui Apr 04 '18 at 09:18chmod
can change this. Androot
user has that permission. So normal user will not be able to do anything. read here https://unix.stackexchange.com/questions/79395/how-does-the-sticky-bit-work/79401#79401 – Dipankar Nalui Apr 04 '18 at 09:21