-
Notifications
You must be signed in to change notification settings - Fork 4
/
ftpscan.c
216 lines (180 loc) · 4.73 KB
/
ftpscan.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <errno.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "ftpscan.h"
#define DEFAULT_TIMEOUT 3000
#define TEST_SUCCESS 0
#define TEST_TIMEOUT 1
#define TEST_ERROR 3
static in_addr_t parse_target(const char *);
static int test_port(int fd, in_port_t port, int timeout);
static in_addr_t get_local_address(int);
static void run_scan();
static void create_port_command(char *, size_t, in_addr_t, in_port_t);
static void create_eprt_command(char *, size_t, in_addr_t, in_port_t);
static in_addr_t local_address;
static in_addr_t target_address;
static in_port_t target_port = 21;
static int use_eprt = 0;
static int verbose = 0;
static int connect_timeout = DEFAULT_TIMEOUT;
static void
usage(const char *progname)
{
fprintf(stderr, "Usage: %s [options] target_ip port_range\n", progname);
fprintf(stderr, "Options:\n");
fprintf(stderr, " -t timeout Time (in milliseconds) to wait for data connection from server. [default %u]\n", DEFAULT_TIMEOUT);
fprintf(stderr, " -p target_port Target FTP port [default 21]\n");
fprintf(stderr, " -x Use EPRT command instead of PORT\n");
fprintf(stderr, " -v Enable verbose output\n");
exit(EXIT_FAILURE);
}
int
main(int argc, char **argv)
{
int ch;
char *progname = argv[0];
while((ch = getopt(argc, argv, "p:t:vx")) != -1) {
switch(ch) {
case 'v':
verbose++;
enable_debug(1);
break;
case 'p':
target_port = atoi(optarg);
break;
case 't':
connect_timeout = atoi(optarg);
case 'x':
use_eprt = 1;
break;
case '?':
default:
usage(argv[0]);
}
}
argc -= optind;
argv += optind;
if(argc < 2)
usage(progname);
target_address = parse_target(argv[0]);
ports_initialize(argv[1]);
run_scan();
return 0;
}
static in_addr_t
parse_target(const char *target)
{
in_addr_t target_ip = inet_addr(target);
if(target_ip != INADDR_NONE)
return target_ip;
struct hostent *hp = gethostbyname(target);
if(hp == NULL) {
errno = 0;
fatal("Could not resolve '%s'", target);
}
memcpy(&target_ip, hp->h_addr, sizeof(target_ip));
struct in_addr in;
in.s_addr = target_ip;
debug("Resolved %s to %s", target, inet_ntoa(in));
return target_ip;
}
static void
run_scan()
{
int fd = connect_server(target_address, target_port);
if(fd < 0)
exit(EXIT_FAILURE);
local_address = get_local_address(fd);
if(ftp_anon_login(fd)) {
warn("Login failed.");
close(fd);
exit(EXIT_FAILURE);
}
info("Logged in.");
int i;
for(i = next_port(); i != 0; i = next_port()) {
fprintf(stderr, "[+] Testing port %d\t", i);
if(verbose) fprintf(stderr, "...\n");
switch(test_port(fd, i, connect_timeout)) {
case TEST_SUCCESS:
fprintf(stderr, "OPEN!\n");
break;
case TEST_ERROR:
fprintf(stderr, "ERROR (%s)\n", ftp_get_last_server_message());
break;
case TEST_TIMEOUT:
switch(test_port(fd, i, connect_timeout * 2)) {
case TEST_SUCCESS:
fprintf(stderr, "OPEN!\n");
break;
case TEST_ERROR:
fprintf(stderr, "ERROR (%s)\n", ftp_get_last_server_message());
break;
case TEST_TIMEOUT:
fprintf(stderr, "BLOCKED (time out)\n");
break;
}
}
}
ftp_exchange_command(fd, "QUIT");
}
static in_addr_t
get_local_address(int fd)
{
struct sockaddr_in sin;
socklen_t sinlen = sizeof(sin);
if(getsockname(fd, (struct sockaddr *)&sin, &sinlen) < 0)
fatal("getsockname() failed");
debug("Local IP address is %s", inet_ntoa(sin.sin_addr));
return sin.sin_addr.s_addr;
}
static int
test_port(int fd, in_port_t port, int timeout)
{
char buffer[256];
if(use_eprt)
create_eprt_command(buffer, sizeof(buffer), local_address, port);
else
create_port_command(buffer, sizeof(buffer), local_address, port);
int code = ftp_exchange_command(fd, buffer);
if(!ftp_code_okay(code))
return TEST_ERROR;
int s = listen_port(port);
code = ftp_exchange_command(fd, "LIST");
if(code != 150)
warn("Unexpected response code from LIST: %d", code);
int s2 = wait_accept(s, timeout);
close(s);
if(s2 == 0)
return TEST_TIMEOUT;
if(s2 == -1)
return TEST_ERROR;
drain_all(s2);
ftp_command_response(fd);
ftp_drain_extra_responses(fd);
return TEST_SUCCESS;
}
static void
create_port_command(char *buffer, size_t size, in_addr_t address, in_port_t port)
{
int h1 = address & 0xFF;
int h2 = (address >> 8) & 0xFF;
int h3 = (address >> 16) & 0xFF;
int h4 = (address >> 24) & 0xFF;
int p1 = (port >> 8) & 0xFF;
int p2 = port & 0xFF;
snprintf(buffer, size, "PORT %u,%u,%u,%u,%u,%u", h1,h2,h3,h4,p1,p2);
}
static void
create_eprt_command(char *buffer, size_t size, in_addr_t address, in_port_t port)
{
struct in_addr in;
in.s_addr = address;
snprintf(buffer, size, "EPRT |1|%s|%u|", inet_ntoa(in), port);
}