利用SQLite數據庫文件實現任意代碼執行

GenesisCana 8年前發布 | 15K 次閱讀 SQLite 數據庫服務器

前言

近期,我們對貝爾金WeMo智能家居設備的安全性進行了分析。在研究過程中,我們開發出了一種新型的SQL注入技術,這項技術針對的是SQLite數據庫。實驗表明,我們可以利用這項SQLite注入技術在SQLite數據庫中實現任意代碼執行。這篇文章將會告訴大家如何去創建一個SQLite數據庫,并且利用純粹的SQL查詢語句來執行一個ashShell腳本。

我們認為,對于滲透測試人員和漏洞研究社區而言,這項技術的適用性是非常廣泛的。我們希望這篇文章能夠給各位帶來有價值的信息,并且各位能夠通過這篇文章中的內容自己動手復現這個漏洞。

背景知識

利用SQLite注入漏洞來執行任意代碼的一個最簡單的方法就是利用load_extension()函數來執行共享庫中的某個函數。但是libsqlite3.so這個庫默認是禁止這個功能的,因為這很明顯就是一個安全漏洞。實際上,在某些 SQLite injection cheat sheets (SQLite注入安全備忘單)中,也有人會使用一個ATTACH DATABASE語句來在目標Web服務器的根目錄下創建SQLite文件。此時,攻擊者就可以使用惡意PHP代碼來對該文件進行處理,當攻擊者向服務器請求該文件時,PHP解釋器就會執行其中的惡意代碼。相關代碼如下所示:

ATTACH DATABASE ‘/var/www/lol.php’ AS lol;
CREATE TABLE lol.pwn (dataz text);
INSERT INTO lol.pwn (dataz) VALUES(‘

    ’);--

ATTACH DATABASE語句首先會檢查指定位置是否存在相應的文件。如果存在,那么它便會嘗試將該文件視作一個SQLite數據庫來打開。如果不存在,它將會在目標地址創建這個文件,并為這個SQLite數據庫文件賦予讀取和寫入權限。在上面這個例子中,語句在/var/www/目錄下創建了一個名為lol.php的文件,我們可以使用“lol”作為數據庫名稱來訪問這個文件接下來,我們在“lol”數據庫中創建了一個名為“pwn”的表,并向該表插入了一個字符串。當Web服務器請求該文件時,該數據庫的后綴名“.php”將會觸發Web服務器的PHP解釋器。解釋器會尋找文件中的“<?”,并嘗試執行該符號之后的所有語句,直到解釋器掃描到“?>”為止。在這種情況下,無論 “cmd”這個GET請求變量中包含的是怎樣的代碼,這些代碼最終都會以系統命令的形式得到執行。這樣一來,我們就可以使用這個方法來利用SQL注入漏洞實現任意命令執行了。但是大多數使用SQLite數據庫的服務器中并不會安裝PHP解釋器,例如很多嵌入式系統就是這樣。這樣一來,我們的技術就不管用了。

將SQLite當作一個ash腳本

很多基于Linux的嵌入式系統都會使用BusyBox工具套件來實現絕大部分基礎的Linux命令。默認情況下,BusyBox會使用ash shell來實現/bin/sh。所以我們打算看看是否可以創建一個SQLite數據庫文件,并將其當作一個ash shell腳本來執行,而且我們希望只使用SQL語句就能夠執行它。因為ash的命令解析器比PHP的代碼解釋器要復雜的多,所以我們就要想一些其他的辦法了。不過幸運的是,ash比bash要簡單得多,看來我們選擇ash是正確的。

首先我們要了解的是,ash的解析器對于換行符(“\n”)和圓括號(“(”和“)”)是非常敏感的。這是因為當用戶在命令行中按下回車之后,便會插入一個新行,而括號中包含的指令是subshell所需要執行的指令。所以,如果我們能夠找到某種方法可以在SQLite數據庫文件中插入這些字符的話,我們就可以用它們來控制ash在處理這個文件時所采用的方式了。

圖片1:向一個SQLite數據庫文件插入并保存換行符

我們使用“插入換行符”這個技巧的主要依據為:SQLite數據庫會將用于構造數據庫模式的SQL語句保存下來,正如圖片1頂部的CREATE語句所表示的那樣,SQLite數據庫會將我們的換行符保存在數據庫模式的定義之中。

圖片1下半部分的代碼顯示的是我們將數據庫文件以ash shell腳本來運行時的情況。ash報告的第一個錯誤是它無法找到“SQLite”命令,因為它在解析代碼時,將文件中的第一個詞當作了命令,然后將CREATE語句中的內容(換行符之前的代碼)當作了命令的執行參數。這樣一來,我們只需要插入新的一行,就可以讓ash忽略整個文件的內容了。現在我們要解決的就是如何修復ash的第二個報錯,即“unterminated quoted string”(未結束引用字符串)。

圖片2:執行“echo”命令

很簡單,解決第二個報錯的方法就是另外插入新的一行。大家可以從圖片2中看到,我們在新的一行中向CREATE語句中添加了“withoutrowid”。我們在定義完數據表中的列之后,又插入了一個換行符。這樣一來,我們就用換行符包裹住了列定義語句了。當文件被當作腳本來解析時,列定義語句就會被視作一個單獨的文本行。圖片2底部的代碼表面,當文件作為腳本來執行時,“echonone primary key”這條語句將會被解析為一個echo命令,“noneprimary key”會被輸出到屏幕上。這樣一來,我們就可以實現任意命令執行了,因為我們可以將列名修改為任何想要執行的命令。當然了,這還不是真正意義上的“任意命令執行”,因為我們無法在命令中設置任意參數。為了得到一個有效的列定義,列名之后的第一個詞必須符合數據庫的類型定義。

圖片3:使用SQLite數據庫文件實現任意命令執行

為了實現任意命令執行,我們先回顧一下之前運行PHP惡意代碼所用的方法,即把需要執行的命令作為表的值來插入。大家可以在圖片3中看到,我們也使用了同樣的方法,只不過字符串的第一個字符和最后一個字符必須為換行符。

總結

閱讀完這篇文章之后,大家應該已經知道了如何去創建一個可以被當作ash shell腳本的SQLite數據庫文件了。

 

 

來自:http://www.freebuf.com/vuls/120213.html

 

 本文由用戶 GenesisCana 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!