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
27 #include <string.h>
28 #include <unistd.h>
29 // #include <time.h>
30
31 #include "unhide-output.h"
32 #include "unhide-tcp.h"
33
34 /*
35 * These are simplified hash set to store the ports that:
36 *
37 * - are visible to netstat
38 * - are found to be hidden by us
39 * - we want to check
40 *
41 * A value of 0 means the port is NOT in the set, and a value != 0 means
42 * otherwise.
43 */
44
45 static char netstat_ports[65536];
46 static char hidden_ports[65536];
47 static char check_ports[65536];
48
49 /* Fill netstat_ports with the ports netstat see as used for protocol proto. */
get_netstat_ports(enum Proto proto)50 static void get_netstat_ports(enum Proto proto)
51 {
52 FILE *fp;
53 int port;
54
55 if (TCP == proto)
56 {
57 fp=popen (tcpcommand1, "r");
58 }
59 else
60 {
61 fp=popen (udpcommand1, "r");
62 }
63
64 if (fp == NULL)
65 {
66 die(unlog, "popen failed to open netstat to get the ports list");
67 }
68
69 memset(netstat_ports, 0, sizeof(netstat_ports));
70
71 errno = 0;
72 while (!feof(fp))
73 {
74 if (fscanf(fp, "%i\n", &port) == EOF && errno != 0)
75 {
76 die(unlog, "fscanf failed to parse int");
77 }
78
79 netstat_ports[port] = 1;
80 }
81
82 pclose(fp);
83 }
84
85
86 /*
87 * Check a list of ports against what netstat report as used ports.
88 *
89 * All ports that are not reported as used by netstat are opened, binded and
90 * put in listen state (for the TCP proto). If any of that operations fail with
91 * an EADDRINUSE, it's reported as a port hidden to netstat.
92 */
check(enum Proto proto)93 static void check(enum Proto proto)
94 {
95 int i;
96 int protocol;
97
98 if (proto == TCP)
99 protocol = SOCK_STREAM;
100 else if (proto == UDP)
101 protocol = SOCK_DGRAM;
102 else
103 abort();
104
105 memset(hidden_ports, 0, sizeof(hidden_ports));
106 hidden_found = 0;
107
108 get_netstat_ports(proto);
109 for (i = 0; i < 65536; i++)
110 {
111 int fd;
112 int reuseaddr;
113 struct sockaddr_in addr;
114
115 /*
116 * skip if is not a port to check or is already visible to
117 * netstat
118 */
119 if (!check_ports[i] || netstat_ports[i])
120 {
121 continue;
122 }
123
124 fd = socket(AF_INET, protocol, 0);
125 if (fd == -1)
126 {
127 die(unlog, "socket creation failed");
128 }
129
130 reuseaddr = 1;
131 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
132 sizeof(reuseaddr)) != 0)
133 {
134 die(unlog, "setsockopt can't set SO_REUSEADDR");
135 }
136
137 addr.sin_family = AF_INET;
138 addr.sin_addr.s_addr = INADDR_ANY;
139 addr.sin_port = htons(i);
140
141 /*
142 * if we can't bind or listen because the address is used, the
143 * port is asumed to be used and added to the hidden_ports list
144 * because we only check for ports not visible by netstat.
145 * If we can bind them, we remove them from the check_ports
146 * list so we don't try to check them again if a new pass is
147 * performed in the future.
148 */
149 errno = 0;
150 if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0 ||
151 (proto == TCP && listen(fd, 1) != 0))
152 {
153 if (errno == EADDRINUSE)
154 {
155 hidden_ports[i] = 1;
156 hidden_found++;
157 }
158 else
159 {
160 warnln(verbose, unlog, "bind failed, maybe you are not root?");
161 check_ports[i] = 0;
162 }
163 }
164 else
165 {
166 check_ports[i] = 0;
167 }
168
169 close(fd);
170 }
171 }
172
173
174 /*
175 * Print ports not visible to netstat but that are being used.
176 *
177 * The check for hidden ports is retried to minimize false positives, see
178 * comments inside the function for details.
179 */
print_hidden_ports(enum Proto proto)180 void print_hidden_ports(enum Proto proto)
181 {
182 /* reset the list of ports to check (we start wanting to check all of
183 * them) and the list of hidden ports (none is hidden until we prove
184 * otherwise)
185 */
186 memset(check_ports, 1, sizeof(check_ports));
187 memset(hidden_ports, 0, sizeof(hidden_ports));
188
189 /*
190 * Double-check to minimize false positives.
191 *
192 * For very short lived connections we have a race condition between
193 * getting the output from netstat and trying to open the port
194 * ourselves. To minize this problem we check again the ports reported
195 * as hidden. If in the next run of netstat those ports are not present
196 * anymore, is fairly safe to asume they were false positives.
197 */
198 check(proto);
199 if (hidden_found)
200 {
201 memcpy(check_ports, hidden_ports, sizeof(hidden_ports));
202 check(proto);
203 }
204
205 if (hidden_found)
206 {
207 int i;
208 for (i = 0; i < 65536; i++)
209 {
210 if (hidden_ports[i])
211 {
212 print_port(proto, i);
213 }
214 }
215 }
216 }
217
218
219