记一次参加CTF比赛翻车记!

 

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

正言:

 

这是入口界面登录+注册,开始注册登录看了一下

 

有了一个简单的提示:你好啊,但是你好像不是XDSEC的人,所以我就不给你flag啦~~

然而成功误导了我,百度了一番找到XDSEC官网,拿XDSEC的队员名称注册了一番,并无卵用!然后爆破目录、并无任何发现。

思路断了!之后才知道是由于Phpstorm IDE 开发过程中会生成一个.idea的缓存目录(里面包含一些敏感文件)输入url/.idea/workspace.xml 成功下载下来

 

发现一个zip压缩包(里面是它的源码无疑)下载后

 

里面只有三个文件注册、登录、用户下面开始我们的代码审计

Register.php

  1. <?php
  2. include('config.php');
  3. try{
  4. $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
  5. }catch (Exception $e){
  6. die('mysql connected error');
  7. }
  8. $admin = "xdsec"."###".str_shuffle('you_are_the_member_of_xdsec_here_is_your_flag');
  9. $username = (isset($_POST['username']) === true && $_POST['username'] !== '') ? (string)$_POST['username'] : die('Missing username');
  10. $password = (isset($_POST['password']) === true && $_POST['password'] !== '') ? (string)$_POST['password'] : die('Missing password');
  11. $code = (isset($_POST['code']) === true) ? (string)$_POST['code'] : '';
  12.  
  13. if (strlen($username) > 16 || strlen($username) > 16) {
  14. die('Invalid input');
  15. }
  16.  
  17. $sth = $pdo->prepare('SELECT username FROM users WHERE username = :username');
  18. $sth->execute([':username' => $username]);
  19. if ($sth->fetch() !== false) {
  20. die('username has been registered');
  21. }
  22.  
  23. $sth = $pdo->prepare('INSERT INTO users (username, password) VALUES (:username, :password)');
  24. $sth->execute([':username' => $username, ':password' => $password]);
  25.  
  26. preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
  27. if (count($matches) === 3 && $admin === $matches[0]) {
  28. $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
  29. $sth->execute([':username' => $username, ':identity' => $matches[1]]);
  30. } else {
  31. $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, "GUEST")');
  32. $sth->execute([':username' => $username]);
  33. }
  34. echo '<script>alert("register success");location.href="http://ashe666.blog.163.com/blog/./index.html"</script>';

Login.php

  1. <?php
  2. session_start();
  3. include('config.php');
  4. try{
  5. $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
  6. }catch (Exception $e){
  7. die('mysql connected error');
  8. }
  9. $username = (isset($_POST['username']) === true && $_POST['username'] !== '') ? (string)$_POST['username'] : die('Missing username');
  10. $password = (isset($_POST['password']) === true && $_POST['password'] !== '') ? (string)$_POST['password'] : die('Missing password');
  11.  
  12. if (strlen($username) > 32 || strlen($password) > 32) {
  13. die('Invalid input');
  14. }
  15.  
  16. $sth = $pdo->prepare('SELECT password FROM users WHERE username = :username');
  17. $sth->execute([':username' => $username]);
  18. if ($sth->fetch()[0] !== $password) {
  19. die('wrong password');
  20. }
  21. $_SESSION['username'] = $username;
  22. unset($_SESSION['is_logined']);
  23. unset($_SESSION['is_guest']);
  24. #echo $username;
  25. header("Location: member.php");
  26. ?>

Member.php

  1. <?php
  2. error_reporting(0);
  3. session_start();
  4. include('config.php');
  5. if (isset($_SESSION['username']) === false) {
  6. die('please login first');
  7. }
  8. try{
  9. $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
  10. }catch (Exception $e){
  11. die('mysql connected error');
  12. }
  13. $sth = $pdo->prepare('SELECT identity FROM identities WHERE username = :username');
  14. $sth->execute([':username' => $_SESSION['username']]);
  15. if ($sth->fetch()[0] === 'GUEST') {
  16. $_SESSION['is_guest'] = true;
  17. }
  18.  
  19. $_SESSION['is_logined'] = true;
  20. if (isset($_SESSION['is_logined']) === false || isset($_SESSION['is_guest']) === true) {
  21.  
  22. }else{
  23. if(isset($_GET['file'])===false)
  24. echo "None";
  25. elseif(is_file($_GET['file']))
  26. echo "you cannot give me a file";
  27. else
  28. readfile($_GET['file']);
  29. }
  30. ?>
  31. <html>
  32. <head>
  33. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  34. </head>
  35. <body background="./images/1.jpg">
  36. <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>
  37. <p style="color:orange">你好啊,但是你好像不是XDSEC的人,所以我就不给你flag啦~~</p>
  38. </body>
  39. </html>

直到member.php发现是一个文件读取漏洞,既然是一个文件读取漏洞而前面看.idea缓存里面有config.php 这样也许就可以获取我们所需要的信息,而漏洞形成是需要条件的下面我们来具体分析一下。

如果你能看懂上面的代码那么应该已经发现漏洞地点了。

漏洞触发地点:

member.php 第28行

  1. <?php
  2. error_reporting(0);
  3. session_start();
  4. include('config.php');
  5. if (isset($_SESSION['username']) === false) {
  6. die('please login first');
  7. }
  8. try{
  9. $pdo = new PDO('mysql:host=localhost;dbname=xdcms', $user, $pass);
  10. }catch (Exception $e){
  11. die('mysql connected error');
  12. }
  13. $sth = $pdo->prepare('SELECT identity FROM identities WHERE username = :username');
  14. $sth->execute([':username' => $_SESSION['username']]);
  15. if ($sth->fetch()[0] === 'GUEST') {
  16. $_SESSION['is_guest'] = true;
  17. }
  18. $_SESSION['is_logined'] = true;
  19. if (isset($_SESSION['is_logined']) === false || isset($_SESSION['is_guest']) === true) {
  20.  
  21. }else{
  22. if(isset($_GET['file'])===false)
  23. echo "None";
  24. elseif(is_file($_GET['file']))
  25. echo "you cannot give me a file";
  26. else
  27. readfile($_GET['file']);
  28. }
  29. ?>

readfile($_GET['file']); 导致文件读取漏洞,漏洞利用的前提是先达到前面的条件

isset($_SESSION['is_logined']) === false || isset($_SESSION['is_guest']) === true

想让他们执行到else语句,必须绕过isset($_SESSION['is_guest']) === true这个判断条件

  1. $sth = $pdo->prepare('SELECT identity FROM identities WHERE username = :username');
  2. $sth->execute([':username' => $_SESSION['username']]);
  3. if ($sth->fetch()[0] === 'GUEST') {
  4. $_SESSION['is_guest'] = true;
  5. }

继续跟踪到register.php

  1. $sth = $pdo->prepare('INSERT INTO users (username, password) VALUES (:username, :password)');
  2. $sth->execute([':username' => $username, ':password' => $password]);
  3.  
  4. preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
  5. if (count($matches) === 3 && $admin === $matches[0]) {
  6. $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
  7. $sth->execute([':username' => $username, ':identity' => $matches[1]]);
  8. } else {
  9. $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, "GUEST")');
  10. $sth->execute([':username' => $username]);
  11. }
  12. echo '<script>alert("register success");location.href="http://ashe666.blog.163.com/blog/./index.html"</script>';

这里进行一个判断满足条件

  1. if (count($matches) === 3 && $admin === $matches[0]) {
  2. $sth = $pdo->prepare('INSERT INTO identities (username, identity) VALUES (:username, :identity)');
  3. $sth->execute([':username' => $username, ':identity' => $matches[1]]);
  4. }

那么我们只需要通过这个判断就可以绕过isset($_SESSION['is_guest']) === true这个条件

  1. $admin = "xdsec"."###".str_shuffle('you_are_the_member_of_xdsec_here_is_your_flag');
  2. $code = (isset($_POST['code']) === true) ? (string)$_POST['code'] : '';
  3. preg_match('/^(xdsec)((?:###|\w)+)$/i', $code, $matches);
  4. 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

  1. $flag = "LCTF{pr3_maTch_1s_A_amaz1ng_Function}"
    到此结束

  1.  

某CTF代码审计题的更多相关文章

  1. 4.ctf实战题

    一道ctf实战题. 先亮出网址: http://fb2ad00f-0a28-4e38-8fff-849d7391e2d0.coding.io 打开连接,看到下面页面.Web题,首先就是扫描(御剑啊还有 ...

  2. 一道简单的CTF登录题题解

    一.解题感受 这道题50分,在实验吧练习场算比较高分,而且通过率只有14%,比较低的水平. 看到这两个数据,一开始就心生惬意,实在不应该呀! 也是因为心态原因,在发现test.php之后,自以为在SQ ...

  3. 社团的CTF逆向题WriteUp

    最近社团弄了CTF比赛,然后我就帮忙写了逆向的题目,这里写一下WriteUp,题目和源码在附件中给出 一个简单的逆向:one_jmp_to_flag.exe 这题算是签到题,直接OD智能搜索就完事了, ...

  4. 百道CTF刷题记录(一)

    简介 最近在刷CTF题,主攻Web,兼职Misc Shiyanbar 0x01 简单的登陆题 简单概括: 考点: %00截断正则 CBC字节翻转攻击 难度: 难 WP:https://blog.csd ...

  5. z3 巧解CTF逆向题

    z3 巧解逆向题 题目下载链接:http://reversing.kr/download.php?n=7 这次实验的题目为Reversing.kr网站中的一道题目. 题目要求: ReversingKr ...

  6. i春秋CTF web题(1)

    之前边看writeup,边做实验吧的web题,多多少少有些收获.但是知识点都已记不清.所以这次借助i春秋这个平台边做题,就当记笔记一样写写writeup(其实都大部分还是借鉴其他人的writeup). ...

  7. 结合order by 解CTF某题

    真tmd不容易 <?php error_reporting(0); if (!isset($_POST['uname']) || !isset($_POST['pwd'])) { echo '& ...

  8. 校园网络安全CTF 第一题 和 你真了解我吗?

    第一题: 需要先找到相应头(REsponse header中的tips) <?php$flag = "***";if (isset($_GET['repo']))//检测变量 ...

  9. 由一道CTF pwn题深入理解libc2.26中的tcache机制

    本文首发安全客:https://www.anquanke.com/post/id/104760 在刚结束的HITB-XCTF有一道pwn题gundam使用了2.26版本的libc.因为2.26版本中加 ...

随机推荐

  1. monkeyrunner多点触摸

    思路是:在屏幕上某个位置按着不放:device.touch(x,y,md.DOWN) 然后再做一个滑动的操作:device.drap((x1,y1),(x2,y2),0.2,10) 然后再松开按键:d ...

  2. scrum 第二次冲刺

    scrum 第二次冲刺 1.本周工作 本周正式开始了开发工作.首先设计了类图,建好了数据库,将整个小组的分工传到了禅道上,我主要负责后台的挂号操作. 本周分工如下: 首先搭建好了ssm框架,其中遇到了 ...

  3. 简单的PHP算法题

    简单的PHP算法题 目录 1.只根据n值打印n个0 2.根据n值打印一行 0101010101010101010101…… 3.根据n值实现1 00 111 0000 11111…… 4.根据n值实现 ...

  4. postgres循环sql

    CREATE OR replace function loop_addDevice(i integer) RETURNS integer as $$ declare count alias ; all ...

  5. BZOJ4415:[SHOI2013]发牌(线段树)

    Description 假设一开始,荷官拿出了一副新牌,这副牌有N张不同的牌,编号依次为1到N.由于是新牌,所以牌是按照顺序排好的,从牌库顶开始,依次为1, 2,……直到N,N号牌在牌库底.为了发完所 ...

  6. 什么是React中的组件

    组件就是页面上的一部分.如图,左边是一个网页.右边是对应的一个组件图.我们可以把一个大的网页拆分成很多小的部分.比如标题部分,对应一个组件,就是标题组件.搜索部分,对应的组件就是搜索组件.而这个搜索组 ...

  7. 如何写一个FMDB帮助类?看看runtime吧

    FMDB是一个封装很好的sqllite类库.项目中调用的时候只需要写SQL语句,就能实现数据的CURD.我试过即使手写SQL语句也很麻烦,需要一个字段一个字段的拼上去,而且容易出错.有没有动态获取字段 ...

  8. ImageNet Classification with Deep Convolutional Nerual Networks(AlexNet)

    Architecture: 整个网络8层,5个卷积层,3个全连接层 Relu Nonlinearity: 非饱和的relu比饱和的sigmoid或者tanh训练速度快很多,并有效解决梯度消失 Over ...

  9. GPU CUDA编程中threadIdx, blockIdx, blockDim, gridDim之间的区别与联系

    前期写代码的时候都会困惑这个实际的threadIdx(tid,实际的线程id)到底是多少,自己写出来的对不对,今天经过自己一些小例子的推敲,以及找到官网的相关介绍,总算自己弄清楚了. 在启动kerne ...

  10. SpringMVC学习记录四——功能开发及参数绑定

    9       商品修改功能开发 9.1      需求 操作流程: 1.进入商品查询列表页面 2.点击修改,进入商品修改页面,页面中显示了要修改的商品(从数据库查询) 要修改的商品从数据库查询,根据 ...