加载中…
个人资料
老徐
老徐
  • 博客等级:
  • 博客积分:0
  • 博客访问:828,517
  • 关注人气:156
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
相关博文
推荐博文
谁看过这篇博文
加载中…
正文 字体大小:

[面试题]EMC易安信-Linux下栈溢出的初步之控制程序执行流程

(2012-09-21 16:28:13)
标签:

kernel

linux

堆栈

函数调用

it

分类: Linux/Shell
昨天看了最基本的Linux下的栈溢出,今天用一个实例来练习一下一个Crackme
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
int valid_serial(char * psz)
{
    size_t len=strlen(psz);
    unsigned total=0;
    size_t i;
    if(len<10)
        return 0;
    for(i=0;i<len;i++)
    {
        if((psz[i]<'0')||(psz[i]>'z'))
            return 0;
        total+=psz[i];
    }
    if(total % 853==83)
        return 1;
    return 0;
}
int validate_serial()
{
    char serial[24];
    fscanf(stdin,"%s",serial);
    if(valid_serial(serial))
       return 1;
    else
       return 0;
}
int do_valid_stuff()
{
    printf("The serial number is valid!\n");
    exit(0);
}
int do_invalid_stuff()
{
    printf("Invaild serial number!\nExiting...\n");
    exit(1);
}
int main()
{
    if(validate_serial())
      do_valid_stuff();
     else
      do_invalid_stuff();
     return 0;
}

 输入正确的序列号可以通过验证,这里在使用fscanf()函数的时候直接将用户的输入保存在了serial[24]这个数组中而没有验证大小,所以存在溢出。

尝试用44个‘a’时程序崩溃

root@bt:~/Desktop/code# ./serial
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Invaild serial number!
Exiting...
root@bt:~/Desktop/code# ./serial
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault

现在用Gdb调试:

查看main函数:

(gdb) disas main
Dump of assembler code for function main:
0x08048551 <+0>: push �p
0x08048552 <+1>: mov %esp,�p
0x08048554 <+3>: sub $0x8,%esp
0x08048557 <+6>: and $0xfffffff0,%esp
0x0804855a <+9>: mov $0x0,�x
0x0804855f <+14>: add $0xf,�x
0x08048562 <+17>: add $0xf,�x
0x08048565 <+20>: shr $0x4,�x
0x08048568 <+23>: shl $0x4,�x
0x0804856b <+26>: sub �x,%esp
0x0804856d <+28>: call 0x80484cf
0x08048572 <+33>: test �x,�x
0x08048574 <+35>: je 0x804857d
0x08048576 <+37>: call 0x8048515
0x0804857b <+42>: jmp 0x8048582
0x0804857d <+44>: call 0x8048533
0x08048582 <+49>: mov $0x0,�x
0x08048587 <+54>: leave
0x08048588 <+55>: ret
End of assembler dump.

可以看到在0x0804856d处调用了validate_serial()函数,假如我们把返回地址覆盖成0x08048576 ,即让验证程序直接返回到通过验证do_valid_stuff()这个分支。

有了这个想法我们先找一下溢出点:

(gdb) disas validate_serial
Dump of assembler code for function validate_serial:
0x080484cf <+0>: push �p
0x080484d0 <+1>: mov %esp,�p
0x080484d2 <+3>: sub $0x48,%esp
0x080484d5 <+6>: lea -0x28(�p),�x
0x080484d8 <+9>: mov �x,0x8(%esp)
0x080484dc <+13>: movl $0x804864c,0x4(%esp)
0x080484e4 <+21>: mov 0x80497a4,�x
0x080484e9 <+26>: mov �x,(%esp)
0x080484ec <+29>: call 0x804834c <__isoc99_fscanf@plt>
0x080484f1 <+34>: lea -0x28(�p),�x
0x080484f4 <+37>: mov �x,(%esp)
0x080484f7 <+40>: call 0x804842c
0x080484fc <+45>: test �x,�x
0x080484fe <+47>: je 0x8048509
0x08048500 <+49>: movl $0x1,-0x2c(�p)
0x08048507 <+56>: jmp 0x8048510
0x08048509 <+58>: movl $0x0,-0x2c(�p)
0x08048510 <+65>: mov -0x2c(�p),�x
0x08048513 <+68>: leave
0x08048514 <+69>: ret
End of assembler dump.

给0x080484ec下断点,

(gdb) break *0x080484ec
Breakpoint 1 at 0x80484ec

运行程序:

(gdb) run
Starting program: /root/Desktop/code/serial

Breakpoint 1, 0x080484ec in validate_serial ()
(gdb) x/20x $esp
0xbffff4c0: 0xb7fc9440 0x0804864c 0xbffff4e0 0xb7fc8ff4
0xbffff4d0: 0xb7f77d19 0xb7ea22a5 0xbffff4e8 0xb7e899d5
0xbffff4e0: 0xb7fc8ff4 0x08049774 0xbffff4f8 0x08048338
0xbffff4f0: 0xb7ff1030 0x08049774 0xbffff528 0x080485b9
0xbffff500: 0xb7fc9324 0xb7fc8ff4 0xbffff528 0x08048572


可以看到现在加粗的地方就是我们要覆盖的返回地址,输入43个‘a’。

(gdb) continue
Continuing.
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

Breakpoint 2, 0x08048514 in validate_serial ()

查看堆栈:

(gdb) x/20x 0xbffff4c0
0xbffff4c0: 0xbffff4e0 0x0804864c 0xbffff4e0 0xb7fc8ff4
0xbffff4d0: 0xb7f77d19 0xb7ea22a5 0xbffff4e8 0x00000000
0xbffff4e0: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff4f0: 0x61616161 0x61616161 0x61616161 0x61616161
0xbffff500: 0x61616161 0x61616161 0x00616161 0x08048572


现在可以看到再继续输入将会覆盖返回地址。

我们bash shell的printf函数,利用管道把printf的输出重定向到溢出程序,攻击字符串:

“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x76\x85\x04\x08”

其中\x76\x85\x04\x08是do_valid_stuff函数的地址。

root@bt:~/Desktop/code# printf "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\x76\x85\x04\x08" | ./serial
The serial number is valid!

成功了哈,我们成功的控制了程序的验证分支,虽然只是一个很简单的例子,我也是个菜鸟,希望可以对初学的同学有帮助,大家一起

交流 :)


0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 欢迎批评指正

    新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑

    新浪公司 版权所有