~ubuntu-branches/ubuntu/saucy/unhide/saucy-proposed

« back to all changes in this revision

Viewing changes to unhide-tcp-simple-check.c

  • Committer: Package Import Robot
  • Author(s): Julien Valroff
  • Date: 2013-02-15 19:14:05 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20130215191405-rq074t0t0wo9bkdj
Tags: 20121229-1
* New upstream release
* Add unhide_rb and unhide-posix to the package

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
          http://www.unhide-forensics.info
 
3
*/
 
4
 
 
5
/*
 
6
This program is free software: you can redistribute it and/or modify
 
7
it under the terms of the GNU General Public License as published by
 
8
the Free Software Foundation, either version 3 of the License, or
 
9
(at your option) any later version.
 
10
 
 
11
This program is distributed in the hope that it will be useful,
 
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
GNU General Public License for more details.
 
15
 
 
16
You should have received a copy of the GNU General Public License
 
17
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <sys/types.h>
 
23
#include <sys/socket.h>
 
24
#include <netinet/in.h>
 
25
#include <errno.h>
 
26
#include <getopt.h>
 
27
#include <string.h>
 
28
#include <unistd.h>
 
29
#include <time.h>
 
30
#include <sys/time.h>
 
31
#include <sys/resource.h>
 
32
 
 
33
#include "unhide-output.h"
 
34
#include "unhide-tcp.h"
 
35
 
 
36
// header
 
37
const char header[] =
 
38
       "Unhide-tcp 20121229\n"
 
39
       "Copyright © 2012 Yago Jesus & Patrick Gouin\n"
 
40
       "License GPLv3+ : GNU GPL version 3 or later\n"
 
41
       "http://www.unhide-forensics.info\n";
 
42
 
 
43
// options
 
44
int verbose = 0;
 
45
int use_fuser = 0;
 
46
int use_lsof = 0;
 
47
int use_ss = 1;   // use ss by default
 
48
int use_quick = 0;
 
49
 
 
50
char checker[10] = "ss" ;
 
51
 
 
52
// Temporary string for output
 
53
char scratch[1000];
 
54
 
 
55
// Temporary string for output
 
56
char used_options[1000] = "";
 
57
 
 
58
// For logging to file
 
59
int logtofile = 0;
 
60
FILE *unlog;
 
61
 
 
62
// Global hidden port counter, used only to set the exit code of the program
 
63
int hidden_found;
 
64
 
 
65
/* thx aramosf@unsec.net for the nice regexp! */
 
66
 
 
67
// Linux
 
68
char tcpcommand1[]= "netstat -tan | sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
69
char udpcommand1[]= "netstat -uan | sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
70
 
 
71
// Alternative commands, needs iproute2
 
72
char tcpcommand2[]= "ss -tan sport = :%d | sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
73
char udpcommand2[]= "ss -uan sport = :%d | sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
74
 
 
75
// fuser commands
 
76
char fuserTCPcommand[]= "fuser -v -n tcp %d 2>&1" ;
 
77
char fuserUDPcommand[]= "fuser -v -n udp %d 2>&1" ;
 
78
 
 
79
// lsof commands
 
80
char lsofTCPcommand[]= "lsof +c 0 -iTCP:%d" ;
 
81
char lsofUDPcommand[]= "lsof +c 0 -iUDP:%d" ;
 
82
 
 
83
// OpenBSD
 
84
// char tcpcommand[]= "netstat -an -p tcp | sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
85
// char udpcommand[]= "netstat -an -p udp| sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
86
 
 
87
 
 
88
// Solaris
 
89
// char tcpcommand[]= "netstat -an -P tcp | sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
90
// char udpcommand[]= "netstat -an -P udp| sed -e '/[\\.:][0-9]/!d' -e 's/.*[\\.:]\\([0-9]*\\) .*[\\.:].*/\\1/'" ;
 
91
 
 
92
 
 
93
 
 
94
/*
 
95
 *  Run a command to get more information about a port. 
 
96
 */
 
97
static void print_info(const char *prog_name, const char *command_fmt, int port)
 
98
{
 
99
 
 
100
   char buffer[1000];
 
101
   FILE* fp;
 
102
 
 
103
   sprintf(buffer, command_fmt, port);
 
104
   fp = popen(buffer, "r") ;
 
105
 
 
106
   if (NULL == fp)
 
107
   {
 
108
      warnln(verbose, unlog, "Couldn't run command: %s", buffer) ;
 
109
      return ;
 
110
   }
 
111
 
 
112
   msgln(unlog, 1, "%s reports :", prog_name) ;
 
113
 
 
114
   while (NULL != fgets(buffer, 1000, fp))
 
115
   {
 
116
      msgln(unlog, 1, buffer) ;
 
117
   }
 
118
 
 
119
   pclose(fp);
 
120
}
 
121
 
 
122
/* Print a port, optionally querying info about it via lsof or fuser. */
 
123
void print_port(enum Proto proto, int port)
 
124
{
 
125
      msgln(unlog, 0, "\nFound Hidden port that not appears in %s: %i", checker, port) ;
 
126
      if (1 == use_fuser)
 
127
      {
 
128
         if (TCP == proto)
 
129
         {
 
130
            print_info("fuser", fuserTCPcommand, port);
 
131
         }
 
132
         else
 
133
         {
 
134
            print_info("fuser", fuserUDPcommand, port);
 
135
         }
 
136
      }
 
137
      if (1 == use_lsof)
 
138
      {
 
139
         if (TCP == proto)
 
140
         {
 
141
            print_info("lsof", lsofTCPcommand, port);
 
142
         }
 
143
         else
 
144
         {
 
145
            print_info("lsof", lsofUDPcommand, port);
 
146
         }
 
147
      }
 
148
}
 
149
 
 
150
 
 
151
/*
 
152
 * Check if port is seen by netstat.
 
153
 *
 
154
 * If not, report it and optionnally run lsof and/or fuser
 
155
 * to show more info.
 
156
 */
 
157
void checkoneport(int port, char command[], enum Proto proto)
 
158
{
 
159
   int ok = 0;
 
160
   char ports[30];
 
161
   char compare[100];
 
162
 
 
163
   FILE *fich_tmp ;
 
164
 
 
165
   if (NULL != (fich_tmp=popen (command, "r")))
 
166
   {
 
167
      sprintf(compare,"%i\n",port);
 
168
      while ((NULL != fgets(ports, 30, fich_tmp)) && ok == 0) {
 
169
         if (strcmp(ports, compare) == 0) {ok = 1;}
 
170
      }
 
171
      pclose(fich_tmp);
 
172
   }
 
173
   else
 
174
   {
 
175
      die(unlog, "Couldn't execute command : %s while checking port %d", command, port) ;
 
176
   }
 
177
// test
 
178
// ok = 0 ;
 
179
   if ( ok == 0 )
 
180
   {
 
181
      hidden_found++;
 
182
      print_port(proto, port) ;
 
183
   }
 
184
}
 
185
 
 
186
/*
 
187
 * Check all TCP ports one by one.
 
188
 */
 
189
static void print_hidden_TCP_ports_1_by_1(enum Proto proto)
 
190
{
 
191
   int i ;
 
192
   char tcpcommand[512] ;
 
193
 
 
194
   hidden_found = 0 ;
 
195
   for (i =1; i <= 65535; i++)
 
196
   {
 
197
      int socket_desc;
 
198
      struct sockaddr_in address;
 
199
 
 
200
      if ( -1 != (socket_desc=socket(AF_INET,SOCK_STREAM,0)))
 
201
      {
 
202
         address.sin_family = AF_INET;
 
203
         address.sin_addr.s_addr = INADDR_ANY;
 
204
         address.sin_port = htons(i);
 
205
         errno= 0 ;
 
206
         if ( -1 != bind(socket_desc,(struct sockaddr *)&address,sizeof(address)))
 
207
         {
 
208
            listen(socket_desc,1);
 
209
            if ( EADDRINUSE == errno )    // port is listened by another process
 
210
            {
 
211
               close(socket_desc);
 
212
               if (1 == use_ss)
 
213
               {
 
214
                  sprintf(tcpcommand, tcpcommand2, i) ;
 
215
               }
 
216
               else
 
217
               {
 
218
                  strncpy(tcpcommand, tcpcommand1, 512) ;
 
219
               }
 
220
               checkoneport(i, tcpcommand, TCP);
 
221
            }
 
222
            else
 
223
            {
 
224
               close(socket_desc);
 
225
            }
 
226
         }
 
227
         else
 
228
         {
 
229
            if (EADDRINUSE == errno)    //port is in use by another process
 
230
            {
 
231
               close(socket_desc);
 
232
               if (1 == use_ss)
 
233
               {
 
234
                  sprintf(tcpcommand, tcpcommand2, i) ;
 
235
               }
 
236
               else
 
237
               {
 
238
                  strncpy(tcpcommand, tcpcommand1, 512) ;
 
239
               }
 
240
               checkoneport(i, tcpcommand, TCP);
 
241
            }
 
242
            else
 
243
            {
 
244
               close(socket_desc);
 
245
               warnln(verbose, unlog, "can't bind to socket while checking port %d", i) ;
 
246
            }
 
247
         }
 
248
      }
 
249
      else
 
250
      {
 
251
         warnln(verbose, unlog, "can't create socket while checking port %d/tcp", i) ;
 
252
      }
 
253
   }
 
254
}
 
255
 
 
256
/*
 
257
 * Check all UDP ports one by one.
 
258
 */
 
259
static void print_hidden_UDP_ports_1_by_1(enum Proto proto)
 
260
{
 
261
   int u ;
 
262
   char udpcommand[512] ;
 
263
 
 
264
   hidden_found = 0 ;
 
265
 
 
266
   for (u = 1; u <= 65535; u++)
 
267
   {
 
268
      int socket_desc;
 
269
      struct sockaddr_in address;
 
270
 
 
271
      if ( -1 != (socket_desc=socket(AF_INET,SOCK_DGRAM,0)))
 
272
      {
 
273
         address.sin_family = AF_INET;
 
274
         address.sin_addr.s_addr = INADDR_ANY;
 
275
         address.sin_port = htons(u);
 
276
         errno= 0 ;
 
277
         if ( 0 != bind(socket_desc,(struct sockaddr *)&address,sizeof(address)))
 
278
         {
 
279
            if ( EADDRINUSE == errno )   //port is in use by another process
 
280
            {
 
281
               close(socket_desc);
 
282
               if (1 == use_ss)
 
283
               {
 
284
                  sprintf(udpcommand, udpcommand2, u) ;
 
285
               }
 
286
               else
 
287
               {
 
288
                  strncpy(udpcommand, udpcommand1, 512) ;
 
289
               }
 
290
               checkoneport(u, udpcommand, UDP);
 
291
            }
 
292
            else      // other error
 
293
            {
 
294
               close(socket_desc);
 
295
               warnln(verbose, unlog, "can't bind to socket while checking port %d", u) ;
 
296
            }
 
297
         }
 
298
         else  // port is available
 
299
         {
 
300
            close(socket_desc);
 
301
         }
 
302
      }
 
303
      else 
 
304
      {
 
305
         warnln(verbose, unlog, "can't create socket while checking port %d/udp", u) ;
 
306
      }
 
307
   }
 
308
}
 
309
 
 
310
 
 
311
/*
 
312
 * Print usage. 
 
313
 */
 
314
void usage(char * command) {
 
315
 
 
316
   printf("Usage: %s [options] \n\n", command);
 
317
   printf("Options :\n");
 
318
   printf("   -V          Show version and exit\n");
 
319
   printf("   -v          verbose\n");
 
320
   printf("   -h          display this help\n");
 
321
   printf("   -f          show fuser output for hidden ports\n");
 
322
   printf("   -l          show lsof output for hidden ports\n");
 
323
   printf("   -o          log result into unhide-tcp.log file\n");
 
324
   printf("   -s          use very quick version for server with lot of opened ports\n");
 
325
   printf("   -n          use netstat instead of ss\n");
 
326
}
 
327
 
 
328
/*
 
329
 * Parse command line arguments (exiting if requested by any option).
 
330
 */
 
331
void parse_args(int argc, char **argv) 
 
332
{
 
333
   int c = 0;
 
334
   
 
335
   static struct option long_options[] =
 
336
   {
 
337
   /* These options set a flag. */
 
338
      {"verbose",  no_argument,      &verbose,   1},
 
339
      {"brief",    no_argument,      &verbose,   0},
 
340
      {"fuser",    no_argument,      &use_fuser, 1},
 
341
      {"lsof",     no_argument,      &use_lsof,  1},
 
342
      {"log",      no_argument,      &logtofile, 1},
 
343
      {"netstat",  no_argument,      &use_ss,    0},
 
344
      {"server",   no_argument,      &use_quick, 1},
 
345
      /* These options don't set a flag.
 
346
         We distinguish them by their indices. */
 
347
      {"help",     no_argument,      0,        'h'},
 
348
      {"version",  no_argument,      0,        'V'},
 
349
      {0, 0, 0, 0}
 
350
   };
 
351
 
 
352
   for(;;)  // until there's no more option
 
353
   {
 
354
      /* getopt_long stores the option index here. */
 
355
      int option_index = 0;
 
356
 
 
357
      c = getopt_long (argc, argv, "Vvhflosn",
 
358
                        long_options, &option_index);
 
359
 
 
360
      /* Detect the end of the options. */
 
361
      if (c == -1)
 
362
         break;
 
363
 
 
364
      switch(c)
 
365
      {
 
366
      case 0 :   // flag long options
 
367
         if (long_options[option_index].flag != 0) //if this option set a flag
 
368
         {
 
369
            break;  // nothing to do
 
370
         }
 
371
         printf ("option %s", long_options[option_index].name);
 
372
         if (optarg) // if there's an argument
 
373
         {
 
374
            printf (" with arg %s", optarg);
 
375
         }
 
376
         printf ("\n");
 
377
         break ;
 
378
      case 'f' :
 
379
         use_fuser = 1 ;
 
380
         break ;
 
381
      case 'h' :
 
382
         usage(argv[0]) ;
 
383
         exit (0) ;
 
384
         break ;
 
385
      case 'l' :
 
386
         use_lsof = 1 ;
 
387
         break;
 
388
      case 'o' :
 
389
         logtofile = 1 ;
 
390
         break ;
 
391
      case 's' :
 
392
         use_quick = 1 ;
 
393
         break ;
 
394
      case 'n' :
 
395
         use_ss = 0 ;
 
396
         break ;
 
397
      case 'v' :
 
398
         verbose++ ; ;
 
399
         break ;
 
400
      case 'V' :
 
401
         exit (0) ;
 
402
         break ;
 
403
      case '?' :     // invalid option
 
404
         exit (2) ;
 
405
         break ;
 
406
      default :      // something very nasty happened
 
407
         exit(-1) ;
 
408
         break ;
 
409
      }
 
410
     
 
411
   }
 
412
   
 
413
   // generate options string for logging
 
414
   strncpy(used_options, "Used options: ", 1000);
 
415
   if (verbose)
 
416
      strncat(used_options, "verbose ", 1000-1-strlen(used_options));
 
417
   if (use_lsof)
 
418
      strncat(used_options, "use_lsof ", 1000-1-strlen(used_options));
 
419
   if (use_fuser)
 
420
      strncat(used_options, "use_fuser ", 1000-1-strlen(used_options));
 
421
   if (!use_ss)
 
422
      strncat(used_options, "use_netscape ", 1000-1-strlen(used_options));
 
423
   if (use_quick)
 
424
      strncat(used_options, "use_quick ", 1000-1-strlen(used_options));
 
425
   if (logtofile)
 
426
      strncat(used_options, "logtofile ", 1000-1-strlen(used_options));
 
427
}
 
428
 
 
429
/*
 
430
 * Look for TCP and UDP ports that are hidden to netstat.
 
431
 *
 
432
 * Returns 0 if none is found, 1 if there is some internal error, 4 if TCP
 
433
 * hidden ports were found, 8 if UDP hidden ports were found or 12 (4 & 8) if
 
434
 * both were found.
 
435
 */
 
436
int main(int argc, char  **argv) 
 
437
{
 
438
   int ret_code = 0;
 
439
 
 
440
   printf(header) ;
 
441
   if(getuid() != 0){
 
442
      die(unlog, "You must be root to run %s !", argv[0]) ;
 
443
   }
 
444
 
 
445
   parse_args(argc, argv) ;
 
446
   
 
447
   if (1 == logtofile) 
 
448
   {
 
449
      unlog = init_log(logtofile, header, "unhide-tcp") ;
 
450
   }
 
451
   msgln(unlog, 0, used_options) ;
 
452
 
 
453
   if (1 == use_ss)
 
454
   {
 
455
      strncpy(checker, "ss", 10);
 
456
   }
 
457
   else
 
458
   {
 
459
      strncpy(checker, "netstat", 10);
 
460
   }
 
461
 
 
462
   setpriority(PRIO_PROCESS,0,-20);  /* reduce risk of race condition - may fail, dont care */
 
463
   
 
464
   msgln(unlog, 0, "[*]Starting TCP checking") ;
 
465
   if (1 == use_quick)
 
466
   {
 
467
      print_hidden_ports(TCP);
 
468
   }
 
469
   else
 
470
   {
 
471
      print_hidden_TCP_ports_1_by_1(TCP) ;
 
472
   }
 
473
   if (hidden_found)
 
474
   {
 
475
      ret_code += 4;
 
476
   }
 
477
 
 
478
   msgln(unlog, 0, "[*]Starting UDP checking") ;
 
479
   if (1 == use_quick)
 
480
   {
 
481
      print_hidden_ports(UDP);
 
482
   }
 
483
   else
 
484
   {
 
485
      print_hidden_UDP_ports_1_by_1(UDP) ;
 
486
   }
 
487
   if (hidden_found)
 
488
   {
 
489
      ret_code += 8;
 
490
   }
 
491
 
 
492
   if (logtofile == 1)
 
493
   {
 
494
      close_log(unlog, "unhide-tcp") ;
 
495
   }
 
496
   return(ret_code);
 
497
 
 
498
}
 
499