⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 157.htm

📁 unix高级编程原吗
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>CTerm非常精华下载</title>
</head>
<body bgcolor="#FFFFFF">
<table border="0" width="100%" cellspacing="0" cellpadding="0" height="577">
<tr><td width="32%" rowspan="3" height="123"><img src="DDl_back.jpg" width="300" height="129" alt="DDl_back.jpg"></td><td width="30%" background="DDl_back2.jpg" height="35"><p align="center"><a href="http://apue.dhs.org"><font face="黑体"><big><big>123</big></big></font></a></td></tr>
<tr>
<td width="68%" background="DDl_back2.jpg" height="44"><big><big><font face="黑体"><p align="center">               ● UNIX网络编程                       (BM: clown)                </font></big></big></td></tr>
<tr>
<td width="68%" height="44" bgcolor="#000000"><font face="黑体"><big><big><p   align="center"></big></big><a href="http://cterm.163.net"><img src="banner.gif" width="400" height="60" alt="banner.gif"border="0"></a></font></td>
</tr>
<tr><td width="100%" colspan="2" height="100" align="center" valign="top"><br><p align="center">[<a href="index.htm">回到开始</a>][<a href="8.htm">上一层</a>][<a href="158.htm">下一篇</a>]
<hr><p align="left"><small>发信人: scz (小四), 信区: Security <br>

标  题: raw_socket server设计文档(1) <br>

发信站: 武汉白云黄鹤站 (Mon Jul 17 12:07:59 2000), 站内信件 <br>

  <br>

作者:小四 < mailto: scz@isbase.com > <br>

主页:http://www.isbase.com <br>

日期:2000-07-06 15:34 <br>

  <br>

socket( PF_INET, SOCK_RAW, IPPROTO_RAW ); <br>

socket( PF_INET, SOCK_RAW, IPPROTO_TCP ); <br>

在RedHat 6.1下这两种socket都可以正常建立,内核支持了的。但是对于 <br>

Solaris 2.6,如果以root身份truss跟踪这两个函数,发现第二个socket建立的时候 <br>

内核不支持这种情况下指定IPPROTO_TCP,库函数本身做了处理: <br>

so_socket(2, 4, 6, "", 1)                       Err#98 EPROTOTYPE <br>

stat("/dev/rawip", 0xEFFFFAC4)                  = 0 <br>

so_socket(2, 4, 6, "/dev/rawip", 1)             = 4 <br>

setsockopt(4, 65535, 4105, 0xEFFFFBB4, 4)       = 0 <br>

从执行效果看,这样的处理和Linux下的意义不同了。 <br>

  <br>

如果考虑广泛兼容性,应该扔弃第二种socket,全部以IPPROTO_RAW方式出现。这样 <br>

的话,理论上可以考虑不用TCP/UDP协议,但是涉及client/server模式,显然应该继 <br>

续使用TCP/UDP。从突破防火墙角度看,还是以鬼子的ACK方式为好。UDP通信被很多 <br>

防火墙屏蔽,TCP也好不到哪里去。而且按照目前的设想,等于仅仅使用TCP的头部概 <br>



念,并没有使用TCP协议的超时、重传等机制,更没有有限状态机介入,为什么不使 <br>

用UDP呢?还是应该从防火墙角度考虑这个设计选择,具体问题具体分析吧。现在的 <br>

难点是完全使用IPPROTO_RAW,写没多大问题,读有了麻烦,又需要重翻UNP;此外, <br>

丢包是毫无疑问的,因此必须尽量设计成无状态方式(NFS Server就是一个例子),这 <br>

个也仅仅是说说,技术问题尚未可知。 <br>

  <br>

关于内核传递IP报文到一个raw_socket,有几点需要注意,我们分别探讨之: <br>

1) TCP/UDP报文(IP报文负载为TCP/UDP)"永远"不会传递给raw_socket。Stevens介绍 <br>

   的时候以BSD家族为例。 <br>

   对于Linux显然已经不适用这个结论,socket( PF_INET, SOCK_RAW, IPPROTO_TCP ) <br>

   就可以接收到TCP报文,Linux内核是给了这个机会的,此时正常的TCP协议层也会 <br>

   收到TCP报文(后面我们会写测试代码验证它)。于是造成潜在的安全隐患,在无需 <br>

   数据链路层和网卡混杂模式介入的情况下,利用raw_socket监视发往本机的TCP报 <br>

   文。尽管只有root才可以创建raw_socket,但获得创建raw_socket的机会和获得 <br>

   完整root权限相比要大得多。对于Solaris系统,内核应该是没有支持 <br>

   socket( PF_INET, SOCK_RAW, IPPROTO_TCP )方式,尽管以root身份执行库函数 <br>

   并没有报错(此时库函数自己做了其他处理)。 <br>

   对于Windows 2K,从backend拖回来的程序执行效果以及袁哥分析代码的结论看, <br>

   2K可能支持socket( PF_INET, SOCK_RAW, IPPROTO_TCP )这种方式。抓包分析 <br>

   backdoor的client/server通信,发现除了预料中的ACK,还夹带有RST,只能说明 <br>

   2K内核传递IP报文到raw_socket的同时传递给了正常的TCP协议层,RST是由正常 <br>

   TCP协议层发出的。NT/9x估计没戏。 <br>



   考虑我们要达到的目的,如果内核不给这个机会(传递TCP报文到raw_socket),意 <br>

   味着ACK方式破产。UDP自然也不用想了。虽然Linux可以,但我们希望得到一个更 <br>

   广泛兼容的backdoor。可以从数据链路层考虑这个问题,牵扯的问题更多,没有 <br>

   太大必要。 <br>

  <br>

2) 对于伯克利实现而言,内核一般处理了几种常见ICMP报文(3种,回应请求、时间 <br>

   戳请求、地址掩码请求),其余未处理ICMP报文交给raw_socket。注意内核并没有 <br>

   处理上面三种请求报文的应答报文,想想ping.c的实现,如果内核处理 <br>

   icmp echo reply,即使指定IPPROTO_ICMP,处于应用层的ping也没有机会得到应 <br>

   答报文。这里所说内核处理,都是指处理入IP报文,对于发送IP报文,基本上任 <br>

   由应用程序处理的,所以ping可以发送自己的icmp echo request。 <br>

   Linux/Solaris的实现有差别,提供给应用层更多机会。内核处理了icmp echo <br>

   request,同时会交给socket( PF_INET, SOCK_RAW, IPPROTO_ICMP ),不同于BSD <br>

   实现。内核未处理的icmp报文依旧交给raw_socket。这给我们一个机会,编写自 <br>

   己的icmp daemon,利用被内核传递到raw_socket的icmp报文进行交互式通信。从 <br>

   突破防火墙角度考虑,比较现实,一般管理员会允许icmp echo request进入。管 <br>

   理员要是在防火墙上过滤了icmp echo request,估计我们也没有机会在这种敌人 <br>

   内部安装icmp daemon,走先。 <br>

  <br>

3) 所有的IGMP报文交给raw_socket。 <br>

   同上,可以利用。现在的操作系统好象已经开始在内核里处理igmp,那样的话, <br>

   机会不大。而且防火墙对IGMP报文比较敏感。 <br>



   socket( AF_INET, SOCK_RAW, IPPROTO_IGMP ),Linux上可以接收到IGMP报文, <br>

   Solaris上不行。 <br>

  <br>

4) 如果内核无法理解IP报文头中高层协议类型,传递该报文给raw_socket。 <br>

   内核无法理解的,对于防火墙也是无法理解的,除非不考虑突破防火墙的网络拓 <br>

   扑,否则暂时别想。此外从前面的测试中看到,Linux/Solaris下必须精确指定第 <br>

   三个参数可以接收匹配IP报文,如果要利用内核无法理解之协议类型,必须确保 <br>

   该类型可以指定在第三个参数中。 <br>

  <br>

5) IP分片一定是在内核中重组完成了才会传递给raw_socket。 <br>

   换句话说,raw_socket无法分析IP分片,数据链路层可以。这里隐含着一个意思, <br>

   IP分片重组永远在内核完成,一旦这部分的处理代码出了问题,就是内核的麻烦, <br>

   所以死得快。 <br>

  <br>

6) 如果内核决定传递一个IP报文到raw_socket,则系统中所有进程创建的所有 <br>

   raw_socket都会收到这个IP报文,这是一个潜在的安全问题。 <br>

   我们在测试程序中创建socket( PF_INET, SOCK_RAW, IPPROTO_ICMP ),启动了两 <br>

   个实例,然后从其他主机ping本机,两个实例都收到了icmp echo request。 <br>

  <br>

7) 创建socket( PF_INET, SOCK_RAW, 0 ),并且不调用bind、connect,这样的 <br>

   raw_socket接收所有内核传递上来的IP报文。第三个参数是指定匹配的,如果非 <br>

   零,不匹配的IP报文不会被传递给该raw_socket。对于这种系统,企图监视本机 <br>



   所有入IP报文,不需要数据链路层介入,也不要求网卡混杂模式,简单创建一个 <br>

   raw_socket,指定第三个参数为0即可。 <br>

   遗憾的是,我们在Linux下测试,根本就不支持第三个参数指定为0,指定成 <br>

   255(IPPROTO_RAW)也无法达到Stevens描述的效果,255主要用于发送,Stevens介 <br>

   绍的可能仅仅是BSD实现吧。 <br>

   关于这个,觉得看看Linux关于raw_socket的实现部分比较好,瞎猜也不是办法。 <br>

  <br>

8) 有些代码使用了raw_socket,并未指定IP_HDRINCL选项。1988年为了解决 <br>

   traceroute问题引入了一个patch,创建SOCK_RAW时,指定第三个参数为 <br>

   IPPROTO_RAW(值255),效果和指定IP_HDRINCL选项一样,还更方便些。 <br>

  <br>

-------------------------------------------------------------------------- <br>

/* <br>

 * For Solaris <br>

 * gcc -O3 -o raw raw.c -lsocket -lnsl <br>

 * <br>

 * For Linux <br>

 * gcc -O3 -o raw raw.c <br>

 */ <br>

#include <stdio.h> <br>

#include <stdlib.h> <br>

#include <sys/types.h> <br>



#include <sys/socket.h> <br>

#include <netinet/in.h> <br>

#include <netinet/in_systm.h> <br>

#include <netdb.h> <br>

#include <netinet/ip.h> <br>

#include <netdb.h> <br>

#include <netinet/udp.h> <br>

#include <time.h> <br>

#define SUCCESS         0 <br>

#define FAILURE        -1 <br>

int     recvSocket; <br>

u_char  packet[ 1500 ]; <br>

void Close ( int fd ) <br>

{ <br>

    if ( close( fd ) == -1 ) <br>

    { <br>

        perror( "close" ); <br>

        exit( FAILURE ); <br>

    } <br>

    return; <br>

}  /* end of Close */ <br>

void outputBinary ( const unsigned char * byteArray, const size_t byteArrayL <br>



en ) <br>

{ <br>

    u_long offset; <br>

    int    i, j, k; <br>

    fprintf( stderr, "byteArray [ %lu bytes ] ----> \n", byteArrayLen ); <br>

    if ( byteArrayLen <= 0 ) <br>

    { <br>

        return; <br>

    } <br>

    i      = 0; <br>

    offset = 0; <br>

    for ( k = byteArrayLen / 16; k > 0; k--, offset += 16 ) <br>

    { <br>

        fprintf( stderr, "%08X ", offset ); <br>

        for ( j = 0; j < 16; j++, i++ ) <br>

        { <br>

            if ( j == 8 ) <br>

            { <br>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -