选拔考试复现
图片
文件是一张图片,根据提示521,直接在RGB里面调整参数521提取图像位数据
可以得到一个压缩包的二进制
这边直接保存成压缩包,解压就可以得到一个图片
之后就没有上面提示了,可以先看属性
得到一个关键字符串,考试就卡在这里,后面要用steghide去提取隐藏数据
就可以得到flag
安卓
用jadx打开,根据提示在layout文件夹里面打开main函数就有了
漫长的旅途(reverse)
可以先用die查一下文件
发现是有upx壳,直接脱发现失败,用010打开去看会发现有魔改壳
考试的时候改了前面的U没改后面的X,脑子不知道在想什么,类似这样去改,一共有三处
改完去脱壳就可以了,要注意这边upx的版本要在3.91往上,脱完之后用ida打开,之际看string可以看到一个迷宫,直接追踪进去
可以看到这边顺序也帮我们排好了,接着利用这个可以直接追踪到主函数,就可以看到类似上下左右的四个方向代表的字母
把迷宫提取出来可以,那么接下来就是判断方向了,其中有两个变量v12和v13在进行自增和自减,自减对应的就是向上和向左,那么v12和v13就是分别对应水平还是垂直的方向,怎么判断呢,下面有代码
这边重新赋值v9和v10对应后面有一个while判断,其中v9对应的是59对应迷宫中,水平方向有60个字符,垂直有30,所以v12就是代表水平,v13代表垂直。
接下来就是脚本解密
from collections import dequedirections = [(0, -1, 'C'), # 向左 (v12减1)(0, 1, 'Z'), # 向右 (v12加1)(-1, 0, 'Y'), # 向上 (v13减1)(1, 0, 'X') # 向下 (v13加1)
]file_path = '1.txt'def read_grid_from_file(file_path):try:with open(file_path, 'r') as file:lines = file.readlines()grid = [list(line.strip()) for line in lines]return gridexcept FileNotFoundError:print(f"文件 {file_path} 未找到。")return Nonedef find_shortest_path(grid):rows = len(grid)cols = len(grid[0]) if rows > 0 else 0start = Noneend = None# 找到起点和终点的坐标for i in range(rows):for j in range(cols):if grid[i][j] == 'A':start = (i, j)elif grid[i][j] == 'B':end = (i, j)if not start or not end:print("未找到起点'A'或终点'B'")return None# 初始化队列和访问集合queue = deque([(start, "")])visited = set([start])while queue:(x, y), path = queue.popleft()# 如果到达终点,返回路径if (x, y) == end:return path# 尝试四个方向for dx, dy, dir_char in directions:new_x, new_y = x + dx, y + dy# 检查新坐标是否合法且未访问过,并且可以通过if (0 <= new_x < rows and0 <= new_y < cols and(new_x, new_y) not in visited andgrid[new_x][new_y] in ('0', 'B')):visited.add((new_x, new_y))queue.append(((new_x, new_y), path + dir_char))return Nonegrid = read_grid_from_file(file_path)
if grid:path = find_shortest_path(grid)if path:print("从 A 到 B 的最短路径是:", path)else:print("没有找到从 A 到 B 的路径。")
这个脚本其实之前是写过一篇博客去理解的,但是现在又忘了很多,所以代码写作能力还是很重要,要去学习一些py库的应用。
java
我尝试去运行这个,但是运行不起来,用jadx打开,可以直接找到main函数
这表调用了一些自定义的办法,去对指定的data.txt进行加密,生成加密之后的文件就是encrypted.enc,后面有一个key一个是定义的加密方法的aes的密钥。题目中给了加密之后的文件,那么我们可以猜测data.txt就是flag,我们现在要找到是key和他加密的方法,从代码中也可以看到,他调用的加密方法在左侧也都看得到,所以我们接着去看。
使用PBKDF2WithHmacSHA256算法从密码"PolarD&N CTF"得到加密的密钥也就是key,这边加密的盐值也给了,迭代次数是10000,输出128位的aes的密钥,然后还套了一层base64加密,所以最后输出的key的格式是base64加密的
package org.ctf.polar;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;public class FileEncryptor {private static final String ALGORITHM = "AES";private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";public static void encryptFile(String inputFile, String outputFile, String key) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException {Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");cipher.init(1, secretKeySpec);byte[] ivBytes = cipher.getIV();try (InputStream inputStream = new FileInputStream(inputFile)) {OutputStream outputStream = new FileOutputStream(outputFile);Throwable var9 = null;try {CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, cipher);Throwable var11 = null;try {outputStream.write(ivBytes);byte[] buffer = new byte[4096];int bytesRead;while((bytesRead = inputStream.read(buffer)) >= 0) {cipherOutputStream.write(buffer, 0, bytesRead);}} catch (Throwable var56) {var11 = var56;throw var56;} finally {if (cipherOutputStream != null) {if (var11 != null) {try {cipherOutputStream.close();} catch (Throwable var55) {var11.addSuppressed(var55);}} else {cipherOutputStream.close();}}}} catch (Throwable var58) {var9 = var58;throw var58;} finally {if (outputStream != null) {if (var9 != null) {try {outputStream.close();} catch (Throwable var54) {var9.addSuppressed(var54);}} else {outputStream.close();}}}}}
}
这个就是主要的加密函数了,上面的那个函数是为了得到key值
可以看到主要用的加密方法是AES/CBC/PAS5Padding的加密算法
通过Cipher.getInstance(TRANSFORMATION)加载AES/CBC/PAS5Padding的加密算法,创建Cipher加密对象,Cipher是java中的一个类,提供假面和解密的功能,他更像一个加载器,就像他这边加载的是AES/CBC/PAS5Padding这个加密算法一样
反编译中的if语句是反编译他加上的不是加密的代码,如果想更清晰一点可以用IDE打开
写解密脚本的话,首先是钥匙,可以直接用他给的函数得到,之后解AES的是要还要一个IV,这个就要用到cipher,利用这个去得到IV
package org.ctf.polar;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;public class FileDecryptor {private static final String ALGORITHM = "AES";private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";public static class KeyGenerator {public String getAesKeyB64String() throws InvalidKeySpecException, NoSuchAlgorithmException {byte[] salt = {1, 35, 69, 103, -119, -85, -51, -17};PBEKeySpec spec = new PBEKeySpec("PolarD&N CTF".toCharArray(), salt, 10000, 128);SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");SecretKey secretKey = secretKeyFactory.generateSecret(spec);return Base64.getEncoder().encodeToString(secretKey.getEncoded());}}public static void decryptFile(String inputFile, String outputFile, String key)throws NoSuchPaddingException, NoSuchAlgorithmException,InvalidKeyException, IOException, InvalidAlgorithmParameterException {try (FileInputStream fileInputStream = new FileInputStream(inputFile)) {// 读取IV (AES CBC模式需要16字节的IV)byte[] ivBytes = new byte[16];Cipher cipher = Cipher.getInstance(TRANSFORMATION);SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), ALGORITHM);IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);try (CipherInputStream cipherInputStream = new CipherInputStream(fileInputStream, cipher);FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = cipherInputStream.read(buffer)) != -1) {fileOutputStream.write(buffer, 0, bytesRead);}}}}public static void main(String[] args) {try {KeyGenerator keyGenerator = new KeyGenerator();String key = keyGenerator.getAesKeyB64String();decryptFile("encrypted.enc", "data.txt", key);} catch (Exception e) {e.printStackTrace();}}
}
File
解压压缩包得到一个没有后缀的文件,用记事本看一下
看到文件头是一个程序,直接改一下后缀格式,运行一下
给了提示可以去搜一下ace是一种压缩包的格式,直接提取
有密码,既然是压缩包用archpr爆破一下,可以得到答案
下载对应的解压ace压缩包的软件可以看到密码提示进而去爆破
EzPyeditor
可以直接用pycharm打开文件比较简洁,这边给了给路由/check,我们尝试访问看看
提交的方式不允许,后面强调是URL,猜测是GET传参,我们没有抓包改成POST传参
可以看到状态码200,主要是后面的绿色的字,类似一些查询还是执行的结果,返回去看源码,上面都是一些层叠样式的应用,我觉得这段才是关键的代码
function checkCode() {var source = editor.getValue();fetch('/check', {method: 'POST',headers: { 'Content-Type': 'application/json' },body: JSON.stringify({ source: source })}).then(response => response.json()).then(data => {editor.operation(function () {editor.eachLine(function (line) {editor.removeLineClass(line, 'background', 'highlight-line');});});if (data.status === false && data.error) {var errorLine = parseInt(data.error.split('line ').pop().split(',')[0]) - 1;console.log("Error at line:", errorLine);editor.addLineClass(errorLine, 'background', 'highlight-line');}});}
这边定义了用POST请求check,发送的格式是json,这边重点还是在ast,去了解会知道这边有一个source的参数是必须要的,还有他的上传格式,那么我们试着传参看看source变量,记得要用json的格式
可以看到是有一些区别的,还是ast的语法,接着我们引入filename,简单来说就是通过报错带出内容,然后题目文件是给了flag的一个文件的,从里面我们可以看到报错在第六行
puls3.0
提取迷宫之后算法没搞出来