攻防系統之SSH入侵的檢測和響應
*本文作者:gncao,本文屬 FreeBuf 原創獎勵計劃,未經許可禁止轉載。
一、前言
作為系列文章的第一篇 https://www.freebuf.com/es/193557.html 介紹了攻防系統的整個環境和搭建方法,按照這篇文章應該是可以把整個環境搭建完畢的.。在這篇文章中還介紹到了課程大綱包含主機安全、web安全、後門/木馬等等,下面就讓我們開始我們的實驗課程。
二、課程目標
首先第一個課程是主機安全的ssh埠入侵&檢測&響應課程。
課程有幾個目標如下所示:
1. 熟練使用nmap類埠掃描工具
2. 熟練使用hydra、msf等平臺對ssh服務開展爆破行為
3. 監測平臺能夠在第一時間檢測到攻擊行為併發出告警
4. 能夠在伺服器上找到入侵痕跡包括攻擊時間、攻擊方式、是否成功、攻擊源等有價值資訊
注:對於很多大佬來說這些都是小菜了,但是在一開始的時候我也是這麼認為的(我不是大佬)直到在做後面環節的時候還是碰到了一些問題,同時也掌握了一些新的知識,相信大家都會在這個過程當中都能夠有所收穫。
三、實驗環境
攻擊主機ip:192.168.171.130(注:因為換了新電腦,物理主機沒有攻擊環境,所以新裝了一個kali虛擬機器作為攻擊主機)
受害者主機ip:192.168.171.121
檢測主機ip:192.168.171.120
四、攻擊思路
1. 使用nmap等埠掃描工具探測目標伺服器是否存在ssh服務
1)在攻擊主機的命令列下輸入nmap -sS 192.168.171.121 對目標主機進行埠掃描:
2)檢測發現目標主機存在ssh服務,嘗試登陸幾次判斷是否存在登陸次數限制或登陸地址限制情況:
經過多次嘗試登陸發現沒有存在限制次數登陸和限制登入地址的情況,所以我們可以使用爆破工具載入字典對ssh服務進行爆破了。
2. 使用msf、hydra等工具載入字典對目標ssh服務開展爆破行為,這裡使用hydra來做演示。
hydra和msf的使用方法不做過多介紹,否則篇幅無法控制。大家如果有不懂的,可以百度或者聯絡我。
1)在命令列下使用hydra載入使用者名稱、密碼字典對目標ssh服務開展爆破行為:
hydra -L user.txt -P pass.txt ssh://192.168.171.121
2)對爆破出來的使用者名稱密碼嘗試登陸
ssh [email protected] 輸入密碼後正常登陸:
3)建立SSH免密登陸
3.1)現在攻擊主機上生成公鑰資訊
ssh-keygen -t rsa
3.2)將生成的公鑰資訊傳到受害主機上
一定要注意是公鑰檔案字尾為.pub。
ssh-copy-id -i .ssh/id_rsa.pub [email protected]
輸入受害主機的密碼後即可。
3.3)嘗試可以免密登陸
ssh [email protected] 直接登陸不用輸入密碼。
正常情況下是需要輸入密碼的,注意標紅位置:
至此基本的SSH攻擊已經結束了,思路很簡單這個應該是基本功無壓力。下面的過程就比較有收穫了。
五、響應方法
1. 登陸目標主機關閉ssh服務、檢視被爆破成功賬戶、判斷是否存在ssh免密登陸。
1)關閉ssh服務
systemctl stop sshd 或者/etc/init.d/sshd stop
2)檢視被爆破成功的賬戶
兩種方案可以檢視到
2.1)第一種是檢視ssh日誌中的關鍵字眼 Accepted password for
注意Accepted的第一個字母大寫否則匹配不到記錄:
cat /var/log/secure | grep "Accepted password for"
從日誌中能夠發現victim和root賬戶均被爆破出來。
2.2)第二種是last命令檢視登陸地址資訊
last 命令效果等同於 who /var/log/wtmp。
3)檢查是否存在免密登陸
因為從日誌和wtmp記錄中我們看到攻擊者已經登陸了victim和root賬戶所以我們需要在這兩個賬戶下面分別檢視是否存在ssh公鑰資訊。
3.1)首先檢視普通賬戶victim的.ssh目錄下是否存在authorized_keys檔案
ls -l /home/victim/.ssh/
從上面可以看出victim賬戶存在免密登陸而且還記錄到了攻擊者伺服器的主機名和使用者名稱資訊。
3.2)然後檢視root賬戶的.ssh目錄是否存在authorized_keys檔案
ls -l /root/.ssh/
從結果可以看到root賬戶下不存在免密登陸。
2. 檢查系統使用者是否存在異常賬號若存在清除異常賬戶
cat /etc/passwd
無異常賬戶
3. 檢查ssh日誌是否存在短時間內大量的嘗試登陸行為,從而判斷這個登入成功的賬戶是正常登陸還是異常登陸
檢視secure日誌檔案判斷是否存在大量的Invalid user 字眼
cat /var/log/secure | grep "Invalid user"
cat /var/log/secure | grep “Accepted password for victim from 192.168.171.130″ 記錄登陸成功的時間點然後判斷是否跟暴力破解的時間段一致,如果一致則表示該賬戶是被爆破成功登陸。或者直接找管理員確認登陸資訊是否正常。
跟上面的secure日誌中的時間點做匹配可以看到該賬戶是被暴力破解出來的。
4,檢查定時任務是否存在異常情況
1)crontab -l檢視當前使用者的定時任務資訊
2)sudo crontab -u root -l 檢視root賬戶的定時任務資訊
3)檢視/etc/cron.d/資料夾中是否存在檔案
能夠看到cron.d資料夾中存在定時任務但是內容不含攻擊行為。
4)檢視/etc/cron.daily/ /etc/cron.weekly/ /etc/cron.hourly/ /etc/cron.monthly/ 這些資料夾下面是否存在定時任務
六、修復方案
1. 修改被爆破賬戶密碼增加密碼複雜度
分別執行passwd victim 和passwd root命令修改victim和root賬戶密碼。
2. 清除免密登陸資訊
刪除.ssh/目錄下的authorized_keys檔案。
rm -rf .ssh/authorized_keys
3,清除定時任務
如果存在定時任務直接刪除定時任務檔案或者進入到定時任務檔案中刪除所在行資訊即可。
4,增加ssh登陸失敗次數限制
編輯sshd_config配置檔案修改MaxAuthTries記錄。
儲存退出後重啟sshd服務。
再次嘗試登陸且輸入密碼超過2次後會出現如下資訊。
再次使用hydra嘗試爆破ssh使用者名稱密碼。
檢視secure日誌:
為什麼呢?為什麼會出現這種情況呢?
我們已經在SSH的配置檔案中增加次數限制了為什麼還是可以爆破成功呢?
是因為我們在這裡對登陸失敗次數做限制了,但是沒有鎖定賬戶。也就是說這個賬戶依然可以被暴力破解只是破解的速度會慢一點而已。
那正確的方式應該怎麼做呢。
需要通過pam來鎖定超過登陸次數的賬戶編輯/etc/pam.d/sshd檔案:
vim /etc/pam.d/sshd
增加如上所示一條記錄該條記錄,表示登陸失敗超過三次後就鎖定300秒,root賬戶如果三次嘗試後也不行將被鎖定1200秒。
欄位解釋:
deny表示的是設定的最大失敗次數 unlock_time 表示的是鎖定多長時間單位是秒 deny_root 表示root賬戶也封鎖 root_unlock_time 表示的是root賬戶的鎖定時間
注:
如果限制ssh登陸則編輯sshd檔案
如果限制終端登陸則編輯login檔案
再次嘗試hydra爆破
發現無法成功爆破檢視secure日誌:
日誌中顯示victim賬戶已經被鎖定。
檢視鎖定的賬戶和登陸失敗的次數:
sudo pam_tally2 --user victim
這時候嘗試輸入正確密碼嘗試登陸:
依然無法登陸。那怎麼解除封鎖呢?
只需要將pam中的記錄清除掉即可。
sudo pam_tally2 --user victim --reset
再次嘗試登陸victim賬戶:
可以發現能夠正常登陸了
5. 限制只允許特定ip地址訪問ssh
通過編輯/etc/hosts.allow和/etc/hosts.deny這兩個檔案來控制訪問源ip地址範圍。當兩個檔案同時存在策略的時候allow檔案的優先順序大於deny檔案。
這裡我們限制victim主機只允許171.1訪問其他全阻斷。
1)vim /etc/hosts.allow 增加如下記錄
sshd:192.168.171.1:allow
2)vim /etc/hosts.deny 增加如下記錄sshd:ALL
然後測試從171.130 ssh訪問171.121主機如下所示可以看到通過171.130無法登陸。
檢視171.1主機仍然處於登陸狀態。
6. 限制只允許特定使用者訪問ssh
通過編輯sshd配置檔案增加AllowUsers和DenyUsers配置選項來控制允許登陸的使用者。
sudo vim /etc/ssh/sshd_config在檔案中追加如下配置,如果記錄存在直接修改記錄即可,如果記錄不存在需要在檔案末尾追加。
AllowUsersvictim DenyUsersroot
配置完畢後重啟sshd服務然後分別嘗試以vicitm和root賬戶登陸victim主機。
可以看到victim賬戶可以直接登陸root賬戶則無法直接登陸。
這樣我們可以通過控制ip和賬戶資訊來實現完美控制限制只允許從某臺主機使用某個賬戶登陸。
但是這樣有點麻煩需要編輯hosts.allow、hosts.deny和sshd_config檔案,其實我們可以直接編輯sshd_config檔案增加如下記錄:
[email protected]
這樣我們就可以限制只允許171.1通過victim賬戶登陸victim主機了。
我們在其他主機嘗試用victim賬戶登陸如下圖所示可以看到無法登陸。
7. 修改對外提供ssh服務的埠號
1)編輯sshd_config檔案增加如下配置
port 22 port 3389
增加另外一個ssh埠號3389避免修改失敗連線不上主機了
2)向防火牆新增修改的埠號
sudo firewall-cmd --zone=public --add-port=3389/tcp --permanent
過載防火牆
sudo firewall-cmd --reload
檢視埠號是否新增成功
sudo firewall-cmd --zone=public --query-port=3389/tcp
提示yes表示成功新增
3)向selinux中新增修改的埠號
3.1)首先要安裝selinux的管理工具semanage
sudo yum provides semanage sudo yum install policycoreutils-python#安裝依賴包
3.2)安裝完成後可以使用semanage命令檢視ssh服務埠
sudo semanage port -l | grep ssh
向selinux新增ssh埠
sudo semanage port -a -t ssh_port_t -p tcp 3389
驗證ssh埠是否新增成功
sudo semanage port -l | grep ssh
新增後重啟ssh服務
systemctl restart sshd
重啟後我們可以嘗試用3389登陸
輸入密碼後成功登陸。
4)刪除22埠號
4.1)編輯sshd_config檔案註釋掉22埠
4.2)firewall_cmd刪除22埠
firewall-cmd --zone=public --remove-port=22/tcp --permanent
過載防火牆
sudo firewall-cmd --reload
4.3)selinux不用刪除22埠或者說你也刪除不了,但是不影響我們的需求
4.4)重啟sshd服務然後嘗試用22埠連線victim主機發現是無法連線的使用3389埠是可以的
策略正常生效
到此加固工作已經完成。
七、檢測方法
檢測需求如下:
1. 能夠檢測到嘗試登陸行為 2. 能夠檢測到登陸成功行為 3. 能夠檢測到登陸成功賬戶 4. 收集使用者字典 5. 記錄登入失敗的使用者名稱/次數、登入失敗使用者正確的次數、登入成功的使用者名稱/次數、登陸成功的攻擊源IP地址/嘗試次數、登入失敗的攻擊源IP地址/嘗試次數(自己可以羅列更詳細需求)
檢測方法:
我們從secure日誌檔案分析來開展檢測工作,通過對secure日誌檔案進行分析我們提取如下關鍵資訊。
ssh服務的預設日誌記錄在/var/log/secure檔案中,關於ssh服務的日誌存在五種情況。注意標黑和標紅的字眼。
1. 使用者名稱錯誤使用者名稱錯誤的日誌如下所示:
Jan 14 07:37:41 victim sshd[54715]: Invalid user victim1 from 192.168.171.130 port 48550
Jan 14 07:37:41 victim sshd[54715]: input_userauth_request: invalid user victim1 [preauth]
在錯誤使用者的基礎上輸入密碼會出現如下日誌
Jan 14 07:37:59 victim sshd[54715]: pam_unix(sshd:auth): check pass; user unknown
Jan 14 07:37:59 victim sshd[54715]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.171.130
Jan 14 07:38:01 victim sshd[54715]: Failed password for invalid user victim1 from 192.168.171.130 port 48550 ssh2
2. 使用者名稱正確但輸入錯誤密碼的日誌如下所示:
Jan 14 07:37:08 victim unix_chkpwd[54691]: password check failed for user (victim)
Jan 14 07:37:08 victim sshd[54689]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=192.168.171.130 user=victim
Jan 14 07:37:10 victim sshd[54689]: Failed password for victim from 192.168.171.130 port 48548 ssh2
3. 使用者名稱正確且輸入正確密碼的日誌如下所示:
Jan 14 07:37:30 victim sshd[54689]: Accepted password for victim from 192.168.171.130 port 48548 ssh2
Jan 14 07:37:30 victim sshd[54689]: pam_unix(sshd:session): session opened for user victim by (uid=0)
4. 客戶端主動退出ssh連線的日誌如下所示
Jan 14 07:37:38 victim sshd[54694]: Received disconnect from 192.168.171.130 port 48548 :11: disconnected by user
Jan 14 07:37:38 victim sshd[54694]: Disconnected from 192.168.171.130 port 48548
Jan 14 07:37:38 victim sshd[54689]: pam_unix(sshd:session): session closed for user victim
5. 客戶端強制關閉ssh連線的日誌如下所示
Jan 14 07:42:25 victim sshd[54718]: <b>Connection closed by</b> 192.168.171.130 port 48552 [preauth]
由上所述,我們需要做的檢測策略如下:
1. 能夠檢測到嘗試登陸行為
1)這裡我們設定10秒鐘內發現5條存在 invalid user 或者password check failed語句的記錄則表示存在嘗試登陸行為(規則可自定義:包括時間和記錄數)
2. 能夠檢測到登陸成功行為
1)檢索所有日誌發現存在 accepted password for 語句的記錄則判定存在登陸成功情況
3. 能夠檢測到登陸成功賬戶
1)提取日誌中匹配到accepted password for關鍵詞語句後面的一個欄位
4. 收集使用者字典
1)提取日誌中匹配到Invalid user關鍵詞語句後面的一個欄位
5. 記錄登入失敗的使用者名稱/次數、登入失敗使用者正確的次數、登入成功的使用者名稱/次數、登陸成功的攻擊源IP地址/嘗試次數、登入失敗的攻擊源IP地址/嘗試次數
1)通過各種計算方法來統計如上資訊
檢查指令碼如下:
#!/usr/bin/python
#coding:utf-8
from collections import Counter
#定義關鍵詞資訊
username_error='Invalid user'
username_correct='password check failed'
username_password_correct='Accepted password for'
user_quit='Received disconnect from'
user_forcequit='Connection closed'
#開啟日誌檔案
f=open('secure','r')
#定義檢測方法
def attack_detect():
#使用者名稱錯誤的請求次數
failed_account=0
#使用者名稱正確且密碼錯誤的請求次數
correct_user_account=0
#使用者名稱正確且密碼正確的請求次數
correct_pass_account=0
#記錄錯誤的使用者名稱
failed_user=[]
#記錄 使用者名稱正確且密碼錯誤 的使用者名稱
correct_user=[]
#記錄使用者名稱正確且密碼正確的使用者名稱
correct_pass=[]
#記錄登入失敗的ip地址
failed_ipaddr=[]
#記錄登入失敗&使用者名稱正確的ip地址
correct_ipaddr=[]
#記錄登入成功的ip地址
correct_pass_ipaddr=[]
#標誌位
alert=True
for i in f:
if username_error in i:
failed_account += 1
failed_user.append(i.split(': ')[1].split()[2])
failed_ipaddr.append(i.split(': ')[1].split()[4])
if username_correct in i:
correct_user_account += 1
correct_user.append(i.split(': ')[1].split('(')[1].strip(')'))
if username_password_correct in i:
correct_pass_account += 1
correct_pass.append(i.split(': ')[1].split()[3])
correct_pass_ipaddr.append(i.split(': ')[1].split()[5])
if failed_account > 30 and alert:
print 'exists ssh enumrate'
alert=False
#記錄登陸失敗攻擊源IP地址和嘗試次數
failed_ipaddr_count=Counter(failed_ipaddr)
failed_ipaddr_dict=dict(failed_ipaddr_count)
#記錄登陸成功攻擊源IP地址和嘗試次數
correct_pass_ipaddr_count=Counter(correct_pass_ipaddr)
correct_pass_ipaddr_dict=dict(correct_pass_ipaddr_count)
#記錄登陸失敗使用者名稱和次數
failed_user_count=Counter(failed_user)
failed_user_dict=dict(failed_user_count)
#記錄登陸失敗使用者名稱正確和次數
correct_user_count=Counter(correct_user)
correct_user_dict=dict(correct_user_count)
#記錄登陸成功使用者名稱和次數
correct_pass_count=Counter(correct_pass)
correct_pass_dict=dict(correct_pass_count)
#記錄所有嘗試次數
all_account=failed_account+correct_user_account+correct_pass_account
return all_account,failed_account,correct_user_account,correct_pass_account,failed_user_dict,correct_user_dict,correct_pass_dict,failed_ipaddr_dict,correct_pass_ipaddr_dict
然後執行該指令碼可以得出如下結果:
從結果中可以看出該指令碼能夠滿足我們的需求,但是我們需要考慮如何把這段指令碼加入到spark streaming中。
八、技術實現
1. victim主機上的flume配置
注意:這裡在配置channels選項的時候,增加了下面兩個條目:
a1.channels.c1.keep-alive = 60
a1.channels.c1.capacity = 1000000
這裡表示增加channels中queue的大小,預設為100,如果使用預設值,當處理大量的日誌時就會發生如下報錯情況。
2. observer主機上的flume配置
3. observer上的kafka、zookeeper配置
kafka和zookeeper的配置保持不變即可
4. spark streaming配置
#!/usr/bin/python
#coding:utf-8
from pyspark import SparkContext
from pyspark.streaming import StreamingContext
from pyspark.streaming.kafka import KafkaUtils
from collections import Counter
import datetime
import json
#定義儲存的檔名
destname="result.json"
#定義讀取檔案方法
def readjson(file_name):
with open (file_name,"r") as file_obj:
numbers = json.load(file_obj)
print "讀取json檔案:",numbers
return numbers
#定義寫入檔案方法
def writejson(file_name,nums):
with open (file_name,"w") as file_obj:
json.dump(nums,file_obj)
print "寫入json檔案:",nums
#第一步:建立一個本地的StreamingContext,並設定批處理週期為1s
sc=SparkContext("local[2]","flumeWordCount")
ssc=StreamingContext(sc,1)
#第二步:建立一個kafka連線
topic="streamingtopic"
brokers="hadoop0:9092"
#引數分別表示ssc連線名,列表形式顯示的topic名稱,brokers列表
directkafkaStream = KafkaUtils.createDirectStream(ssc,[topic],{"metadata.broker.list":brokers})
#第三步:資料處理&轉換
#0,提取kafka資料的第一個欄位為訊息正文欄位
lines = directkafkaStream.map(lambda x: x[1])
#1,定義檢測方法
def attack_detect(i):
username_error='Invalid user'
username_correct='password check failed'
username_password_correct='Accepted password for'
user_quit='Received disconnect from'
user_forcequit='Connection closed'
failed_account=0
correct_user_account=0
correct_pass_account=0
failed_user=[]
correct_user=[]
correct_pass=[]
failed_ipaddr=[]
correct_ipaddr=[]
correct_pass_ipaddr=[]
alert=True
if username_error in i:
print username_error
failed_account += 1
failed_user.append(i.split(': ')[1].split()[2])
failed_ipaddr.append(i.split(': ')[1].split()[4])
#print failed_account
if username_correct in i:
#print username_correct
correct_user_account += 1
correct_user.append(i.split(': ')[1].split('(')[1].strip(')').strip(')\n'))
if username_password_correct in i:
#print username_password_correct
correct_pass_account += 1
correct_pass.append(i.split(': ')[1].split()[3])
correct_pass_ipaddr.append(i.split(': ')[1].split()[5])
if failed_account > 5 and alert:
#print 'exists ssh enumrate'
alert=False
total_count=failed_account+correct_user_account+correct_pass_account
#記錄登陸失敗攻擊源IP地址和嘗試次數
failed_ipaddr_count=Counter(failed_ipaddr)
failed_ipaddr_dict=dict(failed_ipaddr_count)
#記錄登陸成功攻擊源IP地址和嘗試次數
correct_pass_ipaddr_count=Counter(correct_pass_ipaddr)
correct_pass_ipaddr_dict=dict(correct_pass_ipaddr_count)
#記錄登陸失敗使用者名稱和次數
failed_user_count=Counter(failed_user)
failed_user_dict=dict(failed_user_count)
#記錄登陸失敗使用者名稱正確和次數
correct_user_count=Counter(correct_user)
correct_user_dict=dict(correct_user_count)
#記錄登陸成功使用者名稱和次數
correct_pass_count=Counter(correct_pass)
correct_pass_dict=dict(correct_pass_count)
#這裡將處理的資料以字典的形式儲存到json檔案中,每次從json檔案中讀取變數值並跟處理的結果進行累加
nums=[{"total_count":total_count,"failed_account":failed_account,"correct_user_account":correct_user_account,"correct_pass_account":correct_pass_account,"failed_ipaddr_count":failed_ipaddr_count,"failed_ipaddr_dict":failed_ipaddr_dict,"correct_pass_ipadd_count":correct_pass_ipaddr_count,"correct_pass_dict":correct_pass_dict,"correct_pass_ipaddr_dict":correct_pass_ipaddr_dict,"failed_user_count":failed_user_count,"failed_user_dict":failed_user_dict,"correct_user_count":correct_user_count,"correct_user_dict":correct_user_dict}]
rs_old = readjson(destname)
for i in nums:
for j in rs_old:
for k,v in j.items():
if isinstance(v,dict):
for m,n in v.items():
try:
i[k][m] = i[k][m] + j[k][m]
except KeyError as e:
i[k][m] = j[k][m]
else:
i[k] = i[k] + j[k]
writejson(destname,nums)
#第四步:資料輸出,這裡選擇打印出去
pairs=lines.map(lambda x:attack_detect(x))
pairs.pprint()
#第五步:開始sparkstreaming
ssc.start()
ssc.awaitTermination()
5. 啟動各個元件
1)先啟動zookeeper和kafka
./zkServer.sh start ./bin/kafka-server-start.sh $KAFKA_HOME/config/server.properties
2)然後啟動flume-server端(先監聽,後傳送)
./bin/flume-ng agent --name a1 --conf $FLUME_HOME/conf --conf-file $FLUME_HOME/conf/collect-ssh-kafka.conf -Dflume.root.logger=INFO,console
3)啟動flume-client端(監聽檔案,傳送資料到server端)
sudo ./flume-ng agent --name a1 --conf $FLUME_HOME/conf --conf-file $FLUME_HOME/conf/send-ssh.conf -Dflume.root.logger=INFO,console
4)啟動spark-streaming
./bin/spark-submit --packages org.apache.spark:spark-streaming-kafka-0-8_2.11:2.2.0 examples/src/main/python/streaming/sshdirect.py
6. 模擬攻擊者向victim發起ssh爆破行為
hydra -L user -P pass ssh://192.168.171.121:3389
然後我們檢視result.json檔案中的內容不斷實時更新,攻擊完成後的最終結果如下:
由上所述我們能夠看到檔案記錄了ssh總攻擊次數、使用者名稱錯誤嘗試次數、使用者名稱正確登陸次數以及登陸源ip地址等資訊。
注:
1. 這裡我使用的是以檔案形式進行儲存的,沒有使用mysql資料庫,理論上方法是一樣的,這裡我就不演示了,有興趣的小夥伴可以自己搞
2. 這裡的result.json檔案內容是固定的,必須要跟spark streaming指令碼中的變數格式一致,否則可能會出現問題,後面附錄中我會把格式檔案貼上來
九、圖形頁面展示
這裡我就以一個例子來展示吧,以條形圖的形式展示登陸失敗的使用者情況。
1,django環境安裝
注:已安裝django環境的自動忽略
1)使用virtualenv環境
virtualenv -p /usr/bin/python3 myechart source myechart/bin/activate pip install django==1.11.4 pip install pyecharts
2)新建django專案和app程式
django-admin startproject myechart
cd sshechart
python manage.py startapp sshechart
編輯myechart/settings.py檔案,註冊應用程式:
編輯sshechart的urls檔案,該檔案預設不存在,需要建立。內容如下:
from django.conf.urls import url from . import views urlpatterns = [ url(r'^$', views.index, name='index'), ]
編輯myechart的urls檔案,更新內容如下:
2. 資料處理
1)編輯views.py檔案內容如下:
from __future__ import unicode_literals
import math
from django.http import HttpResponse
from django.template import loader
from pyecharts import Line
from django.shortcuts import render
import json
# Create your views here.
#載入echart.js檔案
REMOTE_HOST = " https://pyecharts.github.io/assets/js "
def index(request):
#指定模板檔案
template = loader.get_template('sshechart/index.html')
attack_line=line1()
context = dict(
myechart=attack_line.render_embed(),
host=REMOTE_HOST,
script_list=attack_line.get_js_dependencies()
)
return HttpResponse(template.render(context, request))
def line1():
#Line圖需要指定x軸和y軸資料
x_raw=[]
y_raw=[]
with open('result.json') as f:
numbers = json.load(f)
for i in numbers:
dic=i["failed_user_dict"]
print (dic)
for k,v in dic.items():
x_raw.append(k)
y_raw.append(v)
line_attack=Line("登陸失敗使用者",title_pos="45%")
line_attack.add("",x_raw,y_raw,mark_point=["max","min"],is_datazoom_show=True,datazoom_type="inside")
return line_attack
2)建立模板index.html檔案
在sshechart目錄下建立templates/sshechart目錄。
並編輯index.html檔案,內容如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Proudly presented by PycCharts</title> {% for jsfile_name in script_list %} <script src="{{ host }}/{{ jsfile_name }}.js"></script> {% endfor %} </head> <body> {{ myechart|safe }} </body> </html>
3. 執行程式
執行程式後,在瀏覽器中開啟目標網站,如下所示:
同樣的,還可以多新增幾個echart圖,增加分析維度。
也可以將這個裡面的原始碼拷貝下來整合到其他web程式中。
至此,這個課題就此結束,期間也是碰到各種問題,拖延了不少時間,好在最終是搞定了,希望大家能夠在這裡有所收穫,也希望大家能夠指出文章的不足之處,共勉之。
附錄:
1. result.json檔案格式
[{"failed_account": 0, "correct_user_dict": {}, "correct_pass_ipaddr_count": {}, "correct_pass_account": 0, "failed_ipaddr_dict": {}, "failed_user_dict": {}, "correct_pass_ipaddr_dict": {}, "correct_pass_dict":{},"total_count": 0, "correct_pass_ipadd_count": {}, "correct_user_count": {}, "correct_user_account": 0, "failed_user_count": {}, "failed_ipaddr_count": {}}]
*本文作者:gncao,本文屬 FreeBuf 原創獎勵計劃,未經許可禁止轉載。