【问题标题】:Shellcode and binary filesShellcode 和二进制文件
【发布时间】:2013-09-23 16:51:07
【问题描述】:

下面的代码需要一个二进制文件。

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

#define bufsz 100

const char msg[] = "Usage: %s <shellcode file>\n";

static char buffer1[bufsz];
static char buffer2[bufsz];

void usage(char *self) {
    printf(msg, self);
    exit(1);
}

int main(int argc, char *argv[]) {
    FILE *fp;
    void (*funcptr)();

    if (argc != 2)
        usage(argv[0]);

    if ((fp = fopen(argv[1], "rb")) == NULL ) {
        printf("fail to open file: %s\n", argv[1]);
        exit(1);
    };

    fgets(buffer1, bufsz, fp);
    fclose(fp);

    strcpy(buffer2, buffer1);

    if (strlen(buffer2) >= 40)
        printf("your shellcode is too long! \n");

    if (strlen(buffer2) < 30)
        printf("your shellcode is less than 30 bytes!\n");

    if (strstr(buffer2, "/bin/sh"))
        printf("Malicious code detected!\n");

    funcptr = (void *) buffer2;
    (*funcptr)(); /* execute your shell code */

    return 0;
}

因此,我创建了下面的shellfile.c,其中包含 19 个字节来测试上面的应用程序

int main(){
    /* push trick */
    __asm__("push $0;\n\
             push $2;\n\
             movl %esp, %ebx;\n\
             xorl %ecx, %ecx;\n\
             mov  $162, %al;\n\
             int  $0x80;\n\
             xorl %ebx, %ebx;\n\
             leal 0x1(%ebx), %eax;\n\
             int  $0x80;\n\               
             ");
    return 0;
    }

已编译,但代码正在检索以下错误:

gcc -o codetest -g -ggdb codetest.c
./runshell testcode
your shellcode is less than 30 bytes!
Illegal Instruction 

问题到底出在哪里?

【问题讨论】:

  • 我很好奇——你用什么命令编译shellfile.c
  • gcc -o shellfile -g -ggdb shellfile.c
  • 这将是您的下一个问题。 shellfile 将是一个 ELF 文件,而不仅仅是 x86 指令流。
  • 你的意思是我必须从 shellfile.c 中提取操作码?
  • 修复fgets()后,请阅读:stackoverflow.com/questions/1647359/…

标签: c shellcode


【解决方案1】:

你的 shellcode 的要求是:

  • 长度在 31 到 40 之间
  • 没有零字节 (\x00) 或 strlen 会失败
  • 没有 '\n' 字节 (\x0A) 或 fgets 将失败
  • 没有“/bin/sh”子字符串

你的第一条指令是push $0,所以你的shellcode的前两个字节是\x6A\x00
缓冲区的大小为1strlen 在空字节后停止)。
这就是为什么你有错误your shellcode is less than 30 bytes!

考虑一下这个shellcode,它和你的一样,除了push $1来避免空字节:

6A01          push $1              ;to avoid null byte
6A02          push $2
89E3          movl %esp, %ebx      ;ebx now points on top of stack
31C9          xorl %ecx, %ecx      ;ecx=0
B0A2          mov  $162, %al       ;eax=162
CD80          int  $0x80           ;call sys_nanosleep because eax=162 with arguments ebx and ecx (ebx={1,2} and ecx=NULL)
31DB          xorl %ebx, %ebx      ;ebx=0
678D4301      leal 0x1(%ebx), %eax ;eax=1
CD80          int $0x80            ;call sys_exit because eax=1, with code 0 (ebx value)

基本上,这个 shellcode 等待 2 秒(和 1 纳秒)然后退出。
int 0x80 是一个系统调用,取决于 eax 的值,more information here

你还是有问题,这个shellcode的长度是20字节。
您只需在开头(或结尾)添加 11 个NOP (0x90) 即可满足要求。

试试这个:

echo -e '\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x6A\x01\x6A\x02\x89\xE3\x31\xC9\xB0\xA2\xCD\x80\x31\xDB\x67\x8D\x43\x01\xCD\x80' > shellcode.bin
./runshell shellcode.bin

如果程序等待 2 秒并成功退出(代码为 0),则 shellcode 已执行。

如果有必要,我可以向你解释如何编写一个 shellcode 来获得runshell 程序的权限,这通常是这种练习的目标(很明显,"/bin/sh" 上的测试就是这种情况) .

【讨论】:

  • @moooeeeep if (strlen(buffer2) &gt;= 40)if (strlen(buffer2) &lt; 30)
  • @moooeeeep,警告,而不是通知。这些条件验证了 shellcode。
【解决方案2】:
fgets(buffer1, bufsz, fp);
...
if (strlen(buffer2)<30) 
    printf("your shellcode is less than 30 bytes!\n");

fgets 仅对文本文件中以\n 分隔的行有效。 strlen 仅对以零结尾的字符串有效。两者都不适合这种用途。

改用fread()

【讨论】:

  • 我认为他不能修改这段代码,我猜是创建一个满足代码条件的shellcode的练习。
  • @Michael 即使他设法将正确的字节码放入缓冲区,但当他尝试执行它时,此尝试也会出现段错误。
  • @moooeeeeep,是的,因为该文件不只包含字节码流。
猜你喜欢
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-12
  • 2011-04-14
  • 2014-11-29
  • 2018-12-11
相关资源
最近更新 更多