Xctf

还有两个月Xctf就开始了,也是第一次参加Xctf这样高校中难度级别最高的比赛。最近做了几道历届的Xctf题。

1.

根据提示在URL处尝试hint=1,然后页面给出了一段代码。

 <?php
error_reporting(0);
include_once("flag.php");
$cookie = $_COOKIE['ISecer'];
if(isset($_GET['hint'])){
    show_source(__FILE__);
}
elseif (unserialize($cookie) === "$KEY")
{   
    echo "$flag";
}
else {
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link rel="stylesheet" href="admin.css" type="text/css">
</head>
<body>
<br>
<div class="container" align="center">
  <form method="POST" action="#">
    <p><input name="user" type="text" placeholder="Username"></p>
    <p><input name="password" type="password" placeholder="Password"></p>
    <p><input value="Login" type="button"/></p>
  </form>
</div>
</body>
</html>

<?php
}
$KEY='ISecer:www.isecer.com';
?> 

代码的意思很明确,cookie反序列化后得到的字符串等于key,就得到答案。

开始以为key的值就是最下面的那个isecer但后来看整段代码,发现其实key的值还没有被定义,因此key的值应该是NULL

序列化后的结果s:0:"",于是构造cookie:ISser = s:0:""

但是直接把这个cookie上传到服务器上,服务器不会解析,原因是;(分号)需要被转义,最终的cookie应该是ISser = s:0:""%3B

 这种题在Xctf上出现也不算罕见,提示的信息很重要,例如这道题,给出的hint其实是一个重要的参数,我在做这道题的时候这个切入点也是蒙出来的。

2.php_encrypt(密码学)

题目中给出这样一段字符串

fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=

还有一段代码

<?php
function encrypt($data,$key)
{
    $key = md5('ISCC');
    $x = 0;
    $len = strlen($data);
    $klen = strlen($key);
    for ($i=0; $i < $len; $i++) {
        if ($x == $klen)
        {
            $x = 0;
        }
        $char .= $key[$x];
        $x+=1;
    }
    for ($i=0; $i < $len; $i++) {
        $str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
    }
    return base64_encode($str);
}

?>

flag为一段字符串,将flag传入给data,然后运行这个函数,最终运行结果是提示中的字符串,因此需要逆向找出这个flag。

<?php
function decrypt($str) {
    $mkey = "729623334f0aa2784a1599fd374c120d";
    $klen = strlen($mkey);
    $tmp = $str;
    $tmp = base64_decode($tmp);  // 对 base64 后的字符串 decode
    $md_len = strlen($tmp); //获取字符串长度
    $x = 0;
    $char = "";
    for($i=0;$i < $md_len;$i++) {  //  取二次加密用 key;
        if ($x == $klen)  // 数据长度是否超过 key 长度检测
            $x = 0;
        $char .= $mkey[$x];  // 从 key 中取二次加密用 key
        $x+=1;
    }
    $md_data = array();
    for($i=0;$i<$md_len;$i++) { // 取偏移后密文数据
        array_push($md_data, ord($tmp[$i]));
    }
    $md_data_source = array();
    $data1 = "";
    $data2 = "";
    foreach ($md_data as $key => $value) { // 对偏移后的密文数据进行还原
        $i = $key;
        if($i >= strlen($mkey)) {$i = $i - strlen($mkey);}
        $dd = $value;
        $od = ord($mkey[$i]);
        array_push($md_data_source,$dd);
        $data1 .= chr(($dd+128)-$od);  // 第一种可能, 余数+128-key 为回归数
        $data2 .= chr($dd-$od);  // 第二种可能, 余数直接-key 为回归数
    }
    print "data1 => ".$data1."<br>\n";
    print "data2 => ".$data2."<br>\n";
}
$str = "fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=";
decrypt($str);
?>

Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}

代码审计:

  • extract覆盖变量
<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan))
{
$content=trim(file_get_contents($flag));
if($shiyan==$content)
{
echo'flag{xxx}';
}
else
{
echo'Oh.no';
}
}
?>

存在一个名称为shiyan的字符串,将flag变量的值赋值给content变量。如果shiyan=content,输出flag,extract的作用是可以替换变量,也就是无论传入时的变量名是什么,被extract后都会变成flag。
因此可以构造?shiyan=&flag,这样的写法是因为shiyan这个变量被extract之后是一个空值,flag也是空值,二者相等就可以执行输出flag的语句。
flag{bugku-dmsj-p2sm3N}

  • strcmp

    用法:stramp(a,b) a大于b返回1,等于返回0,小于返回-1。

<?php
$flag = "flag{xxxxx}";
if (isset($_GET['a'])) {
if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
die('Flag: '.$flag);
else
print 'No';
}
?>

这里直接传进去一个a[]=1 a是一个数组类型就可以。

  • urldecode二次编码绕过

<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("

not allowed!
");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "

Access granted!
";
echo "

flag
";
}
?>

  eregi()函数在一个字符串搜索指定的模式的字符串。搜索不区分大小写

因此对于传入的id第一个要求不能为"hackerDJ"

第二个地方id 需要两次urldecode 因为在传入id时已经经过一次编码。

id=hackerD%254A

  • md5()函数

<?php
error_reporting(0);
$flag = 'flag{test}';
if (isset($_GET['username']) and isset($_GET['password'])) {
if ($_GET['username'] == $_GET['password'])
print 'Your password can not be your username.';
else if (md5($_GET['username']) === md5($_GET['password']))
die('Flag: '.$flag);
else
print 'Invalid password';
}
?>

直接以数组的形式进行不同的赋值。username[]=1&password[]=2

  • 数组返回NULL绕过

<?php
$flag = "flag";

if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
echo 'You password must be alphanumeric';
else if (strpos ($_GET['password'], '--') !== FALSE)
die('Flag: ' . $flag);
else
echo 'Invalid password';
}
?>

strops:查找 "php" 在字符串中第一次出现的位置,用空数组可以进行绕过。

erges:字符截断,%00

http://120.24.86.145:9009/19.php?password[]=%00

  • 弱类型整数大小比较绕过

$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag

弱类型包括数字+字符,数组,这里用的是数组;

password[]=1

  • sha()函数比较绕过

<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password']))
{
var_dump($_GET['name']);
echo "
";
var_dump($_GET['password']);
var_dump(sha1($_GET['name']));
var_dump(sha1($_GET['password']));
if ($_GET['name'] == $_GET['password'])
echo '

Your password can not be your name!
';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
echo '

Invalid password.
';

sha和MD5都是加密方式,都无法处理数组,因此和MD5处理方式相同。name[]=1&password[]=2

猜你喜欢

转载自www.cnblogs.com/sylover/p/10640219.html