Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions lib/rex/random_identifier/generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ class ExhaustedSpaceError < StandardError; end
# This should be pretty universal for identifier rules
:char_set => Rex::Text::AlphaNumeric+"_",
:first_char_set => Rex::Text::LowerAlpha,
:forbidden => [].freeze
:forbidden => [].freeze,
:prefix => ''
}

JavaOpts = DefaultOpts.merge(
Expand Down Expand Up @@ -111,11 +112,27 @@ class ExhaustedSpaceError < StandardError; end
).freeze
)

PHPOpts = DefaultOpts.merge(
prefix: '$',
Copy link
Contributor

@adfoster-r7 adfoster-r7 May 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a feeling we might need to come back to this pattern again in the future; as I imagine we'd want to use the same rig for classnames as well as variables, and it wouldn't be possible to use this current approach for that

i.e.

<<~EOF
class #{rig['class']} {
  public function __wake() {
    $#{rig['payload']} = '...';
  }
}
EOF

Also in some scenarios we might want to have the identifier without the $ prefix, such as when accessing params in PHP - such as $_GET['#{rig['injection_param']}']; etc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well if the $ acts as a namespace, then maybe the language should have been named php-vars or something so we could add php-class because you could have a class named Foobar and a variable named $Foobar with separate values right? So it doesn't necessarily make sense to track them together here. For code readability it'd make sense to not reuse the identifiers, but obfuscation is part of the point here, so all the better if names are reused but still valid.

first_char_set: Rex::Text::Alpha + '_',
# see: https://www.php.net/manual/en/reserved.php
# see: https://www.php.net/manual/en/reserved.variables.php
forbidden: (
%w[
$GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV $_COOKIE
$HTTP_GET_VARS $HTTP_POST_VARS $HTTP_COOKIE_VARS $HTTP_SERVER_VARS
$HTTP_ENV_VARS $HTTP_SESSION_VARS $HTTP_POST_FILES $HTTP_RAW_POST_DATA
$php_errormsg $http_response_header $argc $argv $this
]
)
)

Opts = {
default: DefaultOpts,
java: JavaOpts,
jsp: JSPOpts,
javascript: JavaScriptOpts,
php: PHPOpts,
python: PythonOpts
}

Expand Down Expand Up @@ -247,12 +264,14 @@ def generate(len = nil)
# pick a random length within the limits
len ||= rand(@opts[:min_length] .. (@opts[:max_length]))

ident = ""
ident = ''

# XXX: Infinite loop if block returns only values we've already
# generated.
loop do
ident = Rex::Text.rand_base(1, "", @opts[:first_char_set])
ident = +''
ident << @opts[:prefix]
ident << Rex::Text.rand_base(1, "", @opts[:first_char_set])
ident << Rex::Text.rand_base(len-1, "", @opts[:char_set])
if block_given?
ident = yield ident
Expand Down