Having fun and really no profit with $ORIGIN expansion variable in Java gennaio 30th, 2017

Days ago I was reading this [0] interesting article about the dynamic linker expansion variables, and so I tought it would be fun to search for binaries with the RPATH dynamic tag containing the $ORIGIN variable.

So digging through dynamic tags using eu-readelf -d I found that the java ELF binary has the following RPATH:

Library rpath: [$ORIGIN/../lib/amd64/jli:$ORIGIN/../lib/amd64]

Using ldd comes up that java searches this paths looking for the shared object (for which I dunno really the purpose yet):

libjli.so => /home/$USER/jdk1.8.0_65/jre/bin/../lib/amd64/jli/libjli.so

So my attempt to mess with the $ORIGIN var was to create on the same level of the jdk directory a directory called ./bin containing an hard-link or even a copy of the java binary, and a directory tree on the same level of bin, which had the following path: ./lib/amd64/jli.

Trying to run the java binary from the new ./bin/ path happened exactly what I wanted to see:

./bin/java: error while loading shared libraries: libjli.so: cannot open shared
object file: No such file or directory`

So ok, let’s build a shared object called that name into lib/amd64/jli and see what happens…

# cat libjli.c 
int foobar(void)
{
	return 0x29a;
}
gcc -o libjli.so -shared -fPIC libjli.c

And now we try to run again the java binary:

./bin/java: /tmp/spike/java/bin/../lib/amd64/jli/libjli.so: no version
information available (required by ./bin/java)
./bin/java: relocation error: ./bin/java: symbol JLI_Launch, version
SUNWprivate_1.1 not defined in file libjli.so with link time reference

Good, looking at the main function of the java binary we find a call to the JLI_Launch function: 0x0000000000400691 <+113>: call 0x400520 <JLI_Launch@plt>

So we redefine our fake libjli.so adding the JLI_Launch function and also we export the required versioning info.

# cat libjli.c 
#include 

void JLI_Launch(void)
{
	system("/bin/sh");
}

And now a simple version script for the linker:

#cat libjli.map
SUNWprivate_1.1 {
	global:
		JLI_Launch;		
};

Finally we recompile the shared object applying the linker script:

gcc -c libjli.c -fPIC
gcc -o libjli.so -shared -Wl,--version-script=libjli.map

Now trying to execute the java binary from the ./bin/ path:

[spike@zombie java]$ ./bin/java
sh-4.3$

That’s all folks!

[0] https://backtrace.io/blog/blog/2016/06/29/exploiting-elf-expansion-variables/