Natas28 Writeup(ECB分组密码攻击)

Natas28:

页面显示这是一个笑话库,可以查找提交字符串所在的笑话内容并随机返回。

 

初步探索

burp抓包发现,流程是post表单提交一个明文后返回一个重定向,然后get请求一个加密参数返回查询结果。这个加密的参数一定以某种方式包含了我们的输入。

我们尝试修改get请求中query的值,返回报错信息:Invalid PKCS#7 padding encountered。说明此处的加密使用了PKCS7Padding填充模式。

将加密后的数据先URL解码再Base64解码,可以得到原始的加密字节。

方法一,使用burp的Decoder模块进行解码

方法二,使用PHP代码进行解码(缺点是得到的字节未经格式化,不易观察规律)

<?php

$x="G%2BglEae6W%2F1XjA7vRm21nNyEco%2Fc%2BJ2TdR0Qp8dcjPKOvt9wFI9mjTVoT%2FtGtl7FvfoQVOxoUVz5bypVRFkZR5BPSyq%2FLC12hqpypTFRyXA%3D";

$y=bin2hex(base64_decode(urldecode($x)));

echo $y;

?>

//执行PHP代码,得到字符串:
//1be82511a7ba5bfd578c0eef466db59cdc84728fdcf89d93751d10a7c75c8cf28ebedf70148f668d35684ffb46b65ec5bdfa1054ec68515cf96f2a5544591947904f4b2abf2c2d7686aa72a53151c970

  

ECB模式

尝试几种不同的输入,可以注意到以下2点。

一是随着输入文本的不同,加密文本的前32个字节始终相同,不会改变。这意味着get的参数值始终以相同的文本开头。
二是更改输入的第一个字符(输入的长度不变)不会更改加密文本的结尾。这表明用于加密此文本的加密模式未使用链块密码,因此这意味着每个块都是独立的(ECB)。

 

更多观察

ECB模式是分组(块)加密模式,待加密文本被分为大小合适的块,然后分别对每一块独立进行加密或解密处理。当最后一块不足分块大小时,会根据某种模式进行填充。比如说本题使用的就是PKCS7Padding填充模式。目前我们知道了本题的加密方式是ECB,若想要破解它,接下来我们需要知道块大小(BlockSize)。可以通过依次多添加1个字符来观察到这一点。我们可以看到,当输入为10个及以上字符时,第三块16个字节便会停止更改,它将被锁定。因此,我们得出块大小为16个字节,需要10个字符来填充第三块。(这里的一个字符指的是一个英文字母,占1个字节)

 

暴力破解附加文本

再次观察密文发现,即使我们准确地传递了10个字符来填充第三块,此后仍然还有更多的块。这说明在我们输入的文本后面,还有一部分附加文本。下面我们来尝试破解后面的这些块,以解密附加文本。

如果我们提交的输入只有9个字符,则第三个块中的最后一个字符将包含附加文本的第一个字符!

假设我们提交了9个字母“a”,得到加密文本第三个块的值为X。然后,我们再尝试提交以9个字母“a”开头和随机最后1个字符的输入,得到第三个块的值,将其与X进行对比,则可以猜测出此字符。字符是%。

通常,我们能够扩展此过程并解密整个附加文本。但不幸的是,由于输入的某些特殊字符会被转义(比如'变成\'),因此无法猜测附加文本中是否包含将被转义的字符。因此我们只能从此过程中解密该%字符。

 

深入探索

这个%字符表明后台可能对我们的输入文本进行了基于LIKE的模糊查询(%通配符表示任何字符出现任意次数)。猜测格式类似于:

select text from jokes where text like ‘%user_input%’;

我们的思路是构造sql注入,因为服务器端对post表单提交的数据进行了过滤,所有的引号在加密前都将被转义,因此我们不能简单地在输入框中通过输入引号来闭合前面sql的方法进行sql注入。

所以只能考虑get请求,由于get请求所提交的数据是post返回的完整的sql语句,意味着存在修改其他部分的可能。我们希望将它修改为

select text from jokes where text like ‘%user_input%’ union select password from users #

由于所有输入的引号都会被转义('变为\'),所以我们无法直接得到引号的ECB加密,但是我们可以通过构造获得。

 

构造输入

首先输入【aaaaaaaaa' union select password from users #############】,得到加密字节如下:

由于服务器端会先将输入的'转义为\',然后再进行ECB加密,所以上面加密字节中间部分加密的其实是【aaaaaaaaa\' union select password from users #############】,由于【aaaaaaaaa\】是10个字节,正好补齐了第3块,而【' union select password from users #############】正好是48个字符,所以加密字节中的第4,5,6块正好是其加密后的值(设为A)。

接着输入【aaaaaaaaaa】(10个字节正好补齐第三块)得到加密字节(设为B)如下:

可以看到,上面两段加密字节的最后2块正好相同(均是附加文本的加密内容),这也表明我们构造的内容【' union select password from users #############】确实是整组。

B的前三块的内容正好是【select text from jokes where text like ‘%aaaaaaaaaa】的加密文本,而刚才我们又得到了【' union select password from users #############】的加密文本A。然后,我们把A插入到B的第三块和第四块之间,得到加密的字节(设为C)如下:

我们知道,C就是以【select text from jokes where text like ‘%aaaaaaaaaa' union select password from users #############】开头的加密文本(后面附加文本代表什么无所谓,因为已经被注释掉了)。

现在让我们将其先进行base64编码,然后再URL编码,得到字符串:

<?php

$y="1be82511a7ba5bfd578c0eef466db59cdc84728fdcf89d93751d10a7c75c8cf2c0872dee8bc90b1156913b08a223a39ef89dd8dbec15c6a6d9993a3dc7b7a30886951754f7ad56454eb5d5b6768ee64650a4272280fe5b170eb9fc1bdbdde93d738a5ffb4a4500246775175ae596bbd6f34df339c69edce11f6650bbced62702";

$x=urlencode(base64_encode(hex2bin($y)));

echo $x;

?>

//执行PHP代码,得到字符串:
//G%2BglEae6W%2F1XjA7vRm21nNyEco%2Fc%2BJ2TdR0Qp8dcjPLAhy3ui8kLEVaROwiiI6Oe%2BJ3Y2%2BwVxqbZmTo9x7ejCIaVF1T3rVZFTrXVtnaO5kZQpCcigP5bFw65%2FBvb3ek9c4pf%2B0pFACRndRda5Za71vNN8znGntzhH2ZQu87WJwI%3D

将上面字符串带入get请求参数中,最终得到flag。

flag:airooCaiseiyee8he8xongien9euhe8b

 

参考:

http://s0hungry.com/2017/08/27/over-the-wire-natas28-security-puzzle/ (主要参考这个)
https://blog.csdn.net/whklhhhh/article/details/77484274?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.csdn.net/baidu_35297930/article/details/99974886?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
https://blog.anshumanonline.com/natas29/
http://alkalinesecurity.com/blog/ctf-writeups/natas-28-getting-it-wrong/
https://www.youtube.com/watch?v=qpC2sNcRj5o

posted @ 2020-03-06 22:59  zhengna  阅读(1120)  评论(0编辑  收藏  举报