路人甲 · 2015/09/25 14:54
0x01 sqlite load_extension
SQLite從3.3.6版本(http://www.sqlite.org/cgi/src/artifact/71405a8f9fedc0c2
)開始提供了支持擴展的能力,通過sqlite_load_extension API(或者load_extensionSQL語句),開發者可以在不改動SQLite源碼的情況下,通過動態加載的庫(so/dll/dylib)來擴展SQLite的能力。
便利的功能總是最先被黑客利用來實施攻擊。借助SQLite動態加載的這個特性,我們僅需要在可以預測的存儲路徑中預先放置一個覆蓋SQLite擴展規范的動態庫(Android平臺的so庫),然后通過SQL注入漏洞調用load_extension,就可以很輕松的激活這個庫中的代碼,直接形成了遠程代碼執行漏洞。國外黑客早就提出使用load_extension和sql注入漏洞來進行遠程代碼執行攻擊的方法,如下圖。
也許是SQLite官方也意識到了load_extension API的能力過于強大,在放出load_extension功能后僅20天,就在代碼中(http://www.sqlite.org/cgi/src/info/4692319ccf28b0eb)將load_extension的功能設置為默認關閉,需要在代碼中通過sqlite3_enable_load_extensionAPI顯式打開后方可使用,而此API無法在SQL語句中調用,斷絕了利用SQL注入打開的可能性。
0x02 Android平臺下的sqlite load_extension支持
出于功能和優化的原因,Google從 Android 4.1.2開始通過預編譯宏SQLITE_OMIT_LOAD_EXTENSION,從代碼上直接移除了SQLite動態加載擴展的能力,如下圖。
可以通過adb shell來判斷Android系統是不是默認支持load_extension,下圖為Android4.0.3下sqlite3的.help命令:
可以看出支持load extension,而Android4.1.2上則沒有該選項。
0x03 Android平臺下的sqlite extension模塊編譯
sqlite extension必須包含sqlite3ext.h頭文件,實現一個sqlite3_extension_init 入口。下圖為一個sqlite extension的基本框架:
接著是Android.mk文件,如下圖:
我們實現一個加載時打印log輸出的一個sqlie extension:
0x04 Android平臺下sqlite load_extension實戰
由于sqlite是未加密的數據庫,會導致數據泄露的風險,Android App都開始使用第三方透明加密數據庫組件,比如sqlcipher。由于sqlcipher編譯時沒移除load extension,如圖,導致使用它的App存在被遠程代碼執行攻擊的風險。
下面我們將通過一個簡單的demo來展示sql注入配合load_extension的漏洞利用。
首先,實現一個使用sqlcipher的Android程序,下載sqlcipher包,將庫文件導入項目,如下圖:
將導入包換成sqlcipher的:
加載sqlcihper的庫文件,并且打開數據庫時提供密鑰:
編譯的時候如果出錯,則將jar包引入并導出,如下圖:
實現一個存在sql注入的數據庫查詢語句,外部可控,如下圖:
該函數接收一個外部可控的參數,并將數據庫查詢語句進行拼接,導致可被外部植入惡意代碼進行代碼執行攻擊,如下圖:
執行之后,可以看到so加載成功,如下圖:
0x05 Android平臺下sqlite load_extension攻防
攻擊場景:存在漏洞的app可以接收文件,黑客可將文件通過目錄遍歷漏洞放到app私有目錄下,再通過發消息觸發sql注入語句,完美的遠程代碼執行攻擊。
漏洞防御:
- 由于sqlcipher的擴展默認是開啟的,如果需要sqlcipher,編譯sqlcipher的時候通過SQLITE_OMIT_LOAD_EXTENSION宏來關閉sqlcipher的擴展功能。
- 進行數據庫操作時,禁止將查詢語句進行拼接,防止存在sql注入漏洞。