#1 Le 11/06/2019, à 16:21
- FanfanPopo
Permissions scripts : uniquement executable par tout le monde
Bonjour,
j'ai créé un script en root. Je souhaiterais que seul l'utilisateur root puisse lire et écrire dans ce script. Les autres utilisateurs peuvent uniquement l'executer. L'objectif est que les utilisateurs non root puissent executer le script sans pouvoir le lire.
J'ai essayé
sudo chmod 711 script.sh
Voici le résultat du ls -l :
-rwx--x--x 1 root root 24 juin 11 17:01 script.sh
Cependant, l'utilisateur non root ne peut pas l'éxecuter.
/bin/bash : ./script.sh: Permission non accordée
J'ai effectué quelques recherches mais n'ai pas trouvé de solution à mon problème.
Avez-vous une idée ?
Hors ligne
#2 Le 11/06/2019, à 18:06
- Watael
Re : Permissions scripts : uniquement executable par tout le monde
salut,
pour exécuter un script, il faut impérativement pouvoir le lire.
Connected \o/
Welcome to sHell. · eval is evil.
Hors ligne
#3 Le 11/06/2019, à 18:13
- pingouinux
Re : Permissions scripts : uniquement executable par tout le monde
Bonsoir,
Tu peux regarder cette discussion de 2012, notamment mon message #7, auquel je n'ai jamais reçu de réponse :
Interdire lecture d'un script a un utilisateur
Le lien qui y figure ne semble plus actif.
Il s'agit d'utiliser setuid, mais ce n'est pas possible sur un script. Il faut ruser en utilisant setuid sur un lanceur écrit en C qui va appeler le script, et les utilisateurs appelleront le lanceur.
man setuid
Hors ligne
#4 Le 11/06/2019, à 22:34
- kamaris
Re : Permissions scripts : uniquement executable par tout le monde
@pingouinux : le code donné dans ton lien nécessite une petite modif, depuis Ubuntu 16.04 semble-t-il, car le comportement par défaut de dash a alors été changé pour coller à celui de bash concernant le traitement du suid : https://unix.stackexchange.com/question … nsistently
Ceci dit, comme il est finalement conseillé dans ce lien ou dans celui-ci, ne vaut-il pas mieux de toutes façons utiliser la fonctionnalité offerte par sudo d'exécuter une commande spécifique sans mot de passe ?
Hors ligne
#5 Le 12/06/2019, à 08:46
- pingouinux
Re : Permissions scripts : uniquement executable par tout le monde
@kamaris #4 : Effectivement, je viens de faire un test, et ça ne marche plus
$ cat lanceur.c
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
printf("UID=%d EUID=%d\n",getuid(),geteuid());
system("./mon_script.sh");
}
$ make lanceur
cc lanceur.c -o lanceur
$ sudo chown root:root lanceur
$ sudo chmod 4705 lanceur
$ ls -l lanceur mon_script.sh
-rws---r-x 1 root root 8768 Jun 12 09:41 lanceur
-rwx------ 1 root root 62 Jun 12 09:30 mon_script.sh
$ ./lanceur
UID=1000 EUID=0
sh: 1: ./mon_script.sh: Permission denied
Dernière modification par pingouinux (Le 12/06/2019, à 09:15)
Hors ligne
#6 Le 12/06/2019, à 10:45
- kamaris
Re : Permissions scripts : uniquement executable par tout le monde
Oui, comme dit dans une réponse du lien ci-dessus, il faut ajouter un bout de code pour forcer l'uid à rester sur l'euid, car system() appelle sh qui pointe vers dash :
:~$ cat lanceur.c
#define _GNU_SOURCE
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
int main() {
uid_t euid = geteuid();
gid_t egid = getegid();
setresgid(egid, egid, egid);
setresuid(euid, euid, euid);
printf("UID=%d EUID=%d\n",getuid(),geteuid());
system("./script.sh");
}
:~$ sudo cat script.sh
#!/bin/bash
echo "ok"
:~$ make lanceur
cc lanceur.c -o lanceur
:~$ sudo chown root:root lanceur
:~$ sudo chmod 4701 lanceur
:~$ ls -l lanceur script.sh
-rws-----x 1 root root 16760 juin 12 11:34 lanceur
-rwx------ 1 root root 23 juin 12 11:30 script.sh
:~$ ./lanceur
UID=0 EUID=0
ok
:~$
Par contre, encore une fois, l'usage de sudo en éditant /etc/sudoers est surement préférable pour faire ce que veut faire @FanfanPopo.
Hors ligne
#7 Le 12/06/2019, à 12:43
- pingouinux
Re : Permissions scripts : uniquement executable par tout le monde
Merci kamaris. J'ai testé ton lanceur avec succès, et le note sur mes tablettes.
Je ne savais pas qu'un exécutable n'a pas besoin de la permission de lecture, et que l'exécution suffit.
Dans notre cas, il suffit de :
$ sudo chmod 4101 lanceur
$ ls -l lanceur
---s-----x 1 root root 8976 Jun 12 13:27 lanceur
Hors ligne
#8 Le 12/06/2019, à 13:07
- kamaris
Re : Permissions scripts : uniquement executable par tout le monde
Oui effectivement, les droits de lecture (et à fortiori d'écriture) ne sont pas non plus nécessaires pour root. Je suis loin de maitriser toutes les subtilités de la chose, mais comme on s'en doute, c'est parce que l'exécutable est chargé directement dans le noyau, au contraire du script qui doit être lu par l'interpréteur, comme il est dit par exemple dans cette autre lien unix.stackexchange.
Tant qu'on y est, j'ajoute ici une autre version de lanceur.c qui fonctionne aussi (glanée et adaptée à partir d'un lien que je ne retrouve plus), sans s'embêter avec ces histoires de sh/dash, car on peut cette fois utiliser l'option -p de bash :
:~$ cat lanceur.c
#include <unistd.h>
int main () {
char* arr[] = {"bash", "-p", "./script.sh", NULL};
return execv("/bin/bash", arr);
}
:~$
Dernière modification par kamaris (Le 12/06/2019, à 13:11)
Hors ligne
#9 Le 12/06/2019, à 14:47
- LeoMajor
Re : Permissions scripts : uniquement executable par tout le monde
bonjour,
utilise shc - Generic shell script compiler
très simple et efficace
sudo apt/aptitude install shc
exemple;
nano ~/scripts/test_instructions.bash
..
#!/bin/bash
declare -a nums rnums
echo "bonjour"
if [ "$EUID" -ne 0 ]; then printf "%s\n" "vous n'êtes pas root" ; else echo -e "\tcontinue\n"; fi
test -f "$0" && file "$0"
for ((i=1; i<=5; i++)); do nums+=("$i"); done
rnums=($(sort -r < <(printf "%d\n" ${nums[*]})))
declare -p nums
declare -p rnums
exit 9
chmod +x ~/scripts/test_instructions.bash
jusque là le script fonctionne normalement soit par ./scripts/test_instructions.bash ou bash /scripts/test_instructions.bash
le fichier est parfaitement lisible
après cela se complique
shc -f ~/scripts/test_instructions.bash
qui génère
ls -ls ~/scripts/test_instructions.bash*
4 -rwxr-xr-x 1 toto ... /home/toto/scripts/test_instructions.bash
12 -rwx--x--x 1 toto ... /home/toto/scripts/test_instructions.bash.x
12 -rw-r--r-- 1 toto ... /home/toto/scripts/test_instructions.bash.x.c
A/ /home/toto/scripts/test_instructions.bash est le fichier original qui fonctionne de manière classique
B/ le deuxième, est un binaire
:~$ ./scripts/test_instructions.bash.x
bonjour
vous n'êtes pas root
./scripts/test_instructions.bash.x: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=f456c047690b4111dab6e80bf0c07dc2ca22fa92, stripped
declare -a nums='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")'
declare -a rnums='([0]="5" [1]="4" [2]="3" [3]="2" [4]="1")'
ou
sudo ./scripts/test_instructions.bash.x
[sudo] Mot de passe de toto : ...
bonjour
continue
./scripts/test_instructions.bash.x: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 2.6.32, BuildID[sha1]=f456c047690b4111dab6e80bf0c07dc2ca22fa92, stripped
declare -a nums='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")'
declare -a rnums='([0]="5" [1]="4" [2]="3" [3]="2" [4]="1")'
le binaire fonctionne parfaitement mais évidemment parfaitement illisible pour retrouver le script d'origine.
tu peux le vérifier avec hexdump, strings, od, objdump, ... , il y n'y a pas de traces.
donc tu peux laisser ~/scripts/test_instructions.bash.x, accessible à tout le monde
Donc tu auras compris que ~/scripts/test_instructions.bash sera réservé à root, y compris shc
C/ le dernier fichier en C est le code qui sert à la compilation pour B/.
cat ./scripts/test_instructions.bash.x.c
#if 0
shc Version 3.8.9b, Generic Script Compiler
Copyright (c) 1994-2015 Francisco Rosales <frosal@fi.upm.es>
shc -f ./scripts/test_instructions.bash
#endif
static char data [] =
#define tst2_z 19
#define tst2 ((&data[0]))
"\114\325\273\025\111\065\223\303\336\122\055\325\032\214\003\363"
"\042\003\205\140"
#define rlax_z 1
#define rlax ((&data[20]))
"\334"
#define text_z 312
#define text ((&data[62]))
"\351\324\265\361\365\125\213\316\256\032\330\266\036\031\054\371"
"\254\147\025\236\242\372\255\337\132\130\316\264\061\124\013\033"
"\050\300\014\036\026\230\355\305\262\000\340\160\343\236\241\013"
"\127\076\246\354\212\246\345\176\163\051\254\265\035\110\106\316"
"\111\011\104\351\242\302\114\234\316\114\007\216\221\167\064\036"
"\017\026\331\227\000\352\003\307\360\362\123\132\102\004\010\374"
"\370\310\251\015\172\076\374\035\207\374\376\031\175\260\225\122"
"\377\220\365\114\027\236\235\146\045\115\371\073\132\205\114\056"
"\060\224\126\271\022\056\325\351\232\312\210\022\357\206\334\145"
"\037\175\245\236\040\214\177\256\240\002\103\377\217\011\162\343"
"\275\077\210\032\151\072\200\226\146\177\131\230\143\377\307\354"
"\145\113\336\331\002\354\035\141\155\052\015\346\017\311\350\013"
"\142\202\253\241\053\362\106\266\100\220\351\057\320\211\064\252"
"\366\202\133\351\064\251\277\274\165\140\232\177\357\052\364\320"
"\040\107\004\337\363\123\035\171\040\061\252\364\254\356\223\006"
"\052\206\324\051\345\367\363\244\126\151\363\240\036\177\020\145"
"\206\345\014\124\015\124\257\035\132\006\244\236\176\371\056\267"
"\032\235\134\275\125\332\153\250\373\275\120\237\265\073\276\320"
"\020\035\176\275\171\332\072\245\221\137\135\316\023\016\060\342"
"\126\076\201\316\271\320\242\102\272\272\006\176\012\035\003\135"
"\351\061\124\014\236\246\111\357\107\037\332\115\031\012\171\300"
"\250\217\121\274\116\170\330\334\161\036\241\307\052\161\360\150"
"\347\306\173\320\337\250\312\214\020\337\052\262\331\330\222\064"
"\061\140\350\142\265\363\176\336\264\212\375"
#define opts_z 1
#define opts ((&data[400]))
"\151"
#define chk1_z 22
#define chk1 ((&data[406]))
"\013\246\221\263\160\242\333\135\076\134\311\222\140\205\365\131"
"\106\001\152\210\315\115\255\277\070\356\254\035\304\120\107"
#define lsto_z 1
#define lsto ((&data[432]))
"\001"
#define pswd_z 256
#define pswd ((&data[456]))
"\151\106\264\037\072\062\376\356\275\373\271\340\346\111\265\227"
"\125\134\050\011\314\106\315\340\003\107\102\062\377\337\134\340"
"\077\106\356\132\031\050\126\036\051\162\110\324\030\245\277\274"
"\326\241\225\152\113\146\112\116\255\214\200\255\154\335\215\254"
"\043\173\007\075\243\135\133\315\320\244\241\350\112\141\245\041"
"\002\072\213\116\241\325\234\116\142\035\374\317\372\211\173\036"
"\004\203\133\250\340\267\165\260\134\027\231\246\170\076\310\173"
"\171\123\311\032\051\145\151\214\203\145\134\175\356\330\233\363"
"\133\367\233\073\257\020\354\013\047\206\262\240\304\172\033\075"
"\316\345\130\370\112\302\205\316\047\341\113\026\271\347\011\024"
"\337\244\120\216\265\075\231\335\303\113\175\210\306\231\306\225"
"\176\036\215\311\340\023\227\010\364\343\036\255\312\050\302\251"
"\315\023\067\203\120\321\140\023\035\336\233\343\167\142\171\366"
"\200\006\277\141\032\126\151\016\071\210\274\004\261\177\256\177"
"\222\345\002\342\266\142\366\323\101\222\267\270\364\060\256\165"
"\067\156\326\121\305\100\140\376\311\034\003\173\233\261\372\056"
"\227\374\020\115\137\007\041\240\232\331\130\216\011\007\004\101"
"\166\332\222\073\033\362\072\035\216\103\107\256\114\245\000\266"
"\353\264\325\045\347\323\024\244\317\316\205"
#define chk2_z 19
#define chk2 ((&data[732]))
"\054\251\341\141\372\263\124\055\112\313\260\141\200\261\014\104"
"\323\057\261\115"
#define tst1_z 22
#define tst1 ((&data[755]))
"\166\144\274\364\277\352\026\017\044\242\210\262\337\147\104\245"
"\274\231\340\303\132\223\316\235\137\103\201"
#define inlo_z 3
#define inlo ((&data[779]))
"\303\075\014"
#define msg1_z 42
#define msg1 ((&data[791]))
"\371\212\131\255\137\176\224\063\223\137\210\102\263\006\025\014"
"\000\044\360\106\267\152\060\217\346\167\244\274\320\103\240\330"
"\336\276\005\336\372\146\217\252\163\220\020\103\261\112\152\022"
"\027\030\066\071\002\142\276"
#define date_z 1
#define date ((&data[837]))
"\010"
#define shll_z 10
#define shll ((&data[840]))
"\173\135\272\242\042\144\251\014\264\327\317\046\364"
#define xecc_z 15
#define xecc ((&data[853]))
"\202\050\075\317\071\332\102\036\362\043\301\363\372\307\177\000"
"\103\076"
#define msg2_z 19
#define msg2 ((&data[873]))
"\164\206\004\042\166\262\361\176\356\015\157\052\313\347\241\171"
"\177\235\315\363\150\350\274\346\203\267"/* End of data[] */;
#define hide_z 4096
#define DEBUGEXEC 0 /* Define as 1 to debug execvp calls */
#define TRACEABLE 0 /* Define as 1 to enable ptrace the executable */
/* rtc.c */
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
/* 'Alleged RC4' */
static unsigned char stte[256], indx, jndx, kndx;
/*
* Reset arc4 stte.
*/
void stte_0(void)
{
indx = jndx = kndx = 0;
do {
stte[indx] = indx;
} while (++indx);
}
/*
* Set key. Can be used more than once.
*/
void key(void * str, int len)
{
unsigned char tmp, * ptr = (unsigned char *)str;
while (len > 0) {
do {
tmp = stte[indx];
kndx += tmp;
kndx += ptr[(int)indx % len];
stte[indx] = stte[kndx];
stte[kndx] = tmp;
} while (++indx);
ptr += 256;
len -= 256;
}
}
/*
* Crypt data.
*/
void arc4(void * str, int len)
{
unsigned char tmp, * ptr = (unsigned char *)str;
while (len > 0) {
indx++;
tmp = stte[indx];
jndx += tmp;
stte[indx] = stte[jndx];
stte[jndx] = tmp;
tmp += stte[indx];
*ptr ^= stte[tmp];
ptr++;
len--;
}
}
/* End of ARC4 */
/*
* Key with file invariants.
*/
int key_with_file(char * file)
{
struct stat statf[1];
struct stat control[1];
if (stat(file, statf) < 0)
return -1;
/* Turn on stable fields */
memset(control, 0, sizeof(control));
control->st_ino = statf->st_ino;
control->st_dev = statf->st_dev;
control->st_rdev = statf->st_rdev;
control->st_uid = statf->st_uid;
control->st_gid = statf->st_gid;
control->st_size = statf->st_size;
control->st_mtime = statf->st_mtime;
control->st_ctime = statf->st_ctime;
key(control, sizeof(control));
return 0;
}
#if DEBUGEXEC
void debugexec(char * sh11, int argc, char ** argv)
{
int i;
fprintf(stderr, "shll=%s\n", sh11 ? sh11 : "<null>");
fprintf(stderr, "argc=%d\n", argc);
if (!argv) {
fprintf(stderr, "argv=<null>\n");
} else {
for (i = 0; i <= argc ; i++)
fprintf(stderr, "argv[%d]=%.60s\n", i, argv[i] ? argv[i] : "<null>");
}
}
#endif /* DEBUGEXEC */
void rmarg(char ** argv, char * arg)
{
for (; argv && *argv && *argv != arg; argv++);
for (; argv && *argv; argv++)
*argv = argv[1];
}
int chkenv(int argc)
{
char buff[512];
unsigned long mask, m;
int l, a, c;
char * string;
extern char ** environ;
mask = (unsigned long)&chkenv;
mask ^= (unsigned long)getpid() * ~mask;
sprintf(buff, "x%lx", mask);
string = getenv(buff);
#if DEBUGEXEC
fprintf(stderr, "getenv(%s)=%s\n", buff, string ? string : "<null>");
#endif
l = strlen(buff);
if (!string) {
/* 1st */
sprintf(&buff[l], "=%lu %d", mask, argc);
putenv(strdup(buff));
return 0;
}
c = sscanf(string, "%lu %d%c", &m, &a, buff);
if (c == 2 && m == mask) {
/* 3rd */
rmarg(environ, &string[-l - 1]);
return 1 + (argc - a);
}
return -1;
}
#if !defined(TRACEABLE)
#define _LINUX_SOURCE_COMPAT
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#if !defined(PTRACE_ATTACH) && defined(PT_ATTACH)
# define PTRACE_ATTACH PT_ATTACH
#endif
void untraceable(char * argv0)
{
char proc[80];
int pid, mine;
switch(pid = fork()) {
case 0:
pid = getppid();
/* For problematic SunOS ptrace */
#if defined(__FreeBSD__)
sprintf(proc, "/proc/%d/mem", (int)pid);
#else
sprintf(proc, "/proc/%d/as", (int)pid);
#endif
close(0);
mine = !open(proc, O_RDWR|O_EXCL);
if (!mine && errno != EBUSY)
mine = !ptrace(PTRACE_ATTACH, pid, 0, 0);
if (mine) {
kill(pid, SIGCONT);
} else {
perror(argv0);
kill(pid, SIGKILL);
}
_exit(mine);
case -1:
break;
default:
if (pid == waitpid(pid, 0, 0))
return;
}
perror(argv0);
_exit(1);
}
#endif /* !defined(TRACEABLE) */
char * xsh(int argc, char ** argv)
{
char * scrpt;
int ret, i, j;
char ** varg;
char * me = argv[0];
stte_0();
key(pswd, pswd_z);
arc4(msg1, msg1_z);
arc4(date, date_z);
if (date[0] && (atoll(date)<time(NULL)))
return msg1;
arc4(shll, shll_z);
arc4(inlo, inlo_z);
arc4(xecc, xecc_z);
arc4(lsto, lsto_z);
arc4(tst1, tst1_z);
key(tst1, tst1_z);
arc4(chk1, chk1_z);
if ((chk1_z != tst1_z) || memcmp(tst1, chk1, tst1_z))
return tst1;
ret = chkenv(argc);
arc4(msg2, msg2_z);
if (ret < 0)
return msg2;
varg = (char **)calloc(argc + 10, sizeof(char *));
if (!varg)
return 0;
if (ret) {
arc4(rlax, rlax_z);
if (!rlax[0] && key_with_file(shll))
return shll;
arc4(opts, opts_z);
arc4(text, text_z);
arc4(tst2, tst2_z);
key(tst2, tst2_z);
arc4(chk2, chk2_z);
if ((chk2_z != tst2_z) || memcmp(tst2, chk2, tst2_z))
return tst2;
/* Prepend hide_z spaces to script text to hide it. */
scrpt = malloc(hide_z + text_z);
if (!scrpt)
return 0;
memset(scrpt, (int) ' ', hide_z);
memcpy(&scrpt[hide_z], text, text_z);
} else { /* Reexecute */
if (*xecc) {
scrpt = malloc(512);
if (!scrpt)
return 0;
sprintf(scrpt, xecc, me);
} else {
scrpt = me;
}
}
j = 0;
varg[j++] = argv[0]; /* My own name at execution */
if (ret && *opts)
varg[j++] = opts; /* Options on 1st line of code */
if (*inlo)
varg[j++] = inlo; /* Option introducing inline code */
varg[j++] = scrpt; /* The script itself */
if (*lsto)
varg[j++] = lsto; /* Option meaning last option */
i = (ret > 1) ? ret : 0; /* Args numbering correction */
while (i < argc)
varg[j++] = argv[i++]; /* Main run-time arguments */
varg[j] = 0; /* NULL terminated array */
#if DEBUGEXEC
debugexec(shll, j, varg);
#endif
execvp(shll, varg);
return shll;
}
int main(int argc, char ** argv)
{
#if DEBUGEXEC
debugexec("main", argc, argv);
#endif
#if !defined(TRACEABLE)
untraceable(argv[0]);
#endif
argv[1] = xsh(argc, argv);
fprintf(stderr, "%s%s%s: %s\n", argv[0],
errno ? ": " : "",
errno ? strerror(errno) : "",
argv[1] ? argv[1] : "<null>"
);
return 1;
}
dans un contexte d'exploitation, ce dernier fichier est à supprimer
Dernière modification par LeoMajor (Le 12/06/2019, à 14:51)
Hors ligne
#10 Le 12/06/2019, à 17:10
- melixgaro
Re : Permissions scripts : uniquement executable par tout le monde
bonjour,
Attention avec shc. Il y a une limite sur le nombre de caractère que peut contenir le script d'origine et surtout :
$ cat script.sh
#!/bin/bash
while true
do
sleep 0.01
done
Exécution du script bash d'origine
$ ./script.sh
$ ps faux | grep script.sh
melixgaro 27112 3.1 0.0 9564 3504 pts/59 S+ 18:04 0:00 | \_ /bin/bash ./script.sh
Exécution du script passé via shc (regardez tout au bout de la très longue ligne, c'est le copier-coller tel quel du ps)
$ ./script.sh.x
$ ps faux | grep script.sh
melixgaro 4396 2.6 0.0 9568 3572 pts/59 S+ 18:05 0:00 | \_ ./script.sh.x -c #!/bin/bash while true do sleep 0.01 done ./script.sh.x
Linux depuis ~2007. Xubuntu seulement.
Hors ligne