南邮CTF-CG Web题writeup详解

签到题

题目链接

image-20191106162753668

F12 # 查看源代码

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";}

此题有关MD5碰撞,哈希相等的问题,详解MD5碰撞看我之前的文章MD5碰撞和MD5值(哈希值)相等

大概就是: 在PHP的数的处理中,0开头的字符串会被转换成0

所以我们GET请求a=s878926199a,进行碰撞

image-20191106163458184

签到2

题目链接

image-20191106163755543

方式一

​ 添加输入框的值value="zhimakaimen",然后点击开门

方式二

​ 修改输入框的最大输入长度maxlength='11',然后在输入框输入zhimakaimen,再提交即可

这题不是WEB

题目链接

image-20191106164226710

下载动图,直接文本方式打开(notepad也ok)

image-20191106164324505

层层递进

题目链接

F12 # 查看源代码

image-20191106164458500

访问此页面 SO.html

image-20191106164611379

继续F12,访问 S0.html

image-20191106164647154

继续访问, SO.htm

image-20191106164734181

继续进入, S0.htm

image-20191106164806035

进入404.html,点击回退就真的回去了(hhh),F12分析一波

image-20191106164905831

AAencode

题目链接

image-20191106165147839

换编码后

image-20191106165244396

复制,控制台运行,弹出FLAG

image-20191106165337816

单身二十年

题目链接

真的是考验手速的题? 我看未必 Burp抓包

image-20191106165538239

php decode

<?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=="));
?>

复制到php文件运行

image-20191106170009458

eval改成print_r,因为此函数的执行结果是返回值,所以我们需要打印出来

image-20191106170147915

文件包含

题目链接

点击click me? no进入了文件包含页面

image-20191106170323988

我们可以使用php://filter协议包含index.php文件

php://filter/read=convert.base64-encode/resource=index.php

image-20191106170834158

将输出的base64加密的密文,进行解码

image-20191106171055082

文件注释中包含flag

单身一百年也没用

题目链接

burp又登场了

image-20191106171254297

Download~!

页面无法访问,待更新。。。

COOKIE

修改cookie的值为1,即可

image-20191106171645429

MYSQL

题目链接

访问robots.txt文件

image-20191106171740428

发现robots.txt中php代码,我们分析一下

image-20191106172108345

<?php
if($_GET[id]) {
   mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
  mysql_select_db(SAE_MYSQL_DB);
  $id = intval($_GET[id]);
  $query = @mysql_fetch_array(mysql_query("select content from ctf2 where id='$id'"));
  if ($_GET[id]==1024) {
      echo "<p>no! try again</p>";
  }
  else{
    echo($query[content]);
  }
}
?>

根据以上代码分析,这里是利用intval()函数来绕过,输出flag。因此,url传入id=1024.1

image-20191106172211916

intval()

intval() 函数用于获取变量的整数值。

intval() 函数通过使用指定的进制 base 转换(默认是十进制),返回变量 var 的 integer 数值。 intval() 不能用于 object,否则会产生 E_NOTICE 错误并返回 1。

PHP 4, PHP 5, PHP 7

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

参数说明:
$var:要转换成 integer 的数量值。
$base:转化所使用的进制。(默认是十进制)

如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 "0x" (或 "0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)。
返回值
成功时返回 var 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval('1000000000000') 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

字符串有可能返回 0,虽然取决于字符串最左侧的字符。

举例:

<?php
echo intval(42);                      // 42
echo intval(4.2);                     // 4
echo intval('42');                    // 42
echo intval('+42');                   // 42
echo intval('-42');                   // -42
echo intval(042);                     // 34
echo intval('042');                   // 42
echo intval(1e10);                    // 1410065408
echo intval('1e10');                  // 1
echo intval(0x1A);                    // 26
echo intval(42000000);                // 42000000
echo intval(420000000000000000000);   // 0
echo intval('420000000000000000000'); // 2147483647
echo intval(42.88, 8);                // 42,挑一个详解:这里是先将42.88取整,再将它以8进制转换为10进制
echo intval('42', 8);                 // 34
echo intval(array());                 // 0
echo intval(array('foo', 'bar'));     // 1
?>

因此,无论这个intval函数$base用的哪个进制来转换的,都是先将$var取整,再将$var$base进制转换为10进制

GBK Injection

题目链接

访问,需要传id这个参数

image-20191106172640403

一下子都想到sql注入,结果会显发现'和"等特殊字符都被转义

image-20191106172804773

然后发现可以利用宽字节注入(没有被转义)

image-20191107083142890

先判断字段数?id=1%df' order by 3 %23

image-20191107083725957

然后我们自定义回显id=1%df' and 1=2 union select 1,2 %23

image-20191107084020450

我们接下来按照以下步骤

  • 爆数据库(这里只需要知道当前数据库即可)
  • 爆表
  • 爆字段
  • 查询想要的值

注:一下操作全在修改自定义回显中体现

1).查看当前数据库

?id=1%df' and 1=2 union select 1,database() %23,其中database()表示当前数据库名

image-20191107084409642

2).报表( sae-chinalover这个数据库的表)

image-20191107085532993

注意,因为单引号和双引号被转义了,所以我们不能使用单引号来进行约束。我们可以将sae-chinalover转换为16进制

image-20191107085611068

注意:7361652d6368696e616c6f766572==sae-chinalover,其中没有引号,0x表示后面的数字是16进制数

3).通过表( ctf,ctf2,ctf3,ctf4,gbksqli,news )爆字段

​ 这里呢,因为flag在ctf4中,所以我们只拿一个来举例。其余的方法都大同小异
image-20191107090128927

获得两个字段, id,flag ,我们直接通过查询输出,?id=1%df' and 1=2 union select 1,group_concat(flag) from ctf4 %23

image-20191107090431094

/x00

题目链接

进去就是一段php代码

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

因为ereg()函数存在NULL截断漏洞,导致正则过滤被绕过,因此我们可以使用00截断

我们构造nctf=%00#biubiubiu, 尝试一次,发现失败

image-20191107091052578

后面才反应过来, ==url中的#后面的字符都会被浏览器解读为位置标识符。因此,这些字符都不会被发送到服务器端,于是,我们需要对#进行url编码==

image-20191107091214463

bypass again

题目链接

又是代码

<?php
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.';
}
?>

一看代码,就知道了,又是md5值的碰撞问题,参考我之前的文章MD5碰撞和MD5值(哈希值)相等

image-20191107091505130

变量覆盖

题目链接

进去一看

image-20191107091810207

点进去,发现以下代码,分析一波

<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
                        <?php
                        extract($_POST);
                        if ($pass == $thepassword_123) { ?>
                            <div class="alert alert-success">
                                <code><?php echo $theflag; ?></code>
                            </div>
                        <?php } ?>
                    <?php } ?>

可以参考CTF之php变量覆盖漏洞,这里主要就是我们可以通过extract()这个函数

extract()会把符号表中已存在的变量名的值替换掉 ,所以我们通过burp来构造值

image-20191107092353796

PHP是最好的语言

无法访问... 待更新

伪装者

题目链接

image-20191107092534236

一看到本地访问,我第一时间就想到了X-Forwarded-For: 127.0.0.1,打开burp,添加字段

image-20191107092718703

但是很遗憾,在这里行不通,但是我们还可以通过Client-IP:127.0.0.1来伪造

还有一下几种伪造方式:

X-Client-IP:1.1.1.1
X-Remote-IP:2.2.2.2
X-Remote-Addr:3.3.3.3
X-Originating-IP:4.4.4.4
X-Forwarded-For:5.5.5.5 

image-20191107093846799

Header

页面无法访问,待更新...

上传绕过

题目链接

image-20191107094124578

一个上传文件的页面,我们直接利用%00截断上传

image-20191107094342248

发现没用,只允许上传图片,然后将文件名改成1.jpg,但是我尝试使用修改hex为00便可以(至今有点迷,不知道为啥)

image-20191107094705232

image-20191107094512667

SQL注入1

题目链接

这个题特别简单

image-20191107094836626

发现不需要什么猜测,源代码都直接给你,hhh

<html>
<head>
Secure Web Login
</head>
<body>
<?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]);
  $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];
?>
<form method=post action=index.php>
<input type=text name=user value="Username">
<input type=password name=pass value="Password">
<input type=submit>
</form>
</body>
<a href="index.phps">Source</a>
</html>

$sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";重点是这一行代码,我们得想办法绕过

在用户框输入admin,提示如下

image-20191107095043648

我们直接闭合单引号,然后注释后面的代码,拿到flag

image-20191107095158798

pass check

题目链接

代码:

<?php
$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()函数的作用

image-20191107095507687

php5.3之前的strcmp的漏洞
当参数中的一个字符串是对象或者数组时,函数会返回0

通过以上我们知道传入一个数组即可绕过,因为POST传参,所以我们使用burp

image-20191107095955427

注:POST请求

起名字真难

题目地址

源代码:

<?php
function noother_says_correct($number)
{
       $one = ord('1');
       $nine = ord('9');
       for ($i = 0; $i < strlen($number); $i++)
       {   
               $digit = ord($number{$i});
               if ( ($digit >= $one) && ($digit <= $nine) )
               {
                       return false;
               }
       }
          return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
   echo $flag;
else 
   echo 'access denied';
?>

题目要求不能输入数字,但是输入的字符串必须和54975581388相同
用和54975581388等值的16进制表示,很巧,全不是数字,就成功了

image-20191107151919613

image-20191107152003982

当遇到 与数字字符串对比校验的时候,可以尝试转换为等值的16进制字串

密码重置

题目链接

image-20191107152245864

Y3RmdXNlcg==base64解码为ctfyuser

思路就是将url的值admin使用base64编码,输入框的账号也改成admin

admin使用base64加密得YWRtaW4=

image-20191107152635693

php 反序列化(暂时无法做)

暂时无法做...待更新

SQL Injection

题目链接

image-20191107153051664

F12发现php代码,我们分析一波

<!--
#GOAL: login as admin,then get the flag;
error_reporting(0);
require 'db.inc.php';

function clean($str){
    if(get_magic_quotes_gpc()){
        $str=stripslashes($str);
    }
    return htmlentities($str, 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;
-->

注意上面clean function中的htmlentities()函数,它会把输入字符中的 ’ 或者 ” 转变为html实体,这样一来就无法闭合源代码中的 ’ 了,还有就是,如果php的magic_quotes_gpc是开启状态的话,我们输入的转义符也会被去掉的,不过既然这道题目能做,说明我们是可以使用转义符 ,我们解这道题的关键就是使用转义符 来让源代码中
'SELECT * FROM users WHERE name=''.$username.'\' AND pass=\''.$password.'';'
$username后面的 ’ 失效,只要 这个 ’ 失效,就能闭合name=后面的 ’ ,要达到这一目的,我们只需要让username=admin 即可,让后使password的值为一个永真式(or 1=1)就可以得到这道题的flag
这样提交的数据,会导致源代码中的SQL语句变为:

SELECT * FROM users WHERE name='admin \' AND pass=' or 1=1

?username=admin \&password=or 1=1%23 ,%23是#的url编码

image-20191107153424670

综合题

题目链接

image-20191107153553605.png

我们直接将字符放在控制台执行

image-20191107153720908.png

我们访问这个页面

image-20191107153805399.png

history of bash,在linux系统中,history命令都保存在家目录下的.bash_history文件中

访问.bash_history发现压缩包

image-20191107153907913.png

访问flagbak.zip文件

image-20191107154006171.png

system(暂时无法做)

待更新...

SQL注入2

题目链接

image-20191107154110389.png

发现源代码,分析一下

<html>
<head>
Secure Web Login II
</head>
<body>

<?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'"));
  if (($query[pw]) && (!strcasecmp($pass, $query[pw]))) {
      echo "<p>Logged in! Key: ntcf{**************} </p>";
  }
  else {
    echo("<p>Log in failure!</p>");
  }
}
?>


<form method=post action=index.php>
<input type=text name=user value="Username">
<input type=password name=pass value="Password">
<input type=submit>
</form>
</body>
<a href="index.phps">Source</a>
</html>

1.用post方法输入两个变量

2.输入的变量pass的值经过MD5加密了

3.中存储的是sql命令的结果集

4.如果变量存在,并且,$pass与$query[pw]相等(不区分大小写)

所以我们考虑在$user上加上一个union语句,即向$query的结果集中在加一条,同时能够使得条4成立

image-20191107154848929.png

注意需要在union前加一个 ' 用于闭合'$uesr'前的那个引号,#是为了注释点后面的那个引号

综合题2

还不会,待更新...

密码重置2

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

题目链接

image-20191107155203134.png

F12,发现管理员邮箱地址

image-20191107155306673.png

在linux系统中,文件写入出现异常,会在本地生成一个.filename.swp的文件 # 注filename是你的文件名,我们访问.submit.php.swp

image-20191107155606806.png

源代码分析一波


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

/*
如果登录邮箱地址不是管理员则 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');
    $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){
        echo $flag;
    }else{
        echo "失败了呀";
    }
}
    

这边$token长度要等于10,$token= 0,所以我们构造10个0,0000000000

image-20191107160050767.png

file_get_contents

题目链接

F12,发现源代码

image-20191107160357034.png

<!--$file = $_GET['file'];
if(@file_get_contents($file) == "meizijiu"){
    echo $nctf;
}-->

file_put_contens()函数的作用

image-20191107160545789.png

我们使用burp,结合php://input协议,传数据

image-20191107160732042.png

注意,结构如下图

image-20191107160804657.png

变量覆盖

题目链接

F12,发现源代码

image-20191107160957507.png

<!--foreach($_GET as $key => $value){  
        $$key = $value;  
}  
if($name == "meizijiu233"){
    echo $flag;
}-->

GET传name=meizijiu233,使得$key=name,那么$$key=$name,这样来改变变量的值

image-20191107161120433.png

注意!!

image-20191107161312350.png

这个不是题

HateIT

做不了啊,待更新...

Anonymous

做不了啊,待更新...

总结

  • 变量覆盖
  • 进制转换(PHP)

以上两点比较生疏,加强练习,最后,F12无敌!!! 没思路就F12

参考链接

本文链接:

https://www.betao.cn/archives/nyctf.html
1 + 6 =
快来做第一个评论的人吧~