home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / zines / phrack2 / phrack51.010 < prev    next >
Encoding:
Text File  |  2003-06-11  |  6.8 KB  |  280 lines

  1.  
  2. ---[  Phrack Magazine   Volume 7, Issue 51 September 01, 1997, article 10 of 17
  3.  
  4.  
  5. -------------------------[  Scanning for RPC Services
  6.  
  7.  
  8. --------[  halflife <halflife@infonexus.com>
  9.  
  10.  
  11. Remote Procedure Language is a specification for letting procedures be
  12. executable on remote machines.  It is defined in rfc1831.  It has a number of
  13. good traits, and if you run SunOS or Solaris, you are almost required to make
  14. use of it to some degree.
  15.  
  16. Unfortunately, there are vulnerabilities in some RPC services that have
  17. caused many machines to be penetrated.  Many administrators block access to
  18. portmapper (port 111) in an effort to deny external users access to their weak
  19. RPC services.
  20.  
  21. Unfortunately, this is completely inadequate.  This article details how
  22. trivial it is to do a scan for specific RPC program numbers.  The scan can be
  23. performed relatively quickly, and in many cases will not be logged.
  24.  
  25. First, a little information about RPC itself; when I refer to RPC, I am only
  26. referring to ONC RPC, and not DCE RPC.  RPC is a query/reply-based system. You
  27. send an initial query with the program number you are interested in, the
  28. procedure number, any arguments, authentication, and other needed parameters.
  29. In response, you get whatever the procedure returns, and some indication of
  30. the reason for the failure if it failed.
  31.  
  32. Since RPC was designed to be portable, all arguments must be translated into
  33. XDR.  XDR is a data encoding language that superficially reminds me a little
  34. bit of Pascal (at least, as far as strings are concerned). If you want more
  35. information on XDR, it is defined in rfc1832.
  36.  
  37. As you probably surmised by now, RPC programs are made up of various
  38. procedures.  There is one procedure that always exists, it is procedure 0.
  39. This procedure accepts no arguments, and it does not return any value (think
  40. void rpcping(void)).  This is how we will determine if a given port holds a
  41. given program, we will call the ping procedure!
  42.  
  43. So now we have a basic idea on how to determine if a given port is running
  44. a given RPC program number.  Next we need to determine which UDP ports are
  45. listening.  This can be done a number of ways, but the way I am using is
  46. to connect() to the port and try write data.  If nothing is there, we
  47. will (hopefully) get a PORT_UNREACH error in errno, in which case we know
  48. there is nothing on that port.
  49.  
  50. In the given code, we do a udp scan, and for every listening udp port, we
  51. try to query the ping procedure of the program number we are scanning for.
  52. If we get a positive response, the program number we are looking for exists
  53. on that port and we exit.
  54.  
  55. <++> RPCscan/Makefile
  56. CC=gcc
  57. PROGNAME=rpcscan
  58. CFLAGS=-c
  59.  
  60. build: checkrpc.o main.o rpcserv.o udpcheck.o
  61.     $(CC) -o $(PROGNAME) checkrpc.o main.o rpcserv.o udpcheck.o
  62.  
  63. checkrpc.o:
  64.     $(CC) $(CFLAGS) checkrpc.c
  65.  
  66. main.o:
  67.     $(CC) $(CFLAGS) main.c
  68.  
  69. rpcserv.o:
  70.     $(CC) $(CFLAGS) rpcserv.c
  71.  
  72. udpcheck.o:
  73.     $(CC) $(CFLAGS) udpcheck.c
  74.  
  75. clean:
  76.     rm -f *.o $(PROGNAME)
  77. <-->
  78. <++> RPCscan/checkrpc.c
  79. #include <stdio.h>
  80. #include <stdlib.h>
  81. #include <unistd.h>
  82. #include <sys/time.h>
  83. #include <sys/socket.h>
  84. #include <rpc/rpc.h>
  85. #include <netdb.h>
  86.  
  87. extern struct sockaddr_in *saddr;
  88.  
  89. int
  90. check_rpc_service(long program)
  91. {
  92.     int sock = RPC_ANYSOCK;
  93.     CLIENT *client;
  94.     struct timeval timeout;
  95.     enum clnt_stat cstat;
  96.  
  97.     timeout.tv_sec = 10;
  98.     timeout.tv_usec = 0;
  99.     client = clntudp_create(saddr, program, 1, timeout, &sock);
  100.     if(!client)
  101.         return -1;
  102.     timeout.tv_sec = 10;
  103.     timeout.tv_usec = 0;
  104.     cstat = RPC_TIMEDOUT;
  105.     cstat = clnt_call(client, 0, xdr_void, NULL, xdr_void, NULL, timeout);
  106.     if(cstat == RPC_TIMEDOUT)
  107.     {
  108.         timeout.tv_sec = 10;
  109.         timeout.tv_usec = 0;
  110.         cstat = clnt_call(client, 0, xdr_void, NULL, xdr_void, NULL, timeout);
  111.     }
  112.     clnt_destroy(client);
  113.     close(sock);
  114.     if(cstat == RPC_SUCCESS)
  115.         return 1;
  116.     else if(cstat == RPC_PROGVERSMISMATCH)
  117.         return 1;
  118.     else return 0;
  119. }
  120. <-->
  121. <++> RPCscan/main.c
  122. #include <stdio.h>
  123. #include <stdlib.h>
  124. #include <unistd.h>
  125.  
  126. int check_udp_port(char *, u_short);
  127. int check_rpc_service(long);
  128. long get_rpc_prog_number(char *);
  129. #define HIGH_PORT    5000
  130. #define LOW_PORT    512    
  131.  
  132. main(int argc, char **argv)
  133. {
  134.     int i,j;
  135.     long prog;
  136.     if(argc != 3)
  137.     {
  138.         fprintf(stderr, "%s host program\n", argv[0]);
  139.         exit(0);
  140.     }
  141.     prog = get_rpc_prog_number(argv[2]);
  142.     if(prog == -1)
  143.     {
  144.         fprintf(stderr, "invalid rpc program number\n");
  145.         exit(0);
  146.     }
  147.     printf("Scanning %s for program %d\n", argv[1], prog);
  148.     for(i=LOW_PORT;i <= HIGH_PORT;i++)
  149.     {
  150.         if(check_udp_port(argv[1], i) > 0)
  151.         {
  152.             if(check_rpc_service(prog) == 1)
  153.             {
  154.                 printf("%s is on port %u\n", argv[2], i);
  155.                 exit(0);
  156.             }
  157.         }
  158.     }
  159. }
  160. <-->
  161. <++> RPCscan/rpcserv.c
  162. #include <stdio.h>
  163. #include <stdlib.h>
  164. #include <unistd.h>
  165. #include <netdb.h>
  166. #include <ctype.h>
  167. #include <rpc/rpc.h>
  168.  
  169. long
  170. get_rpc_prog_number(char *progname)
  171. {
  172.     struct rpcent *r;
  173.     int i=0;
  174.  
  175.     while(progname[i] != '\0')
  176.     {
  177.         if(!isdigit(progname[i]))
  178.         {
  179.             setrpcent(1);
  180.             r = getrpcbyname(progname);
  181.             endrpcent();
  182.             if(!r)
  183.                 return -1;
  184.             else return r->r_number;
  185.         }
  186.         i++;
  187.     }
  188.     return atoi(progname);
  189. }
  190. <-->
  191. <++> RPCscan/udpcheck.c
  192. #include <stdio.h>
  193. #include <stdlib.h>
  194. #include <unistd.h>
  195. #include <string.h>
  196. #include <netdb.h>
  197. #include <netinet/in.h>
  198. #include <arpa/inet.h>
  199. #include <sys/types.h>
  200. #include <sys/socket.h>
  201. #include <sys/param.h>
  202. #include <sys/time.h>
  203. #include <sys/errno.h>
  204. extern int h_errno;
  205.  
  206. struct sockaddr_in *saddr = NULL;
  207.  
  208. int
  209. check_udp_port(char *hostname, u_short port)
  210. {
  211.     int s, i, sr;
  212.     struct hostent *he;
  213.     fd_set rset;
  214.     struct timeval tv;
  215.  
  216.     if(!saddr)
  217.     {
  218.         saddr = malloc(sizeof(struct sockaddr_in));
  219.         if(!saddr) return -1;
  220.  
  221.         saddr->sin_family = AF_INET;
  222.         saddr->sin_addr.s_addr = inet_addr(hostname);
  223.         if(saddr->sin_addr.s_addr == INADDR_NONE)
  224.         {
  225.             sethostent(1);
  226.             he = gethostbyname(hostname);
  227.             if(!he)
  228.             {
  229.                 herror("gethostbyname");
  230.                 exit(1);
  231.             }
  232.             if(he->h_length <= sizeof(saddr->sin_addr.s_addr))
  233.                 bcopy(he->h_addr, &saddr->sin_addr.s_addr, he->h_length);
  234.             else
  235.                 bcopy(he->h_addr, &saddr->sin_addr.s_addr, sizeof(saddr->sin_addr.s_addr));
  236.             endhostent();
  237.         }
  238.     }
  239.     saddr->sin_port = htons(port);
  240.     s = socket(AF_INET, SOCK_DGRAM, 0);
  241.     if(s < 0)
  242.     {
  243.         perror("socket");
  244.         return -1;
  245.     }
  246.     i = connect(s, (struct sockaddr *)saddr, sizeof(struct sockaddr_in));
  247.     if(i < 0)
  248.     {
  249.         perror("connect");
  250.         return -1;
  251.     }
  252.     for(i=0;i < 3;i++)
  253.     {
  254.         write(s, "", 1);
  255.         FD_ZERO(&rset);
  256.         FD_SET(s, &rset);
  257.         tv.tv_sec = 5;
  258.         tv.tv_usec = 0;
  259.         sr = select(s+1, &rset, NULL, NULL, &tv);
  260.         if(sr != 1)
  261.             continue;
  262.         if(read(s, &sr, sizeof(sr)) < 1)
  263.         {
  264.             close(s);
  265.             return 0;
  266.         }
  267.         else
  268.         {
  269.             close(s);
  270.             return 1;
  271.         }
  272.     }
  273.     close(s);
  274.     return 1;
  275. }
  276. <-->
  277.  
  278.  
  279. ----[  EOF
  280.