某CTF代码审计题
记一次参加CTF比赛翻车记!

开始还是挺有信心的,毕竟也是经常打一些CTF锻炼,然而比赛发现大佬们平时不显山不漏水的一比赛全出来了!赛后看了一下各题的writeup发现自己的确技不如人啊!借鉴一个案例拿出来分析一下!
正言:
这是入口界面登录+注册,开始注册登录看了一下

有了一个简单的提示:你好啊,但是你好像不是XDSEC的人,所以我就不给你flag啦~~
然而成功误导了我,百度了一番找到XDSEC官网,拿XDSEC的队员名称注册了一番,并无卵用!然后爆破目录、并无任何发现。
思路断了!之后才知道是由于Phpstorm IDE 开发过程中会生成一个.idea的缓存目录(里面包含一些敏感文件)输入url/.idea/workspace.xml 成功下载下来

发现一个zip压缩包(里面是它的源码无疑)下载后
里面只有三个文件注册、登录、用户下面开始我们的代码审计
Register.php
- <?php
- include('config.php');
- try{
- $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
- }catch (Exception $e){
- die('mysql connected error');
- }
- $admin = "xdsec"."###".str_shuffle('you_are_the_member_of_xdsec_here_is_your_flag');
- $username = (isset($_POST['username']) === true && $_POST['username'] !== '') ? (string)$_POST['username'] : die('Missing username');
- $password = (isset($_POST['password']) === true && $_POST['password'] !== '') ? (string)$_POST['password'] : die('Missing password');
- $code = (isset($_POST['code']) === true) ? (string)$_POST['code'] : '';
- if (strlen($username) > 16 || strlen($username) > 16) {
- die('Invalid input');
- }
- $sth = $pdo->prepare('SELECT username FROM users WHERE username = :username');
- $sth->execute([':username' => $username]);
- if ($sth->fetch() !== false) {
- die('username has been registered');
- }
- $sth = $pdo->prepare('INSERT INTO users (username, password) VALUES (:username, :password)');
- $sth->execute([':username' => $username, ':password' => $password]);
- preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
- if (count($matches) === 3 && $admin === $matches[0]) {
- $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
- $sth->execute([':username' => $username, ':identity' => $matches[1]]);
- } else {
- $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, "GUEST")');
- $sth->execute([':username' => $username]);
- }
- echo '<script>alert("register success");location.href="http://ashe666.blog.163.com/blog/./index.html"</script>';
Login.php
- <?php
- session_start();
- include('config.php');
- try{
- $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
- }catch (Exception $e){
- die('mysql connected error');
- }
- $username = (isset($_POST['username']) === true && $_POST['username'] !== '') ? (string)$_POST['username'] : die('Missing username');
- $password = (isset($_POST['password']) === true && $_POST['password'] !== '') ? (string)$_POST['password'] : die('Missing password');
- if (strlen($username) > 32 || strlen($password) > 32) {
- die('Invalid input');
- }
- $sth = $pdo->prepare('SELECT password FROM users WHERE username = :username');
- $sth->execute([':username' => $username]);
- if ($sth->fetch()[0] !== $password) {
- die('wrong password');
- }
- $_SESSION['username'] = $username;
- unset($_SESSION['is_logined']);
- unset($_SESSION['is_guest']);
- #echo $username;
- header("Location: member.php");
- ?>
Member.php
- <?php
- error_reporting(0);
- session_start();
- include('config.php');
- if (isset($_SESSION['username']) === false) {
- die('please login first');
- }
- try{
- $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
- }catch (Exception $e){
- die('mysql connected error');
- }
- $sth = $pdo->prepare('SELECT identity FROM identities WHERE username = :username');
- $sth->execute([':username' => $_SESSION['username']]);
- if ($sth->fetch()[0] === 'GUEST') {
- $_SESSION['is_guest'] = true;
- }
- $_SESSION['is_logined'] = true;
- if (isset($_SESSION['is_logined']) === false || isset($_SESSION['is_guest']) === true) {
- }else{
- if(isset($_GET['file'])===false)
- echo "None";
- elseif(is_file($_GET['file']))
- echo "you cannot give me a file";
- else
- readfile($_GET['file']);
- }
- ?>
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- </head>
- <body background="./images/1.jpg">
- <object type="application/x-shockwave-flash" style="outline:none;" data="http://cdn.abowman.com/widgets/hamster/hamster.swf?" width="300" height="225"><param name="movie" value="http://cdn.abowman.com/widgets/hamster/hamster.swf?"></param><param name="AllowScriptAccess" value="always"></param><param name="wmode" value="opaque"></param></object>
- <p style="color:orange">你好啊,但是你好像不是XDSEC的人,所以我就不给你flag啦~~</p>
- </body>
- </html>
直到member.php发现是一个文件读取漏洞,既然是一个文件读取漏洞而前面看.idea缓存里面有config.php 这样也许就可以获取我们所需要的信息,而漏洞形成是需要条件的下面我们来具体分析一下。
如果你能看懂上面的代码那么应该已经发现漏洞地点了。
漏洞触发地点:
member.php 第28行
- <?php
- error_reporting(0);
- session_start();
- include('config.php');
- if (isset($_SESSION['username']) === false) {
- die('please login first');
- }
- try{
- $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
- }catch (Exception $e){
- die('mysql connected error');
- }
- $sth = $pdo->prepare('SELECT identity FROM identities WHERE username = :username');
- $sth->execute([':username' => $_SESSION['username']]);
- if ($sth->fetch()[0] === 'GUEST') {
- $_SESSION['is_guest'] = true;
- }
- $_SESSION['is_logined'] = true;
- if (isset($_SESSION['is_logined']) === false || isset($_SESSION['is_guest']) === true) {
- }else{
- if(isset($_GET['file'])===false)
- echo "None";
- elseif(is_file($_GET['file']))
- echo "you cannot give me a file";
- else
- readfile($_GET['file']);
- }
- ?>
readfile($_GET['file']); 导致文件读取漏洞,漏洞利用的前提是先达到前面的条件
isset($_SESSION['is_logined']) === false || isset($_SESSION['is_guest']) === true
想让他们执行到else语句,必须绕过isset($_SESSION['is_guest']) === true这个判断条件
- $sth = $pdo->prepare('SELECT identity FROM identities WHERE username = :username');
- $sth->execute([':username' => $_SESSION['username']]);
- if ($sth->fetch()[0] === 'GUEST') {
- $_SESSION['is_guest'] = true;
- }
继续跟踪到register.php
- $sth = $pdo->prepare('INSERT INTO users (username, password) VALUES (:username, :password)');
- $sth->execute([':username' => $username, ':password' => $password]);
- preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
- if (count($matches) === 3 && $admin === $matches[0]) {
- $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
- $sth->execute([':username' => $username, ':identity' => $matches[1]]);
- } else {
- $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, "GUEST")');
- $sth->execute([':username' => $username]);
- }
- echo '<script>alert("register success");location.href="http://ashe666.blog.163.com/blog/./index.html"</script>';
这里进行一个判断满足条件
- if (count($matches) === 3 && $admin === $matches[0]) {
- $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
- $sth->execute([':username' => $username, ':identity' => $matches[1]]);
- }
那么我们只需要通过这个判断就可以绕过isset($_SESSION['is_guest']) === true这个条件
- $admin = "xdsec"."###".str_shuffle('you_are_the_member_of_xdsec_here_is_your_flag');
- $code = (isset($_POST['code']) === true) ? (string)$_POST['code'] : '';
- preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
- if (count($matches) === 3 && $admin === $matches[0]) {
而过程就是这个正则
$code 是可控的匹配字符、$matches是返回值储存地址
而上面就是需要让$matches[0]===$admin
而$matches[0]是匹配到的值
$admin的值由于str_shuffle函数是不确定的,当然我们也可以通过爆破来实现,然而我们还有一个更好的方法。
通过$code传入长字符串来让preg_match函数消耗资源(拖延时间)导致后面的语句暂时无法执行,而此时我们的账户已经注册成功了,由于传入大量字符串preg_match不能在短时间内执行完成所以我们可以在这段时间内进行漏洞利用,由于数据库查询是空的所以可以绕过验证。
漏洞复现:
payload:to=reg&did=0&username=coolbreeze&password=coolbreeze&code=xdsec###超长字符串
注册处使用burp拦截修改

这是点击Go
进入登录
直接构造payload:member.php?file=php://filter/resource=config.php
因为前面通过is_file()函数来过滤所以这里通过php伪协议来读取数据
这里成功获取CTF
- $flag = "LCTF{pr3_maTch_1s_A_amaz1ng_Function}"
到此结束
某CTF代码审计题的更多相关文章
- 4.ctf实战题
一道ctf实战题. 先亮出网址: http://fb2ad00f-0a28-4e38-8fff-849d7391e2d0.coding.io 打开连接,看到下面页面.Web题,首先就是扫描(御剑啊还有 ...
- 一道简单的CTF登录题题解
一.解题感受 这道题50分,在实验吧练习场算比较高分,而且通过率只有14%,比较低的水平. 看到这两个数据,一开始就心生惬意,实在不应该呀! 也是因为心态原因,在发现test.php之后,自以为在SQ ...
- 社团的CTF逆向题WriteUp
最近社团弄了CTF比赛,然后我就帮忙写了逆向的题目,这里写一下WriteUp,题目和源码在附件中给出 一个简单的逆向:one_jmp_to_flag.exe 这题算是签到题,直接OD智能搜索就完事了, ...
- 百道CTF刷题记录(一)
简介 最近在刷CTF题,主攻Web,兼职Misc Shiyanbar 0x01 简单的登陆题 简单概括: 考点: %00截断正则 CBC字节翻转攻击 难度: 难 WP:https://blog.csd ...
- z3 巧解CTF逆向题
z3 巧解逆向题 题目下载链接:http://reversing.kr/download.php?n=7 这次实验的题目为Reversing.kr网站中的一道题目. 题目要求: ReversingKr ...
- i春秋CTF web题(1)
之前边看writeup,边做实验吧的web题,多多少少有些收获.但是知识点都已记不清.所以这次借助i春秋这个平台边做题,就当记笔记一样写写writeup(其实都大部分还是借鉴其他人的writeup). ...
- 结合order by 解CTF某题
真tmd不容易 <?php error_reporting(0); if (!isset($_POST['uname']) || !isset($_POST['pwd'])) { echo '& ...
- 校园网络安全CTF 第一题 和 你真了解我吗?
第一题: 需要先找到相应头(REsponse header中的tips) <?php$flag = "***";if (isset($_GET['repo']))//检测变量 ...
- 由一道CTF pwn题深入理解libc2.26中的tcache机制
本文首发安全客:https://www.anquanke.com/post/id/104760 在刚结束的HITB-XCTF有一道pwn题gundam使用了2.26版本的libc.因为2.26版本中加 ...
随机推荐
- 解决Image在canvas以及audio、video在AudioContext下跨域问题
媒体元素嘛,在对应的标签或对象上加上 crossOrigin = 'anonymous' 即可. 例如 Image 在canvas 上绘制时会跨域: <img crossOrigin=" ...
- 实验:将系统进程映射移到 Python 字典中
参考官方文档,测试下列代码,把oracle的进程映射到python的字典中: [oracle@ycr python]$ more pro_get.py import reimport subproce ...
- gridview导出exe处理时遇到RegisterForEventValidation can only be called during Render();错误
如题,今天在利用GridView作execl导出时,遇到RegisterForEventValidation can only be called during Render();问题.根据网上找到的 ...
- mysql数据库 BETWEEN 语法的用法和边界值解析
between用法: 用于where表达式中,选取两个值之间的数据,如: SELECT id FROM user WHERE id BETWEEN value1 AND value2; 当betwee ...
- C语言 字符串处理函数
#include <stdio.h> #include <string.h> // strlen void test() { // 测量字符串常量的字符长度(不包括\0这个字符 ...
- 【洛谷P1118】数字三角形
数字三角形 题目链接 4 16 3 1 2 4 3 1 2 4 (3+1) (1+2) (2+4)(3+1+1+2) (1+2+2+4) (3+1+1+1+2+2+2+4)16=1*3+3*1+3*2 ...
- SpeedTree制作超真实老宅
- H5面试题整理
1.新的HTML5文档类型和字符集是? 文档类型:<!doctype html> 使用UTF-8编码示例:<meta charset="UTF-8"> 2. ...
- GET&&POST请求编码过程
编码.解码 我们在开发过程中不可避免的一个话题就是编码和解码,那么什么是编码什么是解码呢?为什么要进行编码和解码呢?下面我们一一分析! 编码和解码的概念 编码是信息从一种形式或格式转换为另一种形式的过 ...
- Unity 游戏框架搭建 (九) 减少加班利器-QConsole
为毛要实现这个工具? 在我小时候,每当游戏在真机运行时,我们看到的日志是这样的. 没高亮啊,还有乱七八糟的堆栈信息,好干扰日志查看,好影响心情. 还有就是必须始终连着usb线啊,我想要想躺着测试... ...