自製蜜罐之前端部分
直接從blog中copy了一份,圖丟失了,懶得一張一張上傳了,blog原文在這裡:http://www.xsec.io/2016/7/8/how-to-develop-a-honeypot.html
自製蜜罐
背景
生產系統的內網部署蜜罐後可以監控到黑客對內網的探測及攻擊行為,方便安全工程師第一時間發現被入侵併及時止損,防止出現公司重要數據被竊取卻渾然不然的情況。 所以我們有必要在重要業務的內網機房部署蜜罐。
需求
- 第一時間發現攻擊者
- 攻擊行為及指紋記錄、識別
- 覆蓋到全部的協議及埠
目前市面上已經有許多商業或開源的蜜罐系統,如awesome-honeypots中收集了大量的開源的蜜罐系統, 但是這些開源的蜜罐系統存在以下問題:
- 安裝、部署比較複雜、繁瑣,學習成本高
- 自定義或擴展功能的成本高
- 覆蓋不到全部的協議及埠
- 開發進度滯後,沒有覆蓋到最新的redis、elastic、stuct2等漏洞的利用的監控
所以我們有必要自己開發一套易於部署、覆蓋全埠全協議及最新漏洞的蜜罐系統。
蜜罐架構圖
- Agent
- 記錄攻擊log並發送到server中
- 按照策略將攻擊流量轉到後端server
- 定期更新policy
- Server:
- 接收來自各agent的攻擊log
- 通過策略判斷是否需要報警
- 攻擊log及報警log保存、備份
- Backend
- 利用docker構建常見的各服務
- 攻擊行為記錄、指紋識別
- Policy server
- Agent和server的策略管理
Agent的實現
Agent利用iptables記錄了對Agent所有埠的tcp及udp協議的訪問log,並用iptables將請求按policy指定的規則轉到了後端的攻擊行為識別伺服器中。
iptables基礎
netfilter/iptables(簡稱為iptables)組成Linux平台下的包過濾防火牆,與大多數的Linux軟體一樣,這個包過濾防火牆是免費的,它可以代替昂貴的商業防火牆解決方案,完成封包過濾、封包重定向和網路地址轉換(NAT)等功能。 Netfilter是Linux操作系統核心層內部的一個數據包處理模塊,它具有如下功能:
- 網路地址轉換(Network Address Translate)
- 數據包內容修改
- 包過濾的防火牆功能
真正實現防火牆功能的是處於內核級的netfilter,iptables是應用層的netfilter的管理工具,netfilter與iptables在linux操作系統中的位置及角色如下圖所示:
Netfilter提供了數據包的5個Hook Point,當有數據通過這些位置時,鉤子就會觸發,從而可以調用我們自定義的函數,這5個掛載點分別為:
- NF_IP_PRE_ROUTING
- NF_IP_LOCAL_IN
- NF_IP_FORWARD
- NF_IP_LOCAL_OUT
- NF_IP_POST_ROUTING
Netfilter所設置的規則是存放在內核內存中的,而 iptables 是一個應用層的應用程序,它通過 Netfilter 放出的介面來對存放在內核內存中的 XXtables(Netfilter的配置表)進行修改。
這個XXtables由表tables、鏈chains、規則rules組成,iptables在應用層負責修改這個規則文件。
iptables內置了4個表,即Filter表、Nat表、Mangle表和Raw表,分別用於實現包過濾、網路地址轉換、包重構(修改)和數據跟蹤處理。
這幾個表的優先順序為Raw -> Mangle -> Nat -> Filter。 iptables表和鏈的結構如下圖所示:
iptables中的規則表(table)
- Raw表有兩個鏈:OUTPUT、PREROUTING,作用為決定數據包是否被狀態跟蹤機制處理
- Mangle表有五個鏈:PREROUTING、POSTROUTING、INPUT、OUTPUT、FORWARD,作用為修改數據包的服務類型、TTL、並且可以配置路由實現QOS
- Nat表有三個鏈:PREROUTING、POSTROUTING、OUTPUT,作用為用於網路地址轉換
- Filter表有三個鏈:INPUT、FORWARD、OUTPUT,作用為數據包過濾
iptables中的規則鏈接(chain)
- INPUT——進來的數據包應用此規則鏈中的策略。
- OUTPUT——外出的數據包應用此規則鏈中的策略。
- FORWARD——轉發數據包時應用此規則鏈中的策略。
- PREROUTING——對數據包作路由選擇前應用此鏈中的規則,所有的數據包進來的時侯都先由這個鏈處理。
- POSTROUTING——對數據包作路由選擇後應用此鏈中的規則,所有的數據包出來的時侯都先由這個鏈處理。
iptales中的數據流
iptables中的數據流可以總結為以下3句話:
- 發往本地的包,數據流向為:PREROUTING -> INPUT
- 發往其他地址的包,數據流向為:PREROUTING -> FORWARD -> POSTROUTING
- 從本地發出的包的數據流向為: OUTPUT -> POSTROUTING
iptables規則管理
iptables命令參數
[-t 表名]:該規則所操作的哪個表,可以使用filter、nat等,如果沒有指定則默認為filtern-A:新增一條規則,到該規則鏈列表的最後一行n-I:插入一條規則,原本該位置上的規則會往後順序移動,沒有指定編號則為1n-D:從規則鏈中刪除一條規則,要麼輸入完整的規則,或者指定規則編號加以刪除n-R:替換某條規則,規則替換不會改變順序,而且必須指定編號。n-P:設置某條規則鏈的默認動作n-nL:-L、-n,查看當前運行的防火牆規則列表nchain名:指定規則表的哪個鏈,如INPUT、OUPUT、FORWARD、PREROUTING等n[規則編號]:插入、刪除、替換規則時用,--line-numbers顯示號碼n[-i|o 網卡名稱]:i是指定數據包從哪塊網卡進入,o是指定數據包從哪塊網卡輸出n[-p 協議類型]:可以指定規則應用的協議,包含tcp、udp和icmp等n[-s 源IP地址]:源主機的IP地址或子網地址n[--sport 源埠號]:數據包的IP的源埠號n[-d目標IP地址]:目標主機的IP地址或子網地址n[--dport目標埠號]:數據包的IP的目標埠號n-m:extend matches,這個選項用於提供更多的匹配參數,如:nn-m state --state ESTABLISHED,RELATEDn-m tcp --dport 22n-m multiport --dports 80,8080n-m icmp --icmp-type 8n<-j 動作>:處理數據包的動作,包括ACCEPT、DROP、REJECT等n
利用shell實現一個demo
#!/bin/bashn:<<BLOCKnCopyright (c) 2016 www.xsec.ionn - User: netxfly<x@xsec.io>n - Date: 2016/6/20nnPermission is hereby granted, free of charge, to any person obtaining a copynof this software and associated documentation files (the "Software"), to dealnin the Software without restriction, including without limitation the rightsnto use, copy, modify, merge, publish, distribute, sublicense, and/or sellncopies of the Software, and to permit persons to whom the Software isnfurnished to do so, subject to the following conditions:nnThe above copyright notice and this permission notice shall be included innall copies or substantial portions of the Software.nnTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ORnIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THEnAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHERnLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS INnTHE SOFTWARE.nBLOCKnnWHITELIST_IPs=(1.1.1.1.1 111.111.111.111 222.222.222.222)nWHITELIST_PORTS="88,96,99,55522"nBACKEND="10.10.10.10"nATTACK_IP="9.9.9.9.9"nnATTACK_IP1="9.9.9.9.0/24"nUNREAL_TARGET="220.181.112.244:80"nn# set ip_forwardnfunction set_ip_forward()n{n /sbin/sysctl -w net.ipv4.ip_forward=1n sysctl -pn}nn# delete custom iptables chainnfunction delete_policy()n{n /sbin/iptables -t nat -F n /sbin/iptables -t nat -X HONEYPOTn /sbin/iptables -t nat -X FIREWALL_INn /sbin/iptables -t nat -X FIREWALL_OUTnn /sbin/iptables -t filter -F n /sbin/iptables -t filter -X WHITELISTn}nn# init iptables chainnfunction init_policy()n{n /sbin/iptables -t nat -N HONEYPOTn /sbin/iptables -t nat -A PREROUTING -j HONEYPOTnn /sbin/iptables -t filter -N WHITELISTn /sbin/iptables -t filter -A INPUT -j WHITELISTnn /sbin/iptables -t nat -N FIREWALL_INn /sbin/iptables -t nat -A PREROUTING -j FIREWALL_INn /sbin/iptables -t nat -N FIREWALL_OUTn /sbin/iptables -t nat -A POSTROUTING -j FIREWALL_OUTnn /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEnn /sbin/iptables -t nat -A HONEYPOT -i eth0 -p tcp -m state --state NEW,ESTABLISHED,RELATED -j LOG --log-prefix "iptables:"nn}nn# set white policy(ip white)nfunction set_white_policy()n{n for ip in $WHITELIST_IPsn don /sbin/iptables -t filter -A WHITELIST -s $ip -j DROPn donen}nn# set honeypot policy(ports white)nfunction set_honeypot_policy()n{n /sbin/iptables -A HONEYPOT -t nat -i eth0 -p tcp -m multiport ! --dport $WHITELIST_PORTS -j DNAT --to-destination $BACKENDn /sbin/iptables -A HONEYPOT -t nat -i eth0 -p udp -m multiport ! --dport $WHITELIST_PORTS -j DNAT --to-destination $BACKENDn # /sbin/iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADEn}nn# start honeypotnfunction StartHoneypot()n{n set_ip_forwardn init_policyn set_white_policyn set_honeypot_policyn}nn# stop honeypotnfunction StopHoneypot()n{n delete_policyn}nnfunction showHelp()n{n echo "Usage: [sudo] ./honeypot.sh [OPTIONS]"n echo "Options:"n echo -e "t-h | --helptt show this help"n echo -e "t-start tt start honeypot"n echo -e "t-stop tt stop honeypot"n}nn# Check if user is rootn[ $(id -u) != "0" ] && { echo "Must run as root, exit1111..." >&2; exit 1; }nnwhile true ; don case "$1" innn -h|--help)n showHelp;n echo ""n exit 0n ;;nn -start|--start)n echo "start honeypot";n StartHoneypot;n exit 0n ;;nn -stop|--stop)n echo "stop honeypot";n StopHoneypot;n exit 0n ;;nn *)n # echo "invalid option. $1"n showHelp;n exit 1n ;;n esacndonennfunction policy_reset()n{n /sbin/iptables -t nat -F FIREWALL_INn /sbin/iptables -t nat -F FIREWALL_OUTn iptables -t nat -A FIREWALL_OUT -o eth0 -j MASQUERADEn}nn# # douzhuanxingyinfunction douzhuanxingyi()n{n iptables -t nat -A FIREWALL_IN -s $ATTACK_IP -j DNAT --to-destination $ATTACK_IPn n}nnfunction jinghuashuiyue()n{n /sbin/iptables -t nat -A FIREWALL_IN -i eth0 -p tcp -m tcp --dport 1:65535 -s $ATTACK_IP1 -j DNAT --to-destination $UNREAL_TARGETn}n
demo代碼解讀
- set_ip_forward函數將net.ipv4.ip_forward設為了1,這樣才能開啟linux的數據轉發功能。
- init_policy中利用-N指令新建了不同的chain,目的是為了在將同類的操作放到同一個鏈中,防止在操作規則的過程中影響到其他的iptables規則。
- set_white_policy為設置白名單,來自白名單的請求直接drop掉,不會轉到後端伺服器;
- set_honeypot_policy為設置蜜罐的轉發規則,除了伺服器管理、監控外的其他埠外的其他請求全部轉到後端
- douzhuanxingyi使用了金庸武俠小說《天龍八部》中武功名,指將攻擊者的攻擊全部反彈回去
- jinghuashuiyue是使用了動畫片《死神》中藍染的斬魄刀的名字:(幻覺系最強斬魄刀),指將攻擊者的所有請求轉到一個偽造的地址中,誤導攻擊者。
- 在使用了DNAT後,需要在POSTROUTING鏈中設置SNAT,每條規則都需要設置,操作麻煩且容易出錯,用-j MASQUERADE可以自動完成這些操作
golang實現最終的agent
相比python來說,golang寫的程序無任何依賴,直接編譯為一個二進位文件就能執行,所以我們選擇了golang。 agent的功能為:
- 支持配置,配置文件中為策略的URL,轉發數據的網卡名
- 定期從策略伺服器中拉取最新的策略並應用
- 將syslog發送到後端的server中
發送syslog到後端伺服器的功能無需開發,centos 6默認全部為rsyslog,只需配置下rsyslog便可將日誌發送到後端server, 配置完需重啟rsyslog服務/etc/init.d/rsyslog restart,配置參數如下:
[root@honeypot_agent01 agent]# cat /etc/rsyslog.d/iptables.conf n:msg,contains,"iptables" @@111.111.111.111:514n
111.111.111.111 為蜜罐的server,514為埠,@@表示以TCP發送log,@表示以UDP發送數據 建議全部使用TCP,個別網路的ACL導致tcp不通時可以使用udp。
agent的定期運行配置在cronta中,每1分鐘更新一次策略
[root@honeypot_agent01 agent]# crontab -en*/1 * * * * /data/honeypot/agent/honeypot_agentn
Agent的部分代碼如下:
// Get forward policy && white listnfunc GetPolicy() (p Policys, err error) {nntresp, err := http.Get(Url)ntif err != nil {nttlog.Fatal(err)nt}nntbody, err := ioutil.ReadAll(resp.Body)ntif err != nil {nttlog.Fatal(err)nt}nntjson.Unmarshal(body, &p)ntresp.Body.Close()ntreturn p, errn}nn// set iptablesnfunc SetIptables(policy Policys) {n // InitPolicy()nn white_ip_policy := policy.Whiteipn // set white policyn for _, white_ip := range white_ip_policy {n fmt.Println("/sbin/iptables", "-t", "filter", "-A", "WHITELIST", "-i", interfaceName, "-s", white_ip, "-j", "DROP")n exec.Command("/sbin/iptables", "-t", "filter", "-A", "WHITELIST", "-i", interfaceName, "-s", white_ip, "-j", "DROP").Output()n }nn fmt.Println("/sbin/iptables", "-t", "nat", "-A", "HONEYPOT", "-i", interfaceName, "-p", "tcp", "-m", "multiport", "!", "--dports", strings.Join(policy.Whiteport, ","), "-j", "DNAT", "--to-destination", policy.Backend)n ret, err := exec.Command("/sbin/iptables", "-t", "nat", "-A", "HONEYPOT", "-i", interfaceName, "-p", "tcp", "-m", "multiport", "!", "--dports", strings.Join(policy.Whiteport, ","), "-j", "DNAT", "--to-destination", policy.Backend).Output()n fmt.Println(ret, err)n exec.Command("/sbin/iptables", "-t", "nat", "-A", "POSTROUTING", "-o", interfaceName, "-j", "MASQUERADE").Output()n}nn// set ipv4.ip_forwardnfunc SetIp_forward() {n cmd := exec.Command("/sbin/sysctl", "-w", "net.ipv4.ip_forward=1")n cmd.Run()n cmd = exec.Command("/sbin/sysctl", "-p")n cmd.Run()n}nn// Init iptables policynfunc InitPolicy() {n // set honeypot chain in nat tablen exec.Command("/sbin/iptables", "-t", "nat", "-N", "HONEYPOT").Run()n exec.Command("/sbin/iptables", "-t", "nat", "-F", "HONEYPOT").Run()n exec.Command("/sbin/iptables", "-t", "nat", "-A", "PREROUTING", "-j", "HONEYPOT").Run()n exec.Command("/sbin/iptables", "-t", "nat", "-A", "HONEYPOT", "-i", interfaceName, "-p", "tcp", "-m", "state", "--state", "NEW,ESTABLISHED,RELATED", "-j", "LOG", "--log-prefix", "iptables ").Run()n // set white list chain in filter tablen exec.Command("/sbin/iptables", "-t", "filter", "-N", "WHITELIST").Run()n exec.Command("/sbin/iptables", "-t", "filter", "-F", "WHITELIST").Run()n exec.Command("/sbin/iptables", "-t", "filter", "-A", "INPUT", "-j", "WHITELIST").Run()n}nn// Delete Policynfunc DeletePolicy() {n // Flush rulen exec.Command("/sbin/iptables", "-t", "nat", "-F").Run()n exec.Command("/sbin/iptables", "-t", "filter", "-F").Run()n // delete chainn exec.Command("/sbin/iptables", "-t", "nat", "-X", "HONEYPOT").Run()n exec.Command("/sbin/iptables", "-t", "filter", "-X", "WHITELIST").Run()n}nn// Start Agentnfunc Start(p Policys) {n Stop()n // set ip forwardn SetIp_forward()n // create iptables chainn InitPolicy()n // set iptables rulen SetIptables(p)n}nn// Stop Agentnfunc Stop() {n // clean iptables rule and chainn DeletePolicy()n}n
Server的實現
蜜罐server使用http://gopkg.in/mcuadros/go-syslog.v2包實現了一個rsyslog server,將每條收到的rsyslog進行格式化,然後判斷是否在白名單中,如果不在白名單中,然後對攻擊數據進行計數(超過一定的時間後再開始從0開始計數), 如果在規定的時間內超過配置的報警的次數後就不會再報了,防止短時間內產生大量的垃圾郵件。
比如可以把策略設為:同一個來源的攻擊者,3分鐘內只發1封報警郵件,報警策略的代碼如下:
// check if send alarm mailnfunc AlarmPolicy(redisConfig RedisConfig, sysLog map[string]interface{}) (isAlarm bool) {n client := redis.NewClient(&redis.Options{n Addr: fmt.Sprintf("%s:%d", redisConfig.Host, redisConfig.Port),n Password: redisConfig.Password, // password setn DB: redisConfig.Db, // use default DBn })nn src, ok := sysLog["src"].(string)n if ok {n bRet, _ := client.Exists(src).Result()n if bRet {n client.HIncrBy(src, "times", 1)n // client.Expire(src, time.Duration(redisConfig.Duration)*time.Minute)nn } else {n client.HSet(src, "times", "1")n client.Expire(src, time.Duration(redisConfig.Duration)*time.Minute)n }nn strRet, _ := client.HGet(src, "times").Result()n ret, _ := strconv.Atoi(strRet)n fmt.Printf("strRet:%v, ret:%v, AlarmOffTime:%vn", strRet, ret, redisConfig.AlarmOffTime)n if ret <= redisConfig.AlarmOffTime {n isAlarm = truen }n }n return isAlarmn}nn// send alarm mailnfunc Alarm(redisConfig RedisConfig, sysLog map[string]interface{}, subject string, body string, mail_config MailConfig, alarmInfo AlarmInfo) {n if AlarmPolicy(redisConfig, sysLog) {n go SendMail(subject, body, mail_config)n go InsertElastic(*alarmInfo.Client, alarmInfo.EsIndex, alarmInfo.EsDocument, alarmInfo.Id, alarmInfo.LogParts)n }n}n
以下為server處理rsyslog的核心代碼:
func main() {n Loadconfig()nn channel := make(syslog.LogPartsChannel)n handler := syslog.NewChannelHandler(channel)nn server := syslog.NewServer()n server.SetFormat(syslog.Automatic)n server.SetHandler(handler)n server.ListenUDP("0.0.0.0:514")n server.ListenTCP("0.0.0.0:514")nn server.Boot()nn go func(channel syslog.LogPartsChannel) {n client, err := helper.ConnectElastic(es_info)n log.Println(client, err, syslogConfig.Backup)n for logParts := range channel {n // fmt.Printf("%V,%vn", logParts, logParts)n value, ok := logParts["content"].(string)n if ok {n // backup syslog to localhostn if syslogConfig.Backup == 1 {n go helper.BackupSyslog(syslogConfig.Tag, value)n }n ret := helper.ParseLogContent(value)n // logParts["content"] = retn // fmt.Println(ret)n delete(logParts, "content")n for k, v := range ret {n logParts[k] = vn }n // fmt.Println("logParts: ", logParts)n p, _ := helper.GetPolicy(Url)n white_list := helper.GetWhiteList(p)n white_ports := helper.GetWhitePort(p)n src := ret["src"]n id := ret["id"]n dpt := ret["dpt"]nn // for mail content templaten var mailContent helper.MailContentn Timestamp, _ := logParts["timestamp"].(time.Time)n mailContent.Timestamp = Timestamp.Format("2006-01-02 15:04:05")n mailContent.SrcIp, _ = logParts["src"].(string)n mailContent.SrcHostname, _ = helper.GetHostNameByIp(mailContent.SrcIp)n mailContent.SrcPort, _ = logParts["spt"].(string)n mailContent.Proto, _ = logParts["proto"].(string)n mailContent.DestIp, _ = logParts["dst"].(string)n mailContent.DestPort, _ = logParts["dpt"].(string)n mailContent.Hostname, _ = logParts["hostname"].(string)n mailContent.Color = helper.GetColor()nn log.Println(white_list, src, white_ports, dpt, mailContent)n if !white_list[src] && !white_ports[dpt] {n subject := fmt.Sprintf("[蜜罐報警]%v, 截獲來自%v:%v對%v:%v的攻擊(%v)", mailContent.Timestamp, src, ret["spt"], ret["dst"], ret["dpt"], ret["proto"])n // body, _ := json.MarshalIndent(logParts, "", "t")n t, _ := template.New("mail").Parse(helper.HtmlMail)n var body bytes.Buffern t.Execute(&body, mailContent)nn // Alarm info, save to es toon var alarmInfo helper.AlarmInfon alarmInfo.Client = clientn alarmInfo.EsIndex = es_info.Indexn alarmInfo.EsDocument = es_info.DocumentAlarmn alarmInfo.Id = idn alarmInfo.LogParts = logPartsnn go helper.Alarm(redisConfig, logParts, subject, fmt.Sprintf("%s", body.String()), mail_config, alarmInfo)n n go helper.InsertElastic(*client, es_info.Index, es_info.Document, id, logParts)n }n }n // log.Println(strings.Repeat("-", 70))n }n }(channel)nn server.Wait()n}n
蜜罐的測試效果:
擴展功能
以上的Agent放在重要系統的內網網段為一個支持所有協議和埠的蜜罐,其實也可以改為一個適用於小網站的防火牆放在外網。 做成防火牆需要做的改動如下:
- 去掉數據轉發到後端的功能
- 設計防火牆策略(以下僅為舉例,正式使用的話,需要根據對不同的埠的攻擊設置不同的頻率)例如:
- 如果1分鐘內同一個IP的請求超過100,可以將攻擊者的所有請求轉到一個欺騙的地址(鏡花水月)
- 如果1分鐘內同一個IP的請求超過300,可以將攻擊者的所有請求原封不動的反彈回去(斗轉星移)
- 如果1分鐘內同一個IP的請求超過600,直接將攻擊者的IP Block掉,禁止訪問。
參考資料
- How Does It Work: IPTables
- Linux下iptables防火牆原理及使用
- iptables防火牆原理詳解
推薦閱讀:
※win7 實模式到保護模式的轉換是在哪一步做的?
※阿根廷最大社交網站Taringa遭遇大規模數據泄漏,超過2800萬用戶數據暴露
※如何看待「小紅書用戶信息遭大面積泄露:至少50人被騙,總額近90萬」這一事件?
TAG:信息安全 |