曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 6685|回复: 1
打印 上一主题 下一主题

通过堆栈溢出进行注册

[复制链接]

4917

主题

5879

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34382
跳转到指定楼层
楼主
发表于 2010-11-21 13:26:20 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
利用 http://www.groad.net/bbs/read.php?tid-2876.html 中的 C 程序,在 gdb 中反汇编出 return_input 的地址:

(gdb) disas main
Dump of assembler code for function main:
0x080483f2 <main+0>: push %ebp
0x080483f3 <main+1>: mov %esp,%ebp
0x080483f5 <main+3>: call 0x80483d4 <return_input>
0x080483fa <main+8>: mov $0x0,%eax
0x080483ff <main+13>: pop %ebp
0x08048400 <main+14>: ret
End of assembler dump.

利用栈溢出漏洞将返回到 main() 函数中的地址 0x080483fa 替换为 return_input() 函数的入口地址,也就是说希望 return_input() 函数执行 2 次:

[root@centos shellcode]# printf "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD\xf5\x83\x04\x08" | ./stack
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD▒
AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDD

上面,0x080483f5 是 return_input() 函数的入口地址。由于 x86 体系结构采用小端存储格式,所以我们的地址要倒着写。
成功执行了两次。这说明,通过缓冲区的溢出,我们覆盖了程序的返回地址,控制了 EIP 。如果上面的程序是一个注册码验证的函数,我们同样可以通过修改返回地址已达到绕过注册码的目的。

修改上面的 return_input 函数,在它里面添加一段简单的“注册码”验证功能,测试代码:

#include <stdio.h>
#include <stdlib.h>
int return_input (void)
{
        printf ("Please input your serial code:
");
        char array[30];
        int ok = 0;
        gets (array);
        if (array[0] == 'b' && array[1] == 'e' && array[2] == 'y' && array[3] == 'e' && array[4] == 's')
                ok = 1;
        return (ok);
}
int register_ok (void)
{
        printf ("register ok!
");
        exit (EXIT_SUCCESS);
}
int register_invalid(void)
{
        printf ("register failed!
");
        exit (EXIT_FAILURE);
}
int main()
{
        if (return_input())
                register_ok();
        else
                register_invalid();
        return (0);
}

编译运行测试:

[root@centos shellcode]# gcc -mpreferred-stack-boundary=2 -g stack2.c -o stack2
/tmp/ccO3INgh.o: In function `return_input':
/root/shellcode/stack2.c:9: warning: the `gets' function is dangerous and should not be used.
[root@centos shellcode]# ./stack2
Please input your serial code:
dfadsfa
register failed!
[root@centos shellcode]# ./stack2
Please input your serial code:
beyes
register ok!

正确的“注册码”是 beyes 。

下面同样通过缓冲区溢出绕过这个注册码。

在 gdb 中查看这个程序的反汇编:

(gdb) disas main
Dump of assembler code for function main:
0x08048498 <main+0>:    push   %ebp
0x08048499 <main+1>:    mov    %esp,%ebp
0x0804849b <main+3>:    call   0x8048404 <return_input>
0x080484a0 <main+8>:    test   %eax,%eax
0x080484a2 <main+10>:   je     0x80484ab <main+19>
0x080484a4 <main+12>:   call   0x804845c <register_ok>
0x080484a9 <main+17>:   jmp    0x80484b0 <main+24>
0x080484ab <main+19>:   call   0x804847a <register_invalid>
0x080484b0 <main+24>:   mov    $0x0,%eax
0x080484b5 <main+29>:   pop    %ebp
0x080484b6 <main+30>:   ret
End of assembler dump.

上面,地址 0x080484a4 处调用了 register_ok 函数表明注册成功。这里,我们可以通过缓冲区溢出,修改 return_input() 的返回地址,使之直接跳转到此,从而达到成功注册的目的。如下面构造的输入:
[root@centos shellcode]# printf "AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDD\xa4\x84\x04\x08" ./stack2
Please input your serial code:
register ok!

可见,成功注册了。

[/table]
[table=100%,#f9f7ed]这里需要再提及一点,如果主程序中不是调用注册成功函数(register_ok),而是直接打印出成功或失败信息。那么这样修改缓冲区,虽然会看到注册成功的信息(register ok!),但是也还会看到段错误。原因是,当我们输入超长字符串时,也覆盖了 EBP,这个 EBP 在返回时是在 main() 中仍会用来动态的寻找 main 栈中的数据 。如在 printf() 函数执行时,里面的字符串参数地址就是通过 EBP 来寻得。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2024-5-8 07:04 , Processed in 0.075102 second(s), 21 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表