黑客网站渗透入侵破解拿权限
10.4K subscribers
2.39K photos
108 links
Download Telegram
ConnectServerWmi函数的作用是链接WMI服务器,就像之前所说的,位于wminet_utils模块的函数,只是起到存根函数的作用,其最终会调用wbemprox的CLocator::ConnectServe函数。

在CLocator::ConnectServe函数中,最终会调用CDCOMTrans::DoActualConnection函数,其调用堆栈如下。

CDCOMTrans::DoActualConnection函数的主要作用是初始化_COSERVERINFO结构体,或者_COAUTHIDENTITY结构体。_COSERVERINFO结构体是一个包含激活功能的结构体。_COAUTHIDENTITY结构体则是一个包含域名,用户名密码的结构体。

最终调用CDCOMTrans::DoActualCCI函数,在CDCOMTrans::DoActualCCI函数中,最终会调用CoCreateInstanceEx函数,CoCreateInstanceEx函数可以在指定的远程计算机上创建与给定 CLSID 关联的单个未初始化对象。而CoCreateInstance也可以创建一个实例,但是CoCreateInstance与CoCreateInstanceEx函数的区别在于CoCreateInstanceEx可以创建远程计算机的实例。 CoCreateInstanceEx函数的第一个参数是CLSID,表示要实例化对象的CLSID。在上一篇文章中,检测远程WMI连接的CLSID的值为8BC3F05E-D86B-11D0-A075-00C04FB68820。这就是为什么只要针对这个CLSID检测就可以判断是WMI远程连接了。

WMI查询操作,是通过wminet_utils模块的ExecQueryWmi函数调用fastprox模块的CWbemSvcWrapper::XWbemServices::ExecQuery函数,而CWbemSvcWrapper::XWbemServices::ExecQuery的第二第三个参数分别表示执行的查询语句的类型,和SQL语句的内容。WMI拥有自己的查询语句,即WQL。

/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我
@MoA_Ke
windbg附加到WmiPrvSE.exe进程即WMI提供程序进程。因为WMI原理简单来说就是WMI消费程序通过WMI核心架构,向WMI提供程序请求数据,WMI提供程序返回相关结果。WmiPrvSE.exe进程其实是X64进程,当windbg中断在call RPCRT4!Invoke,根据x64函数的调用约定,rcx应该是需要invoke的函数,rdx应该是参数的缓冲区,r9d是参数个数。可以看到,服务端WmiPrvSE.exe接收到了数据,并准备调用CreateInstanceEnumAsync函数实例化Win32_Process。

Get函数最终是通过调用fastprox模块的CWbemObject::Get方法实现的,CWbemObject::Get主要有调用了两个方法,分别是CWbemInstance::GetProperty和CWbemInstance::GetPropertyType。

CWbemInstance::GetProperty函数主要是为了获取指定属性名的属性值,在其底层主要调用了CWbemObject::GetSystemPropertyByName或者CWbemInstance::GetNonsystemPropertyValue函数,前者主要获取的是系统属性值,而后者是获取非系统属性的属性值,在CSystemProperties::FindName函数中,可以看到系统属性有哪些。

在调用CWbemObject::GetSystemPropertyByName函数之前,在堆栈中看到需要查看的属性名为__PATH,调用结束后,可以看到返回的是一个CVar结构。CVAR偏移为0x00表示变量的类型,CVAR偏移为0x08,则表示变量的值。

/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我
@MoA_Ke
其获取进程数据的主要原理是第一次通过调用GetNames方法,获取系统属性名,然后依次调用Get方法获取属性名的属性值,接着第二次调用GetNames方法获取非系统属性值,然后依次调用Get方法获取属性值。

在分析这一部分的时候,因为wminet_utils模块中没有ExecMethod相关的函数,并没有像上面一样通过wminet_utils模块来寻求突破。我们都知道WMI底层是客户端通过RPC协议远程调用服务端的函数,并接收返回值。所以我决定在RPC底层,通过中断NdrClientStub2函数,然后追溯栈回溯的方法确定调用方。最终发现其直接调用了fastprox模块的IWbemServices::ExecMethod函数。

IWbemServices::ExecMethod函数的原型如下,第一个参数是Object的名字,第二个参数为函数名,第5个参数是指向传入参数的类。

根据微软的介绍,创建__PARAMETERS的实例的步骤如下:

确定包含方法定义的类的类路径。
使用从IWbemProviderInit::Initialize传入的类路径和IWbemServices指针,调用IWbemClassObject::GetMethod来检索输入和输出参数类。GetMethod方法返回一个IWbemClassObject用于访问每个类的指针。
使用输出类的IWbemClassObject指针,调用IWbemClassObject::SpawnInstance以创建类的实例。
通过设置与输出值对应的属性来填充类实例,如果方法有返回值,则设置ReturnValue属性。
通过IWbemObjectSink::Indicate方法将__PARAMETERS实例传递回调用者。
根据上述描述,我了解到了如果要创建这个一个__PARAMETERS实例,首先需要调用IWbemClassObject::SpawnInstance以创建类的实例,然后设置与输出值对应的属性来填充类实例。这里填充类实例是使用了CWbemInstance::Put函数。最终把SpawnInstance创建创建类的实例传入IWbemServices::ExecMethod的pInParams参数。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我
@MoA_Ke
函数调用与返回
栈的概念在PPC等CPU中,不是由CPU实现的,而是由编译器维护的。通常情况下,在PPC中栈顶指针寄存器使用r1,栈底指针寄存器使用r11或r31。或者r11为栈顶,其他为栈底。根据不同的编译选项和编译器环境,其使用方式都有不同,但各个编译器的共识为r1是帧栈指针,其他寄存器都可根据他为准灵活使用。

栈帧在函数中,通常用于存储局部变量、编译器产生的临时变量等。由于PPC和ARM等CPU在寄存器较多,所以函数的形参和实参大多数情况下会使用寄存器,参数较多的情况下使用栈。

PowerPC体系结构中栈的增长方向同样是从高地址到低地址,堆的增长方式是从低地址到搞地址,当两者相遇时就会产生溢出。

// powerpc-linux-gnu-gcc -static -g -o t t.c
#include <stdio.h>
unsigned int test(unsigned int n)
{
int ok,n1,n2,n3,n4,n5,n6,n7,n8,n9;
ok=n1=n2=n3=n4=n5=n6=n7=n8=n9=n;
printf("%d%d%d%d%d%d%d%d%d%d%d",ok,n,n1,n2,n3,n4,n5,n6,n7,n8,n9);
return n;
}
void main(void)
{
unsigned int n;
n=test(n);
}

可以看到在进入函数的时候会先执行
r1就类似栈顶指针,第一条指令中,stwu最后的u表示update,指令中有效地址EA=r1+back_chain,该指令首先会将r1的值存放到EA中,接着会把有效地址EA存到r1里。back_chain对应新栈帧大小,是一个负值,此处为0x60,所以这里实际上就是开辟了一块新的栈帧,让r1指向新栈顶,同时在新栈顶处存储了上一个栈帧的栈顶,从而构成一个类似链表的东西,在之后帮助恢复栈帧。

mflr r0,把lr寄存器的值保存到r0中。接着stw将r0保存到栈上,从而在栈上保存了lr返回地址的值。指令中对栈变量的索引使用的是0x60+sender_lr(r1),r1已经指向新栈帧的栈顶,所以这里是通过栈顶指针索引栈上的局部变量,栈帧空间大小即0x60。

下一条stw指令将r31存储到栈上,然后执行mr把r1的值赋给r31。

由于test函数传入了一个参数n,是通过r3传递的。所以在之后看到首先把r3存到了栈上,接着不断连续调用lwz和stw指令,以r9为中间量,并通过r31索引,对栈上局部变量进行赋值。

接下来就是为函数调用布置参数了,这里由于我们使用的参数很多,会同时使用寄存器和栈变量进行传参。ppc中没有push、pop这样的指令,栈帧空间是提前设置好的,这里指令做的就是把参数从右往左把多出来的4个参数依次在栈上从高地址往低地址放置,第9个参数与栈顶位置中间还会留下一个字长的空间,用来存放下一个栈帧的返回地址;剩下的8个参数按照从右往左依次放入r3~r10中,指定执行时是从r10开始存放的。crclr是用来调整条件寄存器CR的。
/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我
@MoA_Ke
首先测一下缓冲区长度,直接莽然后就能控制lr地址了

动态调试
和调试mips、arm的方法类似。执行qemu-ppc-static -g 1234 -L ./ ./PPPPPPC即可在1234端口开启调试

gdb-multiarch加载的脚本如下,其中架构设置为powerpc:403

from pwn import *
import sys

context.log_level = 'debug'
context.endian = 'big'
context.arch='powerpc'
Debug = sys.argv[1]

elf = ELF('./PPPPPPC')

def get_sh(other_libc=null):
if Debug == '1':
return process(["./qemu-ppc-static","-g","1234","-L","./","./PPPPPPC"])
log.info('Please use GDB remote!(Enter to continue)')
pause()
return r
else:
return process(["./qemu-ppc-static","-L","./","./PPPPPPC"])

r = get_sh()
r.recvuntil("Tell me your name: ")

直接用powerpc-linux-gnu-gcc编译出来然后放进ida里看看,发现这最后系统调用的sc指令就对应的是0x44000002,然后把shellstorm那份shellcode的最后sc处改成0x44000002就通了。也就是说这题在本质上就是在栈上输入shellcode然后返回地址控制跳到shellcode上即可

因为ppc属于精简指令集,指令长度固定四字节,qemu模拟的好像一般地址都不变,所以这里赋值r3考虑直接通过计算得到字符串位于栈上的地址。另外编译的时候说是赋值范围要在0xffffffffffff8000到0x0000000000007fff,无法一步到位,所以分成两步加法就行。

shellcode如下,后面再跟上/bin/sh,过程其实也就是清空相应的寄存器,r0赋值成execve的系统调用号,r3作为函数第一个参数让它指向binsh即可,最后sc就是系统调用

当然这里也能写出更加通用的shellcode,由于我们覆盖了lr,所以我们就可以直接通过lr来索引到字符串地址

简单来说add能够申请一个size小于0x91的chunk并写入信息作为book description,会有一个bookname与之一一对应,索引也使用name来索引,最多只能有三个book,bookname、book description和description的size均作为全局变量记录

/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我
@MoA_Ke
漏洞利用
前期的利用就是通过不断用不同大小add和delete填充堆空间,溢出修改size从而造出unsorted bin并得到libc基址,然后通过溢出修改tcache的fd就能任意地址申请了。

在这里由于架构原因泄露出来的基址的计算和平时略有不同,不过计算方法也很简单,在文件所在目录下启动gdb-multiarch,就能直接在其中打印找到__malloc_hook地址位置,再进行索引即可得到libc基址

接着,按照一般的想法只需要劫持__free_hook,写入system地址,然后就能执行system("/bin/sh")getshell了。然而在如此想法下尝试了一下却发现走到了0xdeadbeef。重新看一下给的libc文件,发现里面的execve和system都被修改了

也就是说通过调用函数getshell的路都走不通了

但是,由于题目远程大概率也是用qemu-user模拟的,是可以直接执行shellcode,所以只要通过__free_hook控制执行流后跳转到我们写的shellcode上即可完成getshell

shellcode编写
尝试自己编写shellcode。这里和32位的ppc是类似的,具体实现时针对r3寄存器的设置我用了三种思路

要执行execve("/bin/sh", NULL, NULL),r3要指向对应字符串,可以将/bin/sh写到堆上然后让r3指过去。在调试的时候发现寄存器r9就是一个堆上的地址,所以第一种思路就是直接通过异或把值迁移到r3上再进行相应偏移的调整即可

shellcode做的就是首先清空r3、r4、r5寄存器,将r0赋值为11对应execve,然后通过异或和加法让r3指向/bin/sh,最后sc即执行系统调用

第二种思路是把地址拼出来,需要用到移位操作
addis是将计算结果左移2字节后再进行存储,sld是左移双字的意思。同时由于限制操作数的大小所以低两个字节需要两次加法得到

第三种思路是最通用的,本题由于我们无法控制lr寄存器,所以无法像上一道题目通过lr索引到/bin/sh。然而我们可以换一种思路,即通过shellcode在某个可写地址写入/bin/sh然后指向即可。在所有寄存器中,我们知道r1永远是指向栈空间的,而栈空间必然是可写的,所以不妨借由r1在栈上写入/bin/sh,从而确保r3参数的布置。
sc3='''
li 4, 0
li 5, 0
li 0, 11
li 6, 0
addis 6, 6, 0x2f62
addi 6, 6, 0x696e
stw 6, 0(1)
li 6, 0
addis 6, 6, 0x2f73
addi 6, 6, 0x6800
stw 6, 4(1)
mr 3, 1
sc
'''

最终exp如下,本题思路简单来说就是首先通过不断编辑造成足够多字节的堆溢出,然后修改chunk头的size位造成堆块重叠,从而得到unsorted bin并泄露基址;之后再攻击tcache的fd劫持__free_hook,跳转到布置在堆空间上的shellcode从而getshell。

/网站渗透 /黑客编程技术
/软件渗透 /提取数据
/网站权限 /网站入侵破解
有需求的找我
@MoA_Ke