├── 20171220_smb_at_schedule.pcap ├── 20171220_smb_metasploit_psexec_pth_download_meterpreter.pcap ├── 20171220_smb_mimikatz_copy.pcap ├── 20171220_smb_mimikatz_copy_to_host.pcap ├── 20171220_smb_net_user.pcap ├── 20171220_smb_psexec_add_user.pcap ├── 20171220_smb_psexec_mimikatz_ticket_dump.pcap ├── LICENSE ├── README.md ├── SHA256SUMS.txt ├── bad_smb_share.bro ├── mal_smb_share.bro ├── virustotal.bro └── vt_check.bro /20171220_smb_at_schedule.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_at_schedule.pcap -------------------------------------------------------------------------------- /20171220_smb_metasploit_psexec_pth_download_meterpreter.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_metasploit_psexec_pth_download_meterpreter.pcap -------------------------------------------------------------------------------- /20171220_smb_mimikatz_copy.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_mimikatz_copy.pcap -------------------------------------------------------------------------------- /20171220_smb_mimikatz_copy_to_host.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_mimikatz_copy_to_host.pcap -------------------------------------------------------------------------------- /20171220_smb_net_user.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_net_user.pcap -------------------------------------------------------------------------------- /20171220_smb_psexec_add_user.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_psexec_add_user.pcap -------------------------------------------------------------------------------- /20171220_smb_psexec_mimikatz_ticket_dump.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianyulab/Hunting_lateral_movement/954a1b3ca1c157e443d8da1f7e7651674a9c466a/20171220_smb_psexec_mimikatz_ticket_dump.pcap -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 天御[攻防]实验室 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hunting_lateral_movement 2 | 《横向移动攻击与检测技术》专栏文章 3 | 4 | ### 目录: 5 | 6 | * [1.威胁猎杀实战(六):横向移动攻击检测](https://mp.weixin.qq.com/s?__biz=MzU0MzgyMzM2Nw==&mid=2247483843&idx=1&sn=b3c26b8593f0cbe2b02c896df7b0f7f9&chksm=fb04c2abcc734bbdaebb1dcae8697d8a5e66e7ea1f458e2695d3da065211c3958f97b8c12586&token=641983223&lang=zh_CN#rd) 7 | -------------------------------------------------------------------------------- /SHA256SUMS.txt: -------------------------------------------------------------------------------- 1 | 81a9a85c521d1f9d897c3722c2071bf374be174994f03ef1e9097b8b0a225c37 20171220_smb_at_schedule.pcap 2 | d566704997dd678a2263387c4267cec35dc1030028023b0de6d7ed70ced5bba8 20171220_smb_metasploit_psexec_pth_download_meterpreter.pcap 3 | 0c47499d1f2df131ba28726e14d5fecebe9d274bef95383cb7e7e9fd5f071787 20171220_smb_mimikatz_copy.pcap 4 | 8295ee24914d752eb212f1c48e6f0cd5bdc7bc9ae30f723c8cb9add519727a24 20171220_smb_mimikatz_copy_to_host.pcap 5 | ed7f578d07f849029ca615861696054a38ab89421dcfaf63a8e38e2ea61cba2a 20171220_smb_net_user.pcap 6 | e7edc223e673620a5fd096e78290d27cbfc033879a9570b6dccaef74de88d781 20171220_smb_psexec_add_user.pcap 7 | 098d75a9668ccaa179f2889c11f666c23163391535d0a0981dd8d6aee9ae8d73 20171220_smb_psexec_mimikatz_ticket_dump.pcap 8 | 2fe9f48dc4b7eaa51e107f24cc7d86f6558008110669d4ad662efd311f114ca5 bad_smb_share.bro 9 | 2fa20c1c20b98bd9bc482aed12743f3eedd7dafffd88bdcbb25966a98f941742 LICENSE 10 | 91867f6f77902f0af6db54f8653d7d7e75e5acf308d67bb905380f0c55987821 mal_smb_share.bro 11 | 233d5f8255fc6027c6f7be8ca4131394abcce654f52d32e06b6018e95e4893a2 README.md 12 | 577a91b24a0a394c8c0328bae96e505b421e1e38bdc56e19c53fd2fff78cbe2e virustotal.bro 13 | ddb1404d2d2307f107a19e6b2525779acf27e2d689c6d6de7d45e9d4f941e064 vt_check.bro 14 | -------------------------------------------------------------------------------- /bad_smb_share.bro: -------------------------------------------------------------------------------- 1 | # Version 1.0 (May 2019) 2 | # 3 | # Authors: Zer0d0y@天御实验室 (Zer0d0y@tianyulab.com) 4 | # 5 | # Copyright (c) 2019, 天御[攻防]实验室. 6 | # All rights reserved. 7 | # Licensed under the BSD 3-Clause license. 8 | # 9 | # 支持Zeek Version v2.6.x 10 | # 11 | # 测试:bro -C -r smb_net_user.pcap bad_smb_share.bro 12 | 13 | @load base/frameworks/files 14 | @load base/frameworks/notice 15 | # @load policy/protocols/smb # For Bro Version v2.5.x 16 | 17 | export { redef enum Notice::Type += { Match }; 18 | global isTrusted = T; # 提供IP白名单支持 19 | global trustedIPs: set[addr] = {192.168.8.1,192.168.8.254} &redef; 20 | function hostAdminCheck(sourceip : addr) : bool 21 | { 22 | if (sourceip !in trustedIPs) 23 | { 24 | return F; 25 | } 26 | else 27 | { 28 | return T; 29 | } 30 | } 31 | event smb2_tree_connect_request(c : connection, hdr : SMB2::Header, path : string) 32 | { 33 | isTrusted = hostAdminCheck(c$id$orig_h); 34 | if (isTrusted == F) { 35 | if ("IPC$" in path || "ADMIN$" in path || "C$" in path) 36 | { 37 | NOTICE([$note=Match, $msg=fmt("Potentially Malicious Use of an Administrative Share"), $sub=fmt("%s",path), $conn=c]); 38 | } 39 | } 40 | } 41 | event smb1_tree_connect_andx_request(c : connection, hdr : SMB1::Header, path : string, service : string) 42 | { 43 | isTrusted = hostAdminCheck(c$id$orig_h); 44 | if (isTrusted ==F) { 45 | if ("IPC$" in path || "ADMIN$" in path || "C$" in path) 46 | { 47 | NOTICE([$note=Match, $msg=fmt("Potentially Malicious Use of an Administrative Share"), $sub=fmt ("%s",path), $conn=c]); 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /mal_smb_share.bro: -------------------------------------------------------------------------------- 1 | @load base/frameworks/files 2 | @load base/frameworks/notice 3 | @load frameworks/files/hash-all-files 4 | 5 | export { 6 | redef enum Notice::Type += { 7 | SMB 8 | }; 9 | 10 | 11 | # url needed to use VirusTotal API 12 | const vt_url = "https://www.virustotal.com/vtapi/v2/file/report" &redef; 13 | 14 | # VirusTotal API key 15 | const vt_apikey = "这里填写 VT API key" &redef; 16 | 17 | # threshold of Anti-Virus hits that must be met to trigger an alert 18 | const notice_threshold = 2 &redef; 19 | 20 | } 21 | 22 | 23 | event file_hash(f: fa_file, kind: string, hash: string) 24 | { 25 | # If the file "f" for the event has a source type, and if the source type 26 | # equals SMB, check file hash against VirusTotal 27 | if ( f?$source && f$source == "SMB" ) 28 | { 29 | local data = fmt("resource=%s", hash); 30 | 31 | local key = fmt("-d apikey=%s",vt_apikey); 32 | 33 | # HTTP request out to VirusTotal via API 34 | local req: ActiveHTTP::Request = ActiveHTTP::Request($url=vt_url, $method="POST",$client_data=data, $addl_curl_args=key); 35 | 36 | when (local res = ActiveHTTP::request(req)) 37 | { 38 | if ( |res| > 0) 39 | { 40 | if ( res?$body ) 41 | { 42 | local body = res$body; 43 | 44 | local tmp = split_string(res$body,/\}\},/); 45 | 46 | if ( |tmp| != 0 ) 47 | { 48 | local stuff = split_string( tmp[1], /\,/ ); 49 | 50 | 51 | # splitting the string that contains the amount of 52 | # positive anti-virus hits on ":" "positives:23" 53 | local pos = split_string(stuff[9],/\:/); 54 | 55 | # converting the string from variable pos into a 56 | # integer 57 | local notic = to_int(pos[1]); 58 | 59 | # If the number of positives (number stored in variable 60 | # notic) equals or exceeds the threshold, generate a 61 | # notice 62 | if (notic >= notice_threshold ) 63 | { 64 | 65 | local msg = fmt("%s,%s,%s","Potentially Malicious File Transfered via SMB",stuff[9],stuff[4]); 66 | 67 | local n: Notice::Info = Notice::Info($note=SMB, $msg=msg, $sub=stuff[5]); 68 | 69 | Notice::populate_file_info2(Notice::create_file_info(f), n); 70 | 71 | NOTICE(n); 72 | } 73 | } 74 | } 75 | 76 | } 77 | 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /virustotal.bro: -------------------------------------------------------------------------------- 1 | 2 | module VirusTotal; 3 | 4 | export { 5 | redef enum Log::ID += { LOG }; 6 | 7 | type Report: record { 8 | ts: time &log; 9 | fuid: string &log; 10 | mime_type: string &log &optional; 11 | sent_file: bool &log &default=F; 12 | scan_date: time &log &optional; 13 | permalink: string &log &default=""; 14 | total_scanners: count &log &default=0; 15 | hits: set[string] &log &optional; 16 | av_names: set[string] &log &optional; 17 | }; 18 | 19 | ## This is your VirusTotal API key and *must* be supplied for this plugin to work. 20 | const api_key = "这里填写 VT API key" &redef; 21 | 22 | ## Define the number of queries per minute that your API key can make. 23 | const queries_per_minute = 4 &redef; 24 | 25 | ## Scan a file hash. This is an async function and needs to 26 | ## to be called within a when statement. 27 | global scan_hash: function(f: fa_file, hash: string): Report; 28 | } 29 | 30 | # Help abide by the virus total query limits 31 | global query_limiter: set[string] &create_expire=1min; 32 | 33 | event bro_init() 34 | { 35 | Log::create_stream(VirusTotal::LOG, [$columns=Report]); 36 | } 37 | 38 | function VirusTotal::parse_result(report: Report, result: string) 39 | { 40 | report$hits = set(); 41 | report$av_names = set(); 42 | 43 | # I'm parsing JSON this way. Kill me now. 44 | local parts = split_string(result, /( ?\{|\}, )/); 45 | for ( i in parts ) 46 | { 47 | if ( /\"detected\": true/ in parts[i] ) 48 | { 49 | local hit_parts = split_string(parts[i], /(result\": \"|\", \"update)/); 50 | local av = gsub(parts[i-1], /[\":]/, ""); 51 | add report$hits[av]; 52 | add report$av_names[hit_parts[1]]; 53 | } 54 | if ( /permalink/ in parts[i] ) 55 | { 56 | local scan_parts = split_string(parts[i], /\"/); 57 | for ( part_i in scan_parts ) 58 | { 59 | if ( "scan_date" == scan_parts[part_i] ) 60 | { 61 | report$scan_date = strptime("%Y-%m-%d %H:%M:%S", scan_parts[part_i+2]); 62 | } 63 | else if ( "permalink" == scan_parts[part_i] ) 64 | { 65 | report$permalink = scan_parts[part_i+2]; 66 | } 67 | else if ( "total" == scan_parts[part_i] ) 68 | { 69 | report$total_scanners = to_count(gsub(scan_parts[part_i+1], /[^0-9]/, "")); 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | 77 | function VirusTotal::scan_hash(f: fa_file, hash: string): Report 78 | { 79 | if ( api_key != "" && 80 | |query_limiter| < queries_per_minute ) 81 | { 82 | local addl = fmt("--data resource=%s --data apikey=%s", hash, api_key); 83 | local r = ActiveHTTP::Request($url="https://www.virustotal.com/vtapi/v2/file/report", 84 | $addl_curl_args=addl, 85 | $method="POST"); 86 | return when ( local result = ActiveHTTP::request(r) ) 87 | { 88 | local report = Report($ts = network_time(), 89 | $fuid = f$id); 90 | if ( f$info?$mime_type ) 91 | { 92 | report$mime_type = f$info$mime_type; 93 | } 94 | parse_result(report, result$body); 95 | Log::write(LOG, report); 96 | return report; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /vt_check.bro: -------------------------------------------------------------------------------- 1 | @load base/frameworks/notice 2 | @load frameworks/files/hash-all-files 3 | @load /usr/share/bro/site/virustotal.bro 4 | 5 | module VirusTotal; 6 | 7 | export { 8 | redef enum Notice::Type += { 9 | Match 10 | }; 11 | 12 | ## Number of positive AV hits to do the Match notice. 13 | const hits_to_notice = 10 &redef; 14 | 15 | ## We want to check virustotal for files of the following types. 16 | const match_file_types = /application\/x-dosexec/ | 17 | /application\/x-executable/ &redef; 18 | } 19 | 20 | event file_hash(f: fa_file, kind: string, hash: string) 21 | { 22 | if ( kind == "sha1" && f$info?$mime_type && 23 | match_file_types in f$info$mime_type ) 24 | { 25 | when ( local info = VirusTotal::scan_hash(f, hash) ) 26 | { 27 | if ( |info$hits| < hits_to_notice ) 28 | break; 29 | 30 | local downloader: addr = 0.0.0.0; 31 | for ( host in f$info$rx_hosts ) 32 | { 33 | # Pick a receiver host to use here (typically only one anyway) 34 | downloader = host; 35 | } 36 | 37 | NOTICE([$note=VirusTotal::Match, 38 | $msg=fmt("VirusTotal match on %d AV engines hit by %s", |info$hits|, downloader), 39 | $sub=info$permalink, 40 | $n=|info$hits|, 41 | $src=downloader]); 42 | } 43 | } 44 | } 45 | --------------------------------------------------------------------------------