码迷,mamicode.com
首页 > 数据库 > 详细

SQLSERVER Account Weak Password Detection Automatic By System API

时间:2015-07-22 22:17:08      阅读:562      评论:0      收藏:0      [点我收藏+]

标签:

catalog

1. DB暴力破解方式
2. DB弱密码入侵向量
3. SQLAPI++
4. C++ ADO
5. C++ ODBC
6. tiodbc - TinyODBC C++ Wrapper for ODBC API
7. 基于API调用的自动化检测

 

1. DB暴力破解方式

0x1: 利用存储过程

核心思想,就是存储帐号密码的master.dbo.sysxlogins表和密码比较存储过程pwdcompare

alter proc p_GetPassword2 
    @username sysname=null, --用户名,如果不指定,则列出所有用户 
    @pwdlen int=2 --要破解的密码的位数,默认是2位及以下的 
as 
    set nocount on

    if object_id(Ntempdb..#t) is not null
        drop table #t
    if object_id(Ntempdb..#pwd) is not null
        drop table #pwd

    set @pwdlen=case when isnull(@pwdlen,0)<1 then 1 else @pwdlen-1 end

    declare @ss varchar(256)
    --select @ss= 123456789
    select @ss=    abcdefghijklmnopqrstuvwxyz
    select @ss=@ss+ `0123456789-=[]\;,./
    select @ss=@ss+ ~!@#$%^&*()_+{}|:<>?
    --select @ss=@ss+    ABCDEFGHIJKLMNOPQRSTUVWXYZ

    create table #t(c char(1) not null)
    alter table #t add constraint PK_#t primary key CLUSTERED (c) 
    declare @index int
    select @index=1
    while (@index <=len(@ss))
    begin
        insert #t select SUBSTRING(@ss, @index, 1)
        select @index = @index +1
    end

    select name,password 
        ,type=case when xstatus&2048=2048 then 1 else 0 end 
        ,jm=case when password is null then 1 else 0 end 
        ,pwdstr=cast(‘‘ as sysname) 
        ,pwd=cast(‘‘ as varchar(8000)) 
        ,times =cast(‘‘ as varchar(8000))
        into #pwd 
    from master.dbo.sysxlogins a 
    where srvid is null 
        and name=isnull(@username,name) 
    declare @s1 varchar(8000),@s2 varchar(8000),@s3 varchar(8000), @stimes varchar(8000)

    declare @l int, @t bigint

    select @t = count(1)*POWER(len(@ss),1) from #pwd

    select @l=0 
        ,@s1=aa.c 
        ,@s2=cast(ASCII(aa.c) as varchar) 
        ,@s3=,#t aa
        ,@stimes=1th, + cast(@t as varchar(20)) + rows

    exec( 
        update pwd set jm=1,pwdstr=+@s1+ 
        ,pwd=+@s2+ 
        from #pwd pwd+@s3+ 
        where pwd.jm=0 
        and pwdcompare(+@s1+,pwd.password,pwd.type)=1 
        ) 
    while exists(select 1 from #pwd where jm=0 and @l<@pwdlen) 
    begin 
        select @l=@l+1
        select @t = count(1)*POWER(len(@ss),@l+1) from #pwd
        print @t

        select
        @s1=@s1+++char(@l/26+97)+char(@l%26+97)+.c 
        ,@s2=@s2++‘‘,‘‘+cast(ASCII(+char(@l/26+97)+char(@l%26+97)+.c) as varchar) 
        ,@s3=@s3+,#t +char(@l/26+97)+char(@l%26+97)
        ,@stimes=@stimes+;+ cast(@l+1 as varchar(1)) + th, + cast(@t as varchar(20)) + rows

        exec( 
        update pwd set jm=1,pwdstr=+@s1+ 
        ,pwd=+@s2+ 
        ,times=‘‘‘+@stimes+‘‘‘
        from #pwd pwd+@s3+ 
        where pwd.jm=0 
        and pwdcompare(+@s1+,pwd.password,pwd.type)=1 
        ) 
    end 
    select 用户名=name,密码=pwdstr,密码ASCII=pwd, 查询次数和行数=times 
    from #pwd 

    if object_id(Ntempdb..#t) is not null
        drop table #t
    if object_id(Ntempdb..#pwd) is not null
        drop table #pwd

0x2: 利用Nmap发送网络请求密码破解

nmap -p1433 –script ms-sql-brute –script-args userdb=/var/usernames.txt,passdb=/var/passwords.txt 

0x3: 利用hydra进行数据库密码破解

Relevant Link:

http://www.cnblogs.com/drc/archive/2009/03/20/1417820.html
http://www.freebuf.com/articles/database/8856.html

 

2. DB弱密码入侵向量

1. 修改注册表
2. 增加黑客帐号
3. 写入WEBSHELL
4. 下载、启动恶意木马程序
5. 脱库
..

Relevant Link:

http://www.cnblogs.com/LittleHann/p/4322790.html

 

3. SQLAPI++

SQLAPI++ is a C++ library for accessing multiple SQL databases

1. Oracle
2. SQL Server
3. DB2
4. Sybase
5. Informix
6. InterBase
7. SQLBase
8. MySQL
9. PostgreSQL
10. SQLite
11. SQL Anywhere and ODBC)

It uses native APIs of target DBMS so applications developed with SQLAPI++ library run swiftly and efficiently. The product also provides a low-level interface that allows developers to access database-specific features. By encapsulating a vendor‘s API, SQLAPI++ library acts as middleware and delivers database portability

0x1: details on supporting SQL database servers on different platforms

Server Windows Linux/Unix
Oracle Database Server Supported (OCI) Supported (OCI)
Microsoft SQL Server Supported (SQLNCLI/ODBC, OLE DB, DB-Library) SQLNCLI/ODBC for Linux x86-64, otherwise ODBC driver and connection should be used (FreeTDS, Easysoft,...)
Sybase Supported (Open Client, ASE & ASA) Supported (Open Client, ASE & ASA)
DB2 Supported (DB2 CLI) Supported (DB2 CLI)
Informix Supported (Informix CLI) Supported (Informix CLI)
InterBase/Firebird Supported Supported
SQLBase Supported (CAPI) Supported (CAPI)
MySQL, MariaDB Supported (MySQL C API)  Supported (MySQL C API)
PostgreSQL Supported (libpq) Supported (libpq)
ODBC Supported Supported (iODBC, unixODBC)
SQLite Supported Supported
Sybase SQL Anywhere Supported (SQL Anywhere C API) Supported (SQL Anywhere C API)

Currently SQLAPI++ library supports the following C/C++ compilers:

1. Microsoft Visual C++
2. Embarcadero (Borland) C++
3. GNU GCC C++ compiler
4. Solaris Studio C++ compiler

0x2: Why use SQLAPI++

1. SQLAPI++ directly calls native APIs of target DBMSs (unlike ADO which uses OLEDB and/or ODBC intermediate layer). Thats why SQLAPI++ is the fastest way to manage you data.
2. No need (vs ADO) to install and configure OLEDB and/or ODBC drivers when developing and distributing your applications.
3. Low-level interface that allows developers to access database-specific features.

0x3: Code example

编译、使用sqlapi++需要进行以下配置

1. Header files - Compile time
Programmers need to include the SQLAPI++ header files. Those with a command-line compiler will typically use options such as /I%SQLAPIDIR%\include or -I${SQLAPIDIR}/include. The header files are in the include subdirectory of SQLAPI++ distributions:

2. Static or dynamic libraries - Link time
Programmers need to link with static or dynamic libraries.
Those with a command-line compiler will typically use options such as /L%SQLAPIDIR%\lib sqlapi.lib or or -L${SQLAPIDIR}/lib -lsqlapi.
//SQLAPI++的静态库lib并不包含实际的逻辑代码,它仅仅只是一个跳转地址,并导出的符号表,真正的代码逻辑在dll/so动态链接库文件中

3. Dynamic Link Libraries (DLLs) - Run time
Users of programs built with the dynamic SQLAPI++ libraries need these same dynamic libraries to run the programs. The DLLs are in the bin subdirectory of SQLAPI++ distributions:

4. 对于windows server 03及以下机器还需要额外下发MSVCR100.dll文件

技术分享

#include <stdio.h>  // for printf
#include <SQLAPI.h> // main SQLAPI++ header

int main(int argc, char* argv[])
{
    SAConnection con; // create connection object
    
    try
    {
        // connect to database
        // in this example it is Oracle,
        // but can also be Sybase, Informix, DB2
        // SQLServer, InterBase, SQLBase and ODBC
        con.Connect(
            "test",     // database name
            "tester",   // user name
            "tester",   // password
            SA_Oracle_Client);

        printf("We are connected!\n");

        // Disconnect is optional
        // autodisconnect will ocur in destructor if needed
        con.Disconnect();

        printf("We are disconnected!\n");
    }
    catch(SAException &x)
    {
        // SAConnection::Rollback()
        // can also throw an exception
        // (if a network error for example),
        // we will be ready
        try
        {
            // on error rollback changes
            con.Rollback();
        }
        catch(SAException &)
        {
        }
        // print error message
        printf("%s\n", (const char*)x.ErrText());
    }
    
    return 0;
}

Relevant Link:

https://msdn.microsoft.com/zh-cn/library/ms131321(v=sql.120).aspx
https://msdn.microsoft.com/zh-cn/library/ms131291(v=sql.120).aspx
http://www.sqlapi.com/Examples/step1.cpp
http://www.sqlapi.com/OnLineDoc/index.htm

 

4. C++ ADO

Microsoft ActiveX Data Object (ADO) provides an easy way to data access and manipulation that is independent of data stores, tools, and languages. This flexibility and easy-to-code facility makes ADO the perfect choice for developers.
ADO is implemented with Component Object Model (COM) interfaces. Unlike VB programmers, C++ programmers must know the details of using COM for using ADO. So, using ADO from C++ is still very complex. But, it is possible to get an easy ADO programming model from C++, which can help to hide the details of using COM. 

0x1: Introduction to ADO

ADO consists of a series of objects that are used to manage interfacing to an SQL server. In C++ these objects need to be instantiated using a smart pointer and then set up correctly in order to perform database operations.
Generally ADO is abstracted from the particular syntax issues of various SQL servers. It operates via a driver supplied by a specific SQL server provider. Each provider must supply the driver necessary for ADO to interface to the server properly and handle the various interfaces that ADO operates on.
For instance, the MS-SQL server uses a driver called ‘SQL Native Client‘. In this way, with only a few exceptions, only one piece of code needs to be written in order to interface properly with various SQL servers.

0x2: Connection

The ADO connection object handles the actual persistent connection to the SQL server. The main thing to keep in mind is to properly set up the connection string. The connection string consists of a series of key value pairs. Generally the connection string tells ADO

1. the name of the SQL server computer to connect to
2. the driver to use as a client to connect to the server
3. the database to use and any authentication information 
4. and any other various miscellaneous values that are necessary to properly connect to the SQL server.

0x3: C++ code necessary to access ADO API

To set up ADO for use in the compiler, the importing of a typelib that contains the ADO manager class calls is necessary. ADO is a series of COM interfaces and in C++ it could get rather complex to access all these various interfaces using the COM API.

//Somewhere in one of your main modules you must have the following line:
#import "c:\program files\common files\system\ado\msado15.dll" rename ("EOF","adoEOF") no_namespace

To access the ADO objects in C++, probably the easiest way is to use what are called ‘smart pointers‘. With COM smart pointers the compiler handles all the things like interface instantiation, memory management etc all the programmer has to do is create an instance to the proper interface and start using the pointer as if it were any other instantiated class. The programmer does not need to actually delete the object, when it falls out of scope that is handled by the program

HRESULT _hr =sp.CreateInstance( __uuidof( riid ) ); 
if (FAILED(_hr))
{
        _com_issue_error(_hr);
}

ADO uses COM as its framework for interfacing to the application. You must instantiate COM before performing any ADO operations. Below is an example of how to get COM going and instantiate the four main ADO interface objects in the application

#import "c:\program files\common files\system\ado\msado15.dll" rename ("EOF","adoEOF") no_namespace
int main(int argc, char *argv[])
{
        _ConnectionPtr  pConnection;
        _CommandPtr             pCommand;
        _ParameterPtr   pParameter;
        _RecordsetPtr   pRecordset;
        int iErrorCode;
        HRESULT hr;

        //      Initialize COM  
        if(FAILED(hr = CoInitialize(NULL)))
        {
                goto done_err;
        }
 
//      Intialize the ADO Connection object
        if(FAILED(hr = pConnection.CreateInstance(__uuidof(Connection))))
        {
                goto done_err;
        }

//      Intialize the ADO Command object
        if(FAILED(hr = pCommand.CreateInstance(__uuidof(Command))))
        {
                goto done_err;
        }

//      Intialize the ADO Parameter object
        if(FAILED(hr = pParameter.CreateInstance(__uuidof(Parameter))))
        {
                goto done_err;
        }

//      Intialize the ADO RecordSet object
        if(FAILED(hr = pRecordset.CreateInstance(__uuidof(Recordset))))
        {
                goto done_err;
        }

//      Uninitialize COM        
        CoUninitialize();
        
        // Everything worked out, report an OK
        iErrorCode = 0;

        done:
        return iErrorCode;
        done_err:
// TODO: Cleanup
        iErrorCode = (int)hr;
        goto done;
}

ADO库包含三个基本接口

1. _ConnectionPtr接口返回一个记录集或一个空指针 
通常使用它来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。使用_ConnectionPtr接口返回一个记录集不是一个好的使用方法。通常同Cdatabase一样,使用它创建一个数据连接,然后使用其它对象执行数据输入输出操作。
 
2. _CommandPtr接口返回一个记录集 
它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。在使用_CommandPtr接口时,你可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。如果你只执行一次或几次数据访问操作,后者是比较好的选择。但如果你要频繁访问数据库,并要返回很多记录集,那么,你应该使用全局_ConnectionPtr接口创建一个数据连接,然后使用_CommandPtr接口执行存储过程和SQL语句。
 
3. _RecordsetPtr是一个记录集对象 
与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定,游标控制等。同_CommandPtr接口一样,它不一定要使用一个已经创建的数据连接,可以用一个连接串代替连接指针赋给_RecordsetPtr的connection成员变量,让它自己创建数据连接。如果你要使用多个记录集,最好的方法是同Command对象一样使用已经创建了数据连接的全局_ConnectionPtr接口,然后使用_RecordsetPtr执行存储过程和SQL语句 

基本流程

1. 初始化COM库
使用AfxOleInit()来初始化COM库,这项工作通常在CWinApp::InitInstance()的重载函数中完成 
BOOL CADOTest1App::InitInstance()
{
    AfxOleInit();
    ......
}

2. 引入ADO库定义文件
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
其最终作用和#include类似,编译的时候系统会为我们生成msado15.tlh、ado15.tli两个C++头文件来定义ADO库

3. 创建Connection对象并连接数据库
//添加一个指向Connection对象的指针
_ConnectionPtr m_pConnection; 
BOOL CADOTest1Dlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    try
    {
        HRESULT hr = m_pConnection.CreateInstance("ADODB.Connection");//创建Connection对象
        if(SUCCEEDED(hr))
        {
            /*
            HRESULT Connection15::Open (_bstr_t ConnectionString, _bstr_t UserID, _bstr_t Password, long Options )
            常用的数据库连接方法
            1. 通过JET数据库引擎对ACCESS2000数据库的连接
            m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\test.mdb","","",adModeUnknown);
            
            2. 通过DSN数据源对任何支持ODBC的数据库进行连接:
            m_pConnection->Open("Data Source=adotest;UID=sa;PWD=;","","",adModeUnknown);
            //m_pConnection->Open("DSN=test;","","",0);   //连接叫作test的ODBC数据源
 
            3. 不通过DSN对SQL SERVER数据库进行连接:
            m_pConnection->Open("driver={SQLServer};Server=127.0.0.1;DATABASE=master;UID=sa;PWD=139","","",adModeUnknown);//其中Server是SQL服务器的名称,DATABASE是库的名称
            */
            hr = m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb","","",adModeUnknown);//连接数据库
            //上面一句中连接字串中的Provider是针对ACCESS2000环境的,对于ACCESS97,需要改为:Provider=Microsoft.Jet.OLEDB.3.51;   
        }        
    }
    catch (_com_error e) //COM错误取得,当执行COM功能的时候,如果出错,可以捕捉到_com_error的异常
    { 
        CString strComError;
        strComError.Format("错误编号: %08lx\n错误信息: %s\n错误源: %s\n错误描述: %s",
        e.Error(),                  // 错误编号
        e.ErrorMessage(),           // 错误信息
        (LPCSTR) e.Source(),        // 错误源
        (LPCSTR) e.Description());  // 错误描述     

        ::MessageBox(NULL,strComError,"错误",MB_ICONEXCLAMATION);
    }
} 
//也可以使用UDL文件进行连接。
try
{ 
    m_pConnection.CreateInstance(__uuidof(Connection));  
    m_pConnection->ConnectionString ="File Name=e.udl";
    m_pConnection->Open("","","",NULL);
}
catch(_com_error e)
{....}
 
4. 利用建立好的连接,通过Connection、Command对象执行SQL命令,或利用Recordset对象取得结果记录集进行查询、处理 
5. 使用完毕后关闭连接释放对象 

0x4: Interfacing ADO to various database platforms

ADO is not limited to just one type of SQL server. If the correct driver is installed on your computer, which a provider has made to properly use ADO, ADO can be used to interface to this platform.
The main difference in platforms is the connection string that is used in the Connection object. ADO has five standard keys that it looks at in processing a connection string and all other key value pairs are passed directly to the provider driver

//ADO supports five arguments for the ConnectionString property; any other arguments pass directly to the provider without any processing by ADO. The arguments ADO supports are as follows.
1. Provider=xx: Specifies the name of a provider to use for the connection.
2. File Name=xx: Specifies the name of a provider-specific file (for example, a persisted data source object) containing preset connection information.
3. Remote Provider=xx: Specifies the name of a provider to use when opening a client-side connection. (Remote Data Service only.)
4. Remote Server=xx: Specifies the path name of the server to use when opening a client-side connection. (Remote Data Service only.)
5. URL=xx: Specifies the connection string as an absolute URL identifying a resource, such as a file or directory.

The following table lists the default ADO provider for each Windows operating system:

1. MSDASQL(To improve the readability of source code, explicitly specify the provider name in the connection string.)
    1) Windows 2000 (32-bit)
    2) Windows XP (32-bit)
    3) Windows 2003 Server (32-bit)
    4) Windows Vista (32-bit)
    5) Windows Vista Service Pack 1 or later (32-bit and 64-bit)
    6) Windows versions after Windows Vista (32-bit and 64-bit)
2. No default(When an ADO application runs on the following operating systems and does not specify the provider explicitly, ADO returns the following error: ADODB.Connection: provider is not specified and there is no designated default provider")
    1) Windows 2000 (64-bit)
    2) Windows XP (64-bit)
    3) Windows 2003 Server (64-bit)
    4) Windows Vista (64-bit)

example

DRIVER=SQL Native Client;SERVER=.\SQLExpress;Trusted_Connection=Yes;Initial Catalog=ADOTest;

更多connection string的示例,请参阅下面的链接

http://www.codeproject.com/Articles/2304/ADO-Connection-Strings
http://www.connectionstrings.com/

0x5: Code example

#pragma once

// TODO: 在此处引用程序需要的其他头文件
#import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename("EOF","adoEOF") rename("BOF","adoBOF")

#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include "stdafx.h"
#include "iostream"
#include "algorithm"
using namespace std;

void main()
{
    ::CoInitialize(NULL); 
    _ConnectionPtr m_pConnection; 
    _variant_t RecordsAffected;

    _RecordsetPtr m_pRecordset;
    m_pRecordset.CreateInstance("ADODB.Recordset");

    HRESULT hr; 
    const char* p;
    char XM[22];

    _variant_t var;
    hr = m_pConnection.CreateInstance(__uuidof(Connection));///创建Connection对象 
    if(SUCCEEDED(hr))
        hr =m_pConnection->Open(_T("driver={SQL Server};Server=127.0.0.1;DATABASE=SET;UID=sa;PWD="),"","",adModeUnknown); 
    m_pRecordset=m_pConnection->Execute(_T("select Name From UserList where UserNum=‘user1‘"),&RecordsAffected,adCmdText);
    string strtablename=(char*)(_bstr_t)m_pRecordset->Fields->GetItem(_variant_t("Name"))->Value;
    p=strtablename.c_str();
    strcpy(XM,p);
    int i,l;
    l=strlen(XM);printf("%d",l);
    for(i=0;i<l;i++)
    {
        if(XM[i]== ) {XM[i]=\0;}
        else {}
    }
    printf("%s",XM);

    _pRecordset=m_pConnection->Execute(_T("select deposit From UserList where UserNum=‘user1‘"),&RecordsAffected,adCmdText);
    float f1;
    f1=(float)m_pRecordset->Fields->GetItem(_variant_t("deposit"))->Value;
    printf("%f",f1);

    m_pConnection->Close(); 

    ::CoUninitialize();
    ::CoInitialize(NULL); 
    float f2=3;
    hr = m_pConnection.CreateInstance(__uuidof(Connection));
    m_pRecordset.CreateInstance("ADODB.Recordset");

    hr=m_pConnection->Open(_T("driver={SQL Server};Server=127.0.0.1;DATABASE=SET;UID=sa;PWD="),"","",adModeUnknown);

    m_pRecordset->Open(_T("select * From UserList where UserNum=‘user2‘"),_variant_t((IDispatch *)m_pConnection,true),adOpenStatic,adLockOptimistic,adCmdText);

    m_pRecordset->PutCollect((_variant_t)(_T("deposit")),_variant_t ((long)f2));

    m_pRecordset->Update();

    m_pConnection->Close();
    ::CoUninitialize();
}

Relevant Link:

https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms675810(v=vs.85).aspx 
http://www.codeguru.com/cpp/data/mfc_database/ado/article.php/c6729/Using-ADO-from-C.htm
http://outofmemory.cn/code-snippet/454/c-connection-MS-Sql-Server-database
http://www.codeproject.com/Questions/341111/How-to-connect-SQL-Server-to-Cplus-Program
http://www.cprogramming.com/tutorial/c++_database_access_using_ado.html
http://www.cprogramming.com/tutorial/intro_to_ado_in_c++.html
http://www.cppblog.com/changshoumeng/articles/113437.html

 

5. C++ ODBC

ODBC (Open Database Connectivity)

1. A standard interface for connecting from C++ to relational databases 
2. It allows individual providers to implement and extend the standard with their own ODBC drivers

0x1: Steps of the ODBC

1. Include Header Files
/*
#include <sql.h>
#include<sqltypes.h>
#include<sqlext.h>
*/

2. Open a Connection to a Database
/*
Set the environment handle:
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hdlEnv); 

Set ODBC Driver version:
SQLSetEnvAttr(hdlEnv,SQL_ATTR_ODBC_VERSION,(void*)SQL_OV_ODBC3, 0);

Set the connection handle: 
SQLAllocHandle(SQL_HANDLE_DBC, hdlEnv, &hdlConn); 

Connect to the database:
SQLConnect(hdlConn, (SQLCHAR*)dsnName,SQL_NTS,(SQLCHAR*)userID,SQL_NTS, (SQLCHAR*)passwd, SQL_NTS); 
*/

3. Choose an ODBC Driver
/*
DSN: Data Source Name
Open the GUI ODBC Administrator (ODBCConfig) 
Choose the appropriate ODBC driver
Provide a meaningful name to the DSN
Specify the server and the host string (host string is required if the server is running on a different machine)    
*/

4. Query the Database
/*
1) Creating a Statement
SQLAllocHandle(SQL_HANDLE_STMT, hdlDbc, &hdlStmt);
It allocates the memory for the statement handle. The database handle obtained during connection phase is passed as the second argument.

2) Executing a Query
SQLExecDirect(hdlStmt, stmt, SQL_NTS); 
It executes the query, which is passed in as SQLCHAR* in the second argument.
*/
 
5. Extracting Data from an ODBCResultSet
/*
SQLGetData(hStmt,colNum,type,retVal,buffLength,&cbData);
It extracts data from table as void* data and places it in retVal
*/

6. Closing the ODBCResultSet and ODBCStatement
/*
SQLFreeHandle(SQL_HANDLE_STMT, hdlStmt);
It closes and de-allocates the memory reserved for the statement handle 

SQLFreeHandle(SQL_HANDLE_DBC, hdlConn); 
It disconnects and de-allocates the memory reserved for the connection handle 

SQLFreeHandle(SQL_HANDLE_ENV, hdlEnv); 
It de-allocates the memory occupied by the environment handle 
*/

7. Importance of closing the connection

0x2: 配置ODBC DSN数据源

DSN为 ODBC定义了一个确定的 数据库和必须用到的ODBC驱动程序。每个ODBC 驱动程序定义为该驱动程序支持的一个数据库创建DSN需要的信息。就是说安装ODBC驱动程序以及创建一个数据库之后,必须创建一个DSN
一个DSN中至少应该包含如下一些内容 

1. 关于数据库驱动程序的信息。 
2. 数据库存放位置
    1) 文件型数据库(如Access)的存放位置为数据库文件的路径
    2) 非文件型数据库(如SQL Server)的存放位置是指服务器的名称 
3. 数据库名称。在ODBC数据源管理器中,所有的DSN名称是不能重复的 

一个DSN可以定义为以下3种类型中的任意一种

1. 用户数据源: 这个数据源对于创建它的计算机来说是局部的,并且只能被创建它的用户使用。 
2. 系统数据源: 这个数据源属于创建它的计算机并且是属于这台计算机而不是创建它的用户。任何用户只要拥有适当的权限都可以访问这个数据源 
3. 文件数据源: 这个数据源对底层的数据库文件来说是确定的。换句话说,这个数据源可以被任何安装了合适的驱动程序的用户使用   
Windows DSN 文件(数据源名)主要是用来存储数据库连接信息。如果你有很多网页需要传送数据,就可以很简单的通过DSN文件路径来完成而不需要传送数据到每个页面了。 
出于安全考虑,DSN文件一般放置在主机目录的子目录中,这样不明访问者就访问不了这个目录。DSN文件需要在ASP和ADO一起访问数据库。名称为: "_dsn"在主机帐户的根目录中 

技术分享

可以看到,相比于ADO,ODBC的"可移植性"更差,它和系统的耦合更为严重,使用ODBC技术的前提是需要在操作系统层面配置DSN数据源,ODBC本质上来说是在DSN的基础上的封装,因此ODBC不具备单机编译,大规模部署应用的能力

0x3: Code example

#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <sqltypes.h>
  //#include <sql.h>
#include "sqlext.h"
using namespace std;
 
void show_error(unsigned int handletype, const SQLHANDLE& handle)
{
     SQLWCHAR sqlstate[1024];
     SQLWCHAR message[1024];
     if(SQL_SUCCESS == SQLGetDiagRec(handletype, handle, 1, sqlstate, NULL, message, 1024, NULL))
         cout<<"Message: "<<message<<"\nSQLSTATE: "<<sqlstate<<endl;
 }
int _tmain(int argc, _TCHAR* argv[])
{
    SQLHANDLE sqlenvhandle;    
    SQLHANDLE sqlconnectionhandle;
    SQLHANDLE sqlstatementhandle;
    SQLRETURN retcode;
    if(SQL_SUCCESS!=SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &sqlenvhandle))
        goto FINISHED;
    if(SQL_SUCCESS!=SQLSetEnvAttr(sqlenvhandle,SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0)) 
        goto FINISHED;
    if(SQL_SUCCESS!=SQLAllocHandle(SQL_HANDLE_DBC, sqlenvhandle, &sqlconnectionhandle))
        goto FINISHED;
 
    SQLWCHAR retconstring[1024];
    switch(SQLDriverConnect (sqlconnectionhandle, 
                 NULL, 
                 (SQLWCHAR*)"DSN=test;UID=sa;PWD=123;", 
                 SQL_NTS, 
                 retconstring, 
                 1024, 
                 NULL,
                 SQL_DRIVER_NOPROMPT))
    {
         case SQL_SUCCESS_WITH_INFO:
             show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
             break;
         case SQL_INVALID_HANDLE:
         case SQL_ERROR:
             show_error(SQL_HANDLE_DBC, sqlconnectionhandle);
             goto FINISHED;
         default:
             break;
     }
     
     if(SQL_SUCCESS!=SQLAllocHandle(SQL_HANDLE_STMT, sqlconnectionhandle, &sqlstatementhandle))
         goto FINISHED;
 
     if(SQL_SUCCESS!=SQLExecDirect(sqlstatementhandle, (SQLWCHAR*)"select * from testtable", SQL_NTS))
     {
         show_error(SQL_HANDLE_STMT, sqlstatementhandle);
         goto FINISHED;
     }
     else
     {
         char name[64];
         char address[64];
         int id;
         while(SQLFetch(sqlstatementhandle)==SQL_SUCCESS){
             SQLGetData(sqlstatementhandle, 1, SQL_C_ULONG, &id, 0, NULL);
             SQLGetData(sqlstatementhandle, 2, SQL_C_CHAR, name, 64, NULL);
             SQLGetData(sqlstatementhandle, 3, SQL_C_CHAR, address, 64, NULL);
             cout<<id<<" "<<name<<" "<<address<<endl;
         }
     }
 
 FINISHED:
     SQLFreeHandle(SQL_HANDLE_STMT, sqlstatementhandle );
     SQLDisconnect(sqlconnectionhandle);
     SQLFreeHandle(SQL_HANDLE_DBC, sqlconnectionhandle);
     SQLFreeHandle(SQL_HANDLE_ENV, sqlenvhandle);
 
 
    return 0;
}

Relevant Link:

http://windows.microsoft.com/en-us/windows/using-odbc-data-source-administrator#1TC=windows-7
http://www-01.ibm.com/support/knowledgecenter/SSZJPZ_11.3.0/com.ibm.swg.im.iis.conn.common.usage.doc/topics/t_configuring_conn_odbc.html?lang=zh
https://msdn.microsoft.com/en-us/library/ms715433(v=vs.85).aspx
http://www.baike.com/wiki/DSN
http://www.codeproject.com/Questions/341111/How-to-connect-SQL-Server-to-Cplus-Program
http://www.dreamincode.net/forums/topic/21309-cpp-with-odbc-open-database-connectivity/

 

6. tiodbc - TinyODBC C++ Wrapper for ODBC API

TinyODBC wraps ODBC C API and provides a C++ API that is Object Oriented

#include "./tiodbc.hpp"
#include <iostream>

using namespace std;

int main()
{   
   // Create a connection with an ODBC Data Source
    tiodbc::connection my_connection("MyDSN", "", "");

    // Check if it was connected succesfully
    if (my_connection.connected())
        cout << "Connection has been accomplished";
    else
        cout << "Error connecting with server" << endl
            << my_connection.last_error();

    
    // Do more things here
    //.....

    // Disconnect
    my_connection.disconnect();

    return 0;
}

Relevant Link:

https://code.google.com/p/tiodbc/
http://tiodbc.googlecode.com/svn/tags/0.1.2/docs/html/index.html
http://tiodbc.googlecode.com/svn/tags/0.1.2/docs/html/examples.html

 

7. 基于API调用的自动化检测

SQLAPI++是一款收费的DB连接框架,我们需要自己编码实现数据库连接这个功能

0x1: 技术方案选型

1. DAO
These classes work with the other application framework classes to give easy access to Data Access Object (DAO) databases, which use the same database engine as Microsoft Visual Basic and Microsoft Access. The DAO classes can also access a wide variety of databases for which Open Database Connectivity (ODBC) drivers are available.
Programs that use DAO databases will have at least a CDaoDatabase object and a CDaoRecordset object.

2. ODBC
These classes work with the other application framework classes to give easy access to a wide variety of databases for which Open Database Connectivity (ODBC) drivers are available.
Programs that use ODBC databases will have at least a CDatabase object and a CRecordset object.

3. ADO
ADO 是目前在Windows环境中比较流行的客户端数据库编程技术。ADO是建立在OLE DB底层技术之上的高级编程接口,因而它兼具有强大的数据处理功能(处理各种不同类型的数据源、分布式的数据处理等等)和极其简单、易用的编程接口,因而得到了广泛的应用。而且按微软公司的意图,OLE DB和ADO将逐步取代 ODBC和DAO

本文采取ADO技术进行数据库DB的连接

0x2: 方案思路

1. 通过将密码字典静态编译到程序中,或者单独保存在服务端的一个文件中,需要使用时下载(容易受到客户端网络状况的影响)
2. 枚举获取目标DB的系统帐号列表
3. 调用DB API向SQLServer、Mysql发起登录尝试。实现弱密码检测
4. 将检测结果以JSON形式保存

0x3: SQLserver帐号体系

1. 登录名

登录名是一个可由安全系统进行身份验证的安全主体或实体。用户需要使用登录名连接到 SQL Server。您可基于

1. 根据Windows主体(例如: 域用户或Windows域组)创建登录名
2. 根据非基于Windows主体的登录名(例如: SQL Server登录名)
//若要使用SQL Server身份验证,数据库引擎必须使用混合模式身份验证

可以向作为安全主体的登录名授予权限。登录名的作用域是整个数据库引擎

1. 若要连接SQL Server实例上的特定数据库,登录名必须映射到数据库用户
2. 数据库内的权限是向数据库用户而不是登录名授予和拒绝授予的
3. 可将作用域为整个SQL Server实例的权限(例如 CREATE ENDPOINT 权限)授予一个登录名

2. 数据库用户

数据库用户是连接到数据库时的登录名的标识。 数据库用户可以使用与登录名相同的名称,但这不是必需的
数据库用户是在SQLServer登录名的基础上,加上了

1. 映射数据库用户
2. 服务器角色
3. 用户映射
4. 安全对象

在这种架构下,SQLServer最大程度地保证了权限控制的灵活性、安全性
获取sqlserver所有DB系统的登录名(DB系统帐号)SQL如下

Select * FROM syslogins where status = 9 and password IS NOT NULL
//代表SQLServer验证方式的帐号

0x3: Code

else if(action == "--sqlserverPwdcheck")
    { 
        HRESULT hr; 
        int Pwdlength;
        int i, found = 0;
        //json class
        JsonEasy JsonResult = JsonEasy();
        JsonResult.jRoot["isvul"] = 0;

        Pwdlength = sizeof(windowsMssqlPassword) / sizeof(windowsMssqlPassword[0]);  

        //COM initialize
        ::CoInitialize(NULL); 
        //recordset for get data
        _RecordsetPtr pPtr;  
        _ConnectionPtr m_pConnection; 

        if (FAILED(pPtr.CreateInstance("ADODB.Recordset")))  
        {  
            std::cout << "Create Instance failed!" << std::endl;  
            return FALSE;  
        }   
        //connection string
        CString strConnection = "Provider=SQLOLEDB;Server=.;Database=master;Integrated Security=SSPI;"; 
        //sql string
        CString strSQL = "Select name FROM syslogins where status = 9 and password IS NOT NULL";
        _variant_t varConnection(strConnection);  
        _variant_t varSQL(strSQL);   

        //connect and query
        if(FAILED(pPtr->Open(varSQL,varConnection,adOpenStatic,adLockOptimistic,adCmdText)))  
        {  
            std::cout << "Open table failed!" << std::endl;   
            pPtr.Release();  
            return FALSE;  
        } 

        closeLog();

        //get data from quey result
        while(!pPtr->GetadoEOF())  
        {    
            _variant_t varName;    
            varName = pPtr->GetCollect ("name");    
            CString strName =(TCHAR *)_bstr_t(varName);  

            //start weakpassword test via dynamic username list
            try
            {
                hr = m_pConnection.CreateInstance(_uuidof(Connection));///创建Connection实例
                if(SUCCEEDED(hr))
                {
                   //m_pConnection->ConnectionTimeout = 600;//设置连接超时时间
                   //m_pConnection->CommandTimeout=120;//设置执行命令超时时间
                    for(i = 0; i < Pwdlength; i++)
                    {
                        try
                        {
                            hr = m_pConnection->Open("Provider=SQLOLEDB;Server=.;Database=master;",strName.GetString(), windowsMssqlPassword[i], adModeUnknown);///连接数据库
                            if(SUCCEEDED(hr))
                            {
                                JsonResult.jRoot["isvul"] = 1;
                                //fill username/password
                                JsonResult.execinfoItemMSSQLpwd["password"] = TCHAR2char(windowsMssqlPassword[i]);
                                JsonResult.execinfoItemMSSQLpwd["username"] = TCHAR2char((TCHAR*)strName.GetString()); 

                                JsonResult.execinfoArrayObj.append(JsonResult.execinfoItemMSSQLpwd);  
                                found = 1;
                                break;
                                //std::wcout << strName.GetString() << " password is: " << windowsMssqlPassword[i] << " hr: "<< hr << std::endl;
                            }
                        }
                        catch(_com_error e)///捕捉异常
                        {} 
                    } 
                    if( found == 0 )
                    {
                        JsonResult.execinfoItemMSSQLpwd["password"] = "Your Paaword Is Strong Enough";
                        JsonResult.execinfoItemMSSQLpwd["username"] = TCHAR2char((TCHAR*)strName.GetString()); 

                        JsonResult.execinfoArrayObj.append(JsonResult.execinfoItemMSSQLpwd); 
                    }
                    //end 
                }
            }
            catch(_com_error e)///捕捉异常
            {  
                //go on 
            } 
            //std::wcout << strName.GetString() << std::endl;

            strName.Trim();    
            pPtr->MoveNext();  
        }  
        pPtr->Close();  
        pPtr.Release(); 

        //wrap the json
        JsonResult.jRoot["execinfo"] = JsonResult.execinfoArrayObj;
        JsonResult.jRoot["moduleid"] = sqlserverPwdcheck;
        JsonResult.jRoot["execresult"] = 1; 
        //output finnal result
        std::string out = JsonResult.jRoot.toStyledString();
        std::cout << out << std::endl;   

        openLog();

        return 0;
    }

Relevant Link: 

http://www.cnblogs.com/yongqiudeng/archive/2008/02/12/1067342.html
https://msdn.microsoft.com/en-us/library/8ah8ebwy.aspx 
http://forums.codeguru.com/showthread.php?309072.html
http://blog.csdn.net/zgl_dm/article/details/2076528
https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms677563(v=vs.85).aspx
https://msdn.microsoft.com/zh-cn/library/aa337562(v=sql.120).aspx
https://msdn.microsoft.com/zh-cn/library/aa337545(v=sql.120).aspx#Security
http://developer.51cto.com/art/200911/160833.htm
http://my.oschina.net/u/1035715/blog/156192
https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms681557(v=vs.85).aspx

 

Copyright (c) 2015 LittleHann All rights reserved

 

SQLSERVER Account Weak Password Detection Automatic By System API

标签:

原文地址:http://www.cnblogs.com/LittleHann/p/4664658.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!