美文网首页
【CTF-PHP】Shiyanbar PHP

【CTF-PHP】Shiyanbar PHP

作者: Kirin_say | 来源:发表于2018-03-27 13:28 被阅读288次

0x01 PHP大法

打开后提示:

Can you authenticate to this website? index.php.txt 

访问 index.php.txt :

<?php
if(eregi("hackerDJ",$_GET[id])) {
  echo("<p>not allowed!</p>");
  exit();
}

$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
  echo "<p>Access granted!</p>";
  echo "<p>flag: *****************} </p>";
}
?>


<br><br>
Can you authenticate to this website?

这里对id参数两次url编码即可:

/index.php?id=%2568ackerDJ

0x02 你真的会PHP吗?

抓包发现hint:

 hint  6c525af4059b4fe7d8c33a.txt 

访问文件得到源码:

<?php


$info = ""; 
$req = [];
$flag="xxxxxxxxxx";

ini_set("display_error", false); 
error_reporting(0); 


if(!isset($_POST['number'])){
   header("hint:6c525af4059b4fe7d8c33a.txt");

   die("have a fun!!"); 
}

foreach([$_POST] as $global_var) { 
    foreach($global_var as $key => $value) { 
        $value = trim($value); 
        is_string($value) && $req[$key] = addslashes($value); 
    } 
} 


function is_palindrome_number($number) { 
    $number = strval($number); 
    $i = 0; 
    $j = strlen($number) - 1; 
    while($i < $j) { 
        if($number[$i] !== $number[$j]) { 
            return false; 
        } 
        $i++; 
        $j--; 
    } 
    return true; 
} 


if(is_numeric($_REQUEST['number'])){
    
   $info="sorry, you cann't input a number!";

}elseif($req['number']!=strval(intval($req['number']))){
      
     $info = "number must be equal to it's integer!! ";  

}else{

     $value1 = intval($req["number"]);
     $value2 = intval(strrev($req["number"]));  

     if($value1!=$value2){
          $info="no, this is not a palindrome number!";
     }else{
          
          if(is_palindrome_number($req["number"])){
              $info = "nice! {$value1} is a palindrome number!"; 
          }else{
             $info=$flag;
          }
     }

}

echo $info;

很显然我们需要

  • is_numeric($_REQUEST['number']返回false,即:不能传入数字或数字字符串
  • req['number']!=strval(intval(req['number']返回false,即:需要我们进行弱类型比较时两者相等
  • value1!=value2返回false,即:传入的参数正逆intval转换后相等
  • is_palindrome_number($req["number"]返回false,即:str形式下的number参数正逆不同

注意:

  • ini_set("display_error", false)设置没有报错回显
  • intval()返回的值范围为4字节,对于超过这个范围的值将用边界值代替。( intval的取值范围:与操作系统相关:
    32位系统上为-2147483648到2147483647,
    64位系统上为-9223372036854775808到9223372036854775807)
  • is_numeric中支持多种进制以及科学计数法“e”
  • intval() 不能用于 array 或 object
  • trim() 函数移除字符串两侧的空白字符或其他预定义字符
  • is_numeric和intval函数在开始判断和转换前,会先跳过所有空白字符,而trim过滤的字符中没有 "\f" 可以以此用%0c(\f)过滤,本题不用
  • 由于php存储浮点数的特殊性,也可用于绕过(0.00000000000000000001=0//true)
    最后BP发包
    number:
0x00%00  //说实话,我不太明白这个为什么可以,它好像不能绕过$req['number']!=strval(intval($req['number'],而且0x00在is_numeric可以直接返回false,但直接传入不能绕过第一个条件,估计真实后台和这里有点区别
或者
2147483647%00

补充:
关于 intval:

intval (var, base)

参数列表:
参数  描述
var     必须。可以是任何标量类型。 intval() 不能用于数组 或 对象(类)。在此我得提一下标量类型包含四种:boolean(布尔型)integer(整型) float(浮点型, 也称作 double) string (字符串)
base    可选。转化所使用的进制,默认10进制如果 base 是 0,通过检测 var 参数的格式来决定使用的进制:如果字符串包括了 “0x” (或 “0X”) 的前缀,使用 16 进制如果字符串以 “0” 开始,使用 8 进制其他使用 10 进制

for example:

echo intval("0x1a", 0), "\n"; // 使用16进制。 结果 "26" 
echo intval("057", 0), "\n"; // 使用8进制。 结果 "47" 
echo intval("57"),"\n"; // 使用10进制。结果57
echo intval("42", 0), "\n"; //  结果 "42" 

其他相关姿势:
http://www.chnpanda.com/961.html

0x03 FALSE

打开之后View the source code:

<?php
if (isset($_GET['name']) and isset($_GET['password'])) {
    if ($_GET['name'] == $_GET['password'])
        echo '<p>Your password can not be your name!</p>';
    else if (sha1($_GET['name']) === sha1($_GET['password']))
      die('Flag: '.$flag);
    else
        echo '<p>Invalid password.</p>';
}
else{
    echo '<p>Login first!</p>';
?>

两个思路:
sha1碰撞或者利用sha1()的漏洞
法一:sha1碰撞:
参考文档:https://security.googleblog.com/2017/02/announcing-first-sha1-collision.html
引申md5碰撞:
https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value
以下两文件sha1相同:
https://shattered.io/static/shattered-1.pdf
https://shattered.io/static/shattered-2.pdf
直接脚本得flag:

import urllib
import  requests
str1=urllib.quote(open("shattered-1.pdf", "rb").read()[:320])
str2=urllib.quote(open("shattered-2.pdf", "rb").read()[:320])
url="http://ctf5.shiyanbar.com/web/false.php?name=%s&password=%s" %(str1,str2)
r=requests.get(url)
print  r.content

(不截取[:320]的话发现url过长(get下的url长度上限与服务器和浏览器有关),winhex下查看,其实两文件改变的是前320位,我们只取前320位,发现可以成功)

法二:利用sha1()函数漏洞

当我们向sha1()传入的参数是数组时,会由于无法处理数组类型,将报错并返回false,而利用"flase===flase",即可实现绕过
这里我们传入:

false.php?name[]=123&password[]=abc

即得flag

0x04 NSCTF web200

打开发现源码:


code

脚本解决:

str1="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws"
str2=str1.decode('rot13')[::-1].decode('base64')
ans=""
for  i  in  str2:
    ans+=chr(ord(i)-1)
print   ans[::-1]

其实也可以直接简化为:

str1="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws".decode('rot13')[::-1].decode('base64')

print "".join([chr(ord(i)-1) for i in str1])[::-1]

0x05 Once More

打开之后View the source code:

<?php
if (isset ($_GET['password'])) {
    if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
    {
        echo '<p>You password must be alphanumeric</p>';
    }
    else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
    {
        if (strpos ($_GET['password'], '*-*') !== FALSE)
        {
            die('Flag: ' . $flag);
        }
        else
        {
            echo('<p>*-* have not been found</p>');
        }
    }
    else
    {
        echo '<p>Invalid password</p>';
    }
}
?>

利用ereg函数漏洞
当我们传入数组,返回NULL
当我们利用截断传入%00,返回true

关于比较还有以下几点:

数组具有较少成员的数组较小,如果运算数 1 中的键不存在于运算数 2 中则数组无法比较,否则挨个值比较
array与object和其他类型比较都会大一些
这里构造:

?password[]=1
或者
?password=1e9%00*-*

传入即得flag

END

相关文章

网友评论

      本文标题:【CTF-PHP】Shiyanbar PHP

      本文链接:https://www.haomeiwen.com/subject/svojcftx.html