Skip to content

Commit

Permalink
Add: Add nasl function nasl_send_arp_request(). (#939)
Browse files Browse the repository at this point in the history
* Add libnet support

* Add function capture_next_frame()

* Add nasl function nasl_send_arp_request().

The new function sends an ARP request and return the target's mac address

* Improve docstring
  • Loading branch information
jjnicola committed Nov 15, 2021
1 parent b67e372 commit d1a7c6b
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 11 deletions.
28 changes: 26 additions & 2 deletions nasl/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,29 @@ pkg_check_modules (LIBGVM_UTIL REQUIRED libgvm_util>=21.10)
pkg_check_modules (OPENVAS_WMICLIENT libopenvas_wmiclient>=1.0.5)
pkg_check_modules (OPENVAS_WINCMD libopenvas_wincmd>=1.0.5)

## Check for libnet
message (STATUS "Looking for libnet...")
find_library (NET net)
message (STATUS "Looking for net... ${NET}")
if (NOT NET)
message (SEND_ERROR "The net library is required.")
endif (NOT NET)
message (STATUS "Looking for libnet-config...")
find_program (LIBNET_CONFIG libnet-config)

if (LIBNET_CONFIG)
message (STATUS "Looking for libnet-config... ${LIBNET_CONFIG}")
execute_process (COMMAND libnet-config --libs
OUTPUT_VARIABLE LIBNET_LDFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process (COMMAND libnet-config --cflags
OUTPUT_VARIABLE LIBNET_CFLAGS
OUTPUT_STRIP_TRAILING_WHITESPACE)
else (LIBNET_CONFIG)
message (STATUS "libnet-config not found, using defaults...")
set (LIBNET_LDFLAGS "-L/usr/lib -lnet")
set (LIBNET_CFLAGS "-I/usr/include")
endif (LIBNET_CONFIG)

# for 'nasl' binary
pkg_check_modules (LIBSSH REQUIRED libssh>=0.6.0)
Expand Down Expand Up @@ -167,8 +190,8 @@ endif (NOT BISON_FOUND)
set (FILES arc4.c capture_packet.c charcnv.c exec.c genrand.c hmacmd5.c
iconv.c lint.c md4.c md5.c nasl.c nasl_builtin_find_service.c
nasl_builtin_openvas_tcp_scanner.c nasl_builtin_synscan.c
nasl_cmd_exec.c nasl_crypto2.c nasl_snmp.c nasl_ssh.c nasl_cert.c
nasl_crypto.c nasl_debug.c nasl_func.c nasl_grammar.tab.c nasl_host.c
nasl_cmd_exec.c nasl_crypto2.c nasl_frame_forgery.c nasl_snmp.c nasl_ssh.c
nasl_cert.c nasl_crypto.c nasl_debug.c nasl_func.c nasl_grammar.tab.c nasl_host.c
nasl_http.c nasl_init.c nasl_lex_ctxt.c nasl_misc_funcs.c nasl_scanner_glue.c
nasl_packet_forgery.c nasl_packet_forgery_v6.c nasl_signature.c nasl_smb.c
nasl_socket.c nasl_text_utils.c nasl_tree.c nasl_var.c nasl_wmi.c
Expand Down Expand Up @@ -219,6 +242,7 @@ set_target_properties (openvas_nasl_shared PROPERTIES VERSION "${PROJECT_VERSION
target_link_libraries (openvas_nasl_shared openvas_misc_shared ${GLIB_LDFLAGS}
${GCRYPT_LDFLAGS} ${GPGME_LDFLAGS} m
${LIBGVM_BASE_LDFLAGS}
${LIBNET_LDFLAGS}
${LIBGVM_UTIL_LDFLAGS}
${OPENVAS_WMICLIENT_LDFLAGS} ${OPENVAS_WINCMD_LDFLAGS}
${GNUTLS_LDFLAGS} ${PCAP_LDFLAGS} ${LIBSSH_LDFLAGS}
Expand Down
77 changes: 68 additions & 9 deletions nasl/capture_packet.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <glib.h> /* for gfree */
#include <netinet/ip.h>
#include <pcap.h>
#include <string.h> /* for bcopy */
#include <sys/param.h>
#ifdef __FreeBSD__
#include <sys/socket.h>
Expand Down Expand Up @@ -95,6 +94,65 @@ init_capture_device (struct in_addr src, struct in_addr dest, char *filter)
return ret;
}

/**
* @brief Capture a link layer frame.
*
* @param[in] bpf bpf handler
* @param[in] timeout the timeout
* @param[out] sz size of the frame
*
* @return the link layer frame.
*/
struct ether_header *
capture_next_frame (int bpf, int timeout, int *sz)
{
int len;
int dl_len;
char *frame = NULL;
char *ret = NULL;
struct timeval past, now, then;
struct timezone tz;

if (bpf < 0)
return NULL;

dl_len = get_datalink_size (bpf_datalink (bpf));
memset (&past, '\0', sizeof (past));
memset (&now, '\0', sizeof (now));
gettimeofday (&then, &tz);
for (;;)
{
memcpy (&past, &then, sizeof (then));
frame = (char *) bpf_next (bpf, &len);
if (frame != NULL)
break;
gettimeofday (&now, &tz);

if (now.tv_usec < past.tv_usec)
{
past.tv_sec++;
now.tv_usec += 1000000;
}

if (timeout > 0)
{
if ((now.tv_sec - past.tv_sec) >= timeout)
break;
}
else
break;
}

if (frame != NULL)
{
ret = g_malloc0 (dl_len);
memcpy (ret, frame, dl_len);
if (sz != NULL)
*sz = dl_len;
}
return ((struct ether_header *) ret);
}

struct ip *
capture_next_packet (int bpf, int timeout, int *sz)
{
Expand All @@ -109,12 +167,12 @@ capture_next_packet (int bpf, int timeout, int *sz)
return NULL;

dl_len = get_datalink_size (bpf_datalink (bpf));
bzero (&past, sizeof (past));
bzero (&now, sizeof (now));
memset (&past, '\0', sizeof (past));
memset (&now, '\0', sizeof (now));
gettimeofday (&then, &tz);
for (;;)
{
bcopy (&then, &past, sizeof (then));
memcpy (&past, &then, sizeof (then));
packet = (char *) bpf_next (bpf, &len);
if (packet != NULL)
break;
Expand All @@ -138,14 +196,15 @@ capture_next_packet (int bpf, int timeout, int *sz)
if (packet != NULL)
{
struct ip *ip;

ip = (struct ip *) (packet + dl_len);
#ifdef BSD_BYTE_ORDERING
ip->ip_len = ntohs (ip->ip_len);
ip->ip_off = ntohs (ip->ip_off);
#endif
ip->ip_id = ntohs (ip->ip_id);
ret = g_malloc0 (len - dl_len);
bcopy (ip, ret, len - dl_len);
memcpy (ret, ip, len - dl_len);
if (sz != NULL)
*sz = len - dl_len;
}
Expand Down Expand Up @@ -222,13 +281,13 @@ capture_next_v6_packet (int bpf, int timeout, int *sz)
return NULL;

dl_len = get_datalink_size (bpf_datalink (bpf));
bzero (&past, sizeof (past));
bzero (&now, sizeof (now));
memset (&past, '\0', sizeof (past));
memset (&now, '\0', sizeof (now));
gettimeofday (&then, &tz);

for (;;)
{
bcopy (&then, &past, sizeof (then));
memcpy (&past, &then, sizeof (then));
packet = (char *) bpf_next (bpf, &len);

if (packet != NULL)
Expand Down Expand Up @@ -258,7 +317,7 @@ capture_next_v6_packet (int bpf, int timeout, int *sz)
ip6->ip6_plen = ntohs (ip6->ip6_plen);
#endif
ret = g_malloc0 (len - dl_len);
bcopy (ip6, ret, len - dl_len);
memcpy (ret, ip6, len - dl_len);
if (sz != NULL)
*sz = len - dl_len;
}
Expand Down
3 changes: 3 additions & 0 deletions nasl/capture_packet.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ init_capture_device (struct in_addr, struct in_addr, char *);
struct ip *
capture_next_packet (int, int, int *);

struct ether_header *
capture_next_frame (int, int, int *);

int
init_v6_capture_device (struct in6_addr, struct in6_addr, char *);

Expand Down
175 changes: 175 additions & 0 deletions nasl/nasl_frame_forgery.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
/* Copyright (C) 2021 Greenbone Networks GmbH
*
* SPDX-License-Identifier: GPL-2.0-or-later
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/

/**
* @file nasl_frame_forgery.c
* @brief Functions to forge and manipulate datalink layer frames.
*/

#include "nasl_frame_forgery.h"

#include "../misc/bpf_share.h" /* for bpf_open_live */
#include "../misc/plugutils.h"
#include "capture_packet.h"

#include <gvm/base/networking.h>
#include <libnet.h>
#include <net/ethernet.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#undef G_LOG_DOMAIN
/**
* @brief GLib logging domain.
*/
#define G_LOG_DOMAIN "lib misc"

/**
* @brief Send an arp request to an IP host.
*
* @naslnparam
*
* - @a host Target's IPv4 address
*
* @naslret The MAC address of the host. NULL otherwise
*
* @param[in] lexic Lexical context of NASL interpreter.
*
* @return A tree cell or NULL.
*/
tree_cell *
nasl_send_arp_request (lex_ctxt *lexic)
{
tree_cell *retc = NULL;
struct in6_addr *dst = plug_get_host_ip (lexic->script_infos);
struct in_addr inaddr;
char ip_str[INET6_ADDRSTRLEN];
libnet_t *l; /* the libnet context */
char errbuf[LIBNET_ERRBUF_SIZE];
u_int32_t target_ip_addr, src_ip_addr;
u_int8_t mac_broadcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
u_int8_t mac_zero_addr[6] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
struct libnet_ether_addr *src_mac_addr;
int bytes_written, bpf = -1;
char filter[255];
struct ether_header *answer;
int answer_sz;
int to = get_int_var_by_name (lexic, "pcap_timeout", 5);

l = libnet_init (LIBNET_LINK, NULL, errbuf);
if (l == NULL)
{
g_message ("%s: libnet_init() failed: %s\n", __func__, errbuf);
return retc;
}

/* Getting our own MAC and IP addresses */

src_ip_addr = libnet_get_ipaddr4 (l);
if (src_ip_addr == (u_int32_t) -1)
{
g_message ("%s: Couldn't get own IP address: %s\n", __func__,
libnet_geterror (l));
libnet_destroy (l);
return NULL;
}

src_mac_addr = libnet_get_hwaddr (l);
if (src_mac_addr == NULL)
{
g_message ("%s: Couldn't get own IP address: %s\n", __func__,
libnet_geterror (l));
libnet_destroy (l);
return NULL;
}

/* Getting target IP address */
if (dst == NULL || (IN6_IS_ADDR_V4MAPPED (dst) != 1))
return retc;
inaddr.s_addr = dst->s6_addr32[3];
addr6_to_str (dst, ip_str);
target_ip_addr = libnet_name2addr4 (l, ip_str, LIBNET_DONT_RESOLVE);

if (target_ip_addr == (u_int32_t) -1)
{
g_message ("%s: Error converting IP address.\n", __func__);
libnet_destroy (l);
return retc;
}

/* Building ARP header */

if (libnet_autobuild_arp (ARPOP_REQUEST, src_mac_addr->ether_addr_octet,
(u_int8_t *) (&src_ip_addr), mac_zero_addr,
(u_int8_t *) (&target_ip_addr), l)
== -1)
{
g_message ("%s: Error building ARP header: %s\n", __func__,
libnet_geterror (l));
libnet_destroy (l);
return retc;
}

/* Building Ethernet header */

if (libnet_autobuild_ethernet (mac_broadcast_addr, ETHERTYPE_ARP, l) == -1)
{
g_message ("%s: Error building Ethernet header: %s\n", __func__,
libnet_geterror (l));
libnet_destroy (l);
return retc;
}

/* Prepare filter and init capture */
snprintf (filter, sizeof (filter), "arp and src host %s", inet_ntoa (inaddr));
bpf = init_capture_device (inaddr, inaddr, filter);

/* Writing packet */
bytes_written = libnet_write (l);
if (bytes_written != -1)
{
if (bpf >= 0)
answer = capture_next_frame (bpf, to, &answer_sz);

if (answer)
{
char *daddr;
daddr = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x",
(unsigned int) answer->ether_shost[0],
(unsigned int) answer->ether_shost[1],
(unsigned int) answer->ether_shost[2],
(unsigned int) answer->ether_shost[3],
(unsigned int) answer->ether_shost[4],
(unsigned int) answer->ether_shost[5]);
retc = alloc_typed_cell (CONST_DATA);
retc = alloc_typed_cell (CONST_DATA);
retc->x.str_val = daddr;
retc->size = strlen (daddr);
}
}
else
g_message ("%s: Error writing packet: %s\n", __func__, libnet_geterror (l));

libnet_destroy (l);
if (bpf >= 0)
bpf_close (bpf);

return retc;
}

0 comments on commit d1a7c6b

Please sign in to comment.