Linux下C/C++ 网络扫描(主机扫描技术)

news2024/11/15 5:33:19

主机扫描是网络扫描的基础,通过对目标网络中主机IP地址的扫描,从一堆主机中扫描出存活的主机,然后以他们为目标进行后续的攻击。一般会借助于ICMP、TCP、UDP等协议的工作机制,检查打开的进程,开放的端口号等等。

主机扫描

主机扫描是在可达状态下检测,局域网下的 ARP 扫描和广域网下的 ICMP Echo 扫描、ICMP Sweep 扫描、ICMP Broadcast 扫描、ICMP Non-Echo 扫描都是基本的扫描技术。还有绕过防火墙和网络过滤设备的高级技术。

  • ARP 扫描

向目标主机所在的局域网发送 ARP 广播请求,在局域网连通状态下目标主机必定会响应正常的 ARP 广播请求。故而便可获得IP地址和 MAC 地址等信息。

...
int convertNetworkAddr(const char *inString,uint8_t outNetAddr[PROTOCOL_ADDRESS_LENGTH],uint8_t *netPrefix) 
{
    char *invalidCharPtr;
    // 读取3个八位字节
    for (int i = 0; i < PROTOCOL_ADDRESS_LENGTH - 1; ++i) 
    {
        unsigned long octet = strtoul(inString, &invalidCharPtr, 10);
        if (octet >= 256 || *invalidCharPtr != '.') 
        {
            return 1;
        }
        inString = invalidCharPtr + 1;
        outNetAddr[i] = (uint8_t) octet;
    }
    // 读取最后一个八位字节
    unsigned long octet = strtoul(inString, &invalidCharPtr, 10);
    if (octet >= 256 || *invalidCharPtr != '/') 
    {
        return 1;
    }
    inString = invalidCharPtr + 1;
    outNetAddr[PROTOCOL_ADDRESS_LENGTH - 1] = octet;
    unsigned long prefix = strtoul(inString, &invalidCharPtr, 10);
    if (prefix > 32 || invalidCharPtr == inString) 
    {
        return 1;
    }
    *netPrefix = prefix;
    // 按位AND ip地址和网络掩码
    uint8_t hostPartLength = PROTOCOL_ADDRESS_LENGTH * 8 - prefix;
    for (int j = 0; j < hostPartLength / 8; ++j) 
    {
        outNetAddr[PROTOCOL_ADDRESS_LENGTH - 1 - j] = 0x00;
    }
    if (hostPartLength % 8) 
    {
        uint8_t mask = (0xFF >> hostPartLength % 8) << hostPartLength % 8;
        outNetAddr[PROTOCOL_ADDRESS_LENGTH - hostPartLength / 8 - 1] &= mask;
    }
    return 0;
}
...
void printPacket(struct ArpPacket *p) 
{
    for (int i = 0; i < sizeof(struct ArpPacket); ++i) 
    {
        int c = *((char*)p+i) & 0xFF;
        printf("%2x ", c);
        if (i%8 == 7)
            printf("\n");
    }
    printf("\n");
}

int readNetworkAddr(const char *string,uint8_t dstAddr[PROTOCOL_ADDRESS_LENGTH],uint8_t *dstPrefix) 
{
    if (convertNetworkAddr(string, dstAddr, dstPrefix)) 
    {
        fprintf(stderr, "Cannot recognize network address from: %s\n", string);
        exit(1);
    }
    DEBUG(
            printf("========= RECOGNIZED NETWORK ADDRESS ===========\n");
            printf("IP address: ");
            for (int j = 0; j < PROTOCOL_ADDRESS_LENGTH; ++j) 
            {
                printf("%i ", (int)dstAddr[j]);
            }
            printf("\nNet prefix: %i\n", (int)(*dstPrefix) );
    )
}

int main(int argc, char **argv) 
{
...
    if (argc != 3) 
    {
        fprintf(stderr, "Usage: <interface name> <network address>.\n"
                "For example: scan eth0 192.168.0.1/24\n");
        return 1;
    }
    // 打开套接字
    int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
    if (s == -1) {
        perror("Error in opening socket: ");
        return 1;
    }
    // 读取网络地址
    uint8_t netAddr[PROTOCOL_ADDRESS_LENGTH];
    uint8_t netPrefix;
    readNetworkAddr(argv[2], netAddr, &netPrefix);
    DEBUG(
        setHostPart(netAddr, 255, 8);
        printf("IP address: ");
        for (int j = 0; j < PROTOCOL_ADDRESS_LENGTH; ++j) 
        {
            printf("%i ", (int)netAddr[j]);
        }
        printf("\n");
    )

    struct sockaddr_ll addr;
    prepareSockaddrll(&addr, argv[1]);

    struct ArpPacket packet;
    prepareArpPacket(&packet, &addr, argv[1]);
    DEBUG(
        printf("Packet hex dump: \n");
        printPacket(&packet);
    )
    for (int i = 1; i < powl(2, (32 - netPrefix) ) - 1; ++i) 
    {
        setHostPart(netAddr, i, 32 - netPrefix);
        setDstIP(netAddr, &packet);
        DEBUG(
            printf("Sending ARP request to IP ");
            printIP(netAddr, stdout);
            printf(" ..............");
        )
        if(sendto(s, &packet, sizeof(packet), 0,(struct sockaddr*) &addr, sizeof(addr)) == -1) {
            perror("Error in sending ARP request: ");
            fprintf(stderr, "Error in sending ARP request: %s\n", strerror(errno));
            return 1;
        }
        DEBUG(printf("[ DONE ]\n");)
        // waiting for response
        usleep(200);
        struct ArpPacket response;
        ssize_t receivedResponseSize;
        if (receivedResponseSize = recv(s, &response, sizeof(response), MSG_DONTWAIT | MSG_TRUNC) > 0) 
        {
            DEBUG(
                printf("Received %ld bytes of response: \n", (long) receivedResponseSize);
                printPacket(&response);
            )
            if (memcmp(response.senderLogicAddress, packet.senderLogicAddress, sizeof(packet.senderLogicAddress))) 
            {
                printf("IP ");
                printIP(response.senderLogicAddress, stdout);
                printf(" has MAC: ");
                for (int j = 0; j < HARDWARE_ADDRESS_LENGTH; ++j) 
                {
                    printf("%x:", (int)response.senderHardwareAddress[j]);
                }
                printf("\n");
            }
        }
    }
    return 0;
}

运行结果:

If you need the complete source code, please add the WeChat number (c17865354792)

tcpdump抓包

  • ICMP Echo 扫描

向目标主机发送ICMP Echo Request (type 8)数据包,等待回复的ICMP Echo Reply 包(type 0) 。如果能收到,则表明目标系统可达,否则表明目标系统已经不可达或发送的包被对方的设备过滤掉。

...
/*
获取网络接口的本地信息。
 */
int loadLocalData( LocalData *dst, const char *ifname )
{
	struct ifreq nic;
	int sock = socket( AF_INET, SOCK_DGRAM, 0 );

	strncpy( nic.ifr_name, ifname, IFNAMSIZ-1 );
	nic.ifr_name[IFNAMSIZ-1] = '\0';


	if( ioctl( sock, SIOCGIFINDEX, &nic ) < 0 ){
		close( sock );
		return -1;
	}
	dst->ifindex = nic.ifr_ifindex;

	// 分配的IP地址
	if( ioctl( sock, SIOCGIFADDR, &nic ) < 0 ){
		close( sock );
		return -1;
	}
	memcpy( &dst->ip, nic.ifr_addr.sa_data + 2, INET_ALEN );

	// MAC地址 
	if( ioctl( sock, SIOCGIFHWADDR, &nic ) < 0 ){
		close( sock );
		return -1;
	}
	memcpy( &dst->mac, nic.ifr_hwaddr.sa_data, ETH_ALEN );

	// 子网掩码
	if( ioctl( sock, SIOCGIFNETMASK, &nic ) < 0 ){
		close( sock );
		return -1;
	}
	memcpy( &dst->netmask, nic.ifr_netmask.sa_data + 2, INET_ALEN ); 
	close( sock );
	return 0;
}

/**
 * 为特定协议创建套接字。
 */
int createSocket( SocketType type, int msecs )
{
	int sfd;
	struct timeval timer;

	if( type == ICMPSocket )
		sfd = socket( AF_INET, SOCK_RAW, IPPROTO_ICMP );
	else
		sfd = socket( AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP) );

	if( sfd < 0 )
		return -1;

	// 设置接收数据的最大时间
	timer.tv_sec = msecs / 1000;
	timer.tv_usec = msecs % 1000 * 1000;
	if( setsockopt( sfd, SOL_SOCKET, SO_RCVTIMEO, &timer, sizeof(timer) ) < 0 ){
		close( sfd );
		return -1;
	}
	return sfd;
}
...

/**
 * 计算增加一个IP地址的结果。
 */
struct in_addr ipAddOne( struct in_addr ip )
{
	struct in_addr aux = { ntohl( ip.s_addr ) };
	aux.s_addr++;
	aux.s_addr = htonl( aux.s_addr );
	return aux;
}

/**
 * 交换两个IP地址的值
 */
void ipSwap( struct in_addr *a, struct in_addr *b )
{
    a->s_addr = a->s_addr ^ b->s_addr;    
    b->s_addr = a->s_addr ^ b->s_addr;
    a->s_addr = a->s_addr ^ b->s_addr;
}
...

int main( int argc, char **argv )
{
...

	// 验证接口
	if( !interface )
	{
		fprintf( stderr, "Error: No interface given. Use -h for help\n" );
		return -1;
	}

	// 加载本地数据
	if( loadLocalData( &data, interface ) < 0 )
	{
		perror( interface );
		return -1;
	}

	// 验证是否有特定的IP 
	if( strFirst )
	{
		if( !inet_aton( strFirst, &first ) )
		{
			fprintf( stderr, "%s: Invalid address\n", strFirst );
			return -1;
		}
		if( strLast )
		{ // 验证是否有范围
			if( !inet_aton( strLast, &last ) )
			{
				fprintf( stderr, "%s: Invalid address\n", strLast );
				return -1;
			}
			else
			{
				total = ntohl( last.s_addr ) - ntohl( first.s_addr );
				if( total < 0 ){
					total = -total;
					ipSwap( &first, &last );
				}
				total++;
			}
		}
		else
		{
			total = 1;
		}
	}
	else
	{ // 如果没有,则从本地网络数据中获取范围。
		first.s_addr = data.ip.s_addr & data.netmask.s_addr;
		first = ipAddOne( first );
		last.s_addr = data.ip.s_addr | ~data.netmask.s_addr;
		total = ntohl( last.s_addr ) - ntohl( first.s_addr );
	}

	// 创建套接字
	if( (sfd = createSocket( type, waitTime ) ) < 0 )
	{
		perror( "Failed to create socket" );
		return 2;
	}

...
	// 扫描周期
	for( int i = 1 ; i <= total && running ; i++, first = ipAddOne(first) )
	{
		printf( "\r(%d%%) Testing %s...", (int)(100.0 / total * i), inet_ntoa(first) );
		fflush( stdout );
		if( first.s_addr == data.ip.s_addr )
		{
			printf( " (this host)\n" );
			ups++;
		}
		else
		{
			switch( isUp(sfd, first, &data) )
			{
				case -1:
					perror( " send request" );
					break;
				case 1:
					puts( " is up" );
					ups++;
			}
		}
	}
	close( sfd );
	printf( "\n%d hosts up\n", ups );
	return 0;
}

运行结果:

If you need the complete source code, please add the WeChat number (c17865354792)

tcpdump抓包:

  • ICMP Sweep 扫描


总结

这里我们就知道了其实主机扫描很简单,只需要证明其主机存活就好。我们只需要对目标主机发送特定的数据包,如果目标主机有回应,那么我们就认为该主机是存活的;反之如果对方不回应,我们就认为其不是存活主机。

Welcome to follow WeChat official account【程序猿编码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400004.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot使用缓存

目录 简介 Spring 的缓存主要有如下几个注解 红色标注的注解为最常用的注解&#xff0c;必须熟练掌握 Cacheable/CachePut/CacheEvict 主要的参数 SpEL 提供的运算符 实现步骤 补充 注意 整合 EHCACHE 简介 Spring 框架已经具备了缓存机制&#xff0c;虽然我们可以使用 …

Locust框架从0到1入门

Locust介绍 Locust是使用Python语言编写实现的开源性能测试工具&#xff0c;可以用来测试Web应用程序、API、数据库等各种应用程序的性能&#xff0c;使用起来简洁、轻量、高效&#xff0c;并发机制基于gevent协程&#xff0c;可以实现单机模拟生成较高的并发压力。中文意为&a…

【目标检测】正负样本分配策略

YOLO v3 目标的中心点在哪个网格内由该网格负责预测该目标&#xff0c;max-iou matching策略 &#xff08;1&#xff09;计算GT的中心点在哪个网格&#xff1b; &#xff08;2&#xff09;计算该网格内的所有anchor与GT的IOU&#xff0c;选择IOU最大的anchor负责预测该GT&…

嵌入安防监控项目——BOA服务器的移植

目录 一、源码下载 1.1 boa简介&#xff1a; 1.2BOA再项目中的使用 二、解压源码&#xff1a; 三、进入源码目录下的src目录&#xff1a; 四、make 编译源码&#xff1a; 五、建立安装目录 六、返回boa的顶层目录 --- 修改配置文件 七、建立测试页面 八、查看/boa目…

43-Golang中的goroutine!!!

Golang中的goroutine进程和线程说明并发和并行并发并行Go协程和Go主线程案例小结goroutine的调度机制MPG模式基本介绍MPG模式运行的状态1MPG模式运行的状态2设置GOlang运行的CPU数不同 goroutine之间如何通讯使用全局变量加锁同步改进程序进程和线程说明 1.进程就是程序在操作…

robosuite添加无碰撞的模型

1 前言 最近在使用robosuite时,需要在仿真环境中可视化物体的目标位置,从而方便观察训练情况,可视化的物体有以下要求: 形状尺寸与操作的物体一样半透明只有visual,不与场景其他物体有碰撞可以在每次step后设置位置,且固定在设定的位置,不受重力影响 2 方法 找了半天,最终确…

javaWeb核心04-CookieSession

文章目录会话技术1&#xff0c;会话跟踪技术的概述2&#xff0c;Cookie2.1 Cookie的基本使用2.2 Cookie的原理分析2.3 Cookie的使用细节2.3.1 Cookie的存活时间2.3.2 Cookie存储中文3&#xff0c;Session3.1 Session的基本使用3.2 Session的原理分析3.3 Session的使用细节3.3.1…

2018年MathorCup数学建模D题公交移动支付问题的评估方案解题全过程文档及程序

2018年第八届MathorCup高校数学建模挑战赛 D题 公交移动支付问题的评估方案 原题再现&#xff1a; 随着智能手机的普及和移动支付技术的提高,越来越多的支付手段可以转移到手机端。现有的现金缴费和实体公交卡刷卡的付费方式存在缺点&#xff0c;如公交卡在使用过程中存在着充…

Landsat8中*_MTL.txt文件详解

01 什么是*_MTL.txt文件&#xff1f;所有的Landsat8 1级数据产品中均包含MTL.txt(Metadata File)文件。Landsat MTL文件包含对数据的系统搜索和归档分类有益的信息。该文件还包含关于数据处理和恶对增强陆地卫星数据有重要价值的信息&#xff08;例如转换为反射率和辐射亮度&am…

Java 集合进阶(二)

文章目录一、Set1. 概述2. 哈希值3. 元素唯一性4. 哈希表5. 遍历学生对象6. LinkedHashSet7. TreeSet7.1 自然排序7.2 比较器排序8. 不重复的随机数二、泛型1. 概述2. 泛型类3. 泛型方法4. 泛型接口5. 类型通配符6. 可变参数7. 可变参数的使用一、Set 1. 概述 Set 集合特点&am…

AI领域通识

人工智能的架构&#xff1a;通常来说&#xff0c;人工智能架构分为四层&#xff1a;最底层的基础层一般由软硬件设施以及数据服务组成。软件设施主要包括智能云平台和大数据平台&#xff0c;比如国外的谷歌大数据平台和国内的百度智能云平台等&#xff1b;硬件设施主要包括CPU硬…

讨论基于最新的(v5或v6版本)UXP插件开发的开发框架的选择问题

看过我的上两篇文章后&#xff0c;相信你对UXP的开发环境已经有一定了解了&#xff0c;然后这里讨论一个问题&#xff0c;UXP的开发可以基于纯htmlcssjs、vue框架、react框架、svelte框架&#xff0c;就是到底用哪种方式开发更好了&#xff1f;一般情况是用自己最熟悉的或者是使…

使用vue脚手架创建vue项目

大家好&#xff0c;这里是 一口八宝周 &#x1f44f;欢迎来到我的博客 ❤️一起交流学习文章中有需要改进的地方请大佬们多多指点 谢谢 &#x1f64f;使用脚手架创建vue项目步骤&#xff1a;切换淘宝镜像npm config set registry https://registry.npm.taobao.org安装脚手架npm…

算法拾遗二十七之窗口最大值或最小值的更新结构

算法拾遗二十七之窗口最大值或最小值的更新结构滑动窗口题目一题目二题目三题目四滑动窗口 第一种&#xff1a;R&#xff0c;R右动&#xff0c;数会从右侧进窗口 第二种&#xff1a;L&#xff0c;L右动&#xff0c;数从左侧出窗口 题目一 arr是N&#xff0c;窗口大小为W&…

C++ linux下获取时间戳 秒、微妙、纳秒

1.例子#include <iostream>#include <sys/time.h>#include <cstdlib>#include <cstdio>#include <ctime>#include <cmath>#include <unistd.h>usingnamespace std;time_t clocktime(){time_t t time(NULL);std::cout << &quo…

聚势合力,电巢与SDIA协会“战略合作签约仪式”圆满落成

前言&#xff1a; 2023年03月02日下午&#xff0c;电巢科技与深圳市平板显示行业协会齐聚深圳南山电巢XR演播厅&#xff0c;共同举办了隆重的战略合作签约仪式。 双方就数字化建设、品牌赋能、人才培养、技术创新等企业服务深入合作上达成一致&#xff0c;合力为产业赋能&…

【OJ比赛日历】快周末了,不来一场比赛吗? #03.11-03.17 #12场

CompHub 实时聚合多平台的数据类(Kaggle、天池…)和OJ类(Leetcode、牛客…&#xff09;比赛。本账号同时会推送最新的比赛消息&#xff0c;欢迎关注&#xff01;更多比赛信息见 CompHub主页 或 点击文末阅读原文以下信息仅供参考&#xff0c;以比赛官网为准目录2023-03-11&…

netty-websocket 鉴权token及统一请求和响应头(鉴权控制器)

自己想法和实现&#xff0c;如果有说错的或者有更好的简单的实现方式可以私信交流一下(主要是实现握手时鉴权) 需求实现 握手鉴权是基于前台请求头 Sec-WebSocket-Protocol的本身socket并没有提供自定义请求头&#xff0c;只能自定义 Sec-WebSocket-Protocol的自协议 问题描述…

你几乎不知道的浏览器内置对象/事件/ajax

浏览器内置对象/事件/ajax 浏览器是⼀个 JS 的运⾏时环境&#xff0c;它基于 JS 解析器的同时&#xff0c;增加了许多环境相关的内容。⽤⼀张图表示各个运⾏环境和 JS 解析器的关系如下&#xff1a; 我们把常⻅的&#xff0c;能够⽤ JS 这⻔语⾔控制的内容称为⼀个 JS 的运⾏环…

Leetcode—环形链表

前言&#xff1a;给定一个链表&#xff0c;判断是否为循环链表并找环形链表的入口点 首先我们需要知道什么是双向循环链表&#xff0c;具体如下图所示。 对于链表&#xff0c;我们如何去判断链表是循环链表呢&#xff1f;又寻找入环点呢&#xff1f;我们可以利用快慢指针的方法…