Skip to content

Commit 97723e4

Browse files
author
Ivan Bondar
committed
MAYH-11897 TFTP module
1 parent 760cbe3 commit 97723e4

3 files changed

Lines changed: 130 additions & 1 deletion

File tree

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ set(PROBE_MODULE_SOURCES
3939
probe_modules/module_upnp.c
4040
probe_modules/module_dns.c
4141
probe_modules/module_bacnet.c
42+
probe_modules/module_tftp.c
4243
)
4344

4445
set(SOURCES

src/probe_modules/module_tftp.c

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* ZMap Copyright 2013 Regents of the University of Michigan
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy
6+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
7+
*/
8+
9+
#include <stdlib.h>
10+
#include <stdio.h>
11+
#include <stdint.h>
12+
#include <unistd.h>
13+
#include <string.h>
14+
#include <assert.h>
15+
16+
#include "../../lib/includes.h"
17+
#include "../../lib/logger.h"
18+
#include "../../lib/xalloc.h"
19+
#include "../fieldset.h"
20+
#include "probe_modules.h"
21+
#include "packet.h"
22+
#include "module_udp.h"
23+
24+
#define TFTP_QUERY "\0\1ay9mfwq7xxmd4w6cz\0octet\0" // try to read random filename
25+
static const char *tftp_query = TFTP_QUERY;
26+
static const long unsigned int tftp_query_len = sizeof(TFTP_QUERY) - 1; // -1 for terminating zero
27+
28+
probe_module_t module_tftp;
29+
30+
int tftp_global_initialize(struct state_conf *state)
31+
{
32+
int num_ports = state->source_port_last - state->source_port_first + 1;
33+
udp_set_num_ports(num_ports);
34+
return EXIT_SUCCESS;
35+
}
36+
37+
int tftp_init_perthread(void *buf, macaddr_t *src, macaddr_t *gw,
38+
port_h_t dst_port,
39+
__attribute__((unused)) void **arg_ptr)
40+
{
41+
memset(buf, 0, MAX_PACKET_SIZE);
42+
struct ether_header *eth_header = (struct ether_header *)buf;
43+
make_eth_header(eth_header, src, gw);
44+
struct ip *ip_header = (struct ip *)(&eth_header[1]);
45+
46+
uint16_t len = htons(sizeof(struct ip) + sizeof(struct udphdr) +
47+
tftp_query_len);
48+
make_ip_header(ip_header, IPPROTO_UDP, len);
49+
50+
struct udphdr *udp_header = (struct udphdr *)(&ip_header[1]);
51+
len = sizeof(struct udphdr) + tftp_query_len;
52+
make_udp_header(udp_header, dst_port, len);
53+
54+
char *payload = (char *)(&udp_header[1]);
55+
56+
assert(sizeof(struct ether_header) + sizeof(struct ip) +
57+
sizeof(struct udphdr) + tftp_query_len <=
58+
MAX_PACKET_SIZE);
59+
60+
assert(MAX_PACKET_SIZE - ((char *)payload - (char *)buf) >
61+
(int)tftp_query_len);
62+
memcpy(payload, tftp_query, tftp_query_len);
63+
64+
return EXIT_SUCCESS;
65+
}
66+
67+
int tftp_validate_packet(const struct ip *ip_hdr, uint32_t len,
68+
uint32_t *src_ip, uint32_t *validation)
69+
{
70+
if (!((ip_hdr->ip_p != IPPROTO_UDP) && (ip_hdr->ip_p != IPPROTO_ICMP)) || !blacklist_is_allowed(*src_ip)) {
71+
return PACKET_INVALID;
72+
}
73+
return PACKET_VALID;
74+
}
75+
76+
void tftp_process_packet(const u_char *packet,
77+
__attribute__((unused)) uint32_t len, fieldset_t *fs,
78+
__attribute__((unused)) uint32_t *validation)
79+
{
80+
struct ip *ip_hdr = (struct ip *)&packet[sizeof(struct ether_header)];
81+
struct udphdr *udp =
82+
(struct udphdr *)((char *)ip_hdr + ip_hdr->ip_hl * 4);
83+
char *payload = (char *)(&udp[1]);
84+
uint16_t plen = ntohs(udp->uh_ulen);
85+
86+
if (ip_hdr->ip_p == IPPROTO_UDP && plen > 1 && payload[0] == 0 && payload[1] == 5) {
87+
fs_add_string(fs, "classification", (char *)"TFTP", 0);
88+
fs_add_bool(fs, "success", 1);
89+
fs_add_binary(fs, "data",
90+
(ntohs(udp->uh_ulen) - sizeof(struct udphdr)),
91+
(void *)&udp[1], 0);
92+
} else {
93+
fs_add_string(fs, "classification", (char *)"other", 0);
94+
fs_add_bool(fs, "success", 0);
95+
fs_add_null(fs, "data");
96+
}
97+
}
98+
99+
static fielddef_t fields[] = {
100+
{.name = "classification",
101+
.type = "string",
102+
.desc = "packet classification"},
103+
{.name = "success",
104+
.type = "bool",
105+
.desc = "is response considered success"},
106+
{.name = "data", .type = "binary", .desc = "UDP payload"}};
107+
108+
probe_module_t module_tftp = {
109+
.name = "tftp",
110+
.packet_length = 125,
111+
.pcap_filter = "udp || icmp",
112+
.pcap_snaplen = 2048,
113+
.port_args = 1,
114+
.global_initialize = &tftp_global_initialize,
115+
.thread_initialize = &tftp_init_perthread,
116+
.make_packet = &udp_make_packet,
117+
.print_packet = &udp_print_packet,
118+
.process_packet = &tftp_process_packet,
119+
.validate_packet = &tftp_validate_packet,
120+
// UPnP isn't actually dynamic, however, we don't handle escaping
121+
// properly in the CSV module and this will force users to use JSON.
122+
.output_type = OUTPUT_TYPE_DYNAMIC,
123+
.close = NULL,
124+
.helptext = "Probe module that sends a TFTP read request for random filename and expects TFTP error packet in response.",
125+
.fields = fields,
126+
.numfields = sizeof(fields) / sizeof(fields[0])};

src/probe_modules/probe_modules.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,15 @@ extern probe_module_t module_ntp;
2929
extern probe_module_t module_upnp;
3030
extern probe_module_t module_dns;
3131
extern probe_module_t module_bacnet;
32+
extern probe_module_t module_tftp;
3233
// ADD YOUR MODULE HERE
3334

3435
probe_module_t *probe_modules[] = {
3536
&module_tcp_synscan, &module_tcp_synackscan, &module_icmp_echo,
3637
&module_icmp_echo_time, &module_udp, &module_ntp, &module_upnp, &module_dns,
3738
//&module_tcp_cisco_backdoor,
38-
&module_bacnet
39+
&module_bacnet,
40+
&module_tftp
3941
// ADD YOUR MODULE HERE
4042
};
4143

0 commit comments

Comments
 (0)