我正在研究拦截到达SQL Server 2008进程的查询。

SQLOS体系结构分为以下系统DLL:




sqlmin.dll:存储,复制,安全功能等。

sqllang.dll:TransactSQL查询执行引擎,表达式求值等。
sqldk.dll:任务调度和分派,工作线程创建,消息循环等。

SQLSERVR服务进程通过sqlboot.dll和sqldk.dll实例化SQLOS组件,并且工作线程通过服务器中选定的连接方法接收查询( TCP / IP,本地共享内存或命名管道)。

我调试了sqlservr.exe进程地址空间,以搜索文本查询。看来查询字符串是可读的,但我找不到在查询进入SQLOS调度程序时可以被截取的地方。

目前不能选择监听管道或TCP / IP。我想在更高的层次上进行注入,最好在SQLOS组件层次上进行注入。

关于从哪里开始研究的任何想法?

评论

为什么要在最后一个段落的后面排除明显的首选?

我使用的是0c00l,但我的问题是为什么不使用带有一些薄垫片程序(例如odbc连接器)的输入查询并进行运行跟踪。与套接字连接并进行运行跟踪(以recv或其他名称开头)。然后检查两条迹线之间的联合以了解它们何时开始相交,以查看这是否可行?

@ 0xC0000022L Hernan显然知道其他选择。他想具体知道在更高层次上拦截函数的位置(即使用钩子)。知道它会很有趣,因为我搜索并且找不到关于它的资源,而同时存在很多有关钩住其他东西的资源。我刚刚找到Microsoft的一项建议,不要使用SQL Server:“ SQL Server不支持使用第三方绕行或类似技术” support.microsoft.com/kb/920925

@ 0xC0000022L,对不起,如果我不礼貌。我认为,知道如何挂接SQL Server会很有趣,因为Hernan说:“我想在更高的级别(最好是在SQLOS组件级别)进行注入。”

就像@sw所说,我知道其他替代方法,例如ODBC级拦截。简而言之,我不想在多个点打补丁(例如:共享内存,管道和TCP / IP I / O),而是在单个点安排所有查询的计划和执行,而与客户端无关,服务器接口或通信方法。

#1 楼

这似乎是一个周日下午的有趣项目,所以我去尝试了。直截了当,这是SQL Server中一个函数的调用堆栈,该函数解析然后执行查询(地址和从Windows 32 SP1 32位运行的SQL Server 2008 R2中获取的偏移量):

0x7814500a msvcr80.i386!memcpy+0x5a
0x013aa370 sqlservr!CWCharStream::CwchGetWChars+0x5c
0x013a9db5 sqlservr!CSQLStrings::CbGetChars+0x35
0x012ffa50 sqlservr!CParser::FillBuffer+0x3d
0x0138bbfd sqlservr!CParser::CParser+0x3c8
0x01352e96 sqlservr!sqlpars+0x7b
0x013530f2 sqlservr!CSQLSource::FParse+0x16d
0x013531ed sqlservr!CSQLSource::FParse+0x268
0x012ff9e8 sqlservr!`string'+0x3c
0x015894b8 sqlservr!CSQLSource::Execute+0x2c8
0x0158ad31 sqlservr!process_request+0x2ac
0x0158a328 sqlservr!process_commands+0x15f
0x015cf8b4 sqlservr!SOS_Task::Param::Execute+0xdd
0x015cf9ea sqlservr!SOS_Scheduler::RunTask+0xb4
0x015cf575 sqlservr!SOS_Scheduler::IsShrinkWorkersNecessary+0x48
0x77f06854 ntdll!ZwSignalAndWaitForSingleObject+0xc
0x77e479e2 kernel32!SignalObjectAndWait+0x82


基于此,您可能想仔细看一下CSQLSource类,尤其是其Execute方法。

有了这些信息,我也能够从Microsoft的某人那里找到有关如何从SQL Server的内存转储中提取查询字符串的几篇博客文章。该帖子似乎确认我们走在正确的道路上,并为您提供了插入位置和提取查询字符串的方式。

方法论

我觉得使用某种形式的动态二进制工具(DBI)最容易解决这个问题;由于我们怀疑查询字符串将在SQL Server进程中的某处进行处理,因此我们可以查看该进程进行的内存读取和写入操作,以寻找可读写查询字符串的点。然后,我们可以在那时转储调用栈,查看出现了哪些有趣的地址,并将它们映射回符号(因为Rolf指出,SQL Server具有可用的调试符号)。基本上就这么简单!

当然,诀窍在于可以使您轻松地对过程进行检测。我使用了一个基于QEMU的(希望很快发布的)全系统动态分析框架来解决了这个问题;这让我避免了使SQL Server在例如PIN下运行所带来的不愉快之处。因为该框架包含记录和重放支持,所以我也不必担心使用我的工具来减慢服务器进程的速度。一旦有了调用堆栈,就可以使用PDBParse来获取函数名称。

评论


只是为了澄清一下:您的方法仅在服务器在QEMU中运行时才有效吗?还有一个问题:您可以实际修改查询吗?

–天使
13年4月15日在10:15

我使用的特定方法仅在服务器在QEMU中运行时才有效,是的。但是您可以通过检测内存的读/写操作来使用PIN等相同的功能。我不确定您现在是否可以修改查询;我至少看到了另一个地方,它使用查询字符串来构造MD5哈希(CSQLStrings :: GenerateDurableSqlHandle + 0x40),因此您必须在此之前对其进行修改。

–布伦丹·多兰·加维特(Brendan Dolan-Gavitt)
13年4月15日在21:55

复杂而有趣的方法,技术上正确。感谢您的时间和帮助!

–埃尔南(Hernán)
13年4月17日在1:05

有关调试符号的说明:SQL Server 2012 RTM(11.0.2100.60)具有公共调试符号。目前,我无法获得11.0.3128.0的PDB,而且我不知道它们是否可用于SP1(11.0.3000)。因此,在使用SQL 2012系统DLL时请记住这一点。有关构建信息,请参见sqlserverbuilds.blogspot.com.ar

–埃尔南(Hernán)
13年4月17日在20:20



在Brendan回答之后,可以在github.com/nektra/SQLSvrIntercept上找到Hernan的工作示例。

– sw
13年6月27日在12:58

#2 楼

仅嗅探流量...很容易

如果您只想嗅探流量,则可以使用WireShark随附的TDS协议嗅探器。

让懒惰引导您-懒惰是反向程序的朋友




目前无法选择监听管道或TCP / IP;我想在更高层次上进行注入,最好在SQLOS组件层次上进行注入。随时可用,您所需要做的就是将拼图碎片放在一起。这似乎是最简单,最快的-简而言之:最懒惰的方法。此外,TCP / IP是更高的级别,因为如果可以劫持SQL Server的IP /名称并在两者之间放置“代理”,则可以在TCP / IP到达实际SQL Server计算机之前对其进行拦截。您想要多高的水准?您所坚持的实际上是深入到MS SQL Server的底层。

MS SQL Server使用已记录的协议,并且使用LSP,您应该/将能够嗅探,拦截甚至操纵流量。据我所知,LSP在应用程序的进程空间中运行,它们正在对其进行过滤。实际上,您可以将它们视为临时的应用程序级防火墙。

或者,无论如何,也许也是更好的选择,您可以根据现有的和免费的FreeTDS(根据LGPL许可)编写代理。 tdspool程序将是开始这一努力的好点。是的,这应该适合实际拦截,而不仅仅是嗅探转发流量。您可以使用库(FreeTDS)对查询进行解码和重新编码。显然,该库也将在您的LSP中使用。

尽管我安装了MS SQL Server 2008,并在IDA Pro中进行了简要介绍,但我还是会节省时间来详细了解反汇编。 Brendan的答案提供了很好的概述,即使我不同意这种简单易用的方法,但我对此表示反对。但是后来,你(赫尔南族)要了。

#3 楼

总的来说,我要说的是这样的问题是特定于应用程序的。因此,尽管事实上用户百老汇的答案被否决了,但是如果我不知道针对该问题的任何不错的特殊解决方案,那将是我给出的完全相同的建议。您要做的就是观察数据进入流程,然后在整个程序中复制和操作数据时对其进行跟踪。由于调试符号可用于SQL Server,因此该任务比一般情况要容易。您是否尝试过这些方法?例如,在SQL Server上下文中在网络接收类型函数上设置断点,在通过网络传入的数据上设置硬件RW断点,然后观察数据如何在大量代码中移动?

评论


是的,如果某人已经对此案例有了一些特定于应用程序的知识,那么也许他们会透露出来,尽管缺少这一点,这是显而易见的调查途径。但是,SQL Server可能具有执行SQL语句的相当复杂的系统,因此反向操作可能很耗时。或者,也许很简单。人们想象一种接受SQL语句作为输入;)的函数。

–达斯塔
13年4月14日在17:31

#4 楼

我对该目标没有任何特定的了解,但是我可能会采取的方法是通过管道,tcp和共享内存发送相同的消息,并使用pin跟踪它们,以查找基本块的命中点痕迹应为您提供一些起点,以微调一个好的注入点。

评论


也许只有我一个人,但我无法追踪您的解决方案。也许您可以通过链接,更多信息,描述和细节来充实自己?

– Lizz
13年4月12日在0:49

我认为他只是说要执行SQL命令,记下似乎正在执行的代码,深入研究该代码,并将其追溯到SQL命令执行链中的第一个函数。当然,谁知道它是否“那么简单”,它可能具有相当复杂的执行系统。无论如何,不​​是我的回答,只是澄清我想我读到的内容。

–达斯塔
13年4月14日在17:30

不完全是。我是说使用每种输入类型来输入相同的查询并检查通过程序的路径。 Pin是执行此类操作的一种非常易用的工具(尽管当然不是唯一的工具)。

–百老汇
2013年4月14日19:21在