Data-Hack SQL隱碼攻擊檢測
0x00 前言
這個系列教程我本來打算的是翻譯,後來過了一下文章發現教學過程不是很友好,所以大體是按他的思路,不過其中做了很多改動,還有個事情就是我假定讀者已經瞭解基礎的python和SQL隱碼攻擊的知識。還有一個需要注意的是我是寫在ipython notebook中,所以文中的程式碼可能需要一點改動才能用。
我覺得這篇文章的簡要的主題就是,給"如何識別sql注入" 提供一種思路,這個思路的本身就是用資料科學的形式來解決問題,其實就是所謂的機器學習。
為了達到我們的目標就需要一個過程:
- 收集資料
- 思考資料
- 特徵工程
- 機器學習
0x01 準備
1. tools
這個系列主要以python為主,所以下面的是所需的python庫,我不會教你怎麼安裝這些東西。
sqlparse (一個用於解析sql語法樹的庫) Scikit-Learn (python機器學習庫) Pandas (用於快速處理一定量的資料) numpy (用於科學計算) matplotlib (用於資料視覺化)
2. 什麼是機器學習?
因為本文中用的是監督學習,那麼我們會注入監督學習所需要的知識,機器學習顧名思義就是讓機器具備學習的能力,假設我們已經有了一個演算法能夠進行學習,那麼我們該如何教給它知識,假設一個小孩,我們需要讓它知道如何辨認水果,我們就會放兩堆不同的水果,告訴他左邊的是蘋果,右邊的是香蕉。然後等到他學習了這堆狗屎玩意,我們就可以帶著他去看一堆新的水果讓後讓他自己進行辨認了。 換句話說我們這次就是要準備一堆的資料,告訴演算法,左邊的是正常的sql請求,右邊的是sql注入的請求,讓後讓他進行學習,最後我們再給他一堆未知的資料進行測試。
3. SQL語法樹
你覺得sql語言從輸入資料庫到放回內容都經過了怎樣的處理,sql語言是一種DSL(領域特定語言),比如ruby,c,java,這些可以做任何事,但有一些語言只能做某個領域的事,sql就是這樣一種語言,它只能描述對於資料的操作。但是它在大歸類的時候是被歸類到程式語言裡的,就需要經過詞法分析再到語法分析,對於這個過程不瞭解的同學可以看。 http://zone.wooyun.org/content/17006
0x02 準備資料
因為這次的資料已經準備好了,所以我們所需要就是寫個小指令碼把他讀取出來,所需要的東西我會進行打包。
下載地址:下載
#!python
# -*- coding: utf-8 -*-
import os
import pandas as pd
basedir = '/Users/slay/project/python/datahack/data_hacking/sql_injection/data'
filelist = os.listdir(basedir)
df_list = []
# 迴圈讀取 basedir下面的內容,檔名為 'legit'的是合法內容,malicious的是 惡意sql語句
for file in filelist:
df = pd.read_csv(os.path.join(basedir,file), sep='|||', names=['raw_sql'], header=None)
df['type'] = 'legit' if file.split('.')[0] == 'legit' else 'malicious'
df_list.append(df)
# 將內容放入 dataframe物件
dataframe = pd.concat(df_list, ignore_index=True)
dataframe.dropna(inplace=True)
# 統計內容
print dataframe['type'].value_counts()
# 檢視前五個
dataframe.head()
我們現在可以清楚的知道我們面臨的是一堆什麼樣的資料了。
0x03 特徵工程
1. 概念
So,然後呢?我們是不是就可以把資料丟進演算法裡然後得到一個高大上的sql防火牆了?那麼我們現在來想一個問題,我們有兩個sql語句,從admin表中檢視*的內容。
#!sql
select user from admin;
select hello from admin;
演算法最後得到的輸入是什麼,是[1,1,0,1,1] 和 [1,0,1,1,1] 沒看懂沒關係,就是說得到了這樣的東西。
{select:1, user:1, hello:0, from:1, admin:1} {select:1, user:0, hello:1, from:1, admin:1}
是不是哪裡不對,就是說在機器看來 user 和 hello 在本質來看是屬於不同的型別的玩意,但是對於瞭解sql語言本身的你知道他們是一樣的東西,所以我們就需要給同一種東西打一個標籤讓機器能夠知道。
那麼是否對什麼是特徵工程有了一些模糊的瞭解?要做好特徵工程,就需要對於你所面臨的問題有著深刻的瞭解,就是“領域知識”,帶入這個問題就像你對於sql語言的瞭解,在這個瞭解的基礎上去處理特徵,讓演算法更能將其分類。帶入水果分類問題就是,你得告訴小孩,香蕉是長長的,黃色的,蘋果是紅色的,圓圓的,當然,如果你直接把上面的玩意丟進演算法裡頭,分類器也是可以工作的,準確度大概能過 70%,也許你看起來還行,當是我只能告訴你這是個災難。這讓我想起某次資料探勘的競賽,第一名和第一千名的分差是0.01,這群變態。
2. 轉化資料
所以現在我們需要的就是將原始資料轉化成特徵,這就是為什麼我剛才說到語法樹的,我們需要對sql語句進行處理,對同一種型別的東西給予同一種標示,現在我們使用sqlparse 模組建立一個函式來處理sql語句。
#!python
import sqlparse
import string
def parse_sql(raw_sql):
parsed_sql = []
sql = sqlparse.parse(unicode(raw_sql,'utf-8'))
for parse in sql:
for token in parse.tokens:
if token._get_repr_name() != 'Whitespace':
parsed_sql.append(token._get_repr_name())
return parsed_sql
sql_one = parse_sql("select 2 from admin")
sql_two = parse_sql("INSERT INTO Persons VALUES ('Gates', 'Bill', 'Xuanwumen 10', 'Beijing')")
print "sql one :%s"%(sql_one)
print "sql two :%s"%(sql_two)
輸出 sql one :['DML', 'Integer', 'Keyword', 'Keyword'] sql two :['DML', 'Keyword', 'Identifier', 'Keyword', 'Parenthesis']
我們可以看到 select 和 insert都被認定為 dml,那麼現在我們要做的就是觀測資料,就是檢視特徵是否擁有將資料分類的能力,現在我們先對sql語句進行轉換。
#!python
dataframe['parsed_sql'] = dataframe['raw_sql'].map(lambda x:parse_sql(x))
dataframe.head()
3. Other
理論上我們現在就可以直接把這些東西扔進演算法中,不過為了方便我在說點別的,分類器的效能很大程度上取決於特徵,假設這些無法很好的對資料進行分類,那我們就需要考慮對特徵進行一些別的處理,比如你覺得sql注入的話sql語句貌似都比較長,那麼可以將其轉化成特徵。
#!python
dataframe['len'] = dataframe['parsed_sql'].map(lambda x:len(x))
dataframe.head()
現在我們需要觀測下資料,看看長度是否有將資料進行分類的能力。
#!python
%matplotlib inline
import matplotlib.pyplot as plt
dataframe.boxplot('len','type')
plt.ylabel('SQL Statement Length')
0x04 機器學習
1. Train & Test
這裡我就直接呼叫python庫了,因為解釋起來很麻煩,而且就我對於這次要使用的隨機森林(Random Forest)的瞭解層度,我覺得還不如不講,對於其數學原理有興趣的可以參考下面的paper,是我見過對隨機森林解釋的最清楚的。
Gilles Louppe《隨機森林:從理論到實踐》 http://arxiv.org/pdf/1407.7502v1.pdf
接下來我們再對特徵做一次處理,轉換成0和1的向量形式,x是我們的特徵資料,y表示結果。
#!python
import numpy as np
from sklearn.preprocessing import LabelEncoder
from sklearn.feature_extraction.text import CountVectorizer
import string
vectorizer = CountVectorizer(min_df=1)
le = LabelEncoder()
X = vectorizer.fit_transform(dataframe['parsed_sql'].map(lambda x:string.join(x,' ')))
x_len = dataframe.as_matrix(['len']).reshape(X.shape[0],1)
x = X.toarray()
y = le.fit_transform(dataframe['type'].tolist())
print x[:100]
print y[:100]
輸出
[[0 0 0 ..., 2 0 0]
[0 0 0 ..., 1 0 0]
[0 0 0 ..., 0 0 0]
...,
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]]
[1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
輸入
#!python import sklearn.ensemble
clf = sklearn.ensemble.RandomForestClassifier(n_estimators=30)
scores = sklearn.cross_validation.cross_val_score(clf, x, y, cv=10, n_jobs=4)
print scores
輸出
[ 0.97699497 0.99928109 0.99928058 1. 1. 0.97192225
0.99928006 0.99856012 1. 1. ]
上面的cross_validation是我們測試分類器的一種方法,原理就是把訓練後的分類器在一些分割後的資料集上測試結果,從得出的多個評分中可以更好的評估效能,我們得出了一個貌似不錯的結果,接下來讓我們訓練分類器
#!python
from sklearn.cross_validation import train_test_split
# 將資料分割為 訓練資料 和 測試資料,訓練資料用於訓練模型,測試資料用於測試分類器效能。
X_train, X_test, y_train, y_test, index_train, index_test = train_test_split(x, y, dataframe.index, test_size=0.2)
# 開始訓練
clf.fit(X_train, y_train)
# 預測
X_pred = clf.predict(X_test)
如果剛才那些數值無法直觀的看出你訓練了個什麼玩意出來,那麼你就需要一個混淆矩陣。
#!python
%matplotlib inline
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix
cm = confusion_matrix(X_pred,y_test)
print cm
# Show confusion matrix in a separate window
plt.matshow(cm)
plt.title('Confusion matrix')
plt.colorbar()
plt.ylabel('True label')
plt.xlabel('Predicted label')
plt.show()
混淆矩陣可以更加直觀的讓我們觀察資料,我們的資料氛圍 0,1兩類,比如 [0,0]=196 就是legit被正確分類的樣本,[0,1]=3是被錯誤分類的樣本,那麼第二行就是惡意樣本分類的情況。
現在我們看起來分類起似乎工作的不錯,達到了99%的正確率,可是你想象這個問題,每199個正確樣本就有3個被錯誤分類,一般來說一箇中型的網站需要處理的sql語句就可能會達到 上面的1000倍,就是說你可能會有3000個無害的語句被攔截。所以下面我們需要的是降低legit被錯誤分類的機率。
2. 調整
sklearn大部分的模型有個功能叫predict_proba,就是說預測的機率,predict其實就是內部呼叫下predict_proba,然後按50%。我們可以裝變一下直接呼叫predict_proba,讓我們自己調整分類的機率。
#!python
loss = np.zeros(2)
y_probs = clf.predict_proba(X_test)[:,1]
thres = 0.7 # 用0.7的機率來分類
y_pro = np.zeros(y_probs.shape)
y_pro[y_probs>thres]=1.
cm = confusion_matrix(y_test, y_pro)
print cm
輸出
[[ 197 0]
[ 5 2577]]
legit被錯誤分類的機率降低了,但是0.7只是我們隨意想出來的一個引數,能不能簡單的想個辦法最佳化一下呢?讓我們簡單定義一個函式f(x),會隨著我們輸入的引數輸出誤分類的機率。
#!python
def f(s_x):
loss = np.zeros(2)
y_probs = clf.predict_proba(X_test)[:,1]
thres = s_x # This can be set to whatever you'd like
y_pro = np.zeros(y_probs.shape)
y_pro[y_probs>thres]=1.
cm = confusion_matrix(y_test, y_pro)
counts = sum(cm)
count = sum(counts)
if counts[0]>0:
loss[0]=float(cm[0,1])/count
else:
loss[0]=0.01
if counts[1]>0:
loss[1]=float(cm[1,0])/count
else:
loss[1]=0.01
return loss
# 0.1 到 0.9 之前的 100個數值
x = np.linspace(0.1,0.9,100)
# x輸入f(x)之後得到的結果
y = np.array([f(i) for i in x])
# 視覺化
plt.plot(x,y)
plt.show()
額,繼續用0.7吧。
0x05 結語
這是個系列,可能我這麼說也沒人信吧,中途開始就有點亂了。
上一句老話吧,也不知道誰說的,反正大家天天掛嘴邊。
資料探勘專案的表現,80%取決於特徵工程,剩下的20%才取決於模型等其他部分;又說資料探勘專案表現的上限由特徵工程決定,而其接近上限的程度,則由模型決定。
source:http://nbviewer.ipython.org/github/ClickSecurity/data_hacking/blob/master/sql_injection/sql_injection.ipynb
相關文章
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊-防衛SQL隱碼攻擊-驗證檢查2014-02-16SQL
- SQL隱碼攻擊2024-07-02SQL
- 【SQL Server】--SQL隱碼攻擊2015-01-31SQLServer
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊-SQL隱碼攻擊技術-語句注入2014-02-16SQL
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊-SQL隱碼攻擊技術-語句修改2014-02-16SQL
- MYSQL SQL隱碼攻擊2021-11-20MySql
- 【SQL隱碼攻擊原理】2018-01-17SQL
- 防止SQL隱碼攻擊2010-04-20SQL
- SQL隱碼攻擊(一)2009-12-14SQL
- SQL隱碼攻擊(pikachu)2024-05-10SQL
- SQL隱碼攻擊方法2024-07-08SQL
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊2014-02-16SQL
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊-防衛SQL隱碼攻擊-繫結變數2014-02-16SQL變數
- SQL隱碼攻擊原理是什麼?如何防範SQL隱碼攻擊?2022-11-24SQL
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊-防衛SQL隱碼攻擊-顯式格式化模型2014-02-16SQL模型
- 反恐精英之動態SQL和SQL隱碼攻擊-SQL隱碼攻擊-SQL隱碼攻擊技術-資料型別轉換2014-02-16SQL資料型別
- 在Linux中,如何檢測和防止SQL隱碼攻擊和跨站指令碼(XSS)攻擊?2024-04-09LinuxSQL指令碼
- SQL隱碼攻擊式攻擊掃描器2008-07-15SQL
- 軟體安全測試之SQL隱碼攻擊2020-12-09SQL
- SQL隱碼攻擊漏洞測試工具比較2012-02-02SQL
- SQL隱碼攻擊語句2018-07-25SQL
- pikachu-SQL隱碼攻擊2020-11-21SQL
- SQL隱碼攻擊導圖2018-06-15SQL
- SQL隱碼攻擊問題2017-03-30SQL
- SQL隱碼攻擊的例子2017-03-13SQL
- ZMLCMS-SQL隱碼攻擊2017-08-20SQL
- SQL隱碼攻擊演練2013-09-16SQL
- 預防SQL隱碼攻擊2010-04-02SQL
- SQL隱碼攻擊總結2024-08-31SQL
- SQL隱碼攻擊的檢測方式有幾種?常用方法介紹!2021-10-26SQL
- DVWA-SQL Injection(SQL隱碼攻擊)2023-03-18SQL
- 攻擊JavaWeb應用[3]-SQL隱碼攻擊[1]2020-08-19JavaWebSQL
- 攻擊JavaWeb應用[4]-SQL隱碼攻擊[2]2020-08-19JavaWebSQL
- 【網路安全】什麼是SQL隱碼攻擊漏洞?SQL隱碼攻擊的特點!2021-09-06SQL
- 利用Sqlmap API介面聯動Google Hacking批次SQL隱碼攻擊檢測2024-04-14SQLAPIGo
- SQL隱碼攻擊關聯分析2020-08-19SQL
- SQL隱碼攻擊-堆疊注入2021-07-04SQL
- XSS與SQL隱碼攻擊2020-12-25SQL