java审计-RCE/SSRF
java开发语言中可以执行命令的函数有Runtime.getRuntime.exec和ProcessBuilder.start
java1.5之前用Runtime.getRuntime.exec 1.5后用ProcessBuilder类构造进程
1.ProcessBuilder命令执行漏洞
ProcessBuilder执行命令的方式如下:
ProcessBuilder pb = new ProcessBuilder("command","param");
Process process = pb.start();
例如ProcessBuilder执行ls -al命令
public class exec{ public static void main(String[] args ) throws IOException { //执行系统命令 ProcessBuilder p = new ProcessBuilder("ls","-al");
//ProcessBuilder p = new ProcessBuilder("ping","-t","3",ip); #这里不能用分号链接 127.0.0.1;id 会报错
//ProcessBuilder p = new ProcessBuilder("bash","-c",exec); #这里调用了bash才可以链接命令执行
Process pb = p.start(); //获取执行完成命令后的结果并输出 String line; BufferedReader reader = new BufferedReader(new InputStreamReader(pb.getInputStream(),"GBK")); #缓冲区读取输入流 while((line= reader.readLine())!=null){ #并读取输入流后逐行写入字符串中 System.out.println(line); } reader.close(); } }
tips:直接使用ProcessBuilder进行命令执行的时候是不支持用;号或者&来连接命令一起执行,这些需要使用linux管道之类的功能,必须得使用shell程序来执行
2.Runtime exec 命令执行漏洞
Runtime exec 执行字符串参数和数组参数
Process proc = Runtime.getRuntime(),exec("ping 127.0.0.1");是正常的
当执行 Process proc = Runtime.getRuntime(),exec("ping 127.0.0.1;id")是没有返回值的
因为在exec调用的过程中会对通过StringTokenizer进行处理,它会对传入的字符串进行分割再返回
结论
所以要通过数组类型的传参才能进行多个命令执行
String command ="/bin/sh -c \ "ping -t 3 ip;id \""; \\exec执行字符串参数
String[] command = { "/bin/sh","-c","ping -t 3 ip;id"}` \\执行数组参数
Runtime exec 不以参数的形式来传命令执行
Process proc = Runtime.getRuntime(),exec(cmd); cmd = sh -c ls ;cat /etc/passwd
#因为stringTokenizer对空格处理拆分导致命令无法执行 可以用${IFS},${IFS}$9等替换空格 cmd = sh -c ls ;cat${IFS}/etc/passwd #修改之后会有以下报错 Invaild character found in the request target . The valid characters are defined in RFC 7230 and RFC 3986 RFC规范中url只允许包含 a-z A-Z 0-9 -_.~ !*'();:@&=+$,/?#[]共84个 因此要进行url编码 修改前:cmd = sh -c ls ;cat${IFS}/etc/passwd 编码后:cmd = sh%20-c%20ls;cat$%7BIFS%7B/etc/passwd
SSRF
ssrf通常出现在社交分享,远程图片下载,图片或文章收藏,转码,通过网址在线翻译,网站采集,从远程服务器请求资源等功能点处
java中的SSRF只支持sun.net.www.protocal下所有的协议 file/ftp/http/https/jar/mailto/netdoc
特别留意能够发起http请求的类和函数
URLConnection
URL
HttpURLConnection
HttpClient
OkHttpClient.newCall.execute
1.urlConnection
String url = request.getParameter("url");
URL u = new URL(url);
URLConnection urlConnection = u.openConnection(); #urlConnection获取资源
BufferedReader in = new BufferedReader(new InputStreaReader(urlConnection.getInputSream())); #输入流读取urlconnection对象
String inpuLine;
StringBuffer html = new StringBuffer();
while((inputLine=in.readLine())!= null){
html.append(inputLine);
}
in.close();
return html.toString();
2.HttpURLConnection
继承于URLConnection 用于向指定网站发送GET请求与POST请求.
HttpURLConnection httpUrl = (HttpURLConnection)urlConnection;
BufferedReader in = new BufferedReader(new InputStreaReader(urlConnection.getInputSream()));
3.Request
request与python中的request对象类似,主要用来发http请求
String url = request.getParameter("url");
return Request.Get(url).execute(),returnContent().toString();
4.openStream
通过url对象的openStream()方法,能够得到指定资源的输入流.
String downLoadImgFileName = Files.getNameWithoutExtension(url)+"."+Files.getFileExtension(url); URL u = new URL(url); inputStream = u.openStream();//send request outputStream = response.getOutputStream(); while((length = inputStream.read(bytes))>0){ outputStream.write(bytes,0,length);
5.HttpClient
client.execute(httpGet); BufferedReader rd = new BufferedReader(new InputStreamReader (client.execute(httpdGet).getEntity().getContent())); StringBuffer result = new StringBuffer(); String line=""; while((line = rd.readLine())!=null) { result.append(line); }
浙公网安备 33010602011771号