Networked-Writeup

概述 (Overview)

74921620.png

时间: 2021-07-14
机器作者: guly
困难程度: easy
描述: 考察对Web系统的信息挖掘能力,并利用白盒审计寻找攻击的立足点。
Flags:User: <md5>, Root: <md5>
MACHINE TAGS:

  • Web
  • PHP
  • Arbitrary File Upload
  • Injection

攻击链 (Kiillchain)

通过使用 nmap 枚举出目标系统对外开放的服务端口,枚举Web服务的路径发现存在文件上传功能页面、站点备份压缩包。下载压缩包后对PHP代码进行白盒审计,绕过文件上传check逻辑上传PHP脚本,利用 Apache多后缀解析漏洞 执行上传的PHP脚本代码,成功获得立足点。在 guly 用户文件夹下发现 user.txt 文件,但当前shell无权限查看。分析定时任务执行脚本成功完成用户shell的横移。
执行 sudo -l ,发现可以已root身份执行的 changename.sh 脚本,使用搜索了解到网卡配置 NAME 值可注入恶意bash命令,使用该风险成功完成提权。

枚举(Enumeration)

开局使用 nmap 对目标服务器的端口进行快速的枚举:

nmap -n -Pn -p- -sV --min-rate 2000 10.10.10.146

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey: 
|   2048 22:75:d7:a7:4f:81:a7:af:52:66:e5:27:44:b1:01:5b (RSA)
|   256 2d:63:28:fc:a2:99:c7:d4:35:b9:45:9a:4b:38:f9:c8 (ECDSA)
|_  256 73:cd:a0:5b:84:10:7d:a7:1c:7c:61:1d:f5:54:cf:c4 (ED25519)
80/tcp open  http    Apache httpd 2.4.6 ((CentOS) PHP/5.4.16)
|_http-server-header: Apache/2.4.6 (CentOS) PHP/5.4.16
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).

开放的服务很少,存在一个 apache 服务器,并且推断出目标系统可能是 Centos。浏览器查看后存在一段文字:

45200186.png

从描述中获知到是存在一个上传的,使用 dirsearch 枚举一下目录:

# Dirsearch started Wed Jul 14 00:35:23 2021 as: dirsearch.py -u 10.10.10.146 -o dirsearch.txt


301   235B   http://10.10.10.146:80/backup    -> REDIRECTS TO: http://10.10.10.146/backup/
200   885B   http://10.10.10.146:80/backup/
200   229B   http://10.10.10.146:80/index.php
200   229B   http://10.10.10.146:80/index.php/login/
200     1KB  http://10.10.10.146:80/photos.php
200   169B   http://10.10.10.146:80/upload.php
200     2B   http://10.10.10.146:80/uploads/

在 backup 页面中发现存在一个 backup.tar 的压缩包,下载后得到上诉目录的 php 源码。

45628172.png

立足点(Foothold)

审计 upload.php 文件:

<?php
require '/var/www/html/lib.php';

define("UPLOAD_DIR", "/var/www/html/uploads/");

if( isset($_POST['submit']) ) {
  if (!empty($_FILES["myFile"])) {
    $myFile = $_FILES["myFile"];

    if (!(check_file_type($_FILES["myFile"]) && filesize($_FILES['myFile']['tmp_name']) < 60000)) {
      echo '<pre>Invalid image file.</pre>';
      displayform();
    }

    if ($myFile["error"] !== UPLOAD_ERR_OK) {
        echo "<p>An error occurred.</p>";
        displayform();
        exit;
    }

    //$name = $_SERVER['REMOTE_ADDR'].'-'. $myFile["name"];
    list ($foo,$ext) = getnameUpload($myFile["name"]);
    $validext = array('.jpg', '.png', '.gif', '.jpeg');
    $valid = false;
    foreach ($validext as $vext) {
      if (substr_compare($myFile["name"], $vext, -strlen($vext)) === 0) {
        $valid = true;
      }
    }

    if (!($valid)) {
      echo "<p>Invalid image file</p>";
      displayform();
      exit;
    }
    $name = str_replace('.','_',$_SERVER['REMOTE_ADDR']).'.'.$ext;

    $success = move_uploaded_file($myFile["tmp_name"], UPLOAD_DIR . $name);
    if (!$success) {
        echo "<p>Unable to save file.</p>";
        exit;
    }
    echo "<p>file uploaded, refresh gallery</p>";

    // set proper permissions on the new file
    chmod(UPLOAD_DIR . $name, 0644);
  }
} else {
  displayform();
}
?>

分析得出接收一个上传的文件,通过 check_file_type 函数验证下类型和文件大小,取文件后缀名判断是否为图片,最后利用 move_uploaded_file 函数保存上传的文件。

看下 check_file_type 函数是如何校验的:

function check_file_type($file) {
  $mime_type = file_mime_type($file);
  if (strpos($mime_type, 'image/') === 0) {
      return true;
  } else {
      return false;
  }  
}

利用了 file_mime_type 方法:

function file_mime_type($file) {
  $regexp = '/^([a-z\-]+\/[a-z0-9\-\.\+]+)(;\s.+)?$/';
  if (function_exists('finfo_file')) {
    $finfo = finfo_open(FILEINFO_MIME); 
    if (is_resource($finfo)) // It is possible that a FALSE value is returned, if there is no magic MIME database file found on the system
    {
      $mime = @finfo_file($finfo, $file['tmp_name']);
      finfo_close($finfo);
      if (is_string($mime) && preg_match($regexp, $mime, $matches)) {
        $file_type = $matches[1];
        return $file_type;
      }
    }
  }
  if (function_exists('mime_content_type'))
  {
    $file_type = @mime_content_type($file['tmp_name']);
    if (strlen($file_type) > 0) // It's possible that mime_content_type() returns FALSE or an empty string
    {
      return $file_type;
    }
  }
  return $file['type'];
}

很明显是验证了文件的 MIME 类型,在看一眼后缀名是怎么取的 getnameUpload:

function getnameUpload($filename) {
  $pieces = explode('.',$filename);
  $name= array_shift($pieces);
  $name = str_replace('_','.',$name);
  $ext = implode('.',$pieces);
  return array($name,$ext);
}

这里利用文件的 MIME 类型,绕过检测判断,请求包中还需要加入Content-Type字段 image/png 值,文件首行加入 GIF89a; 绕过对上传文件类型检查的判断。

64074899.png

查看 photos.php 发现文件已经成功上传至服务器:

64058465.png

随后在此处尬住了一下午,根据版本尝试 apache httpd换行解析漏洞(CVE-2017-15715) 失败。

最后发现利用 Apache HTTPD 多后缀解析漏洞 能成功反弹shell:

64244735.png

apache解析文件名从右向左解析,即使最右边的文件格式在mime.types文件内,只要文件中出现.php,就可以被php模块解析。该漏洞和apache版本和php版本无关,属于用户配置不当造成的解析漏洞 AddHandler application/x-httpd-php .php

尝试使用 md5sum 对目录文件进行比对,发现服务文件与本地一致,不存在隐藏内容,转而查找其他可疑内容。
64601229.png

横向移动(Lateral Movement)

gulu 用户下发现多个文件,其中的 user.txtgulu 用户可读,看来是需要进行横移了:

64366197.png

查看下 crontab.gulycheck_attack.php 内容:

64455809.png
每三分钟会执行一次定时任务运行PHP脚,该脚本会读取uploads文件夹内容,检查符合符合IP + filename命名的文件,将其带入exec函数中去执行。结合先前的文件上传,用户是可以控制$value` 变量的,很明显这里是存在命令注入漏洞。

scandir() 函数返回指定目录中的文件和目录的数组。

cduploads 文件夹,使用 touch 配合双引号写入nc反弹语句。等待定时任务执行,成功获得 guly 用户shell:

70597513.png

权限提升(Privilege Escalation)

运行 sudo -l 发现存在运行已root身份执行 changename.sh:

71326819.png
查看脚本内容,结合搜索搜索了解到,network-scripts 为存放对特定的网卡进行设置的配置文件,这段 bash 的含义是通过用户输入的内容生成新的网卡配置:
73420648.png

尝试搜索看看是否存在可用的exploit:

74085754.png

最终指向 https://seclists.org/fulldisclosure/2019/Apr/24 文件,从中了解到当用户可控 NAME 参数时,可以注入恶意的 bash 实现命令注入:

74138652.png

测试一下运行脚本,并在 NAME 中传递 /bin/id,可以看到最终回显了该命令的执行结果:

74251456.png

接下来就简单了,只需要传入 /bin/bash 就可以轻松实现权限提权:
74843181.png


77418536.png

参考