2
http://www.unhide-forensics.info
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.
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.
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/>.
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <netinet/in.h>
31
#include <sys/resource.h>
33
#include "unhide-output.h"
34
#include "unhide-tcp.h"
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";
47
int use_ss = 1; // use ss by default
50
char checker[10] = "ss" ;
52
// Temporary string for output
55
// Temporary string for output
56
char used_options[1000] = "";
58
// For logging to file
62
// Global hidden port counter, used only to set the exit code of the program
65
/* thx aramosf@unsec.net for the nice regexp! */
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/'" ;
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/'" ;
76
char fuserTCPcommand[]= "fuser -v -n tcp %d 2>&1" ;
77
char fuserUDPcommand[]= "fuser -v -n udp %d 2>&1" ;
80
char lsofTCPcommand[]= "lsof +c 0 -iTCP:%d" ;
81
char lsofUDPcommand[]= "lsof +c 0 -iUDP:%d" ;
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/'" ;
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/'" ;
95
* Run a command to get more information about a port.
97
static void print_info(const char *prog_name, const char *command_fmt, int port)
103
sprintf(buffer, command_fmt, port);
104
fp = popen(buffer, "r") ;
108
warnln(verbose, unlog, "Couldn't run command: %s", buffer) ;
112
msgln(unlog, 1, "%s reports :", prog_name) ;
114
while (NULL != fgets(buffer, 1000, fp))
116
msgln(unlog, 1, buffer) ;
122
/* Print a port, optionally querying info about it via lsof or fuser. */
123
void print_port(enum Proto proto, int port)
125
msgln(unlog, 0, "\nFound Hidden port that not appears in %s: %i", checker, port) ;
130
print_info("fuser", fuserTCPcommand, port);
134
print_info("fuser", fuserUDPcommand, port);
141
print_info("lsof", lsofTCPcommand, port);
145
print_info("lsof", lsofUDPcommand, port);
152
* Check if port is seen by netstat.
154
* If not, report it and optionnally run lsof and/or fuser
157
void checkoneport(int port, char command[], enum Proto proto)
165
if (NULL != (fich_tmp=popen (command, "r")))
167
sprintf(compare,"%i\n",port);
168
while ((NULL != fgets(ports, 30, fich_tmp)) && ok == 0) {
169
if (strcmp(ports, compare) == 0) {ok = 1;}
175
die(unlog, "Couldn't execute command : %s while checking port %d", command, port) ;
182
print_port(proto, port) ;
187
* Check all TCP ports one by one.
189
static void print_hidden_TCP_ports_1_by_1(enum Proto proto)
192
char tcpcommand[512] ;
195
for (i =1; i <= 65535; i++)
198
struct sockaddr_in address;
200
if ( -1 != (socket_desc=socket(AF_INET,SOCK_STREAM,0)))
202
address.sin_family = AF_INET;
203
address.sin_addr.s_addr = INADDR_ANY;
204
address.sin_port = htons(i);
206
if ( -1 != bind(socket_desc,(struct sockaddr *)&address,sizeof(address)))
208
listen(socket_desc,1);
209
if ( EADDRINUSE == errno ) // port is listened by another process
214
sprintf(tcpcommand, tcpcommand2, i) ;
218
strncpy(tcpcommand, tcpcommand1, 512) ;
220
checkoneport(i, tcpcommand, TCP);
229
if (EADDRINUSE == errno) //port is in use by another process
234
sprintf(tcpcommand, tcpcommand2, i) ;
238
strncpy(tcpcommand, tcpcommand1, 512) ;
240
checkoneport(i, tcpcommand, TCP);
245
warnln(verbose, unlog, "can't bind to socket while checking port %d", i) ;
251
warnln(verbose, unlog, "can't create socket while checking port %d/tcp", i) ;
257
* Check all UDP ports one by one.
259
static void print_hidden_UDP_ports_1_by_1(enum Proto proto)
262
char udpcommand[512] ;
266
for (u = 1; u <= 65535; u++)
269
struct sockaddr_in address;
271
if ( -1 != (socket_desc=socket(AF_INET,SOCK_DGRAM,0)))
273
address.sin_family = AF_INET;
274
address.sin_addr.s_addr = INADDR_ANY;
275
address.sin_port = htons(u);
277
if ( 0 != bind(socket_desc,(struct sockaddr *)&address,sizeof(address)))
279
if ( EADDRINUSE == errno ) //port is in use by another process
284
sprintf(udpcommand, udpcommand2, u) ;
288
strncpy(udpcommand, udpcommand1, 512) ;
290
checkoneport(u, udpcommand, UDP);
295
warnln(verbose, unlog, "can't bind to socket while checking port %d", u) ;
298
else // port is available
305
warnln(verbose, unlog, "can't create socket while checking port %d/udp", u) ;
314
void usage(char * command) {
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");
329
* Parse command line arguments (exiting if requested by any option).
331
void parse_args(int argc, char **argv)
335
static struct option long_options[] =
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'},
352
for(;;) // until there's no more option
354
/* getopt_long stores the option index here. */
355
int option_index = 0;
357
c = getopt_long (argc, argv, "Vvhflosn",
358
long_options, &option_index);
360
/* Detect the end of the options. */
366
case 0 : // flag long options
367
if (long_options[option_index].flag != 0) //if this option set a flag
369
break; // nothing to do
371
printf ("option %s", long_options[option_index].name);
372
if (optarg) // if there's an argument
374
printf (" with arg %s", optarg);
403
case '?' : // invalid option
406
default : // something very nasty happened
413
// generate options string for logging
414
strncpy(used_options, "Used options: ", 1000);
416
strncat(used_options, "verbose ", 1000-1-strlen(used_options));
418
strncat(used_options, "use_lsof ", 1000-1-strlen(used_options));
420
strncat(used_options, "use_fuser ", 1000-1-strlen(used_options));
422
strncat(used_options, "use_netscape ", 1000-1-strlen(used_options));
424
strncat(used_options, "use_quick ", 1000-1-strlen(used_options));
426
strncat(used_options, "logtofile ", 1000-1-strlen(used_options));
430
* Look for TCP and UDP ports that are hidden to netstat.
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
436
int main(int argc, char **argv)
442
die(unlog, "You must be root to run %s !", argv[0]) ;
445
parse_args(argc, argv) ;
449
unlog = init_log(logtofile, header, "unhide-tcp") ;
451
msgln(unlog, 0, used_options) ;
455
strncpy(checker, "ss", 10);
459
strncpy(checker, "netstat", 10);
462
setpriority(PRIO_PROCESS,0,-20); /* reduce risk of race condition - may fail, dont care */
464
msgln(unlog, 0, "[*]Starting TCP checking") ;
467
print_hidden_ports(TCP);
471
print_hidden_TCP_ports_1_by_1(TCP) ;
478
msgln(unlog, 0, "[*]Starting UDP checking") ;
481
print_hidden_ports(UDP);
485
print_hidden_UDP_ports_1_by_1(UDP) ;
494
close_log(unlog, "unhide-tcp") ;