2

该程序在我的机器上以 root 权限运行,我需要对以下代码执行堆栈溢出攻击并获得 root 权限:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <openssl/sha.h>

void sha256(char *string, char outputBuffer[65])
{
    unsigned char hash[SHA256_DIGEST_LENGTH];
    int i = 0;
    SHA256_CTX sha256;
    SHA256_Init(&sha256);
    SHA256_Update(&sha256, string, strlen(string));
    SHA256_Final(hash, &sha256);

    for(i = 0; i < SHA256_DIGEST_LENGTH; i++)
    {
        sprintf(outputBuffer + (i * 2), "%02x", hash[i]);
    }
    outputBuffer[64] = 0;
}

int password_check(char *userpass)
{
    char text[20] = "thisisasalt";
    unsigned int password_match = 0;
    char output[65] = { 0, };
    // >>> hashlib.sha256("Hello, world!").hexdigest()
    char pass[] = "315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3"; 

    text[0] = 'a';
    text[1] = 't';
    text[2] = 'j';
    text[3] = '5';
    text[4] = '3';
    text[5] = 'k';
    text[6] = '$';
    text[7] = 'g';
    text[8] = 'f';
    text[9] = '[';
    text[10] = ']';
    text[11] = '\0';
    strcat(text, userpass);
    sha256(text, output);

    if (strcmp(output, pass) == 0)
    {
        password_match = 1;
    }

    return (password_match == 1);
}

int main(int argc, char **argv)
{
    if (argc < 3)
    {
        printf("Usage: %s <pass> <command>\n", argv[0]);
        exit(1);
    }
    if (strlen((const char *) argv[1]) > 10)
    {
        printf("Error: pasword too long\n");
        exit(1);
    }

    if (password_check(argv[1]))
    {
        printf("Running command as root: %s\n", argv[2]);
        setuid(0);
        setgid(0);
        system(argv[2]);
    }
    else
    {
        printf("Authentication failed! This activity will be logged!\n");
    }

    return 0;
}

所以我尝试用 IDA 分析程序,我看到文本段从低地址到高地址,高于我看到的数据,然后是 bss,最后是外部命令。

现在据我所知,堆栈应该就在上面,但我不确定如何查看它,我应该如何查看堆栈才能知道我在写什么?(我什至需要它还是我完全一无所知?)

第二个问题是考虑输入的长度,我如何绕过代码中的这个检查:

if (strlen((const char *) argv[1]) > 10)
    {
        printf("Error: pasword too long\n");
        exit(1);
    }

我可以通过引用以某种方式将字符串提供给程序吗?如果是这样,我该怎么做?(再次,希望我不是完全一无所知)

4

1 回答 1

3

现在据我所知,堆栈应该就在上面,但我不确定如何查看它,我应该如何查看堆栈才能知道我在写什么?(我什至需要它还是我完全一无所知?)

栈位置一直在变化——需要看ESP/RSP寄存器的值,它的值就是栈顶的当前地址。通常,变量寻址将基于EBP而不是ESP,但它们都将指向相同的一般内存区域。

在分析过程中,IDA 为每个函数设置了一个堆栈框架,它的作用很像struct- 您可以在其中定义具有类型和名称的变量。这个框架总结在函数的顶部:堆栈摘要视图 双击它或函数体中的任何局部变量将打开一个更详细的窗口。这与您无需在调试器中实际运行程序一样好。

您可以看到它就在text旁边password_match,并且从地址来看,正如人们所期望的那样,为0x14分配了字节。text但是,这并不能保证,编译器可以自由地改变变量,填充它们或将它们优化到寄存器中。

第二个问题是考虑输入的长度,我如何绕过代码中的这个检查:

if (strlen((const char *) argv[1]) > 10)
{
    printf("Error: pasword too long\n");
    exit(1);
}

你不需要绕过这个检查,它已经够坏了。有一个错误。

如果您想自己弄清楚溢出,请停止阅读此处。


从到的有效索引text范围。在代码中,用户输入被写入从 开始的内存区域。检查允许的最大输入长度为 10 个符号 + NULL 终止符。不幸的是,这意味着包含第 9 个用户输入的符号,并且第 10 个符号 + 终止符溢出到相邻的内存空间。在某些情况下,这允许您用任意值覆盖 的最低有效字节,并用. 如果等于,则您的函数接受密码,这意味着密码中的第 10 个字符必须是(请注意,这与 不同的字符)。text[0]text[19]text[11]strlentext[19]password_match0
password_match1'\x01''1'

这是 IDA 作为调试器运行的两个屏幕截图。text以黄色突出显示,password_match以绿色突出显示。

我输入的密码是123456789\x01

  1. 用户输入密码之前的堆栈被strcat'd into text. 溢出前堆栈变量

  2. 后堆叠strcat。注意password_match改变了。 溢出后堆栈变量

于 2013-04-08T19:36:12.553 回答