直播閱讀神器SqlMap源碼(第一集)
SQLmap閱讀筆記 -1
我使用的閱讀工具:PyCharm
我的SQLmap版本:1.1.3.2#dev
前言:
國內我沒有找到SQLmap的完整源碼分析文章,就打算在我16歲的時候完成我人生的第一個小目標,讀完SQLmap源碼。
SQLmap是用來對付SQL漏洞的最佳工具,用Python編寫。
點擊閱讀原文查看官方GIT地址
這將是一個完整的系列且會穩定更新,作者高中生,學業繁忙。如果我斷更了,我也很絕望。
這篇文章的定位是,會用PyCharm和SQLmap以及Python的入門人群,對小白將很不友好,建議小白先點亮前置技能,再來學習。
其實我之前寫了一篇很照顧小白且很詳細的分析筆記,然而被FB退稿了,我也很無奈啊。
我沒看完,我是一邊看一邊寫,算是直播,所以分析很可能出錯和不嚴謹,求大佬不噴,給我點信心。
我會跳過我認為不重要的函數。
歡迎大家加我的QQ交流:1478023488
虎頭:
閱讀的準備工具:
PyCharm(一個很好用的IDE,只是用它就對了):https://www.jetbrains.com/pycharm/
SQLmap(SQLmap的源碼都沒有,你還真的只是來讀文章的?):https://github.com/sqlmapproject/sqlmap
Python2.7(Python環境都沒有,你是來搞笑的嗎?):https://www.python.org/downloads/release/python-2712/
一個注入測試環境(一個注入測試環境):一個注入測試環境
用PyCharm打開SQLmap,然後開始設置運行參數。
run->Edit Configurations
第一個是運行文件的路徑,請填sqlmap.py的路徑
第二個是參數,平時怎麼用就怎麼寫,建議加入--tamper
然後在main下個斷點。 Debug模式運行
上面的藍色三邊形是運行的下一處代碼。
下面的綠色三邊形是運行到下一處斷點。
紅色四邊形是停止運行。
好了,上車吧
SQLmap的框架
我們先在仔細看代碼之前,先大略的看一遍代碼,了解一下
SQLmap
的整體框架和結構,這會方便我們之後的仔細分析。
首先,我們可以發現,SQLmap的消息和提示,是用
logging
模塊完成的。我們喜聞樂見的SQLmaplogo就是用這個模塊輸出的
配置信息在
SQLmap目錄/lib/core/log.py
,現在我們即使不看具體代碼,也可以通過logging這個模塊猜到-v參數是怎麼控制消息的輸出等級的了吧。
然後我在
sqlmap.py
中的
mian
函數裡面,看到了這兩句代碼:
sys.stdout = StdDbOut(conf.taskid, messagetype="stdout")
sys.stderr = StdDbOut(conf.taskid, messagetype="stderr")
看到這段代碼,我是懵逼的。這?。。。作者你不按照基本法寫代碼啊!你居然賦值替換Python原生的
sys.stdout
和
sys.stderr
???
好吧,我查了半天資料,發現確實可以....
只要任何類重寫了write()方法,就可以替換sys.stdout和sys.stderr
文檔連接:https://docs.python.org/2/library/sys.html?highlight=sys#sys.stdout
我們暫時不管我們內心的懵逼之情,先跟進
StdDbOut
函數,來到
SQLmap目錄/lib/api.py
看到
StdDbOut
的代碼。開頭沒什麼好說的,我們先來看
write
函數。
def write(self, value, status=CONTENT_STATUS.IN_PROGRESS, content_type=None):
開頭就又冒出了個
CONTENT_STATUS
:
我們跟進,跳到
SQLmap目錄/lib/core/enums.py
發現一堆
class
.....
這熟悉的定義,這麼多這種模式的
class
....
莫非...你是傳說中的
enum
了?(其實文件名就已經暴露一切了)
看起來作者拿
class
當
enum
,存了一堆配置信息。
引用一下百度對enum的解釋,詳細信息自己去查。
enum是計算機編程語言中的一種數據類型。枚舉類型:在實際問題中,有些變數的取值被限定在一個有限的範圍內。例如,一個星期內只有七天,一年只有十二個月,一個班每周有六門課程等等。如果把這些量說明為整型,字元型或其它類型顯然是不妥當的。
為此,C語言提供了一種稱為「枚舉」的類型。在「枚舉」類型的定義中列舉出所有可能的取值,被說明為該「枚舉」類型的變數取值不能超過定義的範圍。應該說明的是,枚舉類型是一種基本數據類型,而不是一種構造類型,因為它不能再分解為任何基本類型。
好了,我們回到
SQLmap目錄/lib/api.py
,看完剩下的
write
函數。我們又發現了一個新類名....kb
if kb.partRun is not None:
content_type = PART_RUN_CONTENT_TYPES.get(kb.partRun)
kb又是什麼鬼....算了,我們繼續跟進!
來到
SQLmap目錄/lib/core/data.py
我們發現
AttribDict
賦值給了
kb
,我們只能繼續跟進
AttribDict
函數
來到
SQLmap目錄/lib/core/datatype.py
好吧,我們先看第一行類的定義,發現
AttribDict
繼承了Python原生
dict
,看起來作者自己封裝了一個
dict
。但是,為啥要自己在封裝一個????
我們先繼續往下看
等等,我們抓到了一隻野生的深拷貝函數,去掉頭就可以吃,富含....呸!
看起來和自帶的深拷貝函數沒有區別....才怪啊!
首先,我們都知道Python原生的dist的key是不可變的,dict的key不能為list,dict,set.,value可以為任意。
另外在普及一下淺拷貝和深拷貝區別:
copy.copy 淺拷貝 只拷貝父對象,不會拷貝對象的內部的子對象。
copy.deepcopy 深拷貝 拷貝對象及其子對象
舉個例子:
默認賦值操作是淺拷貝,所以我們只修改了C,但是P的值也同意改變了,你可以理解為C和P都只是一個指針,它們指向同一個數據,另外也可以看到他們的ID是一樣的。
深拷貝就不會出現這種情況。
可能作者需要一個
key
能修改的
dist
且默認都是深拷貝,這個函數把凡是不能直接拷貝的比如id,私有變數,內建函數都特殊處理,其他的都用直接拷貝。看起來這就是作者大佬自己寫一個
dict
的目的了。
好了,我們應該回頭繼續分析了,我也不知道跟進了多少函數,我們回到
sqlmap.py
文件。
開頭的幾個函數沒什麼好講的
checkEnvironment():就是檢查系統環境
setPaths(modulePath()):檢測SQLmap關鍵文件的完整性,可讀可寫等等
banner():輸出我們喜聞樂見的logo
我們先跟進
cmdLineParser().__dict__
,來到
SQLmap目錄/lib/parse/cmdine.py
if not argv:
argv = sys.argv
checkSystemEncoding()
_ = getUnicode(os.path.basename(argv[0]),encoding=sys.getfilesystemencoding() or UNICODE_ENCODING)
開頭首先判斷有沒有傳遞argv進來,沒有的話,就默認拿sys.argv作為默認值。
我們從這裡就可以猜到,這個函數是用來處理我們傳遞的指令的。
checkSystemEncoding()
和剩下的一句,都是處理編碼的:
def checkSystemEncoding():
if sys.getdefaultencoding() == "cp720":
try:
codecs.lookup("cp720")
except LookupError:
errMsg = "there is a known Python issue (#1616979) related "
errMsg += "to support for charset "cp720". Please visit "
errMsg +=""http://blog.oneortheother.info/tip/python-fix-cp720-encoding/index.html""
errMsg += "and follow the instructions to be able to fix it"
logger.critical(errMsg)
warnMsg = "temporary switching to charset "cp1256""
logger.warn(warnMsg)
reload(sys)
sys.setdefaultencoding("cp1256")
看起來不支持cp720編碼,如果是cp720,就臨時切換為cp1256。應該是為了兼容日文系統。
我們來到
parser = OptionParser(usage=usage)
這句,SQLmap的作者用
OptionParser
模塊處理的命令。在然後下面就是用
OptionParser
初始化各種參數,差不多千行,沒什麼分析的價值。
我們回到
sqlmap.py
,跟進
cmdLineOptions.update
。又來到了
SQLmap目錄/lib/core/data.py
。發現
cmdLineOptions
是
AttrDict
的一個實例,至於
AttrDict
就是之前我們分析的那個作者自己封裝的
dist
。而
update
方法是
AttrDict
的父類
dict
的方法,沒有重寫,接受一個
dict
或者
mapping object
為參數,更新調用者,在這裡就是拿
cmdLineParser
更新
cmdLineOptions
。同時,我們看到
cmdLineParser
有一個
__dict__
。
那麼關係我們就理清楚了,
cmdLineOptions
通過
update
方法,用
cmdLineParser
的
__dict__
屬性構建了一個新對象。
在這裡,我先科普一下
__dict__
屬性還有類和父類的繼承關係,本來在分析
AttrDict
的時候就該講的,然而不想講的,但是不講就說不清,果然躲不了啊:
首先,可以看到,我創建了一個新
class
,然後又創建了它的兩個子類,分別是
CNM
和
FUCK
。然後我通過子類
CNM
給
W
賦值為20,然後我們全部輸出。發現只有子類的
W
改變了。
在然後我們通過他們的父類
hello
給
W
賦值為30,然後輸出,發現除了
CNM
還是20.父類
hello
和它的子類
FUCK
都發生了改變,為什麼會這樣呢?
因為一個對象的屬性查找順序遵循首先查找實例對象自己,然後是類,接著是類的父類。具體我們要來了解
__dict__
屬性。
__dict__
是一個
dist
,
key
是屬性名,
value
為屬性值。Python的實例有自己的
__dict__
,它對應的類也有自己的
__dict__
這裡我輸出了它們的
__dist__
屬性,我們可以看到,
CNM
這個子類的
__dist__
裡面有一個key為W,value為20的參數,所以他輸出的值是20,父類的W是30,所以父類輸出的是30。
那麼,
FUCK
的
__dist__
裡面沒有W,為什麼也會輸出30呢?
因為一個對象的屬性查找順序遵循首先查找實例對象自己,然後是類,接著是類的父類。同樣,父類的方法也會被子類繼承,這就是之前作者重寫
AttrDict
的基礎
OK,現在我們知道了
__dist__
這個方法的功能和知道了父類和子類的關係,我們在學一個相當Python的Python的技巧,我們就明白這一行代碼的意思了。
cmdLineOptions.update(cmdLineParser().__dict__)
我們回來繼續看這行代碼,但是我們注意到,
cmdLineParser
是一個函數啊......
函數怎麼會有
__dict__
方法呢???????
我試著去掉了
__dict__
方法,如圖:
發現報了一個類型錯誤。
我們之前跟進過
cmdLineParser
函數,知道那是用
OptionParser
模塊寫的一個處理命令的函數,我們先去看它的返回值類型。
我們可以看到返回類型的不同,
.update
方法只支持
dist
類型。
這個時候我們就可以理解為什麼作者要自己封裝一個
AttrDict
並在裡面寫了一個
__dist__
,作者用
__dist__
把返回類型轉換為
dist
類型,然後傳遞給
cmdLineOptions
(
cmdLineOptions
父類是
AttrDict
)用
update
更新為一個
class
類型。
一個設計和思想極其偉大的創意!
蛇尾
以上只是對SQLmap源碼的簡單的一個框架分析,我們可以看出來,作者用
OptionParser
模塊處理用戶傳遞進來的參數。同時自己寫了一個
dist
的子類
AttrDict
來替代原生
dist
的功能。SQLmap的全部
dist
都是用
AttrDict
來做的,同時作者也覆蓋重寫
sys.stdout
和
sys.stderr
。為什麼覆蓋重寫目前還沒找到原因。
框架因為分析的代碼很少,暫時還給不出來。我們仔細看看我們分析了main的幾行代碼.....好像,10行都沒有???????
但是根據我們已經分析的代碼,我們心中應該也有個模型了-。-
沒有的話,等我下篇文章寫吧-。-
補一句,SQLmap的源碼和作者簡直是大佬,能開無雙那種-。-
豬屁股
好了,下篇文章會在星期6寫出來。
假如我沒懶癌發作的話!
還有我沒被拒稿和被你們噴的話
有錯誤直接說,但是求不噴,我還是很玻璃心的-。-
*本文作者:溫酒,轉載請註明來自Freebuf.COM
※朝鮮使用先進工具監視公民的數字生活
※聊聊身份欺詐和竊取那些事
TAG:FreeBuf |
※掌閱第三代閱讀器iReader Light評測
※Python 源碼閱讀:類型
※Python 源碼閱讀:tuple
※Python 源碼閱讀:list
※Python 源碼閱讀:dict
※Python 源碼閱讀: String
※Python 源碼閱讀:int
※閱讀「新貴」 —Amazon 亞馬遜 Kindle Oasis 電子書閱讀器&Kindle微信公眾號輕體驗
※Python 源碼閱讀:內存管理機制(1)
※Python 源碼閱讀:對象
※Nonfiction閱讀 D第6課:Dollars and Cents
※Yuval Noah Harari 的《人類簡史》閱讀感悟(下)
※iReader Light 上手:支持 Wi-Fi 傳書、微信推送的輕薄電子閱讀器
※Bookeen與家樂福合推電子閱讀器Nolim
※新Kindle Oasis:亞馬遜首款防水電子閱讀器
※業餘草教你解讀Spark源碼閱讀之HistoryServer
※另類手機殼:給iPhone7穿上一件Kindle閱讀器
※法語A1閱讀第3期:17天手把手帶你精讀一本法語書「La mort dessinée」
※閱讀器一哥之爭 掌閱iReader Light對比Kindle