6 extern globalconfig config
;
8 static int parse_dhcp_sig_opts(dhcp_fp_entry
*sig
, char* p
);
9 static int parse_dhcp_sig_optreq(dhcp_fp_entry
*sig
, char* p
);
10 static dhcp_fp_entry
*alloc_dhcp_sig(dhcp_fp_entry
*e
);
11 static void free_dhcp_sigs(dhcp_fp_entry
*e
);
13 static const unsigned char vendcookie
[] = { 99, 130, 83, 99 };
14 #define BOOTP_COOKIE_SIZE 4
17 void print_dhcp_header(dhcp_header
*dhcph
)
19 plog("OP:%d\n",dhcph
->op
);
20 plog("HTYPE:%d\n",dhcph
->htype
);
21 plog("HLEN:%d\n",dhcph
->hlen
);
22 plog("HOPS:%d\n",dhcph
->hops
);
23 plog("XID:%d\n",dhcph
->xid
);
24 plog("SECS:%d\n",dhcph
->secs
);
25 plog("FLAGS:%d\n",dhcph
->flags
);
27 char dest
[INET_ADDRSTRLEN
];
28 inet_ntop(AF_INET
,&(dhcph
->ciaddr
),dest
,INET_ADDRSTRLEN
+ 1);
29 plog("CIP:%s\n",dest
);
30 inet_ntop(AF_INET
,&(dhcph
->yiaddr
),dest
,INET_ADDRSTRLEN
+ 1);
31 plog("YIP:%s\n",dest
);
32 inet_ntop(AF_INET
,&(dhcph
->siaddr
),dest
,INET_ADDRSTRLEN
+ 1);
33 plog("SIP:%s\n",dest
);
34 inet_ntop(AF_INET
,&(dhcph
->giaddr
),dest
,INET_ADDRSTRLEN
+ 1);
35 plog("GIP:%s\n",dest
);
38 for(i
= 0; i
< 6; i
++){
39 printf("%02hhx", dhcph
->chaddr
[i
]);
40 if (i
!= dhcph
->hlen
-1)
44 plog("SNAME:%s\n",dhcph
->sname
);
45 plog("FILE:%s\n",dhcph
->file
);
49 dhcp_fp_entry
*dhcp_fingerprint(packetinfo
*pi
)
51 plog("Got DHCP packet:\n");
52 config
.pr_s
.dhcp_os_assets
++;
54 uint8_t dhcp_header_length
;
56 uint8_t *dhcp_options
;
58 uint8_t dhcp_opt_type
= 0;
59 uint8_t end_opt_parsing
= 0;
63 dhcph = (dhcp_header *) (pi->payload);
64 print_dhcp_header(dhcph);
66 dhcp_header_length
= sizeof(dhcp_header
);
67 dhcp_mc
= (uint8_t *) (pi
->payload
+ dhcp_header_length
);
69 /* TODO: check and bail if not there */
70 //plog("Magic Cookie: %d%d%d%d\n", *dhcp_mc, *(dhcp_mc+1), *(dhcp_mc+2), *(dhcp_mc+3)); // 99 130 83 99
72 dhcp_options
= (uint8_t *) dhcp_mc
+ BOOTP_COOKIE_SIZE
;
73 uint8_t *optptr
= dhcp_options
;
74 uint8_t max_len
= (pi
->plen
- dhcp_header_length
- BOOTP_COOKIE_SIZE
);
76 dhcp_fp_entry dhcpfp
= {0}; //guarantee it's empty this sig
77 dhcpfp
.ttl
= pi
->ip4
->ip_ttl
;
82 while (optlen
< max_len
) {
85 uint8_t opt
= *(optptr
);
86 uint8_t optsize
= *(optptr
+1);
87 uint8_t *optdata
= optptr
+2;
89 dhcpfp
.opt
[optcnt
] = opt
;
92 case DHCP_OPTION_TYPE
: /* 53 */
94 dhcp_opt_type
= *optdata
;
95 dhcpfp
.type
= dhcp_opt_type
;
98 case DHCP_OPTION_OPTIONREQ
: /* 55 */
100 uint8_t optreqcnt
= 0;
101 for (i
=2; i
< optsize
+2; i
++) {
102 dhcpfp
.optreq
[optreqcnt
] = *(optptr
+i
);
105 dhcpfp
.optreqcnt
= optreqcnt
;
108 case DHCP_OPTION_CLASS_IDENTIFIER
: /* 60 */
110 dhcpfp
.vc
= calloc(1, optsize
+ 1);
111 strncpy(dhcpfp
.vc
, (char*) optdata
, optsize
);
114 case DHCP_OPTION_PAD
: /* 0 */
116 case DHCP_OPTION_END
: /* 255 */
124 optptr
= optptr
+ optsize
+ 2;
126 optlen
= optlen
+ optsize
+ 2;
128 if (end_opt_parsing
== 1) break;
130 /* Just to be sure */
131 if (*(optptr
) != DHCP_OPTION_END
) {
132 if (optptr
+ *(optptr
+1) + 2 > pi
->payload
+ pi
->plen
) break;
136 dhcpfp
.optcnt
= optcnt
;
138 print_dhcp_sig(&dhcpfp
);
141 dhcp_fp_entry
*match
= find_dhcp_match(&dhcpfp
, pi
);
143 #define OS_DHCP = 0x01
144 //update_asset_os(pi, OS_DHCP, NULL, &dhcpfp, tstamp);
148 dhcp_fp_entry
*find_dhcp_match(dhcp_fp_entry
*dhcpfp
, packetinfo
*pi
)
153 //uint32_t hashsize; // = config.sig_hashsize;
156 // hashsize = DHCP_SIG_HASHSIZE;
160 index
= (DHCP_SIGHASH(dhcpfp
->type
, dhcpfp
->optcnt
) % 331);
162 p
= config
.sig_dhcp
[index
];
164 /* Cheap and specific checks first... */
165 if (dhcpfp
->type
^ p
->type
) { p
= p
->next
; continue; }
166 if (dhcpfp
->optcnt
^ p
->optcnt
) { p
= p
->next
; continue; }
167 if (dhcpfp
->optreqcnt
^ p
->optreqcnt
) { p
= p
->next
; continue; }
169 /* Numbers agree. Let's check options 53 first */
170 if (dhcpfp
->optreqcnt
!= 0) {
171 for (j
=0;j
<dhcpfp
->optreqcnt
;j
++){
172 if (p
->optreq
[j
] ^ dhcpfp
->optreq
[j
]) goto continue_search
;
176 /* Let's check options */
177 if (dhcpfp
->optcnt
!= 0) {
178 for (j
=0;j
<dhcpfp
->optcnt
;j
++){
179 if (p
->opt
[j
] ^ dhcpfp
->opt
[j
]) goto continue_search
;
183 /* Numbers agree. Lets match Vendor Code */
184 if (p
->vc
!= NULL
&& dhcpfp
->vc
!= NULL
) {
185 if (strcmp(p
->vc
, dhcpfp
->vc
) == 0) {
186 /* Huston - we have a match */
187 plog("[*] We have a match (");
190 //plog("OS: %s\n",p->os);
191 //plog("DESC: %s\n",p->desc);
195 /* Huston - we have a match */
196 plog("[*] We have a match (");
199 //plog("OS: %s, ",p->os);
200 //plog("DESC: %s)\n",p->desc);
210 void print_data(const uint8_t* data
, uint16_t dlen
) {
211 uint8_t tbuf
[PKT_MAXPAY
+2];
214 uint8_t max
= dlen
> PKT_MAXPAY
? PKT_MAXPAY
: dlen
;
218 for (i
=0;i
<max
;i
++) {
219 if (isprint(*data
)) *(t
++) = *data
;
220 else if (!*data
) *(t
++) = '?';
230 int load_dhcp_sigs(const char *file
, dhcp_fp_entry
**dhcpsp
[], int hashsize
)
233 dhcp_fp_entry
**sig
; // output
235 FILE *f
= fopen(file
, "r");
239 perror("failed to open file");
244 perror("need a pointer to fill");
248 hashsize
= DHCP_SIG_HASHSIZE
;
250 *dhcpsp
= calloc(hashsize
, sizeof(dhcp_fp_entry
*));
254 while ((p
= fgets(buf
, sizeof(buf
), f
))) {
257 char opts
[MAXLINE
], optreq
[MAXLINE
], genre
[MAXLINE
], desc
[MAXLINE
];
261 dhcp_fp_entry asig
= {0}; //guarantee it's empty this sig
266 /* Remove leading and trailing blanks */
270 while (l
&& isspace(*(p
+ l
- 1)))
271 *(p
+ (l
--) - 1) = 0;
273 /* Skip empty lines and comments */
279 /* T4:64:1:60:M*,S,T,N,W7:.:Linux:2.6 (newer, 7) */
280 /* 53-OPTION:TTL:ALL-OPTIONS:55-OPTIONS:60-OPTIONS:OS:OS Details */
281 /* 1:128:53,116,61,12,60,55,43:1,15,3,6,44,46,47,31,33,121,249,43:MSFT 5.0:Windows:Windows XP SP3 */
283 (p
, "%d:%d:%[^:]:%[^:]:%[^:]:%[^:]:%[^:]",
284 &type
, &t
, opts
, optreq
, vc
, genre
, desc
) != 7)
285 fatal("Syntax error in config line %d.\n", ln
);
291 asig
.os
= strdup(gptr
);
292 asig
.desc
= strdup(desc
);
293 asig
.vc
= strdup(vc
);
296 parse_dhcp_sig_opts(&asig
, opts
);
297 parse_dhcp_sig_optreq(&asig
, optreq
);
299 uint32_t index
= (DHCP_SIGHASH(asig
.type
, asig
.optcnt
) % 331);
303 sig
[index
] = alloc_dhcp_sig(&asig
);
312 fprintf(stderr, "hash collision: %s\n", p);
314 e
->next
= alloc_dhcp_sig(&asig
);
322 for (i
= 0; i
< sigcnt
; i
++) {
323 print_dhcp_sig(&sig
[i
]);
331 printf("DHCP hash table layout: ");
332 for (i
= 0; i
< hashsize
; i
++) {
343 #endif /* DEBUG_HASH */
345 // if (check_collide)
346 // debug("[+] DHCP signature collision check successful.\n");
351 /* run through the hash, free entries, then free hash */
352 void unload_dhcp_sigs(dhcp_fp_entry
**sigp
, int size
)
360 sigp
[i
] = NULL
; // clear
366 /* alloc_sig return a newly allocated copy of *e */
367 static dhcp_fp_entry
*alloc_dhcp_sig(dhcp_fp_entry
*e
)
369 dhcp_fp_entry
*n
= calloc(1, sizeof(dhcp_fp_entry
));
374 /* recursively free signatures */
375 static void free_dhcp_sigs(dhcp_fp_entry
*e
){
377 free_dhcp_sigs(e
->next
);
381 void dump_dhcp_sigs(dhcp_fp_entry
*mysig
[], int max
)
384 for (i
= 0; i
< max
; i
++){
385 if (!mysig
[i
] || !mysig
[i
]->os
)
387 print_dhcp_sig(mysig
[i
]);
391 void print_dhcp_sig(dhcp_fp_entry
* e
)
395 plog("[%d:%d:",e
->type
,e
->ttl
);
396 for (j
=0;j
<e
->optcnt
;j
++){
397 plog("%d",e
->opt
[j
]);
398 if ((j
+1) < (e
->optcnt
)) plog(",");
401 for (j
=0;j
<e
->optreqcnt
;j
++){
402 plog("%d",e
->optreq
[j
]);
403 if ((j
+1) < (e
->optreqcnt
)) plog(",");
405 if (e
->optreqcnt
==0) plog(".");
419 if (e
->desc
== NULL
) {
426 void print_dhcp_sigs(dhcp_fp_entry
* e
)
430 print_dhcp_sigs(e
->next
);
434 /* parse the option field of the signature line */
435 static int parse_dhcp_sig_opts(dhcp_fp_entry
*sig
, char* p
)
443 if (!isdigit(*(p
))) {
444 fatal("Bogus DHCP value in line %d.\n", sig
->line
);
446 if (!isdigit(*(p
+1))) {
447 sig
->opt
[optcnt
] = atoi(p
);
448 } else if (!isdigit(*(p
+2))) {
449 sig
->opt
[optcnt
] = atoi(p
);
451 } else if (!isdigit(*(p
+3))) {
452 sig
->opt
[optcnt
] = atoi(p
);
458 if (++optcnt
>= MAXDHCPOPTS
)
460 ("Too many DHCP options specified in config line %d.\n",
467 } while (*p
&& !isdigit(*p
));
469 sig
->optcnt
= optcnt
;
473 /* parse the option field of the signature line */
474 static int parse_dhcp_sig_optreq(dhcp_fp_entry
*sig
, char* p
)
476 uint8_t optreqcnt
= 0;
482 if (!isdigit(*(p
))) {
483 fatal("Bogus DHCP value in line %d.\n", sig
->line
);
485 if (!isdigit(*(p
+ 1))) {
486 sig
->optreq
[optreqcnt
] = atoi(p
);
487 } else if (!isdigit(*(p
+ 2))) {
488 sig
->optreq
[optreqcnt
] = atoi(p
);
490 } else if (!isdigit(*(p
+ 3))) {
491 sig
->optreq
[optreqcnt
] = atoi(p
);
497 if (++optreqcnt
>= MAXDHCPOPTS
)
499 ("Too many DHCP request options specified in config line %d.\n",
506 } while (*p
&& !isdigit(*p
));
508 sig
->optreqcnt
= optreqcnt
;