本系列重点分析TNS 314下的客户端与服务端之间的通讯,通过抓包分析,查看在不同客户端,不同服务端情况下传输方式的不同,尝试还原其协议细节,实现对协议中一些关键内容的解析,如登录用户名,协议版本,oracle版本,sql命令,同时给出示例LUA代码。为了分析不同客户端架构,本系列使用了两类客户端32位与64位客户端进行测试,同时重点使用了多个厂商的不同客户端(Navicat、PLSQL、SQLPlus)同时也兼顾分析了OJDBC Thin Client的情况。服务端采用11g和12c两个版本。本文主要分析连接建立,身份验证、命令传输和返回、以及错误信息返回的过程。
错误信息返回流程(以SQL错误为例)
Client
|
|
|
|
Server
|
1
|
-------
|
Data Piggyback(11) Cursor Close All(69)
或 03 5e
|
----->
|
具体语句
|
2
|
<-----
|
Marker(0C)
|
-------
|
返回Marker
|
3
|
<-----
|
Marker(0C)
|
-------
|
返回Marker
|
4
|
-------
|
Marker(0C)
|
----->
|
Request Marker
|
5
|
<-----
|
Data Error(17) 02
|
-------
|
错误信息
|
错误请求涉及的包有Marker包(PacketType 0x0C)和Data Error(DataType 0x06 DataID 0x17 CallID 0x02)包
错误请求发出后,服务端会返回两个Marker(2,3),然后客户端会主动通过一个Marker(4)请求去获取错误信息(5)
Marker包不是data包,他的的dataflag是0C,所以头部是
0x00,0x0b,0x00,0x00,0x0c,0x00,0x00,0x00
从当前看似乎Marker包长度固定为0b
除去头部固定的8个字节后,剩下三个字节是Marker的具体内容
返回的第一个Marker
01 00 01 或者01 00 03
Attention
Marker Type: Data Marker - 1 Data Bytes (0x01)
Marker Data Byte: 0x00
Marker Data Byte: 0x03 或者 0x01
返回的第二个Marker
01 00 02
Attention
Marker Type: Data Marker - 1 Data Bytes (0x01)
Marker Data Byte: 0x00
Marker Data Byte: 0x02
请求Marker
01 00 02
Attention
Marker Type: Data Marker - 1 Data Bytes (0x01)
Marker Data Byte: 0x00
Marker Data Byte: 0x02
错误信息返回
此包根据服务端,客户端不同有很多变化,且不能通用
64bitOCIclient to 12c 错误返回
此包此包为Data包,DataID=17 CALLID=02
包含两个部分,前一个部分固定长度为155字节,表示内部错误信息,后一部分是前序一个长度字节的错误字符串,和语言及编码设定有关
.....
64bitOCIclient to 11g 错误返回
此包此包为Data包,DataID=04 CALLID=05
包含两个部分,前一个部分固定长度为68字节,表示内部错误信息,后一部分与12c版本相同是前序长度的错误字符串,和语言及编码设定有关
注意与12c一样,绿色部分的错误编码要和蓝色字符串中的错误编码相同,才能显示字符串中的信息,否则显示默认信息
TNS312版本错误返回
如果将版本改为312,返回错误又不相同,
此包此包为Data包,DataID=17 CALLID=02
绿色部分的错误编码要和蓝色字符串中的错误编码相同,才能显示字符串中的信息,否则显示默认信息
代码示例
功能:在接收命令处如果满足禁止条件,则返回权限不足,效果如图
首先在接收命令处如果满足禁止条件,则返回两个marker
当代理收到marker时,返回具体错误,需要根据各种条件进行判断
--process req marker, if flag true then return error
if(data:byte(3)==12 and ngx.ctx.responseError) then
print("return error message")
--11g
if(tnsVersion==314 and oracleVersion.major==11) then
reqsock:send(string.char(
0x00, 0x75, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x05,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x04, 0x00,
0x00, 0x00, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x4f, 0x52, 0x41,
0x2d, 0x30, 0x30, 0x39, 0x34, 0x32, 0x3a, 0x20,
0x74, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x72,
0x20, 0x76, 0x69, 0x65, 0x77, 0x20, 0x64, 0x6f,
0x65, 0x73, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x65,
0x78, 0x69, 0x73, 0x74, 0x0a))
end
--12c
if(tnsVersion==314 and oracleVersion.major==12) then
reqsock:send(string.char(
0x00, 0xb4, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x17, 0x02, 0x04, 0x00, 0x04, 0x33,
0x35, 0x38, 0x34, 0x04, 0x01, 0x00, 0x00, 0x00,
0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x07,
0x04, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0xbb, 0x3d, 0x24, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00,