sup

small tool for privilege escalation
git clone https://git.parazyd.org/sup
Log | Files | Refs | README | LICENSE

sup.c (2238B)


      1 /* See LICENSE file for copyright and license details. */
      2 
      3 #include <stdio.h>
      4 #include <stdlib.h>
      5 #include <string.h>
      6 #include <sys/stat.h>
      7 #include <unistd.h>
      8 
      9 #include "arg.h"
     10 #include "sha256.h"
     11 
     12 #define nelem(x) (sizeof (x) / sizeof *(x))
     13 #define CHUNK 1048576		/* 1MiB */
     14 
     15 struct rule_t {
     16 	const int uid;
     17 	const char *cmd;
     18 	const char *path;
     19 	const char *hash;
     20 };
     21 
     22 #include "config.h"
     23 
     24 char *argv0;
     25 
     26 static void die(char *msg)
     27 {
     28 	fprintf(stderr, "%s\n", msg);
     29 	exit(1);
     30 }
     31 
     32 static uint32 getsha(const char *path, unsigned char *dest)
     33 {
     34 	static sha256_context sha;
     35 	unsigned char buf[CHUNK];
     36 	uint32 len, tot = 0;
     37 	FILE *fd;
     38 
     39 	fd = fopen(path, "r");
     40 	if (!fd)
     41 		die("Can not read binary file.");
     42 
     43 	sha256_starts(&sha);
     44 
     45 	while ((len = fread(buf, 1, CHUNK, fd))) {
     46 		sha256_update(&sha, buf, len);
     47 		tot += len;
     48 	}
     49 	fclose(fd);
     50 
     51 	sha256_finish(&sha, dest);
     52 	return tot;
     53 }
     54 
     55 int main(int argc, char *argv[])
     56 {
     57 	unsigned int c, i, lflag = 0;
     58 	unsigned char digest[32];
     59 	char output[65];
     60 	struct stat st;
     61 
     62 	ARGBEGIN {
     63 	case 'l':
     64 		lflag = 1;
     65 		break;
     66 	default:
     67 		die("Usage: sup [-l] command [ args ... ]");
     68 	} ARGEND;
     69 
     70 	if (lflag) {
     71 		printf("List of compiled authorizations:\n");
     72 		for (i = 0; i < nelem(rules); i++)
     73 			printf("\nuser: %d\ncmd: %s\nbinary: %s\nsha256: %s\n",
     74 			       rules[i].uid, rules[i].cmd, rules[i].path,
     75 			       rules[i].hash);
     76 		return 0;
     77 	}
     78 
     79 	if (argc < 1)
     80 		die("Usage: sup [-l] command [ args ... ]");
     81 
     82 	for (i = 0; i < nelem(rules); i++) {
     83 		if (!strcmp(argv[0], rules[i].cmd)) {
     84 
     85 			if (rules[i].uid != getuid() && rules[i].uid != -1)
     86 				die("Unauthorized user.");
     87 
     88 			if (stat(rules[i].path, &st) == -1)
     89 				die("Can not stat program.");
     90 
     91 			if (st.st_mode & 0022)
     92 				die("Can not run writable binaries.");
     93 
     94 			if (getsha(rules[i].path, digest) != st.st_size)
     95 				die("Binary file differs from size read.");
     96 
     97 			for (c = 0; c < 32; c++)
     98 				sprintf(output + (c * 2), "%02x", digest[c]);
     99 			output[64] = '\0';
    100 
    101 			if (strncmp(rules[i].hash, output, 64))
    102 				die("Checksums do not match.");
    103 
    104 			if (setgid(SETGID) < 0)
    105 				die("setgid failed");
    106 			if (setuid(SETUID) < 0)
    107 				die("setuid failed");
    108 
    109 			if (execv(rules[i].path, argv) < 0)
    110 				die("execv failed.");
    111 		}
    112 	}
    113 	die("Unauthorized command.");
    114 }