作者:niexinming
作者博客:https://www.n0tr00t.com/2018/08/30/Python-dynamic-codereview.html

議題 PPT 下載地址:/static/ppt/KCon-2018-Python-dynamic-codereview.pptx

0x00 動態代碼審計用處

  1. 大型項目代碼結構復雜
  2. 有些危險的功能隱藏較深(危險的定時計劃任務、sqlite數據庫任意創建導致任意文件覆蓋……)
  3. 提高效率,希望通過一些黑盒的方法比較快速的找到漏洞。

0x01 常見漏洞分類

  1. 數據庫操作
  2. 敏感函數的調用和傳參
  3. 文件讀寫操作
  4. 網絡訪問操作

0x02 正文目錄

  1. 數據庫general log 日志
  2. hook關鍵函數
  3. 結合auditd
  4. http盲攻擊
  5. fuzzing

0x03 數據庫日志

general-log是記錄所有的操作日志,不過他會耗費數據庫5%-10%的性能,所以一般沒什么特別需要,大多數情況是不開的,例如一些sql審計和代碼審計等,那就是打開來使用了

Mysql通過命令行的方式打開general log:

    set global general_log_file='';
    set global general_log=on;

Postgresql 通過編輯配置文件打開general log:

編輯:postgresql.conf

    log_directory = 'pg_log'                    
    log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
    log_statement = 'all'

打開之后用burp向web api發送一些包含sql注入的畸形數據

利用Linux的grep指令過濾出sql執行中的ERROR關鍵字,就可以很快的找到sql注入漏洞

0x04 Hook關鍵函數

根據基于python的自動化代碼審計pyekaboo這兩個文章的啟發而來

Python對象可以被輕易的改變,通過設置PYTHONPATH這個環境變量,使python在加載string這個模塊的時候優先加載我自定義的string模塊,下圖演示的是劫持string模塊的upper函數

之后我的思路是,通過劫持python的函數,把輸入到危險函數的參數輸出到日志中,最后調用正常的python函數

這樣就可以劫持我們認為敏感的函數

劫持模塊的demo:

    import imp
    import sys
    class _InstallFcnHook(object):
        def __init__(self,fcn):
            self._fcn=fcn

        def _pre_hook(self,*args,**kwargs):
            print "hook:"+str(args)
            return (args,kwargs)
        def __call__(self,*args,**kwargs):
            (_hook_args,_hook_kwargs)=self._pre_hook(*args,**kwargs)
            retval=self._fcn(*_hook_args,**_hook_kwargs)
            return retval

    fd,pathname,desc=imp.find_module(__name__,sys.path[::-1])
    mod =imp.load_module(__name__,fd,pathname,desc)

    system=_InstallFcnHook(system)

劫持效果:

這就意味著我們可以劫持危險的函數,把參數輸出到日志里面,通過日志信息,可以判斷這些參數是否可以被輸入控制。通過這種方式可以方便找到ssti、pickle反序列化漏洞和命令執行漏洞等其他的漏洞

而且這些可以很方面的拓展到其他的模塊中

  1. cd hook/ #進入到hook模塊所在目錄
  2. cp os.py xxx.py #把os模塊復制一份,xxx模塊是你想hook的模塊
  3. 編輯xxx.py :注釋掉原來被hook的函數,添加想要hook的函數,下面的示例是hook了subprocess模塊中check_call函數

Ps 需要填一些坑:

  1. 修改啟動代碼從shell中啟動python web
    因為有一些python web是從wsgi中啟動的,這些只要簡單修改啟動代碼就可以從WSGI方式啟動切換到shell啟動
  2. 從內存中刪掉已加載的模塊
    一些模塊通過import動態導入,需要在動態導入后通過del modules刪掉被裝載的模塊
  3. 關閉調試選項
    例如在flask啟動時將debug選項設置為false,否則會產生兩個python進程
  4. 其他問題 Python web性能下降、代碼不兼容、有些模塊無法被hook,其中python的內置函數open就無法通過這樣的方式被hook。

0x05 結合Auditd

網上有很多方法去獲取python web的文件讀寫操作,其中有一種是在文件讀寫函數前面添加裝飾器,但是我覺得那種方法太過于煩瑣,且不能覆蓋到所有的文件讀寫操作,那怎么不通過修改原始代碼去獲取文件讀寫操作?

可以利用Auditd:

auditd(或 auditd 守護進程)是Linux審計系統中用戶空間的一個組件,其可以記錄Linux中文件,進程等操作,且安裝方便

CentOS 默認安裝

Ubuntu 安裝:apt-get install auditd

只要簡單的配置就可以監視一些文件操作

    sudo auditctl -a exclude,always -F msgtype!=PATH -F msgtype!=SYSCALL    #記錄文件操作
    sudo auditctl -a always,exit -F arch=b64 -S execve -k rule01_exec_command  #記錄所有的shell指令的執行
    sudo auditctl -a always,exit -F pid=$mypid    #記錄指定進程文件操作

執行 sudo auditctl -l 查看所有的規則

只要發送一些包含目錄跳轉的畸形數據給webapi,如有任意文件讀取的漏洞就可以很快的發現。

因為Auditd日志中包含大量其他的日志,通過grep和關鍵字高亮工具(https://github.com/paoloantinori/hhighlighter)進行查看日志(grep過濾PATH,高亮name)

除了記錄文件讀取,還能記錄文件的其他操作

這樣就可以找到:

  1. 任意文件上傳
  2. 任意文件創建
  3. 任意文件讀取
  4. 任意文件刪除

0x06 http盲攻擊

怎么解決諸如ssrf等網絡操作的問題?

ssrf攻擊可以讓黑客越過防火墻來探測或者攻擊一個大型企業的內網

那么在動態代碼審計過程中就可以通過構造特定的poc,來探測代碼中是否有對應的漏洞

可以構造請求dns解析的數據

  1. 命令執行的常見形式 Ping –c 1 xxx.pw
  2. ssrf的常見形式 url=http://xxx.pw
  3. xxe的常見形式

通過dns日志的記錄可以很快找到諸如ssrf、xxe、命令執行等,包括可以找到一些隱藏的比較深的定時計劃任務的中漏洞

0x07 fuzzing

做完上面的一些工作之后,我在想如何提高我的工作效率,畢竟我們部門產品眾多,但是代碼審計這個工作只有我一個在做。我把正常數據,畸形數據,poc數據,等其他數據全發給web api,然后在審計數據庫日志,危險函數日志,auditd日志,dns日志,web報錯日志,希望能從日志中發現潛藏的漏洞

利用burp的intruder這個功能就可以實現,測試用例可以使用wooyun提供的fuzzing數據

Ps 還是有幾個自己需要處理的問題:

  1. 需要根據自己的業務類型制定自己的測試用例
  2. 自己要想辦法處理產生的大量的日志
  3. 其他問題

0x08 TODO

  1. 自動化部署客戶端
  2. 開發一個日志處理平臺
  3. 盡可能的覆蓋更多的漏洞類型
  4. 豐富測試用例
  5. 開源( https://github.com/niexinming/python_hook

Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/689/