新手教程之和webshell学php(二)

#info

本期主要介绍webshell中文件操作类函数

%E6%96%87%E4%BB%B6%E6%93%8D%E4%BD%9C

#function

filew(file_write写文件)

##实现代码

function filew($filename, $filedata, $filemode)
{
    if ((!is_writable($filename)) && file_exists($filename)) {
        chmod($filename, 0666);
    }
    $handle = fopen($filename, $filemode);
    $key = fputs($handle, $filedata);
    fclose($handle);
    return $key;
}

##功能用途

用于webshell写入文件

##实现思路

首先判断了文件是否存在,如果存在不可写,赋予文件读写权限

##知识点

  • chmod 0666 改变文件权限

####在这里科普一下777 在Linux下,文件类型包含如下几类:

d:目录directory
	
l:符号链接link
	
s:套接字socket
	
c:字符设备char
	
p:命名管道pipe
	
-:其他,不属于以上几类

文件创建后,有三种访问方式

读(read):显示内容
	
写(write):编辑内容,删除文件
	
执行(execute):执行文件

针对用户,文件有三类权限:

创建人(user)权限:创建文件的人

组(group)用户权限:和拥有者处于同一用户组的其他人

其他(other):用户权限

首先要清楚一点mode是一个3位八进制数:

第一位表示创建者权限

第二位表示组用户权限

第三位表示其他用户权限

再举一个具体的例子:

400:创建者可读

200:创建者可写

100:创建者可执行

040:组用户可读

020:组用户可写

010:组用户可执行

004:其他用户可读

002:其他用户可写

001:其他用户可执行

所以 chmod($filename, 0666); 是将文件权限变更为所有人都拥有读写权限

拥有者(4 write +2 read)
  
组用户(4 write + 2 read)
  
其他用户(4 write + 2 read)
  • is_writable(判断文件是否可写)

    通过上述知识科普,只要nginx/apche/tomcat所属组有文件的写权限即可。

    php还有类似
    is_readable(文件是否可读)

    is_executable(文件是否可执行)

  • file_exists(判断文件是否存在)

    这里有一篇当file_exists遇到eval的文章供大家参考

    https://www.freebuf.com/articles/web/53656.html

  • fopen fclose

    如第一个参数可控,可能存在SSRF漏洞,漏洞利用老哥们可搜索论坛帖子。

      $handle = fopen("/home/rasmus/file.txt", "r");
      	
      $handle = fopen("http://www.example.com/", "r");
      
      $handle = fopen("file:///etc/passwd", "r");
      	
      $handle = fopen("ftp://user:[email protected]/somefile.txt", "w");
    

    medium上面有大佬对SSRF进行介绍的帖子,介绍的非常详细,还请各位看官移步medium

      https://medium.com/@madrobot/ssrf-server-side-request-forgery-types-and-ways-to-exploit-it-part-1-29d034c27978
      
      https://medium.com/@madrobot/ssrf-server-side-request-forgery-types-and-ways-to-exploit-it-part-2-a085ec4332c0
      
      https://medium.com/@madrobot/ssrf-server-side-request-forgery-types-and-ways-to-exploit-it-part-3-b0f5997e3739
    

filer(file_read 读文件)

##实现代码

function filer($filename)
{
    $handle = fopen($filename, 'r');
    $filedata = fread($handle, filesize($filename));
    fclose($handle);
    return $filedata;
}

##功能用途

用于webshell文件读取

##实现思路

直接读取文件

##知识点

  • fsopen

关于mode值的介绍,如果是文件读取的话,一般都是用fopen($filename, 'r')

具体关于mode的介绍如下所示:

	"r". 只读方式打开,将文件指针指向文件头。
	"r+"  读写方式打开,将文件指针指向文件头。
	"w"	  写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
	"w+" 读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
	"a"	  写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
	"a+" 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
	"x"	  创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。

fileu(file_upload 文件上传)

##实现代码

function fileu($filenamea, $filenameb)
{
    $key = move_uploaded_file($filenamea, $filenameb) ? true : false;
    if (!$key) {
        $key = copy($filenamea, $filenameb) ? true : false;
    }
    return $key;
}

##功能用途

用于webshell实现文件上传

##实现思路

尝试将POST的文件,即$_FILE["file"]["tmp_name"]上传到服务器.如果移动失败使用copy方法进行复制。

##知识点

  • move_uploaded_file copy

初步看了一下官方文档说明,思考move_uploaded_file和copy有什么区别。move_uploaded_file,如果不是通过HTTP POST上传的合法文件,不予移动,所以这里作者又补充了copy写法。

我们再看一个写法,如果move_uploaded_file和copy方法的第二个参数可控,思考一下会发生什么?

	<?php
	// $dest = $_GET['dest'];
	$dest = 'xxx/tmp/123.php';
	copy('./xxx.jpg', $dest);
  • POST

    这是说到了文件上传,初学者在开发的过程中可能会遇到?为什么我用_$POST取不到前端POST的数据呢?

    答案是因为前端发送数据格式josn,而使用$_POST数据取不到,应该使用\file_get_contents("php://input")

    $_POST只能取到appilicat/x-www-form-urlencoded和form-data的数据,取不到application/json数据

    如果是application/json POST的数据只可以通过,file_get_contents("php://input")取到。

    具体源码分析详见

    https://segmentfault.com/a/1190000016868502?utm_source=tag-newest

filed(file_download 文件下载)

##实现代码

function filed($filename)
{
    if (!file_exists($filename)) return false;
    ob_end_clean();
    $name = basename($filename);
    $array = explode('.', $name);
    header('Content-type: application/x-' . array_pop($array));
    header('Content-Disposition: attachment; filename=' . $name);
    header('Content-Length: ' . filesize($filename));
    @readfile($filename);
    exit;
}

##功能用途

用于webshell下载文件

##实现思路

首先判断文件是否存在,清空缓存区,根据文件后缀判指定文件类型实现文件下载。

##知识点

  • ob_start ob_end_clean readfile

    缓冲区相关内容,不在这里详细赘述。

    reafile将文件内容读取缓冲区

  • @错误抑制符

    试想一下,如果在生产环境,如果服务器在运行中产生了一个错误,会报XX/xxx.php. xxx 行出现问题,这样就会泄露一些服务器的一些敏感信息,这样的结果通常是我们不希望看见的。所以可以在函数前面增加@符,隐藏这些错误信息。

    和@符类似的方法还有

      error_reporting(0);
        
      ini_set('display_errors', 'Off');
    
  • Mime-Type

    互联网媒体类型,也叫做MIME类型。最初MIME是用于电子邮件系统的,后来HTTP也采用了这一方案。

    Mime-Type 对照表

    http://tool.oschina.net/commons/

    在测试上传功能点时老生常谈了,某些开发只校验了Mime-Type,并没有在后端校验文件后缀,直接导致了get-shell.或者见过一些开发连文件后缀都不会取。

    既然在这里提到了文件上传,那就稍微补充一点,我自己认为文件上传存在的风险点了:

      1、中间件漏洞,apache、nginx、IIS、ImageMagick
      2、加载远程图片,限制host和协议,避免出现ssrf
      3、路径穿越
      4、并发竞争
      5、大文件上传造成Dos
      6、上传视频耗费CDN流量费
    

    在这里给出几种取文件后缀名的demo,当然了代码写的并不健壮,还需各位去补充判断是否为array、isset参数名是否存在等等。

      $ext = strrchr($filename, '.');
        
      $ext = pathinfo($filename)['extension'];
        
      $ext = array_pop(explode('.', $filename));

一个优秀的webshell的PHP使用技巧真的是花样百出
另外 PHP是最好的语言 哈哈