在windows的域环境中有非常多的协议和服务是基于DCE/RPC协议进行实现的,例如NETLOGON,LSA,SAMR,DSSETUP等。因此在 windows的环境下会大量的遇到DCE/RPC协议,因此有必要对该协议有一个初步的了解,这样的话在遇到对应的数据包,则能够比较清楚的还原数据包中发生了什么。本文将通过数据包对DCE/RPC协议进行详细的分析, 作为专栏《计算机网络协议快速入门教程》中的一篇。
什么是RPC和DCE/RPC
RPC的全称是Remote Procedure Call,即远程过程调用,最早提出来用来保证两台电脑之间的功能调用。写过程序的都了解,本地的程序可以调用本地的类库(.so,.lib,.dll等文件),通过调用对应的API并传递对应的参数即可完成某一项功能。如果需要调用的功能不在本地,而是在另外一台机器上,则需要一套机制来保证远程的功能调用以及完成参数的传递,完成和本地调用同样的效果,RPC的作用就在于此。RPC本身不应该理解为一个具体的协议,和SMB一样,是一类协议统称,用来实现进程间远程调用。在RPC的发展过程中,形成了如图1一些不同的协议分支和框架:
图1
应用最广泛的是DCE/RPC,对应的设计文档见这里,微软的MSRPC也是在扩展了DCE/RPC的功能,对应的设计文档见这里,SUN公司的实现较早被称之为ONC RPC或者RPC,对应的RFC见这里。
这些协议虽然是源于RPC,可以认为RPC的不同分支,但是实现上由于应用场景的不同,在演进过程中差异在慢慢的变大,最终形成了不同的协议,如下图2是wireshark针对不同的RPC协议提供了解析支持。
图2
可以看到DCE/RPC 是RPC的一个分支,但是由于微软的有的协议需要基于DCE/RPC实现,有的协议增强了DCE/RPC 的功能,因此DCE/RPC成了windows系统中非常常见的协议。
DCE/RPC概览
DCE/RPC即可以基于面向连接的协议也可以基于面向非连接的协议,其和对应承载协议的关系如下如图3:
图3
针对面向连接和非连接两种方式DCE/RPC的头部等定义稍微不同,本文以面向连接的RPC为例进行讲解,主要是基于TCP/SMB/NBT协议的DCE/RPC实现最为常见。
DCE/RPC总体上采用请求响应式的交互方式,主要的请求响应过程如下图4:
图4
其中bind/bind_ack,alert_context/alert_context_resp,request/response是不同的请求和响应类型,后续也主要是基于这三种请求响应类型进行说明。DCE/RPC中和具体功能相关的数据主要是由type类型为request/response来发起的,如下图5:
图5
图5中可以看到每个request和response中对应着不同的操作,可以理解为对应不同的函数,即opnum指示的值。
DCE/RPC过程详解
本例中使用的数据包为,下载链接这里,通常DCE/RPC的数据包含如下三个部分:
- 头部信息是所有RPC请求和响应都具备的,主要是包含一些协议控制信息,即完成远程过程调用传输过程中一些必要的约定,如下图6。
- 内容数据即请求/响应体,根据请求/响应类型的不同,这部分数据存在差异,内容数据主要包含的是一些操作的输入输出参数信息,如下图9。
- 认证数据,主要是调用认证协议相关的数据信息,如图11。关于认证,也是采用kerberos以及NTLM,其调用方式和SMB等是一致的,见这里和这里。
bind/bind_ack
bind请求主要是建立和远程服务的连接,如下图6:
图6
针对图6中各个字段的解释如下:
version:因为协议在不断地演进,所以通常协议都会有这个字段信息。针对面向连接的RPC来说,版本为5.1或者5.0,本例中的版本为5.0。面向非连接的RPC,只有主版本字段,为4。
packet type:wireshark解析的是数据包,因此这里面描述写成packet type。在DEC/RPC文档中,其解释为PDU type。不过在wireshark中packet type似乎更为的精准,表述的是请求数据包的类型。DCE/RPC有多种不同类型的请求和响应,如下图7:
图7
上图中的CO表示Connection-oriented,CL表示Connectionless。其中面向连接的类型为bind/bind_ack,request/response,alert_context/alert_context_resp。
Flags:一些标志位字段约定。
Data Representation:针对发送数据的格式说明,点开之后,可以发现该字段规定了发送数据的字节序以及字符集等信息。
Frag length:表示整个RPC数据包的长度,包括RPC头部,内容数据以及认证数据长度的总和。
Auth length:表示身份认证数据的长度,没有认证数据的情况下为0。如果有认证数据,这部分会有对应的长度值。
Call ID:该字段有客户端生成维护,用来标记一对请求和响应,即同一对请求和响应的call id相同。如果没有该字段,在RPC层无法确定请求对应的响应数据是哪一个,例如在一些请求或者响应超时的情况下。
Max Xmit Frag: 是max transimit frag的缩写,表示能够传输RPC最长字节数。
Max Recv Frag: 是max receive frag的缩写,表示能够接受RPC最长的字节数。
Assoc Group: 是association group缩写,如果客户端该字段为0,则服务端会分配服务端的唯一标识到该字段。
从DCE/RPC的头部可以看到是传输相关的一些约定,内容数据即请求服务位于Ctx Item的内容数据部分,由Abstract Syntax和Transfer Syntax两个部分组成,解释如下:
- Abstract Syntax部分由interface UUID 和 interface version两部分组成,表示请求的服务是什么。由上图表示的是请求调用EPMV4服务。 Transfer
- Syntax表示的是传输相关参数,该部分由interface UUID 和 interface version两部分组成,表示的是传输相关(字节序,字符集等)的约定,上图使用的是NDR格式的数据表达式。
bind_ack用于响应服务绑定结果,如下图8:
图8
- bind_ack的响应中不同于请求中的字段解释如下: packet type的值为bind_ack表示服务端对于请求服务的确认。
- Scndry Addr:表示的是第二个端口地址,在服务端支持并发RPC的时候,服务端会返回该字段,然后客户端会使用该端口发起后续的RPC链接。
- ack result表示的是 请求的结果,上图结果为请求服务绑定成功。
request/response
由上述的bind可以看到,服务层面的链接已经建立(服务器通过bind_ack表明该服务处于服务状态),接下来就需要调用该服务,即向对应的服务对应的函数传递对应的参数,如下图9:
图9
request中和上述DEC/RPC bind中重合的部分不在赘述,不同的部分解释如下:
- Alloc hint:该字段是一个可选项,可由字面意思得知是内存分配的提示,由客户端生成告诉服务端后续请求的大小,让服务器准备好内存空间。
- Context ID:请求内容的ID,由于是远程的请求,因此相关数据实体需要由一个标识符,该示例中表示的是请求内容数据的标识符,即stub data部分。
- Opnum:是operation num的缩写,表示的是对应接口的第几个功能。本示例中,由上述bind可知,请求的服务接口为EPMV4,opnum为3表示EPMV4服务中的num为3的功能。
- Stub data:前面说阐述的字段都是DCE/RPC协议所定义的部分,采用的都是NDR的数据表示法进行编码的。RPC携带的具体请求功能的数据部分,被称之为stub data。stub data有可能是DCE/RPC协议所定义的内容,例如本例中stub data就是EMP的内容数据(EPM协议不是本文讨论的重点,不过多阐述),也有可能不是DCE/RPC协议定义的,因为其他的协议也可以使用DCE/RPC进行远程的服务调用,如下图10就是微软的DSSETUP服务借助RPC完成远程域服务相关查询:
图10
图9 request中对应的response服务如下图10:
图10
cancel count:顾名思义就是指拒绝请求的次数。由于有call ID以及context ID 的指示,虽然响应的数据中没有传输opnum字段,wireshark也是能够解析出对应的Opnum为3(即中括号中的部分)。由于RPC只是到构建远程服务链接这个层次,而request和response的stub data已经具体到对应的服务对应的函数,可以看到在DCE/RPC之上还存在着多种协议,后续的文章会挑选常见的windows和DCE/RPC内置的函数进行介绍。
alter_context/alter_context_resp
alert_context的请求和响应的格式和bind基本是一致的,除了packet type 字段的值为14外。在同一条流中,第一次的服务接口请求使用bind,如果还需要请求额外的服务接口或者不同的接口版本或者新的和安全相关内容时候,客户端会发起alert_context请求,如下图11所示:
图11
上图中第一次使用bind请求和bind_ack响应,第二次由于携带安全认证数据的不同,因此使用了alert_context以及alert_context_resp。但是对于我们还原数据包的意图,其功能和bind的功能类似,不再赘述。
其他类型
上述几种请求响应基本是基于TCP的DCE/RPC的主要功能,除此之外DCE/RPC针对一些错误等情况也提供了对应的类型,由前图可知包括:
- RPC fault:服务器通知客户端服务端RPC相关组件出现异常
- RPC orphaned:客户端通知服务器,丢弃某一次请求。
- RPC shutdown:服务端通知客户端终止该次的RPC连接。
- RPC cancel:该类型用于转发一次取消。
至此DCE/RPC身份认证的过程就完成了,可以看到最主要的是要区分出几种不同的DCE/RPC 服务请求类型,以及区分不同服务对应的函数目的,这块需要涉及到对应的服务接口,后在后续的文章进行讲述。希望整个数据包交互过程对于你理解DCE/RPC远程过程调用协议有所帮助。
本文为****村中少年原创文章,未经允许不得转载,博主链接这里。