pass14-环境说明
phpstudy中php版本为7.3.4nts
补充一点:upload-labs这个靶场要想全部通过,必须要 调整环境(phpstudy的环境不行,就自行搭建一个apache和php的环境),而且在我已经做好的前13关靶场中,php的版本切换非常正常。所以如果你没有做出来,也很正常,关键是要理解各种绕过的姿势。
pass14-提示和源码
检查图标内容开头2个字节
这里牵扯到一个知识点。先买个小关子。
这一关跟前几关都很不一样:
要求上传的是图片马。
源码:
function getReailFileType($filename){
$file = fopen($filename, "rb");
$bin = fread($file, 2);
fclose($file);
$strInfo = @unpack("C2chars", $bin);
$typeCode = intval($strInfo['chars1'].$strInfo['chars2']);
$fileType = '';
switch($typeCode){
case 255216:
$fileType = 'jpg';
break;
case 13780:
$fileType = 'png';
break;
case 7173:
$fileType = 'gif';
break;
default:
$fileType = 'unknown';
}
return $fileType;
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$file_type = getReailFileType($temp_file);
if($file_type == 'unknown'){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
其实在switch中已经写的很清楚了: 255216–》JPG 13780—〉PNG 7173–》GIF 其余都是unknown
为什么读取前两个字节就知道这属于什么文件呢?这就是“文件头”的概念
pass14-文件头
不同的文件类型(txt,exe,jpg等),编码方式不同,其解析方式也会不一样(打开方式的程序也会不一样)。
比如练习过CTF- MISC的人一定都知道:二进制文件用winhex打开很友好,但是用记事本或者Notepas++打开就是一堆乱码。
对应的解析工具在打开任意一个文件之前,必须首先确定这个文件能不能解析,规不规范。(只修改文件的扩展名也没有用哦)
所以根据什么来判断这个文件真正的打开方式,判断文件的类型呢?只看文件扩展名是不是就不靠谱了,只能看文件头。
所以一定的文件一定在产生的时候对应自己的规范,文件头就必须这么写。(这里不考虑一些隐写或者恶意修改等异常情况)
这个规范到底是什么呢?
(文件头长度不同文件类型是不一样的)
比如: JPEG (jpg),文件头:FFD8FF
PNG (png),文件头:89504E47
GIF (gif),文件头:47494638
TIFF (tif),文件头:49492A00
Windows Bitmap (bmp),文件头:424D
CAD (dwg),文件头:41433130
Adobe Photoshop (psd),文件头:38425053
Rich Text Format (rtf),文件头:7B5C727466
XML (xml),文件头:3C3F786D6C
HTML (html),文件头:68746D6C3E
上面的要不要记?那肯定是不用的,人生这么苦短,记这些有什么意义,简单看一看就行,实际要用再查就行(实际你用多了早就记住不少了)
我在这里列举一些最为常见的文件头(网安可能经常会用到的):
常见文件头列举
1.png图片文件包括8字节: 89 50 4E 47 0D 0A 1A 0A 即为.PNG
2.jpg图片文件包括2字节: FF D8
3.gif图片文件包括6字节: 47 49 46 38 39|37 61 即为GIF89(7)a
4.bmp图片文件包括2字节: 42 4D 即为BM
5…class文件的文件头:ca fe ba be
简单来说这种还是很靠谱的,如果攻击者在上传的时候,故意将php扩展名改为了jpg,但是如果其校验的时候看的是文件内容的前两个字节,那还是无法绕过的。
如何产生有一句话木马的图片呢?
制作图片马
Windows中命令:(cmder)
copy huaji.jpg /b + shell.php /a shell.gif
看到shell.gif生成了
现在如果用记事本或者notepad++打开发现文件头就是GIF89a。
补充如果是linux那么命令就是
cat huaji.jpg shell.php > shell.jpg
pass14-上传图片马
现在准备上传:
上传是成功了,但是连接webshell失败了。
因为代码在图片中,没有办法执行。
现在该怎么办呢?
可以看看提示:
要利用文件包含漏洞。
在文件上传靶场里面有这么一个文件,可以直接访问:
upload-labs/include.php
<?php
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
include $file;
}else{
show_source(__file__);
}
?>
连接的webshell改成:
连接webshell成功
pass15
依然是图片马。
看源码:
function isImage($filename){
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);
if(stripos($types,$ext)>=0){
return $ext;
}else{
return false;
}
}else{
return false;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
这一关主要用到一个函数getimagesize()
提示: 通过getimagesize()来判断上传的文件是否是图片文件。
关于这个函数的介绍,可以看看官网的介绍: https://www.php.net/getimagesize
getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。
如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 false 并产生一条 E_WARNING 级的错误。
貌似没有其他的拦截。
最关键的就是如果上传的不是一张图片那么久返回false,报异常。
还是利用14关的图片马,上传:(上传之前把之前上传的清空)
然后还是利用文件包含漏洞,连接webshell(URL结构和刚才一致) 再次上传成功。
所以这一关就是很简单(有了14关的铺垫),就是学习了一个函数getimagesize
pass16
也是图片马。 看源码:
function isImage($filename){
$image_type = exif_imagetype($filename);
switch ($image_type) {
case IMAGETYPE_GIF:
return "gif";
break;
case IMAGETYPE_JPEG:
return "jpg";
break;
case IMAGETYPE_PNG:
return "png";
break;
default:
return false;
break;
}
}
$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
$temp_file = $_FILES['upload_file']['tmp_name'];
$res = isImage($temp_file);
if(!$res){
$msg = "文件未知,上传失败!";
}else{
$img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
if(move_uploaded_file($temp_file,$img_path)){
$is_upload = true;
} else {
$msg = "上传出错!";
}
}
}
这一关利用到了一个新的函数exif_imagetype()
提示:
关于这个函数的介绍:
exif_imagetype() 读取一个图像的第一个字节并检查其签名。
本函数可用来避免调用其它 exif 函数用到了不支持的文件类型上或和 $_SERVER[‘HTTP_ACCEPT’] 结合使用来检查浏览器是否可以显示某个指定的图像。
这个其实和第14关的文件头检查是差不多的。
但是这一关要注意:需要开启php_exif模块
所以需要更改PHP的版本: 更改成线程安全的7.4.22
(我这里就是用的7.4的版本,是线程安全的,具体的小版本实在是没有记录)
同时还要启用扩展:
上传木马之前先清空一下之前上传的。 然后开始上传:
好吧上传没有成功。。。
但是某一次我的同学用这个版本成功了,所以大家也可以多试试,当然也可以试试其他版本。
最后只能说一点吧,掌握绕过的姿势很重要,至于有没有成功,不用太纠结,本身环境对于这种绕过影响是很大的,所以我pass16没有成功我也没有气馁。
再接再厉吧
欢迎关注本人懒的更新的公众号“小东方不败”!欢迎大家跟我交流。
|