【问题标题】:Linux Capture the flag programming puzzleLinux 夺旗编程难题
【发布时间】:2017-02-12 21:50:26
【问题描述】:

我是 linux 的新手(只知道基本的东西)。我正在尝试在 linux 虚拟机中完成 Capture-the-flag (CTF) 风格的挑战。所以基本上我有一个 C 程序文件和一个标志。我无权访问标志。我可以读取程序文件并运行它。这是 C 代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    void check () {

    int invalid;
    if (invalid) {
    printf ("Password invalid!\n");

    }

    else{
    printf ("Password accepted!\n");
    system ("/bin/cat flag3");
    }
    }
    void password() {

    char password [200];
    printf ("Enter the password: ");
    scanf ("%s" , password);
    }

    int main () {
    password ();
    check();
    return 0;
    }

我已经尝试调试它并查看了汇编程序的内容,但我不明白如何捕获密码以了解标志的内容。我试图从这个链接的帮助下破解密码,http://eliteinformatiker.de/2012/11/16/howto-crack-a-small-c-program-with-assembler 但我不确定我是否可以编辑 C 程序的二进制文件,因为在 c 文件的给定权限中,我只能读取它不能写入它。所以我想如果我不能修改一个c文件,我怎么能修改它的二进制文件(也许我错了)。在这一点上,我有点卡住了,我尝试调试它,查看了程序集内容,但我不确定我是否可以编辑二进制文件。我不确定要采取什么方法来捕获标志?

【问题讨论】:

  • invalid 在哪里/如何设置?我看到它在函数check 中使用,但我看不到它是如何设置的。
  • 我不确定。其实我也对这一点感到困惑。我没有写过这段代码。我得到了这个代码。当我运行它时,它会要求输入密码,以便让我访问标志的内容。我不知道密码,所以现在我必须找到一些漏洞利用/后门来猜测密码以获得对标志的访问权限。而且我似乎找不到任何漏洞。
  • 如果可以调试程序,应该可以修改比较。例如,invalid 是一个局部变量,因此存储在堆栈中。您应该能够在测试之前更改它的值。

标签: c linux binary virtual-machine disassembly


【解决方案1】:

免责声明:我使用的是 Ubuntu-12.04 和 gcc-4.8.-2 和 gdb-7.7.1 调试器。

我在调试器下执行程序,直到输入check 并单步执行 if。然后我反汇编了代码并查看了程序集:

(gdb) disass
Dump of assembler code for function check:
   0x000000000040062d <+0>: push   %rbp
   0x000000000040062e <+1>: mov    %rsp,%rbp
   0x0000000000400631 <+4>: sub    $0x10,%rsp
=> 0x0000000000400635 <+8>: cmpl   $0x0,-0x4(%rbp)
   0x0000000000400639 <+12>:    je     0x400647 <check+26>
   0x000000000040063b <+14>:    mov    $0x400754,%edi
   0x0000000000400640 <+19>:    callq  0x4004e0 <puts@plt>
   0x0000000000400645 <+24>:    jmp    0x400651 <check+36>
   0x0000000000400647 <+26>:    mov    $0x400766,%edi
   0x000000000040064c <+31>:    callq  0x4004e0 <puts@plt>
   0x0000000000400651 <+36>:    leaveq 

我查看了我的寄存器的值(只显示重要的):

(gdb) info reg
    rbp            0x7fffffffdf00   0x7fffffffdf00
    rsp            0x7fffffffdef0   0x7fffffffdef0
    rip            0x400635 0x400635 <check+8>
    eflags         0x206    [ PF IF ]

接下来单步指令(gdb) ni,反复反汇编,得到eflags的值:

(gdb) disass
Dump of assembler code for function check:
   0x000000000040062d <+0>: push   %rbp
   0x000000000040062e <+1>: mov    %rsp,%rbp
   0x0000000000400631 <+4>: sub    $0x10,%rsp
   0x0000000000400635 <+8>: cmpl   $0x0,-0x4(%rbp)
=> 0x0000000000400639 <+12>:    je     0x400647 <check+26>
   0x000000000040063b <+14>:    mov    $0x400754,%edi
   0x0000000000400640 <+19>:    callq  0x4004e0 <puts@plt>
   0x0000000000400645 <+24>:    jmp    0x400651 <check+36>
   0x0000000000400647 <+26>:    mov    $0x400766,%edi
   0x000000000040064c <+31>:    callq  0x4004e0 <puts@plt>
   0x0000000000400651 <+36>:    leaveq 
   0x0000000000400652 <+37>:    retq   
 End of assembler dump.
(gdb) info reg
eflags         0x206    [ PF IF ]

回想一下,cmp 的工作方式是模拟减法,根据需要设置标志,这就是 je 然后使用的。因此,此代码将从 0 中减去 -0x4(%rpb)(将零标志设置为适当的)。如果数字相同,jz会跳。

所以我用命令序列修改了标志寄存器:

(gdb) set $ZF = 6
(gdb) set $eflags |= (1 << $ZF)
(gdb) print $eflags
$1 = [ PF ZF IF ]

请注意,现在设置了零标志。单条指令集(ni),看看反汇编:

(gdb) ni
(gdb) disass
Dump of assembler code for function check:
   0x000000000040062d <+0>: push   %rbp
   0x000000000040062e <+1>: mov    %rsp,%rbp
   0x0000000000400631 <+4>: sub    $0x10,%rsp
   0x0000000000400635 <+8>: cmpl   $0x0,-0x4(%rbp)
   0x0000000000400639 <+12>:    je     0x400647 <check+26>
   0x000000000040063b <+14>:    mov    $0x400754,%edi
   0x0000000000400640 <+19>:    callq  0x4004e0 <puts@plt>
   0x0000000000400645 <+24>:    jmp    0x400651 <check+36>
=> 0x0000000000400647 <+26>:    mov    $0x400766,%edi
   0x000000000040064c <+31>:    callq  0x4004e0 <puts@plt>
   0x0000000000400651 <+36>:    leaveq 
   0x0000000000400652 <+37>:    retq   
End of assembler dump.

哪个在 else 块中,你应该得到显示的标志。 (请注意,在我的测试程序中,我注释掉了标记标志的行)。

【讨论】:

  • 我理解你的逻辑,我试过了。但是,它仍然没有显示标志,而是向我显示标志无法打开并且权限被拒绝。
  • 设置零标志后,它跳转到else,但是当涉及到调用标志内容的指令时,它显示我无法打开标志。我认为因为没有 root 访问权限,所以这就是为什么我仍然无法打开标志。我必须找到其他一些漏洞才能获得对标志的访问权。
  • @sar drat... 查看程序,system 命令让我相信标志位于程序所在的同一目录中(注意 system /bin/cat flag3 是相对路径,而不是绝对路径)。我很想知道您是否可以导航到找到 flag3 的目录,以及它的权限是什么。我不得不怀疑我们是不是想多了,如果你转到标志所在的文件夹并运行cat flag3,结果是什么。 (可能权限被拒绝,但你永远不知道)。
  • 不,我无法导航到目录并直接运行标志。我无权这样做。该问题的目的是在代码中找到漏洞以访问标志。我认为由于变量 invalid 未正确初始化,因此必须以某种方式覆盖它(可能是缓冲区溢出攻击)。我的主要问题是我是 linux 的新手,所以我面前有信息,但我不知道如何利用该漏洞来访问 flag 的内容。
  • 我认为你在这里遗漏了一些东西。调试器的诀窍是,对于所有意图,更改invalid 的值,以便代码执行到其他地方。如果我们修改invalid 的值,我们将在else 块中结束,就像修改标志一样。只是好奇,当您修改零标志时,您得到的确切错误是什么?另外,如果这个挑战是公开的,那么 URL 是什么?最后,当您调试时,可执行文件在哪里(即在您的主目录或文件系统的其他位置)?
【解决方案2】:

看起来这需要缓冲区溢出损坏。输入超过 200 个字符的密码,它会从默认的零值损坏无效?

【讨论】:

  • 我已经试过了。如果密码超过 200 个字符,则会出现分段错误。
  • 这是评论,不是答案。
  • Scant 不安全,因为它在变量中存储的字符最多为空字符。你能用'\0'做点什么有趣的事吗?
  • 我没有 root 权限来编辑代码。所以我对scanf无能为力。我必须找到一些利用/后门来猜测密码才能知道标志的内容。
猜你喜欢
  • 2020-03-03
  • 1970-01-01
  • 2021-03-02
  • 1970-01-01
  • 1970-01-01
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多