Skip to content

Add Malicious Windows Script Host JScript (.js) File module #20398

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2025

Conversation

bcoles
Copy link
Contributor

@bcoles bcoles commented Jul 20, 2025

This is unlikely to allow initial access without substantial social engineering efforts (or additional obfuscation), as malicious WSH files will almost certainly be blocked by EDR.

)

register_options([
OptString.new('FILENAME', [true, 'The JScript file name.', 'msf.js']),
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it make sense to have the name be randomly generated to avoid the mention of msf?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe. That's not something we're in the habit of doing.

# grep -rn FILENAME modules/exploits/**/fileformat | wc -l
395
# grep -rn FILENAME modules/exploits/**/fileformat | grep msf | wc -l
180

Most fileformat modules use a static file name.

# grep -rn FILENAME modules/exploits/**/fileformat | grep -i rand
modules/exploits/linux/fileformat/unrar_cve_2022_30333.rb:62:        OptString.new('SYMLINK_FILENAME', [ true, 'The name of the symlink file to use (must be 12 characters or less; default: random)', Rex::Text.rand_text_alpha_lower(4..12)])
modules/exploits/windows/fileformat/cve_2017_8464_lnk_rce.rb:99:      lnk_filename = datastore['FILENAME'] || "#{rand_text_alpha(16)}.lnk"
modules/exploits/windows/fileformat/cve_2017_8464_lnk_rce.rb:107:        fname, ext = (datastore['FILENAME'] || "#{rand_text_alpha(16)}.lnk").split('.')
modules/exploits/windows/fileformat/office_dde_delivery.rb:68:      filename = datastore['BinaryEXE-FILENAME'].blank? ? random : datastore['BinaryEXE-FILENAME']
modules/exploits/windows/fileformat/greenshot_deserialize_cve_2023_34634.rb:58:    datastore['FILENAME'] = Rex::Text.rand_text_alpha(rand(6..13)) if datastore['FILENAME'].blank?
modules/exploits/windows/fileformat/office_ms17_11882.rb:261:      filename = datastore['BinaryEXE-FILENAME'].blank? ? random : datastore['BinaryEXE-FILENAME']
modules/exploits/windows/fileformat/office_excel_slk.rb:62:      OptString.new('FILENAME', [true, "Filename to save as", "#{rand_text_alphanumeric 8}.slk"])
modules/exploits/windows/fileformat/office_excel_slk.rb:90:      filename = datastore['BinaryEXE-FILENAME'].blank? ? random : datastore['BinaryEXE-FILENAME']

Copy link
Contributor

Choose a reason for hiding this comment

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

IIRC, most of fileformat modules do use static file name, but they also create random file name if static file name is not supplied. I think that might be a way to be consistent with fileformat modules.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IIRC, most of fileformat modules do use static file name, but they also create random file name if static file name is not supplied. I think that might be a way to be consistent with fileformat modules.

No. Most of the fileformat modules require the FILENAME option to be set, thus never allowing the opportunity for the filename to be blank.

# grep -rn FILENAME modules/exploits/**/fileformat | grep Opt | grep false | wc -l
67
# grep -rn FILENAME modules/exploits/**/fileformat | grep Opt | grep true | wc -l
138
# grep -rn FILENAME modules/exploits/**/fileformat | grep Opt | grep -i rand | wc -l
2

If the FILENAME option is not required and the FILENAME is blank, the store_local method will create a <random>.bin file.

def store_local(ltype=nil, ctype=nil, data=nil, filename=nil)
if ! ::File.directory?(Msf::Config.local_directory)
FileUtils.mkdir_p(Msf::Config.local_directory)
end
# Split by fname an extension
if filename and not filename.empty?
if filename =~ /(.*)\.(.*)/
ext = $2
fname = $1
else
fname = filename
end
else
fname = ctype || "local_#{Time.now.utc.to_i}"
end
# Split by path separator
fname = ::File.split(fname).last
case ctype # Probably could use more cases
when "text/plain"
ext ||= "txt"
when "text/xml"
ext ||= "xml"
when "text/html"
ext ||= "html"
when "application/pdf"
ext ||= "pdf"
else
ext ||= "bin"
end

This does not preserve the expected file extension. This also results in an output message with preceding space where the filename should have been:

msf exploit(windows/fileformat/windows_script_host_jscript) > run
[+]  stored at /root/.msf4/local/local_1753623988.bin

This is an objectively uglier solution than the current implementation.

If the goal is to be consistent with the other modules, then the existing approach is more consistent.

A cleaner approach would be to implement custom file name randomization on a per-module basis. This would allow the module to support generating file names with the expected file extension. To achieve this, the module must clobber datastore['FILENAME'] because the Msf::Exploit::FILEFORMAT library does not support passing the filename to the file_create method. Clobbering datastore is generally frowned upon in Framework, but not entirely forbidden.

def file_format_filename
datastore['FILENAME']
end
def file_create(data)
fname = file_format_filename
ltype = "exploit.fileformat.#{self.shortname}"
full_path = store_local(ltype, nil, data, fname)
print_good "#{fname} stored at #{full_path}"
end


register_options([
OptString.new('FILENAME', [true, 'The JScript file name.', 'msf.js']),
OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
Copy link
Contributor

Choose a reason for hiding this comment

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

OBFUSCATE seems slightly generic in this context, with my initial impression being e.g. PrependBenignCode being an obfuscation technique.
Could we rename this to be something more specific, e.g.
JAVASCRIPT_OBSUCATION or similar?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This seems like needless differentiation, especially as PrependBenignCode is an advanced option not shown in the default list of options.

OBFUSCATE is tradition:

# grep -rn OBFUSCATE modules/ | grep Opt
modules/exploits/windows/fileformat/windows_script_host_vbscript.rb:54:      OptBool.new('OBFUSCATE', [false, 'Enable VBScript obfuscation', true])
modules/exploits/windows/fileformat/word_mshtml_rce.rb:63:      OptBool.new('OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])
modules/exploits/windows/fileformat/word_msdtjs_rce.rb:67:      OptBool.new('OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])
modules/exploits/windows/fileformat/adobe_reader_u3d.rb:81:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/fileformat/windows_script_host_jscript.rb:56:      OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
modules/exploits/windows/browser/notes_handler_cmdinject.rb:72:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms11_003_ie_css_import.rb:143:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
modules/exploits/windows/browser/hp_loadrunner_writefilebinary.rb:81:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/teechart_pro.rb:104:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true])
modules/exploits/windows/browser/hp_loadrunner_writefilestring.rb:72:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/viscom_movieplayer_drawtext.rb:63:      [ OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true]) ]
modules/exploits/windows/browser/adobe_flash_rtmp.rb:103:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]),
modules/exploits/windows/browser/samsung_security_manager_put.rb:47:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/honeywell_tema_exec.rb:71:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms13_009_ie_slayoutrun_uaf.rb:59:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/quickr_qp2_bof.rb:84:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/inotes_dwa85w_bof.rb:86:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/vlc_amv.rb:69:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/adobe_flashplayer_flash10o.rb:119:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
modules/exploits/windows/browser/novell_groupwise_gwcls1_actvx.rb:81:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/tom_sawyer_tsgetx71ex552.rb:111:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/ibm_spss_c1sizer.rb:104:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ntr_activex_stopmodule.rb:75:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/cisco_playerpt_setsource.rb:102:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/samsung_neti_wiewer_backuptoavi_bof.rb:77:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/crystal_reports_printcontrol.rb:111:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ie_cbutton_uaf.rb:85:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/asus_net4switch_ipswcom.rb:59:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/cisco_playerpt_setsource_surl.rb:146:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms12_037_same_id.rb:87:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/realplayer_qcp.rb:64:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/oracle_autovue_setmarkupmode.rb:130:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/vlc_mms_bof.rb:89:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/indusoft_issymbol_internationalseparator.rb:81:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/pcvue_func.rb:66:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true]),
modules/exploits/windows/browser/ms13_037_svg_dashstyle.rb:86:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/mozilla_nstreerange.rb:132:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true]),
modules/exploits/windows/browser/mozilla_interleaved_write.rb:79:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
modules/exploits/windows/browser/ms12_037_ie_colspan.rb:80:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ie_cgenericelement_uaf.rb:80:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms11_081_option.rb:62:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/adobe_flash_sps.rb:67:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/siemens_solid_edge_selistctrlx.rb:80:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/hp_alm_xgo_setshapenodetype_exec.rb:80:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/msxml_get_definition_code_exec.rb:131:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms11_050_mshtml_cobjectelement.rb:116:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/imgeviewer_tifmergemultifiles.rb:65:      [ OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true]) ]
modules/exploits/windows/browser/apple_quicktime_texml_font_table.rb:73:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/ie_execcommand_uaf.rb:83:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms12_004_midi.rb:102:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/zenworks_helplauncher_exec.rb:68:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]),
modules/exploits/windows/browser/mozilla_reduceright.rb:81:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/ibm_tivoli_pme_activex_bof.rb:107:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
modules/exploits/windows/browser/aladdin_choosefilepath_bof.rb:112:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ms11_093_ole32.rb:77:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/ntr_activex_check_bof.rb:139:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
modules/exploits/windows/browser/intrust_annotatex_add.rb:85:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true])
modules/exploits/windows/browser/apple_quicktime_mime_type.rb:93:        OptBool.new('OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
# grep -rn OBFUSCATE modules/ | grep Opt | cut -d '(' -f2- | sort -u | wc -l
10
# grep -rn OBFUSCATE modules/ | grep Opt | cut -d '(' -f2- | sort -u 
'OBFUSCATE', [false, 'Enable JavaScript obfuscation'])
'OBFUSCATE', [false, 'Enable JavaScript obfuscation', false])
'OBFUSCATE', [false, 'Enable JavaScript obfuscation', false]),
'OBFUSCATE', [false, 'Enable JavaScript obfuscation', true])
'OBFUSCATE', [false, 'Enable JavaScript obfuscation', true]),
'OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true])
'OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true]) ]
'OBFUSCATE', [false, 'Enable JavaScript Obfuscation', true]),
'OBFUSCATE', [false, 'Enable VBScript obfuscation', true])
'OBFUSCATE', [true, 'Obfuscate JavaScript content.', true])

Copy link
Contributor

@msutovsky-r7 msutovsky-r7 left a comment

Choose a reason for hiding this comment

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

msf exploit(multi/handler) > run
[*] Started reverse TCP handler on 192.168.3.7:4444 
[*] Sending stage (203846 bytes) to 10.5.132.152
[*] Meterpreter session 1 opened (192.168.3.7:4444 -> 10.5.132.152:49810) at 2025-07-25 08:12:34 +0200

meterpreter > sysinfo
Computer        : WIN10_1709_1000
OS              : Windows 10 1709 (10.0 Build 16299).
Architecture    : x64
System Language : en_US
Domain          : WORKGROUP
Logged On Users : 2
Meterpreter     : x64/windows
meterpreter > getuid
Server username: WIN10_1709_1000\msfuser

)

register_options([
OptString.new('FILENAME', [true, 'The JScript file name.', 'msf.js']),
Copy link
Contributor

Choose a reason for hiding this comment

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

IIRC, most of fileformat modules do use static file name, but they also create random file name if static file name is not supplied. I think that might be a way to be consistent with fileformat modules.

js_payload << "#{shell_var}.Run(\"#{cmd}\");"

if obfuscate
js_obfu = Rex::Exploitation::JSObfu.new(js_payload)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can use Msf::Exploit::JSObfu which would spare one require

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've made this change.

@msutovsky-r7 msutovsky-r7 self-assigned this Jul 25, 2025
@msutovsky-r7 msutovsky-r7 added the rn-modules release notes for new or majorly enhanced modules label Jul 28, 2025
@msutovsky-r7 msutovsky-r7 merged commit 12340ef into rapid7:master Jul 28, 2025
18 checks passed
@msutovsky-r7
Copy link
Contributor

msutovsky-r7 commented Jul 28, 2025

Release Notes

This adds a new file format module that drops a Windows Script Host JScript file containing a malicious payload.

@bcoles bcoles deleted the windows_script_host_jscript branch July 28, 2025 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants