Compilando Shell Scripts com o SHC
Introdução
Em algumas situações você pode querer que seu código escrito em shell script seja compilado por diversos motivos como por exemplo: esconder alguma informação sigilosa que está dentro do script, uma credencial de acesso à base de dados, ou porque você não quer que alguém altere o código sem a sua permissão, ou porque você não quer entregar o "ouro" da sua consultoria. Enfim, é uma maneira de esconder o seu código dos olhos alheios. Mas existem algumas coisas que temos que ter em mente quando formos usá-lo:
- Ele não é a prova de NSA (National Security Agency). Não possui uma criptografia de alto nível mas ajuda bastante na tarefa.
- Não gera binários independentes. Você continuará dependendo do shell e de todos os programas que ele chama.
- O SHC (Shell Script Compiler) precisa ter no topo do arquivo o shebang, a informação que aponta o shell que será usado, por exemplo: #!/usr/bin/bash ou #!/usr/bin/sh
- O SHC gera um código em fonte C do shell script, que na sequência é compilado. Sim você precisa ter um compilador C para isso. No processo de execução, o programa é desencriptado e executado como um bash normal; por isso não é um binário independente.
- Você pode colocar um prazo de validade do binário e uma mensagem para quem executar o programa após vencer a validade. Ex: "Programa expirado contacte fulano".
- O binário fica bem maior que o seu arquivo shell script.
- Não pense que a execução do seu novo binário será muito mais rápido que o seu shell, porque como eu disse, o processo é rodado como shell após ser desencriptado.
Instalação
Como é de hábito aqui, faremos isso no Debian, nesse caso a versão 11 (Bullseye). Você pode instalar o SHC em qualquer distribuição GNU/Linux de sua preferência, só precisará checar se já existe um pacote para ele ou se vai precisar compilar o fonte e logicamente ter um compilador C também instalado para isso.
apt install shc build-essential
Utilizando o SHC
Vou pegar como exemplo um script de backup que tenho aqui e que além de fazer backup dos arquivos e diretórios que tenho no servidor, ele gera um backup da base de dados e as tabelas separadamente.
#!/usr/bin/bash SERVIDOR="azn" PROVEDOR="Area Zero Network" TEMP="/usr/local/backup/azn" USER="root" PASS="tua_senha_aqui" dpkg -l > $TEMP/`date +%d`/lista_pacotes.txt tar -czpf $TEMP/`date +%d`/$SERVIDOR.tar.gz /etc /root /var/www tar -tzpf $TEMP/`date +%d`/$SERVIDOR.tar.gz if [ $? -ne 0 ]; then echo "Erro gerando backup AZN tar.gz!" | /usr/local/sbin/telegram-notify --error --text - exit fi rm $TEMP/`date +%d`/*.bz2 for banco in $(mysql -u$USER -p$PASS --execute="show databases" | grep -v Database) ; do for tabela in $(mysql -u$USER -p$PASS --execute="show tables" $banco | grep -v Tables_in_) ; do if [ "$banco" == "mysql" -a "$tabela" == "general_log" ]; then mysqldump -c -u$USER -p$PASS --lock-tables=0 $banco $tabela | bzip2 -9 > $TEMP/`date +%d`/$SERVIDOR-$banco-$tabela.sql.bz2 else if [ "$banco" == "mysql" -a "$tabela" == "slow_log" ]; then mysqldump -c -u$USER -p$PASS --lock-tables=0 $banco $tabela | bzip2 -9 > $TEMP/`date +%d`/$SERVIDOR-$banco-$tabela.sql.bz2 else mysqldump -c -u$USER -p$PASS --single-transaction=TRUE $banco $tabela | bzip2 -9 > $TEMP/`date +%d`/$SERVIDOR-$banco-$tabela.sql.bz2 fi fi if [ $? -ne 0 ]; then echo "Erro gerando backup AZN MariaDB!" | /usr/local/sbin/telegram-notify --error --text - exit fi done done echo "Backup do servidor AZN feito corretamente!" | /usr/local/sbin/telegram-notify --success --text -
Esse script além de fazer o backup, me avisa pelo Telegram se foi tudo bem ou se deu algum erro. Percebam que ali na variável PASS teria a senha da base de dados para o backup e não é bom que fique assim disponível para qualquer um ver. Então vamos compilar nosso shell script assim, supondo que o nome dele seja backup.sh.
# shc -o backup -f backup.sh
Esse comando lerá o backup.sh, gerará nosso binário chamado backup e o fonte em C chamado backup.sh.x.c.
# ls -lah backup_* -rwxrwxr-x 1 root root 17K fev 5 14:19 backup -rwx------ 1 root root 1,5K fev 5 13:59 backup.sh -rw-r--r-- 1 root root 25K fev 5 14:19 backup.sh.x.c
Primeira coisa que reparamos é o tamanho de cada arquivo; nosso backup.sh possui um apenas 1,5k de tamanho enquanto o binário ficou com 17k. Mas não vamos ser mesquinhos quanto a isso, porque na maioria das vezes temos bastante recurso de memória nos servidores que mexemos não é mesmo?
Após a execução do binário
Para testar rodei o binário, este fez todo o backup e por fim ainda avisou no meu Telegram. Obs.: em outro artigo mostrarei como configurar esse programa que uso para o Telegram.
Código fonte em C
Vamos olhar como ficou nosso fonte em C?
#if 0 shc Version 4.0.3, Generic Shell Script Compiler GNU GPL Version 3 Md Jahidul Hamid <[email protected]> shc -o backup -f backup.sh #endif static char data [] = #define chk2_z 19 #define chk2 ((&data[3])) "\132\367\223\065\273\354\372\026\336\302\175\261\134\337\354\357" "\375\203\257\174\303\036" #define msg2_z 19 #define msg2 ((&data[26])) "\155\236\003\175\207\220\316\347\020\101\333\207\160\021\241\204" "\017\071\370\357\256\164\171\203\210" #define tst1_z 22 #define tst1 ((&data[47])) "\230\215\223\271\263\242\067\162\123\145\022\201\376\321\007\232" "\336\205\051\005\242\301\356\243\232\046\200" #define rlax_z 1 #define rlax ((&data[74])) "\166" #define opts_z 1 #define opts ((&data[75])) "\315" #define xecc_z 15 #define xecc ((&data[76])) "\355\244\240\352\251\255\145\034\004\045\341\147\267\353\330\001" "\113" #define text_z 1447 #define text ((&data[445])) "\200\361\155\356\220\160\153\024\371\350\061\363\327\324\216\376" "\125\100\311\217\007\243\030\145\307\233\147\023\170\140\363\371" "\122\140\347\342\321\123\366\313\073\050\277\023\375\115\021\123" "\216\332\343\226\176\373\373\106\227\143\131\020\303\115\011\025" "\256\360\370\177\103\357\113\177\027\012\222\025\130\244\151\346" "\176\114\175\374\110\171\102\337\334\234\357\237\351\371\265\227" "\351\255\027\055\234\143\255\264\156\100\312\306\344\063\255\143" "\200\052\140\310\243\243\250\200\100\230\037\052\221\324\301\173" "\202\331\250\037\075\126\323\253\226\236\162\173\321\037\336\121" "\112\077\032\356\342\302\156\042\133\216\114\354\143\016\147\345" "\350\020\004\045\146\330\321\375\166\103\171\110\143\127\231\255" "\227\264\233\171\167\012\233\322\230\347\276\373\366\045\340\336" "\066\345\004\234\276\325\232\064\030\023\174\173\153\026\051\002" "\313\304\174\102\317\027\024\147\377\323\142\366\371\103\324\057" "\051\330\314\347\255\146\034\306\172\231\101\346\257\152\351\172" "\057\145\275\376\175\321\146\174\245\311\163\236\015\107\315\066" "\040\231\036\315\000\072\224\172\323\325\140\203\100\111\376\157" "\257\274\156\054\216\325\251\063\236\034\321\253\143\236\342\204" "\070\001\122\070\073\346\262\017\273\023\223\373\135\221\153\014" "\116\332\071\334\257\342\017\115\376\340\371\142\177\334\347\267" "\335\071\357\030\037\242\050\332\266\273\326\024\115\102\040\233" "\034\132\167\313\074\207\030\073\147\022\236\347\356\205\236\313" "\233\371\176\335\105\332\023\173\031\136\021\047\075\346\271\136" "\355\074\167\335\232\056\205\052\300\064\000\012\377\036\170\333" "\057\321\206\064\306\260\160\276\226\217\301\254\246\003\034\075" "\257\100\264\272\042\105\117\252\060\211\073\163\331\064\317\164" "\320\321\000\067\012\234\257\331\110\110\324\153\257\206\234\041" "\147\271\357\244\113\105\017\227\127\300\255\111\014\120\272\366" "\156\313\217\171\257\066\331\320\066\150\073\234\275\012\364\237" "\054\001\154\276\113\361\373\317\053\211\251\217\103\015\043\302" "\054\207\100\301\337\232\137\013\056\301\145\105\116\226\222\077" "\316\346\311\273\066\256\334\022\176\152\031\351\327\270\315\177" "\335\333\154\367\367\166\355\106\355\275\336\335\221\052\350\323" "\320\337\211\040\255\271\012\073\311\170\010\055\335\351\360\207" "\302\240\366\061\057\042\116\177\165\160\102\357\307\137\053\163" "\036\045\043\123\231\007\217\000\212\012\310\121\345\104\343\370" "\360\153\324\133\045\353\127\072\167\153\011\151\161\076\067\300" "\337\371\270\330\232\207\030\213\046\316\006\302\246\274\005\160" "\100\037\351\126\142\242\051\117\046\220\175\351\041\156\155\220" "\333\334\125\112\135\336\246\374\252\132\355\054\046\132\326\175" "\363\134\114\056\113\163\326\163\160\237\364\026\371\301\226\111" "\373\126\264\325\310\061\066\274\115\230\137\055\203\255\047\213" "\016\140\143\000\222\073\247\120\056\002\263\170\367\313\050\376" "\314\215\225\061\254\140\241\057\151\147\047\342\040\314\174\132" "\236\136\154\160\032\233\256\101\310\117\367\264\053\216\326\231" "\323\172\362\243\136\201\150\136\035\067\055\325\311\171\307\042" "\336\305\276\370\071\123\371\063\006\214\225\125\141\036\076\151" "\330\247\141\231\030\370\271\216\140\030\163\365\252\157\224\041" "\261\125\147\245\060\030\307\240\300\260\263\021\324\174\203\010" "\275\313\254\145\266\340\162\052\020\245\060\232\307\002\102\354" "\270\110\011\230\332\035\234\135\020\342\122\260\372\251\302\250" "\034\114\171\362\307\166\142\137\270\153\371\117\073\251\352\267" "\016\157\220\362\226\117\075\275\041\261\210\074\227\274\045\073" "\154\250\217\233\322\023\211\163\044\316\326\372\347\334\310\036" "\277\062\335\045\163\221\136\162\147\321\170\016\037\043\073\115" "\115\352\250\143\314\210\017\337\211\071\222\026\064\022\115\336" "\341\214\240\217\320\057\167\232\043\020\155\272\144\316\222\305" "\311\112\213\346\377\036\142\270\241\272\163\363\024\264\157\131" "\215\371\345\323\264\074\135\126\222\062\352\220\154\101\363\256" "\071\161\210\254\372\312\106\076\273\272\062\221\007\306\164\351" "\112\343\360\006\011\362\304\071\307\112\274\125\172\024\174\375" "\365\150\307\106\042\357\220\337\253\174\225\247\110\374\066\005" "\311\376\230\335\232\304\206\340\374\302\112\346\353\063\340\061" "\261\075\302\367\344\374\125\256\245\002\142\105\162\212\060\350" "\033\351\206\150\162\020\033\064\375\035\035\016\360\001\373\304" "\317\157\266\202\333\316\127\203\041\124\162\347\167\064\322\033" "\072\343\231\126\224\371\234\171\372\263\051\075\262\363\203\024" "\151\304\264\210\021\353\204\124\245\271\072\250\042\226\044\174" "\330\246\271\012\246\334\325\261\331\147\334\335\257\010\362\076" "\306\364\231\134\167\242\025\050\273\207\125\166\007\132\101\226" "\130\331\174\070\236\063\356\140\371\375\265\270\066\244\010\004" "\013\321\352\126\200\372\211\275\204\327\361\346\121\273\121\277" "\326\116\013\114\200\245\060\225\047\223\051\172\310\113\065\364" "\165\064\225\330\032\240\013\252\074\301\222\162\005\252\223\055" "\271\361\313\161\147\236\176\145\315\354\140\111\341\331\207\164" "\103\353\061\217\155\135\226\260\263\223\150\124\271\151\146\261" "\041\362\050\276\377\350\021\045\336\103\134\235\042\200\217\142" "\271\273\154\035\056\354\351\014\077\214\141\057\111\220\255\137" "\064\171\377\324\146\251\362\020\325\124\260\101\246\117\167\102" "\152\274\034\161\330\240\317\360\155\002\232\256\111\031\336\152" "\036\235\015\137\006\314\211\130\310\237\045\034\177\375\143\322" "\116\164\006\005\203\260\012\361\012\073\054\014\125\263\301\327" "\040\002\072\235\274\002\342\355\042\025\131\250\204\231\300\374" "\125\015\006\327\105\311\126\142\257\371\156\034\333\051\316\072" "\014\116\327\250\164\037\337\370\254\345\323\067\055\225\257\247" "\104\045\176\142\215\246\367\323\356\303\131\101\172\034\356\101" "\001\115\054\102\300\062\367\053\056\011\254\375\147\244\265\131" "\305\054\230\031\144\171\224\223\246\072\002\244\020\212\303\053" "\033\377\017\314\210\064\064\152\303\323\230\152\373\060\070\360" "\006\063\272\334\232\257\273\004\002\162\041\177\032\143\334\303" "\207\021\153\210\257\075\336\344\151\250\255\111\022\167\104\342" "\265\150\000\057\271\331\265\210\357\315\141\374\252\120\035\273" "\023\170\117\234\324\071\372\345\272\155\334\311\102\173\026\030" "\156\355\362\244\025\367\361\100\212\117\220\342\311\111\240\052" "\133\117\365\363\324\364\357\121\171\320\352\103\110\017\055\352" "\050\034\222\060\374\335\253\120\211\310\175\374\243\376\135\003" "\367\015\374\311\250\146\137\001\377\132\211\136\125\163\124\246" "\034\373\002\201\347\376\023\211\010\122\073\356\066\333\234\151" "\010\075\141\220\377\163\045\253\001\043\005\170\014\232\005\226" "\017\113\177\153\123\350\047\151\174\300\340\060\226\163\072\205" "\257\124\101\113\132\112\165\150\040\231\016\245\301\165\020\055" "\205\214\260\014\245\213\013\075\062\267\244\162\247\154\301\332" "\031\200\231\146\364\111\123\237\273\376\145\000\347\117\017\215" "\077\105\240\013\024\024\301\233\046\331\016\242\340\211\212\374" "\270\310\037\126\321\133\344\136\336\352\023\075\277\107\011\065" "\053\061\041\130\367\217\004\074\300\224\177\361\313\375\215\356" "\203\354\272\353\174\144\374\261\210\277\365\073\246\064\061\041" "\176\311\260\345\340\164\310\322\133\125\161\330\044\214\346\221" "\132\260\311\232\240\364\126\026\242\077\155\122\012\202\163\041" "\367\266\130\106\306\360\301\335\175\035\301\253\066\163\163\027" "\243\112\112\015\141\013\130\354\204\030\172\043\043\126\003\040" "\357\032\200\104\074\042\146\243\003\001\271\132\352\030\310\062" "\151\107\040\340\311\050\064\276\216\344\335\061\014\270\350\310" "\217\374\026\321\035\261\355\167\051\270\263\260\321\357\030\343" "\215\377\322\023\236\235\321\055\202\257\137\217\150\107\130\367" "\103\156\310\140\040\265\327\112\156\213\373\077\173\023\043\010" "\023\365\034\262\223\355\337\026\235\076\245\005\206\375\374\311" "\154\305\052\214\172\001\327\351\215\322\051\010\345\115\021\371" "\102\055\253\326\033\213\354\270\311\222\276\117\220\272\031\374" "\177\103\211\372\105\140\344\323\062\015\333\030\132\355\021\235" "\033\275\164\066\110\141\357\022\363\256\142\204\150\173\201\350" "\277\013\343\004\153\307\327\236\325\263\267\057\240\311\315\274" "\206\101\363\316\242\342\340\226\220\102\033\371\276\234\342\175" "\247\305\202\023\215\132\262\142\015\152\222\256\063\140\152\271" "\242\135\210\105\100\150\333\321\253\367\313\151\223\255\347\073" "\163\151\117\001\303\001\144\321\153\366\177\237\127\352\131\371" "\110\341\076\211\112\032\132\365\021\045\137\245\323\107\340\107" "\260\060\110\164\062\254\105\236\243\305\075\372\260\226\363\371" "\167\062\202\302\114\334\270\136\002\027\003\326\137\344\035\017" "\024\145\204\106\022\312\345\265\220\042\257\100\271\243\072\060" "\325\274\363\042\230\253\200\233\303\203\161\042\150\216\062\174" "\364\266\303\006\201\250\273\021\313\153\122\204\016\214\265\343" "\110\250" #define pswd_z 256 #define pswd ((&data[2264])) "\206\174\026\011\356\071\161\175\153\356\161\041\262\167\243\133" "\063\264\047\236\007\253\254\223\141\220\334\012\226\276\135\034" "\073\164\046\051\255\230\246\031\207\027\073\072\217\336\225\302" "\223\274\141\232\150\015\056\311\236\101\076\361\044\220\317\170" "\261\011\034\377\147\300\222\275\137\211\064\206\360\045\346\355" "\231\152\334\061\323\337\213\050\041\312\031\106\133\351\276\014" "\362\332\014\131\233\237\027\372\050\113\201\030\161\147\006\012" "\322\342\073\245\302\307\315\343\222\347\051\355\320\347\372\302" "\302\006\034\135\245\063\130\315\177\332\346\360\102\354\373\024" "\317\067\271\221\377\207\165\221\157\236\176\077\206\170\002\111" "\176\036\247\044\122\000\361\321\332\330\302\034\304\275\060\224" "\364\352\046\363\162\233\205\341\071\003\041\300\174\043\011\373" "\102\260\037\225\260\021\146\213\351\050\247\256\346\330\102\332" "\302\150\316\065\004\123\026\076\127\067\376\323\133\007\317\236" "\270\356\063\151\000\232\364\351\303\234\227\251\164\332\204\067" "\103\122\154\107\246\202\205\375\272\204\321\026\214\240\264\105" "\217\350\256\217\202\243\171\105\077\021\356\264\353\163\353\057" "\305\130\167\154\333\375\152\225\201\073\253\015\334\140\123\153" "\110\001\373\312\245\164\020\345\205\377\231\161\162\205\240\067" "\335\027\244\270\024\016\116\226\112\012\324\064\311\061\121\004" "\246\170\055\124\020\324\155\230\354\250\322\174\207\147" #define shll_z 14 #define shll ((&data[2541])) "\201\333\141\250\373\350\322\221\324\376\333\204\172\165" #define tst2_z 19 #define tst2 ((&data[2558])) "\255\342\127\230\174\067\202\133\305\341\056\052\041\216\246\161" "\266\045\220\035\116\151\114\355" #define date_z 1 #define date ((&data[2579])) "\173" #define lsto_z 1 #define lsto ((&data[2580])) "\061" #define msg1_z 65 #define msg1 ((&data[2585])) "\130\134\275\306\206\170\220\063\325\271\325\374\376\070\240\216" "\263\032\004\000\156\271\123\225\240\070\024\223\202\157\071\257" "\103\314\022\152\374\277\174\330\076\251\125\113\033\155\230\356" "\032\306\005\320\306\227\244\323\257\032\172\026\305\153\101\147" "\346\271\102\230\037\364\251\157\306\045\366\056\144\020\123\004" "\304\340\262\247" #define inlo_z 3 #define inlo ((&data[2665])) "\054\131\301" #define chk1_z 22 #define chk1 ((&data[2670])) "\300\122\272\277\177\234\273\371\140\206\142\100\226\064\304\245" "\163\143\142\034\026\135\015\306\006"/* End of data[] */; #define hide_z 4096 #define SETUID 0 /* Define as 1 to call setuid(0) at start of script */ #define DEBUGEXEC 0 /* Define as 1 to debug execvp calls */ #define TRACEABLE 1 /* Define as 1 to enable ptrace the executable */ #define HARDENING 0 /* Define as 1 to disable ptrace/dump the executable */ #define BUSYBOXON 0 /* Define as 1 to enable work with busybox */ #if HARDENING static const char * shc_x[] = { "/*", " * Copyright 2019 - Intika <[email protected]>", " * Replace ******** with secret read from fd 21", " * Also change arguments location of sub commands (sh script commands)", " * gcc -Wall -fpic -shared -o shc_secret.so shc_secret.c -ldl", " */", "", "#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */", "#define PLACEHOLDER \"********\"", "#include <dlfcn.h>", "#include <stdlib.h>", "#include <string.h>", "#include <unistd.h>", "#include <stdio.h>", "#include <signal.h>", "", "static char secret[128000]; //max size", "typedef int (*pfi)(int, char **, char **);", "static pfi real_main;", "", "// copy argv to new location", "char **copyargs(int argc, char** argv){", " char **newargv = malloc((argc+1)*sizeof(*argv));", " char *from,*to;", " int i,len;", "", " for(i = 0; i<argc; i++){", " from = argv[i];", " len = strlen(from)+1;", " to = malloc(len);", " memcpy(to,from,len);", " // zap old argv space", " memset(from,'\\0',len);", " newargv[i] = to;", " argv[i] = 0;", " }", " newargv[argc] = 0;", " return newargv;", "}", "", "static int mymain(int argc, char** argv, char** env) {", " //fprintf(stderr, \"Inject main argc = %d\\n\", argc);", " return real_main(argc, copyargs(argc,argv), env);", "}", "", "int __libc_start_main(int (*main) (int, char**, char**),", " int argc,", " char **argv,", " void (*init) (void),", " void (*fini)(void),", " void (*rtld_fini)(void),", " void (*stack_end)){", " static int (*real___libc_start_main)() = NULL;", " int n;", "", " if (!real___libc_start_main) {", " real___libc_start_main = dlsym(RTLD_NEXT, \"__libc_start_main\");", " if (!real___libc_start_main) abort();", " }", "", " n = read(21, secret, sizeof(secret));", " if (n > 0) {", " int i;", "", " if (secret[n - 1] == '\\n') secret[--n] = '\\0';", " for (i = 1; i < argc; i++)", " if (strcmp(argv[i], PLACEHOLDER) == 0)", " argv[i] = secret;", " }", "", " real_main = main;", "", " return real___libc_start_main(mymain, argc, argv, init, fini, rtld_fini, stack_end);", "}", "", 0}; #endif /* HARDENING */ /* 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 */ #if HARDENING #include <sys/ptrace.h> #include <sys/wait.h> #include <signal.h> #include <sys/prctl.h> #define PR_SET_PTRACER 0x59616d61 /* Seccomp Sandboxing Init */ #include <stdlib.h> #include <stdio.h> #include <stddef.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/prctl.h> #include <sys/syscall.h> #include <sys/socket.h> #include <linux/filter.h> #include <linux/seccomp.h> #include <linux/audit.h> #define ArchField offsetof(struct seccomp_data, arch) #define Allow(syscall) \ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, SYS_##syscall, 0, 1), \ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW) struct sock_filter filter[] = { /* validate arch */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, ArchField), BPF_JUMP( BPF_JMP+BPF_JEQ+BPF_K, AUDIT_ARCH_X86_64, 1, 0), BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), /* load syscall */ BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)), /* list of allowed syscalls */ Allow(exit_group), /* exits a process */ Allow(brk), /* for malloc(), inside libc */ Allow(mmap), /* also for malloc() */ Allow(munmap), /* for free(), inside libc */ /* and if we don't match above, die */ BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_KILL), }; struct sock_fprog filterprog = { .len = sizeof(filter)/sizeof(filter[0]), .filter = filter }; /* Seccomp Sandboxing - Set up the restricted environment */ void seccomp_hardening() { if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { perror("Could not start seccomp:"); exit(1); } if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &filterprog) == -1) { perror("Could not start seccomp:"); exit(1); } } /* End Seccomp Sandboxing Init */ void shc_x_file() { FILE *fp; int line = 0; if ((fp = fopen("/tmp/shc_x.c", "w")) == NULL ) {exit(1); exit(1);} for (line = 0; shc_x[line]; line++) fprintf(fp, "%s\n", shc_x[line]); fflush(fp);fclose(fp); } int make() { char * cc, * cflags, * ldflags; char cmd[4096]; cc = getenv("CC"); if (!cc) cc = "cc"; sprintf(cmd, "%s %s -o %s %s", cc, "-Wall -fpic -shared", "/tmp/shc_x.so", "/tmp/shc_x.c -ldl"); if (system(cmd)) {remove("/tmp/shc_x.c"); return -1;} remove("/tmp/shc_x.c"); return 0; } void arc4_hardrun(void * str, int len) { //Decode locally char tmp2[len]; char tmp3[len+1024]; memcpy(tmp2, str, len); unsigned char tmp, * ptr = (unsigned char *)tmp2; int lentmp = len; int pid, status; pid = fork(); shc_x_file(); if (make()) {exit(1);} setenv("LD_PRELOAD","/tmp/shc_x.so",1); if(pid==0) { //Start tracing to protect from dump & trace if (ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) { kill(getpid(), SIGKILL); _exit(1); } //Decode Bash while (len > 0) { indx++; tmp = stte[indx]; jndx += tmp; stte[indx] = stte[jndx]; stte[jndx] = tmp; tmp += stte[indx]; *ptr ^= stte[tmp]; ptr++; len--; } //Do the magic sprintf(tmp3, "%s %s", "'********' 21<<<", tmp2); //Exec bash script //fork execl with 'sh -c' system(tmp2); //Empty script variable memcpy(tmp2, str, lentmp); //Clean temp remove("/tmp/shc_x.so"); //Sinal to detach ptrace ptrace(PTRACE_DETACH, 0, 0, 0); exit(0); } else {wait(&status);} /* Seccomp Sandboxing - Start */ seccomp_hardening(); exit(0); } #endif /* HARDENING */ /* * 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]; } void chkenv_end(void); int chkenv(int argc) { char buff[512]; unsigned long mask, m; int l, a, c; char * string; extern char ** environ; mask = (unsigned long)getpid(); stte_0(); key(&chkenv, (void*)&chkenv_end - (void*)&chkenv); key(&data, sizeof(data)); key(&mask, sizeof(mask)); arc4(&mask, sizeof(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; } void chkenv_end(void){} #if HARDENING static void gets_process_name(const pid_t pid, char * name) { char procfile[BUFSIZ]; sprintf(procfile, "/proc/%d/cmdline", pid); FILE* f = fopen(procfile, "r"); if (f) { size_t size; size = fread(name, sizeof (char), sizeof (procfile), f); if (size > 0) { if ('\n' == name[size - 1]) name[size - 1] = '\0'; } fclose(f); } } void hardening() { prctl(PR_SET_DUMPABLE, 0); prctl(PR_SET_PTRACER, -1); int pid = getppid(); char name[256] = {0}; gets_process_name(pid, name); if ( (strcmp(name, "bash") != 0) && (strcmp(name, "/bin/bash") != 0) && (strcmp(name, "sh") != 0) && (strcmp(name, "/bin/sh") != 0) && (strcmp(name, "sudo") != 0) && (strcmp(name, "/bin/sudo") != 0) && (strcmp(name, "/usr/bin/sudo") != 0) && (strcmp(name, "gksudo") != 0) && (strcmp(name, "/bin/gksudo") != 0) && (strcmp(name, "/usr/bin/gksudo") != 0) && (strcmp(name, "kdesu") != 0) && (strcmp(name, "/bin/kdesu") != 0) && (strcmp(name, "/usr/bin/kdesu") != 0) ) { printf("Operation not permitted\n"); kill(getpid(), SIGKILL); exit(1); } } #endif /* HARDENING */ #if !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(PT_ATTACHEXC) /* New replacement for PT_ATTACH */ #if !defined(PTRACE_ATTACH) && defined(PT_ATTACH) #define PT_ATTACHEXC PT_ATTACH #elif defined(PTRACE_ATTACH) #define PT_ATTACHEXC PTRACE_ATTACH #endif #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(PT_ATTACHEXC, 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 /* !TRACEABLE */ char * xsh(int argc, char ** argv) { char * scrpt; int ret, i, j; char ** varg; char * me = argv[0]; if (me == NULL) { me = getenv("_"); } if (me == 0) { fprintf(stderr, "E: neither argv[0] nor $_ works."); exit(1); } ret = chkenv(argc); 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; 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); #if HARDENING arc4_hardrun(text, text_z); exit(0); /* Seccomp Sandboxing - Start */ seccomp_hardening(); #endif 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; #if BUSYBOXON varg[j++] = "busybox"; varg[j++] = "sh"; #else varg[j++] = argv[0]; /* My own name at execution */ #endif 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 SETUID setuid(0); #endif #if DEBUGEXEC debugexec("main", argc, argv); #endif #if HARDENING hardening(); #endif #if !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; }
Conferindo o sigilo
Agora lembra que coloquei na variável de senha da base de dados isso aqui PASS="tua_senha_aqui" ? Vamos checar se ela aparece em algum lugar no binário usando o programa strings, que existe na maioria das distribuições GNU/Linux, e permite extrair strings visíveis de dentro de binários.
# strings backup | grep "tua_senha_aqui" #
Como pudemos ver, não foi encontrada a senha no binário mas ela encontra-se codificada no fonte em C; então não esqueça de apagar o fonte.
Colocando um prazo de validade no binário
Para colocarmos um prazo de validade no binário façamos assim como exemplo. A data é no formato dd/mm/yyyy (dia/mês/ano).
shc -e 04/03/2023 -m "Seu programa expirou falar com fulano" -o backup -f backup.sh
Dessa data em diante ao executar o binário irá aparecer a mensagem que colocamos.
# ./backup ./backup: has expired! Seu programa expirou falar com fulano
Finalizando
Basicamente é isso que o SHC faz, acho bem útil para determinadas situações e acredito que possa ajudá-lo em algo nesse sentido. Lembre-se que compartilhar conhecimento é uma via de duas mãos e procure contribuir com seus códigos também. Procure usar esse artifício para necessidades que envolvam um pouco mais de segurança na sua administração de sistemas.
Já ia esquecendo! Depois você pode remover o shc e o build-essential caso não precise mais compilar os scripts.
# apt remove shc build-essential # apt autoremove
Essa documentação foi útil? Compartilhe, divulgue e ajude outras pessoas. Meus contatos podem ser vistos aqui.