您现在的位置是:首页 >技术杂谈 >Linux下C/C++(端口扫描技术)网站首页技术杂谈
Linux下C/C++(端口扫描技术)
随着互联网使用的不断增加,网络攻击也在增加。互联网本质上已经成为现代。因此,了解互联网和使用互联网是非常重要的。网络技术的安全性在当今时代是非常重要和必要的。
在本文中,我们将讨论一个非常重要的主题,即可能破坏计算机设备端口扫描安全的计算机设备的安全性。端口扫描是极其危险的,如果个人/组织及时了解并意识到这种网络攻击,则可以防止端口扫描的发生。
Linux下的开放端口?
侦听端口是应用程序侦听的网络端口。通过使用ss、netstat或lsof等命令查询网络堆栈,可以获得系统上侦听端口的列表。可以使用防火墙打开或关闭(过滤)每个侦听端口。
一般来说,开放端口是接受来自远程位置的传入数据包的网络端口。
例如,如果您运行的web服务器在端口80和443上侦听,并且这些端口在防火墙上是打开的,则任何人(被阻止的ip除外)都可以使用浏览器访问web服务器上托管的网站。在这种情况下,80和443都是开放端口。
开放端口可能会带来安全风险,因为每个开放端口都可能被攻击者用来利用漏洞或执行任何其他类型的攻击。您应该只公开应用程序功能所需的端口,并关闭所有其他端口。
端口扫描基础知识
端口扫描程序发送TCP或UDP网络数据包,并询问端口的当前状态。以下是三种类型的回复:
1.打开,接受:电脑会做出回应,询问是否有什么可以为你做的。
2.关闭,未侦听:计算机响应“此端口当前正在使用,此时不可用。
3.已筛选、已丢弃、已阻止:计算机甚至都懒得响应。
端口扫描通常发生在网络杀伤链的早期,即侦察和入侵期间。攻击者使用端口扫描来检测具有打开和未使用端口的目标,这些端口可以重新用于渗透、命令和控制以及数据泄露,或者发现该计算机上运行的应用程序利用该应用程序中的漏洞。
nmap是目前最流行的开源端口扫描工具之一。Nmap为不同的场景提供了许多不同的端口扫描技术。
使用nmap检查打开的端口
Nmap是一个强大的网络扫描工具,可以扫描单个主机和大型网络。它主要用于安全审计和渗透测试。
如果可用,nmap应该是端口扫描的第一个工具。除了端口扫描,nmap还可以检测Mac地址、操作系统类型、内核版本等。
从控制台发出的以下命令确定哪些端口正在侦听来自网络的TCP连接:
-sT告诉nmap扫描TCP端口,并告诉-p扫描所有65535端口。如果不使用-p-,nmap将只扫描1000个最受欢迎的端口。
要扫描UDP端口,请使用-sU而不是-sT:
nmap -sU -p- 192.168.227.128
有关更多信息,请访问nmap手册页,并阅读该工具的所有其他强大选项。
端口扫描类型有哪些
当我们经过了主机扫描得到了存活主机,有了攻击目标后,我们就需要扫描目标主机的开放端口了。端口扫描技术主要分为三类:开放扫描、隐蔽扫描、半开放扫描。
- 开放扫描
TCP Connect 扫描 :
实现原理:通过调用socket函数connect()连接到目标计算机 上,完成一次完整的三次握手过程。如果端口处于侦听状态, 那么connect()就能成功返回。否则,这个端口不可用,即没有提供服务。
优点:稳定可靠,不需要特殊的权限
缺点:扫描方式不隐蔽,服务器日志会记录下大量密集的连接和错误记录 ,并容易被防火墙发现和屏蔽
- 隐蔽扫描
TCP FIN 扫描:
实现原理: 扫描器向目标主机端口发送FIN包。当一个FIN数据包到达一个关闭的端
口,数据包会被丢掉,并且返回一个RST数据包。否则,若是打开的端 口,数据包只是简单的丢掉(不返回RST)。
优点:由于这种技术不包含标准的TCP三次握手协议的任何部分,所以无法被记录下来,从而比SYN扫描隐蔽得多,FIN数据包能够通过只监测SYN
包的包过滤器。
缺点:需要自己构造数据包,要求权限高; 通常适用于UNIX目标主机,但在Windows95/NT环境下,该方法无效。 因为不论目标端口是否打开,操作系统都返回RST包。
TCP Null 扫描 :
实现原理: TCP Xmas和Null扫描是FIN扫描的两个变种。Xmas扫描打开FIN,
URG和PUSH标记,而Null扫描关闭所有标记。 这些组合的目的是为了通过对FIN标记数据包的过滤。
当此类数据包到达一个关闭的端口,数据包会被丢掉,并且返回一个 RST数据包。否则,若是打开的端口,数据包只是简单的丢掉(不返回 RST)。
优点: 隐蔽性好;
缺点: 需要自己构造数据包,要求有超级用户或者授权用户权限; 通常适用于UNIX目标主机,而Windows系统不支持。
- 半开放扫描
隐蔽性和可靠性介于前两者之间。
TCP SYN 扫描:
实现原理:扫描器向目标主机端口发送SYN包。如果应答是RST包,那么说明端口是关闭的;如果应答中包含SYN和ACK包,说明目标端口处于监听状态,
再传送一个RST包给目标机从而停止建立连接。由于在SYN扫描时,全连接尚未建立,所以这种技术通常被称为半连接扫描。
优点:隐蔽性较全连接扫描好,一般系统对这种半扫描很少记录。
缺点:通常构造SYN数据包需要超级用户或者授权用户访问专门的系统调用。
UDP端口扫描:
向目标端口发送UDP 包。如果得到的应答为“ICMP port Unreachable”(ICMP 端口不可到达),那么目标端口是关闭的。反之,如果没有收到这个应答消息,则目标端口极有可能是开放的。
由于UDP 是无连接的不可靠协议,UDP 扫描的准确性在很大程度上取决于网络及系统资源的使用率等多个因素。
TCP间接扫描:
实现原理:利用第三方的IP(欺骗主机)来隐藏真正扫描者的IP。由于扫描主机会对欺骗主机发送回应信息,所以必须监控欺骗主机的IP行为,从而获得原始扫描的结果。扫描主机通过伪造第三方主机IP地址向目标主机发起SYN扫描,
并通过观察其IP序列号的增长规律获取端口的状态 。
优点:隐蔽性好。
缺点:对第三方主机的要求较高。
我们讨论的扫描是最常见的,但这并不是一个详尽的列表。
shell脚本实现端口扫描
扫描linux机器上的tcp和udp端口的Bash脚本
#!/bin/bash
...
function scan_port {
host=$1
port=$2
timeout 1 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null && echo "Port $port: Open"
}
function scan_range {
host=$1
start_port=$2
end_port=$3
for ((port=start_port; port<=end_port; port++)); do
scan_port $host $port
done
}
function get_risk_level {
...
}
while getopts ":p:r:h" opt; do
case $opt in
p)
port=$OPTARG
;;
r)
range=(${OPTARG//:/ })
start_port=${range[0]}
end_port=${range[1]}
;;
h)
echo "Usage: $0 [-p PORT] [-r START_PORT:END_PORT] host"
exit 1
;;
?)
echo "Invalid option: -$OPTARG" >&2
echo "Usage: $0 [-p PORT] [-r START_PORT:END_PORT] host"
exit 1
;;
:)
echo "Option -$OPTARG requires an argument." >&2
echo "Usage: $0 [-p PORT] [-r START_PORT:END_PORT] host"
exit 1
;;
esac
done
shift $((OPTIND -1))
host=$1
if [ -z "$host" ]; then
echo "Error: Host argument missing."
echo "Usage: $0 [-p PORT] [-r START_PORT:END_PORT] host"
exit 1
fi
if [ -z "$port" ] && [ -z "$range" ]; then
echo "Error: Either -p or -r must be specified."
echo "Usage: $0 [-p PORT] [-r START_PORT:END_PORT] host"
exit 1
fi
if [ -n "$port" ]; then
...
fi
if [ -n "$range" ]; then
scan_range $host $start_port $end_port
for ((port=start_port; port<=end_port; port++)); do
timeout 1 bash -c "echo >/dev/tcp/$host/$port" 2>/dev/null && echo "Port $port: Open" && risk_level=$(get_risk_level $port) && echo "Risk level: $risk_level"
done
fi
运行结果:
Linux下C/C++实现(端口扫描技术)
该项目是端口扫描仪的基本实现,它可以帮助网络管理员确保网络中的机器正常运行。
基本上,这个端口扫描仪可以扫描用户给定的ip地址的所有端口。通过向远程主机的端口发送适当的数据包,它可以解析从该主机返回的指示该端口状态的数据包。执行过程中还需要Ip地址。端口扫描仪可以读取的ip格式是用户输入(xxx.xxx.xxx.xxx)、ip文件(类似于此)和ip前缀(xxx.xxx.xxx.xxx/20)。
void parse_args(ps_args_t *ps_args, int argc, char *argv[]);
struct port_queue *init_queue();
int is_empty(struct port_queue *pqueue);
void free_queue(struct port_queue *pqueue);
void clear_queue(struct port_queue *pqueue);
void enqueue(struct port_queue *pqueue, char *ip_addr, int port);
void dequeue(struct port_queue *pqueue, char *ip_addr, int *port);
void connection(int socket, ps_args_t *ps_args);
void get_local_ip(char *source_ip);
u_int16_t cal_checksum(u_int16_t *ptr, int byte_num);
void build_ip_header(struct iphdr *ip_header, char *datagram, u_int8_t protocol, struct sockaddr_in dest_addr);
void build_tcp_header(struct tcphdr *tcp_header, int port, int scan_type);
void build_udp_header(struct udphdr *udp_header, int port);
void build_dns_header(struct DNS_HEADER *dns_header);
results tcp_scan(char *ip_address, int port, int scan_type, int thread);
results udp_scan(char *ip_address, int port, int thread);
void get_service_response(char *message, char *recv_buf, struct sockaddr_in dest_addr);
void check_services(int port, char *result, struct sockaddr_in dest_addr);
void check_http(char *recv_buf, char *result, struct sockaddr_in dest_addr);
void check_ssh(char *recv_buf, char *result, struct sockaddr_in dest_addr);
void check_smtp(char *recv_buf, char *result, struct sockaddr_in dest_addr);
void check_pop(char *recv_buf, char *result, struct sockaddr_in dest_addr);
void check_whois(char *recv_buf, char *result, struct sockaddr_in dest_addr);
void check_imap(char *recv_buf, char *result, struct sockaddr_in dest_addr);
...
int main(int argc, char *argv[])
{
...
memcpy(&scan_name[0], "SYN", 3);
memcpy(&scan_name[1], "NULL", 4);
memcpy(&scan_name[2], "FIN", 3);
memcpy(&scan_name[3], "XMAS", 4);
memcpy(&scan_name[4], "ACK", 3);
memcpy(&scan_name[5], "UDP", 3);
parse_args(&ps_args, argc, argv);
for (i = 0; i < PORT_NUM; i++)
{
if (ps_args.ports[i] == 1)
{
num_ports++;
}
}
for (i = 0; i < 6; i++)
{
if (ps_args.scan_types[i] == 1)
{
num_scans++;
}
}
int res_size = ps_args.ip_num * num_ports * num_scans;
result = (results *)malloc(res_size * sizeof(results));
int res_index = 0;
get_local_ip(source_ip);
pqueue = init_queue();
// init task queue
for (i = 0; i < ps_args.ip_num; i++)
{
for (port = 0; port < PORT_NUM; port++)
{
if (ps_args.ports[port] == 1)
{
enqueue(pqueue, ps_args.ip_addr[i], port);
}
}
}
pthread_mutex_init(&scan_mutex, NULL);
pthread_mutex_init(&result_mutex, NULL);
...
for (id = 0; id < ps_args.threads; id++)
{
thread_id[id] = id;
pthread_create(&thread[id], NULL, thread_func, (void *)&thread_id[id]);
}
for (i = 0; i < ps_args.threads; i++)
{
thread_res = pthread_join(thread[i], &retval);
if (thread_res)
{
// printf("pthread_join() failed. Error num: %d. Error: %s.
", errno, strerror(errno));
exit(thread_res);
}
}
...
if (end.tv_usec < start.tv_usec)
{
usec = end.tv_usec - start.tv_usec + 1000000;
end.tv_sec--;
}
else
{
usec = end.tv_usec - start.tv_usec;
}
sec = end.tv_sec - start.tv_sec;
printf("Scan took %d.%d seconds.
", sec, usec);
for (i = 0; i < ps_args.ip_num; i++)
{
printf("IP address: %s
", ps_args.ip_addr[i]);
printf("Port Service Name (if applicable) Scan Type Results
");
printf("--------------------------------------------------------------------------------------------------
");
print_res(ps_args.ip_addr[i], res_size);
}
...
return 0;
}
端口扫描仪可以对一个端口进行多次扫描,支持扫描类型:
TCP SYN
TCP FIN
TCP NULL
TCP XMAS
TCP ACK
UDP
运行结果:
If you need the complete source code, please add the WeChat number (c17865354792)
总结
端口扫描技术向目标系统的TCP/UDP端口发送探测数据包,记录目标系统的响应,通过分析响应来查看该系统处于监听或运行状态的服务。
最后,端口扫描是网络犯罪分子用来识别计算机开放端口的一种方法。计算机利用许多端口来实现其功能和操作。其中包括打开和关闭端口。计算机网络中的开放端口被网络攻击者利用,通过这种机制进入系统进行端口扫描网络犯罪。
Welcome to follow WeChat official account【程序猿编码】
参考:
https://nmap.org/man/zh/
https://www.osgeo.cn/scapy/