安全研究
安全漏洞
Firebird op_connect_request请求远程拒绝服务漏洞
发布日期:2009-07-28
更新日期:2009-07-29
受影响系统:
Firebird Firebird SQL v2.5.0 Beta 1描述:
Firebird Firebird SQL v2.1.3 RC1
Firebird Firebird SQL v2.1.2
Firebird Firebird SQL v2.1.1
Firebird Firebird SQL v2.0.5
Firebird Firebird SQL v2.0.1
Firebird Firebird SQL v1.5.5
BUGTRAQ ID: 35842
CVE(CAN) ID: CVE-2009-2620
Firebird是一款提供多个ANSI SQL-92功能的关系型数据库,可运行在Linux、Windows和各种Unix平台下。
在Firebird的src/remote/server.cpp文件中,process_packet2()函数负责处理从客户端发送过来的报文。这个函数有一个switch语句考虑协议中所定义的所有可能的opcode。
/-----------
src/remote/server.cpp:
...
3404 P_OP op = receive->p_operation;
3405 switch (op)
3406 {
3407 case op_connect:
...
3426 case op_compile:
...
3430 case op_attach:
...
- -----------/
在op_connect_request报文的情况下,执行流进入switch语句的以下case:
/-----------
src/remote/server.cpp:
...
3584 case op_connect_request:
3585 aux_request(port, &receive->p_req, sendL);
3586 break;
- -----------/
在调用aux_request()函数并执行break语句后,执行流到达:
/-----------
src/remote/server.cpp:
...
3652 if (port && port->port_state == state_broken) {
3653 if (!port->port_parent) {
3654 gds__log("SERVER/process_packet: broken port, server exiting");
3655 port->disconnect(sendL, receive);
3656 ThreadData::restoreSpecific();
3657 return false;
3658 }
3659 port->disconnect(sendL, receive);
3660 port = NULL;
3661 }
- -----------/
通过在接收到op_connect_request报文时调试fbserver.exe二进制程序可以看出满足了第一个if语句的条件,但没有满足第二个if的条件,因此执行流到达port->disconnect()调用:
/-----------
005ACE2C |> 837E 0C 03 CMP DWORD PTR DS:[ESI+C],3
;port->port_state == state_broken ?
005ACE30 |. 75 1B JNZ SHORT fbserver.005ACE4D
005ACE32 |. 837E 1C 00 CMP DWORD PTR DS:[ESI+1C],0
;port->port_parent == 0?
005ACE36 |. 75 0A JNZ SHORT fbserver.005ACE42
;this conditional jump is taken
005ACE38 |. 68 D4D65F00 PUSH fbserver.005FD6D4
; ASCII "SERVER/process_packet: broken port, server exiting"
005ACE3D |.^ E9 44FDFFFF JMP fbserver.005ACB86
005ACE42 |> 53 PUSH EBX
; /Arg2
005ACE43 |. 57 PUSH EDI
; |Arg1
005ACE44 |. 8BCE MOV ECX,ESI
; |
005ACE46 |. E8 65D7FFFF CALL <fbserver.rem_port::disconnect>
; \port->disconnect(sendL, receive)
- -----------/
根据src/remote/remote.h中的定义,port的类型为struct rem_port。这种结构类型在src/remote/server.cpp中实现了disconnect()函数:
/-----------
src/remote/server.cpp:
1464 void rem_port::disconnect(PACKET* sendL, PACKET* receiveL)
- -----------/
在这个函数中执行以下代码以释放发送和接收的报文并关闭相关的套接字:
/-----------
src/remote/server.cpp:
...
1492 REMOTE_free_packet(this, sendL);
1493 REMOTE_free_packet(this, receiveL);
1494 this->disconnect();
- -----------/
对this->disconnect()的调用最终会导致src/remote/inet.cpp中的disconnect()函数,该函数用于中断远程连接并接收rem_port结构参数。
/-----------
src/remote/inet.cpp:
1731 static void disconnect( rem_port* port)
1732 {
- -----------/
首先函数通过调用shutdown函数关闭客户端所创建的连接:
/-----------
src/remote/inet.cpp:
...
1763 if (port->port_handle && (SOCKET) port->port_handle !=
INVALID_SOCKET) {
1764 shutdown((int) port->port_handle, 2);
1765 }
- -----------/
之后如果当前正在断开的rem_port结构是其他rem_port结构的子代,就会递归的调用disconnect()断开存储在port->port_async的rem_port。port_async是rem_port结构的成员,描述异步同级端口。
/-----------
src/remote/inet.cpp:
/* If this is a sub-port, unlink it from it's parent */
...
1789 rem_port* parent = port->port_parent;
1790 if (parent != NULL) {
1791 if (port->port_async) {
1792 disconnect(port->port_async);
1793 port->port_async = NULL;
1794 }
- -----------/
在执行对disconnect()的递归调用时,作为将要断开参数传送的port->port_async对应到主服务器套接字,也就是在3050/TCP端口上监听入站连接的套接字。一旦在递归调用中调用了shutdown()和closesocket()函数,服务器就会停止监听默认的3050/TCP端口,拒绝对合法用户的服务。
<*来源:Francisco Falcon
链接:http://marc.info/?l=bugtraq&m=124881637520977&w=2
http://secunia.com/advisories/36026/
*>
测试方法:
警 告
以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!
建议:
厂商补丁:
Firebird
--------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:
http://tracker.firebirdsql.org/browse/CORE-2563
浏览次数:2722
严重程度:0(网友投票)
绿盟科技给您安全的保障
