SLAE x86 - Assignment 0x7

4 minute read

Custom Shellcode Crypter

Objectives

  • Create a custom crypter
  • Free to use any existing encryption schema
  • Use any programming language

Crypter

Another process to conceal a shellcode by means of encrypting with different schema. “Encryption is the foundation of modern security.” as snowden mentioned. In case of exploit development, it is another technique such as Encoding & Polymorphism from previous assignments to make detection harder.

Advanced Encryption Standard (AES)

The AES is originally Rijndael cipher, the winner of the NIST’s AES selection, is widely used. It can be implemented with 128, 192, or 256 bits of key. The algorithm consist of several steps: sub bytes, shift rows, mix columns, & add round key. More details of the process here: https://formaestudio.com/rijndaelinspector/archivos/Rijndael_Animation_v4_eng-html5.html.

Fortunately, AES can be implemented using the OpenSSL gem in Ruby. With the Cipher class, AES with 256-bit key can be intantiated by:

OpenSSL::Cipher.new('AES-256-CBC')

Encryption and decryption are possible by passing the method .encrypt and .decrypt into the instance as decribed in the documentation. Also, a key is passed using the .key method. But before passing the key, it can be processed further to make it 256-bit. OpenSSL’s Digest class is capable of creating a 256-bit hash from an input data by using its .digest method.

Ruby Script

Below Ruby script used the mentioned functionalities above. Comments are added to explain the functionality of the codes used. The script have three options in processing the shellcode: encrypt only, decode only, or decode & execute.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#!/usr/bin/env ruby
# Author: Jason Villaluna

require 'optparse'
require "openssl"

def run
  parse_args
  validate_inputs
  process_shellcode
rescue OptionParser::MissingArgument
  puts "\e[33m[!] Missing argument:\e[0m"
  @parser.parse %w[--help]
rescue StandardError => e
  puts "\e[31m[-]\e[0m Encountered: \e[31m'#{e.class}' #{e}\e[0m"
  exit(1)
end

# Simple check to validate cli arguments
def validate_inputs
  messages = [
    "Please provide both shellcode and key",
    "Please choose one from encrypt, decrypt_only, and decrypt_run"
  ]
  messages.shift if [@shellcode, @key].all? { |arg| arg }
  messages.pop if ['encrypt', 'decrypt_only', 'decrypt_run'].include?(@execute)
  return if messages.empty?

  messages.each { |message| puts "\e[33m[!] #{message}\e[0m" }
  exit(1)
end

# Choose which method to execute depending on the user's options
def process_shellcode
  case @execute
  when /^encrypt$/i
    encrypt_shellcode
  when /^decrypt_only$/i
    decrypt_only
  when /^decrypt_run$/i
    decrypt_run
  end
end

# Encrypt the shellcode with AES-256-CBC
def encrypt_shellcode
  encrypted_shellcode = aes(@key, @shellcode) { |aes| aes.encrypt }
  puts "\e[32m[+] Encrypted successfully:\e[0m "\
    "'#{encrypted_shellcode.to_s.unpack('C*').map { |c| '\x%02x' % c }.join}'"
end

# Decrypt the encrypted shellcode
def decrypt_shellcode
  shellcode = [@shellcode.split('\\x').join].pack('H*')
  aes(@key, shellcode) { |aes| aes.decrypt }
end

# Displays the decrypted shellcode in stdout
def decrypt_only
  decrypted_shellcode = decrypt_shellcode
  puts "\e[32m[+] Decrypted successfully:\e[0m '#{decrypted_shellcode}'"
end

# Decrypt the shellcode, compile using 'shell.c', and then run
def decrypt_run
  @decrypted_shellcode = decrypt_shellcode
  replace_shellcode
  compile_binary
  run_binary
end

# AES-256-CBC encryption and decryption
# depending on what code is pass in the block
def aes(key, data)
  aes = OpenSSL::Cipher.new('AES-256-CBC')
  yield(aes)
  aes.key = OpenSSL::Digest.digest("SHA256", key)
  aes.update(data) + aes.final
end

# Replace a value inside a file
def replace_content(filename)
  file_content = File.read(filename)
  yield(file_content)
  File.write(filename, file_content)
end

# Replace shellcode in the shellcode tester program
def replace_shellcode
  replace_content('./shellcode.c') do |c_code|
    c_code.gsub!(/\"\S+\"\;/, "\"#{@decrypted_shellcode}\"\;")
  end
end

# Compile the shellcode into binary with the help of the shellcode.c program
def compile_binary
  `gcc -fno-stack-protector -m32 -z execstack shellcode.c -o shellcode 2> /dev/null`
  puts "\n\e[32m[+]\e[0m Successfully generated \e[32mshellcode\e[0m "
end

# Execute the shellcode binary
def run_binary
  system('./shellcode')
end

def parse_args
  @parser = OptionParser.new do |opts|
    opts.banner = "Usage: #{$0} -s [shellcode] -k [key] -[e|d|r]"
    opts.separator ""
    opts.separator "Options:"

    opts.on("--shellcode", "-s SHELLCODE", "Input Shellcode") do |value|
      @shellcode = value
    end

    opts.on("--key", "-k KEY", "Pass key") do |value|
      @key = value
    end

    opts.on(
      "--execute", "-e [encrypt|decrypt_only|decrypt_run]",
      "\n\t\tencrypt: displays encrypted shellcode"\
      "\n\t\tdecrypt_only: displays decrypted shellcode:"\
      "\n\t\tdecryp_run: decrypt, compile, and then run the shellcode"
           ) do |value|
      @execute = value&.downcase
    end

    opts.on_tail("--help", "-h", "Print options") do |show_help|
      warn opts
      exit(0)
    end
  end
  @parser.parse!
end

if __FILE__ == $PROGRAM_NAME
  run
end

Script usage and testing


This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE - 1558


Link to Github repository | Link to index page