PHP SECURITY CALENDAR 2017 学习笔记

:)

day1 Wish List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Challenge {
const UPLOAD_DIRECTORY = './solutions/';
private $file;
private $whitelist;

public function __construct($file) {
$this->file = $file;
$this->whitelist = range(1, 24);
}

public function __destruct() {
if (in_array($this->file['name'], $this->whitelist)) {
move_uploaded_file(
$this->file['tmp_name'],
self::UPLOAD_DIRECTORY . $this->file['name']
);
}
}
}

$challenge = new Challenge($_FILES['solution']);

这里是对上传的文件名做了白名单检查,要求是文件名为1-23的数字。然而,这里的判断用了in_array,但是没有设置$strict = true

如果没有设置 strict 则使用宽松的比较 —— php.net

所以文件名为1backdoor.php就能绕过白名单了

day2 Twig

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
// composer require "twig/twig"
require 'vendor/autoload.php';

class Template {
private $twig;

public function __construct() {
$indexTemplate = '<img ' .
'src="https://loremflickr.com/320/240">' .
'<a href="{{link|escape}}">Next slide »</a>';

// Default twig setup, simulate loading
// index.html file from disk
$loader = new Twig\Loader\ArrayLoader([
'index.html' => $indexTemplate
]);
$this->twig = new Twig\Environment($loader);
}

public function getNexSlideUrl() {
$nextSlide = $_GET['nextSlide'];
return filter_var($nextSlide, FILTER_VALIDATE_URL);
}

public function render() {
echo $this->twig->render(
'index.html',
['link' => $this->getNexSlideUrl()]
);
}
}

(new Template())->render();

第10行使用了模板输出,link生成的方式为getNexSlideUrl(),在这个函数中,验证是否为URL格式则用了filter_var,然而用js协议就能绕过?nextSlide=javascript://comment%250aalert(1),这样只要点击链接,就能触发xss

day3 Snow Flake

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
function __autoload($className) {
include $className;
}

$controllerName = $_GET['c'];
$data = $_GET['d'];

if (class_exists($controllerName)) {
$controller = new $controllerName($data['t'], $data['v']);
$controller->render();
} else {
echo 'There is no page with this name';
}

class HomeController {
private $template;
private $variables;

public function __construct($template, $variables) {
$this->template = $template;
$this->variables = $variables;
}

public function render() {
if ($this->variables['new']) {
echo 'controller rendering new response';
} else {
echo 'controller rendering old response';
}
}
}
1
if (class_exists($controllerName))

这里会触发__autoload,如果php < 5.3,那当/?c=../../../../etc/passwd时,会将文件包含进来。
那么当php版本大于5.3,就可以使用php内置的类,比如SimpleXMLElement就能造成xxe盲攻击,xxe近期会写一篇文章(愿此flag不倒)

day4 False Beard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Login {
public function __construct($user, $pass) {
$this->loginViaXml($user, $pass);
}

public function loginViaXml($user, $pass) {
if (
(!strpos($user, '<') || !strpos($user, '>')) &&
(!strpos($pass, '<') || !strpos($pass, '>'))
) {
$format = '<?xml version="1.0"?>' .
'<user v="%s"/><pass v="%s"/>';
$xml = sprintf($format, $user, $pass);
$xmlElement = new SimpleXMLElement($xml);
// Perform the actual login.
$this->login($xmlElement);
}
}
}

new Login($_POST['username'], $_POST['password']);

很明显是个xxe,使用了strpos

strpos — 查找字符串首次出现的位置

1
2
var_dump(strpos("h", "helloword"));
// bool(false)

所以只要usernamepassword的第一个字符是<就能绕过判断,进行xxe攻击
username=<"><injected-tag%20property="&password=<injected-tag>